commit 5af7724e0d34b1756ab8882de39d5ad09fcc3a9b Author: github-classroom[bot] <66690702+github-classroom[bot]@users.noreply.github.com> Date: Mon Mar 6 13:35:46 2023 +0000 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c64692c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +virtualenv/ \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..f90c17f --- /dev/null +++ b/readme.md @@ -0,0 +1,12 @@ +### Information Modelling & Analysis: Project 1 + +Student: *enter your name here* + +### Project instructions: +Please follow the instructions provided in the project slides. +For your convenience, the source code to be analyzed (xerces2) + has already been added to this repository (*/resources/xerces2-j-src*). + +**Attention**: Please consider the submission instructions available on iCorsi. + +**Report**: You may want to use the template distributed on iCorsi. diff --git a/resources/xerces2-j-src/manifest.xerces b/resources/xerces2-j-src/manifest.xerces new file mode 100644 index 0000000..332a00f --- /dev/null +++ b/resources/xerces2-j-src/manifest.xerces @@ -0,0 +1,119 @@ +Manifest-Version: 1.0 +Created-By: @java.version@ (@java.vendor@) + +Name: org/apache/xerces/impl/ +Comment: @impl.name@ +Implementation-Title: org.apache.xerces.impl.Version +Implementation-Version: @impl.version@ +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xerces.apache.org/xerces2-j/ + +Name: org/xml/sax/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Simple API for XML +Specification-Vendor: David Megginson +Specification-Version: 2.0.2 +Implementation-Title: org.xml.sax +Implementation-Version: 2.0.2 +Implementation-Vendor: David Megginson +Implementation-URL: http://www.saxproject.org/ + +Name: org/w3c/dom/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Document Object Model, Level 3 Core +Specification-Vendor: World Wide Web Consortium +Specification-Version: 1.0 +Implementation-Title: org.w3c.dom +Implementation-Version: 1.0 +Implementation-Vendor: World Wide Web Consortium +Implementation-URL: http://www.w3c.org/DOM/ + +Name: org/w3c/dom/ls/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Document Object Model, Level 3 Load and Save +Specification-Vendor: World Wide Web Consortium +Specification-Version: 1.0 +Implementation-Title: org.w3c.dom.ls +Implementation-Version: 1.0 +Implementation-Vendor: World Wide Web Consortium +Implementation-URL: http://www.w3c.org/DOM/ + +Name: javax/xml/stream/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Streaming API for XML +Specification-Vendor: BEA Systems, Inc. +Specification-Version: 1.0 +Implementation-Title: javax.xml.stream +Implementation-Version: 1.4.01 +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xml.apache.org/commons/ + +Name: javax/xml/datatype/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Java API for XML Processing +Specification-Version: 1.4 +Specification-Vendor: Sun Microsystems Inc. +Implementation-Title: javax.xml.datatype +Implementation-Version: 1.4.01 +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xml.apache.org/commons/ + +Name: javax/xml/namespace/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Java API for XML Processing +Specification-Version: 1.4 +Specification-Vendor: Sun Microsystems Inc. +Implementation-Title: javax.xml.namespace +Implementation-Version: 1.4.01 +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xml.apache.org/commons/ + +Name: javax/xml/parsers/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Java API for XML Processing +Specification-Version: 1.4 +Specification-Vendor: Sun Microsystems Inc. +Implementation-Title: javax.xml.parsers +Implementation-Version: 1.4.01 +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xml.apache.org/commons/ + +Name: javax/xml/transform/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Java API for XML Processing +Specification-Version: 1.4 +Specification-Vendor: Sun Microsystems Inc. +Implementation-Title: javax.xml.transform +Implementation-Version: 1.4.01 +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xml.apache.org/commons/ + +Name: javax/xml/validation/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Java API for XML Processing +Specification-Version: 1.4 +Specification-Vendor: Sun Microsystems Inc. +Implementation-Title: javax.xml.validation +Implementation-Version: 1.4.01 +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xml.apache.org/commons/ + +Name: javax/xml/xpath/ +Comment: based on xml-commons external 1.4.01 +Specification-Title: Java API for XML Processing +Specification-Version: 1.4 +Specification-Vendor: Sun Microsystems Inc. +Implementation-Title: javax.xml.xpath +Implementation-Version: 1.4.01 +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xml.apache.org/commons/ + +Name: org/apache/xerces/xni/ +Comment: Xerces Native Interface +Specification-Title: Xerces Native Interface +Specification-Version: 1.2 +Specification-Vendor: Apache Software Foundation +Implementation-Title: org.apache.xerces.xni +Implementation-Version: 1.2 +Implementation-Vendor: Apache Software Foundation +Implementation-URL: http://xerces.apache.org/xerces2-j/ diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLAnchorElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLAnchorElementImpl.java new file mode 100644 index 0000000..69a1c95 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLAnchorElementImpl.java @@ -0,0 +1,210 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLAnchorElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLAnchorElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLAnchorElementImpl + extends HTMLElementImpl + implements HTMLAnchorElement +{ + private static final long serialVersionUID = -140558580924061847L; + + public String getAccessKey() + { + String accessKey; + + // Make sure that the access key is a single character. + accessKey = getAttribute( "accesskey" ); + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + return accessKey; + } + + + public void setAccessKey( String accessKey ) + { + // Make sure that the access key is a single character. + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + setAttribute( "accesskey", accessKey ); + } + + + public String getCharset() + { + return getAttribute( "charset" ); + } + + + public void setCharset( String charset ) + { + setAttribute( "charset", charset ); + } + + + public String getCoords() + { + return getAttribute( "coords" ); + } + + + public void setCoords( String coords ) + { + setAttribute( "coords", coords ); + } + + + public String getHref() + { + return getAttribute( "href" ); + } + + + public void setHref( String href ) + { + setAttribute( "href", href ); + } + + + public String getHreflang() + { + return getAttribute( "hreflang" ); + } + + + public void setHreflang( String hreflang ) + { + setAttribute( "hreflang", hreflang ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public String getRel() + { + return getAttribute( "rel" ); + } + + + public void setRel( String rel ) + { + setAttribute( "rel", rel ); + } + + + public String getRev() + { + return getAttribute( "rev" ); + } + + + public void setRev( String rev ) + { + setAttribute( "rev", rev ); + } + + + public String getShape() + { + return capitalize( getAttribute( "shape" ) ); + } + + + public void setShape( String shape ) + { + setAttribute( "shape", shape ); + } + + + public int getTabIndex() + { + return this.getInteger( getAttribute( "tabindex" ) ); + } + + + public void setTabIndex( int tabIndex ) + { + setAttribute( "tabindex", String.valueOf( tabIndex ) ); + } + + + public String getTarget() + { + return getAttribute( "target" ); + } + + + public void setTarget( String target ) + { + setAttribute( "target", target ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + public void blur() + { + // No scripting in server-side DOM. This method is moot. + } + + public void focus() + { + // No scripting in server-side DOM. This method is moot. + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLAnchorElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLAppletElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLAppletElementImpl.java new file mode 100644 index 0000000..855732a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLAppletElementImpl.java @@ -0,0 +1,178 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLAppletElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLAppletElement + * @see HTMLElementImpl + */ +public class HTMLAppletElementImpl + extends HTMLElementImpl + implements HTMLAppletElement +{ + + private static final long serialVersionUID = 8375794094117740967L; + + public String getAlign() + { + return getAttribute( "align" ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getAlt() + { + return getAttribute( "alt" ); + } + + + public void setAlt( String alt ) + { + setAttribute( "alt", alt ); + } + + + public String getArchive() + { + return getAttribute( "archive" ); + } + + + public void setArchive( String archive ) + { + setAttribute( "archive", archive ); + } + + + public String getCode() + { + return getAttribute( "code" ); + } + + + public void setCode( String code ) + { + setAttribute( "code", code ); + } + + + public String getCodeBase() + { + return getAttribute( "codebase" ); + } + + + public void setCodeBase( String codeBase ) + { + setAttribute( "codebase", codeBase ); + } + + + public String getHeight() + { + return getAttribute( "height" ); + } + + + public void setHeight( String height ) + { + setAttribute( "height", height ); + } + + + public String getHspace() + { + return getAttribute( "height" ); + } + + + public void setHspace( String height ) + { + setAttribute( "height", height ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public String getObject() + { + return getAttribute( "object" ); + } + + + public void setObject( String object ) + { + setAttribute( "object", object ); + } + + + public String getVspace() + { + return getAttribute( "vspace" ); + } + + + public void setVspace( String vspace ) + { + setAttribute( "vspace", vspace ); + } + + + public String getWidth() + { + return getAttribute( "width" ); + } + + + public void setWidth( String width ) + { + setAttribute( "width", width ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLAppletElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLAreaElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLAreaElementImpl.java new file mode 100644 index 0000000..b4c6d20 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLAreaElementImpl.java @@ -0,0 +1,150 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLAreaElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLAreaElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLAreaElementImpl + extends HTMLElementImpl + implements HTMLAreaElement +{ + + private static final long serialVersionUID = 7164004431531608995L; + + public String getAccessKey() + { + String accessKey; + + // Make sure that the access key is a single character. + accessKey = getAttribute( "accesskey" ); + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + return accessKey; + } + + + public void setAccessKey( String accessKey ) + { + // Make sure that the access key is a single character. + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + setAttribute( "accesskey", accessKey ); + } + + + public String getAlt() + { + return getAttribute( "alt" ); + } + + + public void setAlt( String alt ) + { + setAttribute( "alt", alt ); + } + + public String getCoords() + { + return getAttribute( "coords" ); + } + + + public void setCoords( String coords ) + { + setAttribute( "coords", coords ); + } + + + public String getHref() + { + return getAttribute( "href" ); + } + + + public void setHref( String href ) + { + setAttribute( "href", href ); + } + + + public boolean getNoHref() + { + return getBinary( "nohref" ); + } + + + public void setNoHref( boolean noHref ) + { + setAttribute( "nohref", noHref ); + } + + + public String getShape() + { + return capitalize( getAttribute( "shape" ) ); + } + + + public void setShape( String shape ) + { + setAttribute( "shape", shape ); + } + + + public int getTabIndex() + { + return getInteger( getAttribute( "tabindex" ) ); + } + + + public void setTabIndex( int tabIndex ) + { + setAttribute( "tabindex", String.valueOf( tabIndex ) ); + } + + + public String getTarget() + { + return getAttribute( "target" ); + } + + + public void setTarget( String target ) + { + setAttribute( "target", target ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLAreaElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLBRElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLBRElementImpl.java new file mode 100644 index 0000000..e163ac9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLBRElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLBRElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLBRElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLBRElementImpl + extends HTMLElementImpl + implements HTMLBRElement +{ + + private static final long serialVersionUID = 311960206282154750L; + + public String getClear() + { + return capitalize( getAttribute( "clear" ) ); + } + + + public void setClear( String clear ) + { + setAttribute( "clear", clear ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLBRElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLBaseElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLBaseElementImpl.java new file mode 100644 index 0000000..40039fc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLBaseElementImpl.java @@ -0,0 +1,70 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLBaseElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLBaseElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLBaseElementImpl + extends HTMLElementImpl + implements HTMLBaseElement +{ + + private static final long serialVersionUID = -396648580810072153L; + + public String getHref() + { + return getAttribute( "href" ); + } + + + public void setHref( String href ) + { + setAttribute( "href", href ); + } + + public String getTarget() + { + return getAttribute( "target" ); + } + + + public void setTarget( String target ) + { + setAttribute( "target", target ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLBaseElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLBaseFontElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLBaseFontElementImpl.java new file mode 100644 index 0000000..af9de29 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLBaseFontElementImpl.java @@ -0,0 +1,83 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLBaseFontElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLBaseFontElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLBaseFontElementImpl + extends HTMLElementImpl + implements HTMLBaseFontElement +{ + + private static final long serialVersionUID = -3650249921091097229L; + + public String getColor() + { + return capitalize( getAttribute( "color" ) ); + } + + + public void setColor( String color ) + { + setAttribute( "color", color ); + } + + + public String getFace() + { + return capitalize( getAttribute( "face" ) ); + } + + + public void setFace( String face ) + { + setAttribute( "face", face ); + } + + + public String getSize() + { + return getAttribute( "size" ); + } + + + public void setSize( String size ) + { + setAttribute( "size", size ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLBaseFontElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLBodyElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLBodyElementImpl.java new file mode 100644 index 0000000..32e41b2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLBodyElementImpl.java @@ -0,0 +1,119 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLBodyElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLBodyElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLBodyElementImpl + extends HTMLElementImpl + implements HTMLBodyElement +{ + + private static final long serialVersionUID = 9058852459426595202L; + + public String getALink() + { + return getAttribute( "alink" ); + } + + + public void setALink(String aLink) + { + setAttribute( "alink", aLink ); + } + + + public String getBackground() + { + return getAttribute( "background" ); + } + + + public void setBackground( String background ) + { + setAttribute( "background", background ); + } + + + public String getBgColor() + { + return getAttribute( "bgcolor" ); + } + + + public void setBgColor(String bgColor) + { + setAttribute( "bgcolor", bgColor ); + } + + + public String getLink() + { + return getAttribute( "link" ); + } + + + public void setLink(String link) + { + setAttribute( "link", link ); + } + + + public String getText() + { + return getAttribute( "text" ); + } + + + public void setText(String text) + { + setAttribute( "text", text ); + } + + + public String getVLink() + { + return getAttribute( "vlink" ); + } + + + public void setVLink(String vLink) + { + setAttribute( "vlink", vLink ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLBodyElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLBuilder.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLBuilder.java new file mode 100644 index 0000000..1ceee2a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLBuilder.java @@ -0,0 +1,227 @@ +/* + * 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. + */ +package org.apache.html.dom; + + +import java.util.Vector; + +import org.apache.xerces.dom.ElementImpl; +import org.apache.xerces.dom.ProcessingInstructionImpl; +import org.w3c.dom.Node; +import org.w3c.dom.html.HTMLDocument; +import org.xml.sax.AttributeList; +import org.xml.sax.DocumentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; + + +/** + * This is a SAX document handler that is used to build an HTML document. + * It can build a document from any SAX parser, but is specifically tuned + * for working with the OpenXML HTML parser. + * + * + * @version $Revision$ $Date$ + * @author Assaf Arkin + */ +public class HTMLBuilder + implements DocumentHandler +{ + + + /** + * The document that is being built. + */ + protected HTMLDocumentImpl _document; + + + /** + * The current node in the document into which elements, text and + * other nodes will be inserted. This starts as the document itself + * and reflects each element that is currently being parsed. + */ + protected ElementImpl _current; + + + /** + * Applies only to whitespace appearing between element tags in element content, + * as per the SAX definition, and true by default. + */ + private boolean _ignoreWhitespace = true; + + + /** + * Indicates whether finished building a document. If so, can start building + * another document. Must be initially true to get the first document processed. + */ + private boolean _done = true; + + + /** + * The document is only created the same time as the document element, however, certain + * nodes may precede the document element (comment and PI), and they are accumulated + * in this vector. + */ + protected Vector _preRootNodes; + + + public void startDocument() + throws SAXException + { + if ( ! _done ) + throw new SAXException( "HTM001 State error: startDocument fired twice on one builder." ); + _document = null; + _done = false; + } + + + public void endDocument() + throws SAXException + { + if ( _document == null ) + throw new SAXException( "HTM002 State error: document never started or missing document element." ); + if ( _current != null ) + throw new SAXException( "HTM003 State error: document ended before end of document element." ); + _current = null; + _done = true; + } + + + public synchronized void startElement( String tagName, AttributeList attrList ) + throws SAXException + { + ElementImpl elem; + int i; + + if ( tagName == null ) + throw new SAXException( "HTM004 Argument 'tagName' is null." ); + + // If this is the root element, this is the time to create a new document, + // because only know we know the document element name and namespace URI. + if ( _document == null ) + { + // No need to create the element explicitly. + _document = new HTMLDocumentImpl(); + elem = (ElementImpl) _document.getDocumentElement(); + _current = elem; + if ( _current == null ) + throw new SAXException( "HTM005 State error: Document.getDocumentElement returns null." ); + + // Insert nodes (comment and PI) that appear before the root element. + if ( _preRootNodes != null ) + { + for ( i = _preRootNodes.size() ; i-- > 0 ; ) + _document.insertBefore( (Node) _preRootNodes.elementAt( i ), elem ); + _preRootNodes = null; + } + + } + else + { + // This is a state error, indicates that document has been parsed in full, + // or that there are two root elements. + if ( _current == null ) + throw new SAXException( "HTM006 State error: startElement called after end of document element." ); + elem = (ElementImpl) _document.createElement( tagName ); + _current.appendChild( elem ); + _current = elem; + } + + // Add the attributes (specified and not-specified) to this element. + if ( attrList != null ) + { + for ( i = 0 ; i < attrList.getLength() ; ++ i ) + elem.setAttribute( attrList.getName( i ), attrList.getValue( i ) ); + } + } + + + public void endElement( String tagName ) + throws SAXException + { + if ( _current == null ) + throw new SAXException( "HTM007 State error: endElement called with no current node." ); + if ( ! _current.getNodeName().equalsIgnoreCase( tagName )) + throw new SAXException( "HTM008 State error: mismatch in closing tag name " + tagName + "\n" + tagName); + + // Move up to the parent element. When you reach the top (closing the root element). + // the parent is document and current is null. + if ( _current.getParentNode() == _current.getOwnerDocument() ) + _current = null; + else + _current = (ElementImpl) _current.getParentNode(); + } + + + public void characters( String text ) + throws SAXException + { + if ( _current == null ) + throw new SAXException( "HTM009 State error: character data found outside of root element." ); + _current.appendChild( _document.createTextNode(text) ); + } + + + public void characters( char[] text, int start, int length ) + throws SAXException + { + if ( _current == null ) + throw new SAXException( "HTM010 State error: character data found outside of root element." ); + _current.appendChild( _document.createTextNode(new String(text, start, length)) ); + } + + + public void ignorableWhitespace( char[] text, int start, int length ) + throws SAXException + { + if ( ! _ignoreWhitespace ) + _current.appendChild( _document.createTextNode(new String(text, start, length)) ); + } + + + public void processingInstruction( String target, String instruction ) + throws SAXException + { + // Processing instruction may appear before the document element (in fact, before the + // document has been created, or after the document element has been closed. + if ( _current == null && _document == null ) + { + if ( _preRootNodes == null ) + _preRootNodes = new Vector(); + _preRootNodes.addElement( new ProcessingInstructionImpl( null, target, instruction ) ); + } + else + if ( _current == null && _document != null ) + _document.appendChild( _document.createProcessingInstruction(target, instruction) ); + else + _current.appendChild( _document.createProcessingInstruction(target, instruction) ); + } + + + public HTMLDocument getHTMLDocument() + { + return _document; + } + + + public void setDocumentLocator( Locator locator ) + { + // ignored + } + + +} diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLButtonElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLButtonElementImpl.java new file mode 100644 index 0000000..fd2738e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLButtonElementImpl.java @@ -0,0 +1,129 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLButtonElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLButtonElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLButtonElementImpl + extends HTMLElementImpl + implements HTMLButtonElement, HTMLFormControl +{ + + private static final long serialVersionUID = -753685852948076730L; + + public String getAccessKey() + { + String accessKey; + + // Make sure that the access key is a single character. + accessKey = getAttribute( "accesskey" ); + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + return accessKey; + } + + + public void setAccessKey( String accessKey ) + { + // Make sure that the access key is a single character. + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + setAttribute( "accesskey", accessKey ); + } + + + public boolean getDisabled() + { + return getBinary( "disabled" ); + } + + + public void setDisabled( boolean disabled ) + { + setAttribute( "disabled", disabled ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public int getTabIndex() + { + try + { + return Integer.parseInt( getAttribute( "tabindex" ) ); + } + catch ( NumberFormatException except ) + { + return 0; + } + } + + + public void setTabIndex( int tabIndex ) + { + setAttribute( "tabindex", String.valueOf( tabIndex ) ); + } + + + public String getType() + { + return capitalize( getAttribute( "type" ) ); + } + + + public String getValue() + { + return getAttribute( "value" ); + } + + + public void setValue( String value ) + { + setAttribute( "value", value ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLButtonElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLCollectionImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLCollectionImpl.java new file mode 100644 index 0000000..b69bf00 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLCollectionImpl.java @@ -0,0 +1,536 @@ +/* + * 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. + */ + +package org.apache.html.dom; + +import java.io.Serializable; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.html.HTMLAnchorElement; +import org.w3c.dom.html.HTMLAppletElement; +import org.w3c.dom.html.HTMLAreaElement; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLFormElement; +import org.w3c.dom.html.HTMLImageElement; +import org.w3c.dom.html.HTMLObjectElement; +import org.w3c.dom.html.HTMLOptionElement; +import org.w3c.dom.html.HTMLTableCellElement; +import org.w3c.dom.html.HTMLTableRowElement; +import org.w3c.dom.html.HTMLTableSectionElement; + +/** + * Implements {@link org.w3c.dom.html.HTMLCollection} to traverse any named + * elements on a {@link org.w3c.dom.html.HTMLDocument}. The elements type to + * look for is identified in the constructor by code. This collection is not + * optimized for traversing large trees. + *

+ * The collection has to meet two requirements: it has to be live, and it has + * to traverse depth first and always return results in that order. As such, + * using an object container (such as {@link java.util.Vector}) is expensive on + * insert/remove operations. Instead, the collection has been implemented using + * three traversing functions. As a result, operations on large documents will + * result in traversal of the entire document tree and consume a considerable + * amount of time. + *

+ * Note that synchronization on the traversed document cannot be achieved. + * The document itself cannot be locked, and locking each traversed node is + * likely to lead to a dead lock condition. Therefore, there is a chance of the + * document being changed as results are fetched; in all likelihood, the results + * might be out dated, but not erroneous. + * + * @xerces.internal + * + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLCollection + */ +class HTMLCollectionImpl + implements HTMLCollection, Serializable +{ + + private static final long serialVersionUID = 9112122196669185082L; + + /** + * Request collection of all anchors in document: <A> elements that + * have a name attribute. + */ + static final short ANCHOR = 1; + + + /** + * Request collection of all forms in document: <FORM> elements. + */ + static final short FORM = 2; + + + /** + * Request collection of all images in document: <IMG> elements. + */ + static final short IMAGE = 3; + + + /** + * Request collection of all Applets in document: <APPLET> and + * <OBJECT> elements (<OBJECT> must contain an Applet). + */ + static final short APPLET = 4; + + + /** + * Request collection of all links in document: <A> and <AREA> + * elements (must have a href attribute). + */ + static final short LINK = 5; + + + /** + * Request collection of all options in selection: <OPTION> elements in + * <SELECT> or <OPTGROUP>. + */ + static final short OPTION = 6; + + + /** + * Request collection of all rows in table: <TR> elements in table or + * table section. + */ + static final short ROW = 7; + + + /** + * Request collection of all form elements: <INPUT>, <BUTTON>, + * <SELECT>, and <TEXTAREA> elements inside form <FORM>. + */ + static final short ELEMENT = 8; + + + /** + * Request collection of all areas in map: <AREA> element in <MAP> + * (non recursive). + */ + static final short AREA = -1; + + + /** + * Request collection of all table bodies in table: <TBODY> element in + * table <TABLE> (non recursive). + */ + static final short TBODY = -2; + + + /** + * Request collection of all cells in row: <TD> and <TH> + * elements in <TR> (non recursive). + */ + static final short CELL = -3; + + + /** + * Indicates what this collection is looking for. Holds one of the enumerated + * values and used by {@link #collectionMatch}. Set by the constructor and + * determine the collection's use for its life time. + */ + private short _lookingFor; + + + /** + * This is the top level element underneath which the collection exists. + */ + private Element _topLevel; + + + /** + * Construct a new collection that retrieves element of the specific type + * (lookingFor) from the specific document portion + * (topLevel). + * + * @param topLevel The element underneath which the collection exists + * @param lookingFor Code indicating what elements to look for + */ + HTMLCollectionImpl( HTMLElement topLevel, short lookingFor ) + { + if ( topLevel == null ) + throw new NullPointerException( "HTM011 Argument 'topLevel' is null." ); + _topLevel = topLevel; + _lookingFor = lookingFor; + } + + + /** + * Returns the length of the collection. This method might traverse the + * entire document tree. + * + * @return Length of the collection + */ + public final int getLength() + { + // Call recursive function on top-level element. + return getLength( _topLevel ); + } + + + /** + * Retrieves the indexed node from the collection. Nodes are numbered in + * tree order - depth-first traversal order. This method might traverse + * the entire document tree. + * + * @param index The index of the node to return + * @return The specified node or null if no such node found + */ + public final Node item( int index ) + { + if ( index < 0 ) + throw new IllegalArgumentException( "HTM012 Argument 'index' is negative." ); + // Call recursive function on top-level element. + return item( _topLevel, new CollectionIndex( index ) ); + } + + + /** + * Retrieves the named node from the collection. The name is matched case + * sensitive against the id attribute of each element in the + * collection, returning the first match. The tree is traversed in + * depth-first order. This method might traverse the entire document tree. + * + * @param name The name of the node to return + * @return The specified node or null if no such node found + */ + public final Node namedItem( String name ) + { + if ( name == null ) + throw new NullPointerException( "HTM013 Argument 'name' is null." ); + // Call recursive function on top-level element. + return namedItem( _topLevel, name ); + } + + + /** + * Recursive function returns the number of elements of a particular type + * that exist under the top level element. This is a recursive function + * and the top level element is passed along. + * + * @param topLevel Top level element from which to scan + * @return Number of elements + */ + private int getLength( Element topLevel ) + { + int length; + Node node; + + synchronized ( topLevel ) + { + // Always count from zero and traverse all the childs of the + // current element in the order they appear. + length = 0; + node = topLevel.getFirstChild(); + while ( node != null ) + { + // If a particular node is an element (could be HTML or XML), + // do two things: if it's the one we're looking for, count + // another matched element; at any rate, traverse it's + // children as well. + if ( node instanceof Element ) + { + if ( collectionMatch( (Element) node, null ) ) + ++ length; + else if ( recurse() ) + length += getLength( (Element) node ); + } + node = node.getNextSibling(); + } + } + return length; + } + + + /** + * Recursive function returns the numbered element of a particular type + * that exist under the top level element. This is a recursive function + * and the top level element is passed along. + *

+ * Note that this function must call itself with an index and get back both + * the element (if one was found) and the new index which is decremeneted + * for any like element found. Since integers are only passed by value, + * this function makes use of a separate class ({@link CollectionIndex}) + * to hold that index. + * + * @param topLevel Top level element from which to scan + * @param index The index of the item to retreive + * @return Number of elements + * @see CollectionIndex + */ + private Node item( Element topLevel, CollectionIndex index ) + { + Node node; + Node result; + + synchronized ( topLevel ) + { + // Traverse all the childs of the current element in the order + // they appear. Count from the index backwards until you reach + // matching element with an index of zero. Return that element. + node = topLevel.getFirstChild(); + while ( node != null ) + { + // If a particular node is an element (could be HTML or XML), + // do two things: if it's the one we're looking for, decrease + // the index and if zero, return this node; at any rate, + // traverse it's children as well. + if ( node instanceof Element ) + { + if ( collectionMatch( (Element) node, null ) ) + { + if ( index.isZero() ) + return node; + index.decrement(); + } else if ( recurse() ) + { + result = item( (Element) node, index ); + if ( result != null ) + return result; + } + } + node = node.getNextSibling(); + } + } + return null; + } + + + /** + * Recursive function returns an element of a particular type with the + * specified name (id attribute). + * + * @param topLevel Top level element from which to scan + * @param name The named element to look for + * @return The first named element found + */ + private Node namedItem( Element topLevel, String name ) + { + Node node; + Node result; + + synchronized ( topLevel ) + { + // Traverse all the childs of the current element in the order + // they appear. + node = topLevel.getFirstChild(); + while ( node != null ) + { + // If a particular node is an element (could be HTML or XML), + // do two things: if it's the one we're looking for, and the + // name (id attribute) attribute is the one we're looking for, + // return this element; otherwise, traverse it's children. + if ( node instanceof Element ) + { + if ( collectionMatch( (Element) node, name ) ) + return node; + else if ( recurse() ) + { + result = namedItem( (Element) node, name ); + if ( result != null ) + return result; + } + } + node = node.getNextSibling(); + } + return node; + } + } + + + /** + * Returns true if scanning methods should iterate through the collection. + * When looking for elements in the document, recursing is needed to traverse + * the full document tree. When looking inside a specific element (e.g. for a + * cell inside a row), recursing can lead to erroneous results. + * + * @return True if methods should recurse to traverse entire tree + */ + protected boolean recurse() + { + return _lookingFor > 0; + } + + + /** + * Determines if current element matches based on what we're looking for. + * The element is passed along with an optional identifier name. If the + * element is the one we're looking for, return true. If the name is also + * specified, the name must match the id attribute + * (match name first for anchors). + * + * @param elem The current element + * @param name The identifier name or null + * @return The element matches what we're looking for + */ + protected boolean collectionMatch( Element elem, String name ) + { + boolean match; + + synchronized ( elem ) + { + // Begin with no matching. Depending on what we're looking for, + // attempt to match based on the element type. This is the quickest + // way to match involving only a cast. Do the expensive string + // comparison later on. + match = false; + switch ( _lookingFor ) + { + case ANCHOR: + // Anchor is an element with a 'name' attribute. Otherwise, it's + // just a link. + match = ( elem instanceof HTMLAnchorElement ) && + elem.getAttribute( "name" ).length() > 0; + break; + case FORM: + // Any

element. + match = ( elem instanceof HTMLFormElement ); + break; + case IMAGE: + // Any element. elements with images are not returned. + match = ( elem instanceof HTMLImageElement ); + break; + case APPLET: + // Any element, and any element which represents an + // Applet. This is determined by 'codetype' attribute being + // 'application/java' or 'classid' attribute starting with 'java:'. + match = ( elem instanceof HTMLAppletElement ) || + ( elem instanceof HTMLObjectElement && + ( "application/java".equals( elem.getAttribute( "codetype" ) ) || + elem.getAttribute( "classid" ).startsWith( "java:" ) ) ); + break; + case ELEMENT: + // All form elements implement HTMLFormControl for easy identification. + match = ( elem instanceof HTMLFormControl ); + break; + case LINK: + // Any element, and any elements with an 'href' attribute. + match = ( ( elem instanceof HTMLAnchorElement || + elem instanceof HTMLAreaElement ) && + elem.getAttribute( "href" ).length() > 0 ); + break; + case AREA: + // Any element. + match = ( elem instanceof HTMLAreaElement ); + break; + case OPTION: + // Any elements for backward compatibility. + if ( match && name != null ) + { + // If an anchor and 'name' attribute matches, return true. Otherwise, + // try 'id' attribute. + if ( elem instanceof HTMLAnchorElement && + name.equals( elem.getAttribute( "name" ) ) ) + return true; + match = name.equals( elem.getAttribute( "id" ) ); + } + } + return match; + } + + +} + + +/** + * {@link CollectionImpl#item} must traverse down the tree and decrement the + * index until it matches an element who's index is zero. Since integers are + * passed by value, this class servers to pass the index into each recursion + * by reference. It encompasses all the operations that need be performed on + * the index, although direct access is possible. + * + * @xerces.internal + * + * @see CollectionImpl#item + */ +class CollectionIndex +{ + + + /** + * Returns the current index. + * + * @return Current index + */ + int getIndex() + { + return _index; + } + + + /** + * Decrements the index by one. + */ + void decrement() + { + -- _index; + } + + + /** + * Returns true if index is zero (or negative). + * + * @return True if index is zero + */ + boolean isZero() + { + return _index <= 0; + } + + + /** + * Constructs a new index with the specified initial value. The index will + * then be decremeneted until it reaches zero. + * + * @param index The initial value + */ + CollectionIndex( int index ) + { + _index = index; + } + + + /** + * Holds the actual value that is passed by reference using this class. + */ + private int _index; + + +} diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLDListElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLDListElementImpl.java new file mode 100644 index 0000000..1174c83 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLDListElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLDListElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLDListElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLDListElementImpl + extends HTMLElementImpl + implements HTMLDListElement +{ + + private static final long serialVersionUID = -2130005642453038604L; + + public boolean getCompact() + { + return getBinary( "compact" ); + } + + + public void setCompact( boolean compact ) + { + setAttribute( "compact", compact ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLDListElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLDOMImplementationImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLDOMImplementationImpl.java new file mode 100644 index 0000000..fb127a1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLDOMImplementationImpl.java @@ -0,0 +1,93 @@ +/* + * 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. + */ +package org.apache.html.dom; + + +import org.apache.xerces.dom.DOMImplementationImpl; +import org.w3c.dom.DOMException; +import org.w3c.dom.html.HTMLDOMImplementation; +import org.w3c.dom.html.HTMLDocument; + + +/** + * Provides number of methods for performing operations that are independent + * of any particular instance of the document object model. This class is + * unconstructable, the only way to obtain an instance of a DOM implementation + * is by calling the static method {@link #getDOMImplementation}. + * + * @xerces.internal + * + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.DOMImplementation + */ +public class HTMLDOMImplementationImpl + extends DOMImplementationImpl + implements HTMLDOMImplementation +{ + + + /** + * Holds a reference to the single instance of the DOM implementation. + * Only one instance is required since this class is multiple entry. + */ + private static final HTMLDOMImplementation _instance = new HTMLDOMImplementationImpl(); + + + /** + * Private constructor assures that an object of this class cannot + * be created. The only way to obtain an object is by calling {@link + * #getDOMImplementation}. + */ + private HTMLDOMImplementationImpl() + { + } + + + /** + * Create a new HTML document of the specified TITLE text. + * + * @param title The document title text + * @return New HTML document + */ + public final HTMLDocument createHTMLDocument( String title ) + throws DOMException + { + HTMLDocument doc; + + if ( title == null ) + throw new NullPointerException( "HTM014 Argument 'title' is null." ); + doc = new HTMLDocumentImpl(); + doc.setTitle( title ); + return doc; + } + + + /** + * Returns an instance of a {@link HTMLDOMImplementation} that can be + * used to perform operations that are not specific to a particular + * document instance, e.g. to create a new document. + * + * @return Reference to a valid DOM implementation + */ + public static HTMLDOMImplementation getHTMLDOMImplementation() + { + return _instance; + } + + +} diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLDirectoryElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLDirectoryElementImpl.java new file mode 100644 index 0000000..b556b89 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLDirectoryElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLDirectoryElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLDirectoryElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLDirectoryElementImpl + extends HTMLElementImpl + implements HTMLDirectoryElement +{ + + private static final long serialVersionUID = -1010376135190194454L; + + public boolean getCompact() + { + return getBinary( "compact" ); + } + + + public void setCompact( boolean compact ) + { + setAttribute( "compact", compact ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLDirectoryElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLDivElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLDivElementImpl.java new file mode 100644 index 0000000..ad781c1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLDivElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLDivElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLDivElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLDivElementImpl + extends HTMLElementImpl + implements HTMLDivElement +{ + + private static final long serialVersionUID = 2327098984177358833L; + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLDivElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLDocumentImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLDocumentImpl.java new file mode 100644 index 0000000..20f484d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLDocumentImpl.java @@ -0,0 +1,788 @@ +/* + * 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. + */ + +package org.apache.html.dom; + +import java.io.StringWriter; +import java.lang.reflect.Constructor; +import java.util.Hashtable; +import java.util.Locale; + +import org.apache.xerces.dom.DocumentImpl; +import org.apache.xerces.dom.ElementImpl; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.html.HTMLBodyElement; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLDocument; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLFrameSetElement; +import org.w3c.dom.html.HTMLHeadElement; +import org.w3c.dom.html.HTMLHtmlElement; +import org.w3c.dom.html.HTMLTitleElement; + +/** + * Implements an HTML document. Provides access to the top level element in the + * document, its body and title. + *

+ * Several methods create new nodes of all basic types (comment, text, element, + * etc.). These methods create new nodes but do not place them in the document + * tree. The nodes may be placed in the document tree using {@link + * org.w3c.dom.Node#appendChild} or {@link org.w3c.dom.Node#insertBefore}, or + * they may be placed in some other document tree. + *

+ * Note: <FRAMESET> documents are not supported at the moment, neither + * are direct document writing ({@link #open}, {@link #write}) and HTTP attribute + * methods ({@link #getURL}, {@link #getCookie}). + * + * @xerces.internal + * + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLDocument + */ +public class HTMLDocumentImpl + extends DocumentImpl + implements HTMLDocument +{ + + private static final long serialVersionUID = 4285791750126227180L; + + /** + * Holds HTMLCollectionImpl object with live collection of all + * anchors in document. This reference is on demand only once. + */ + private HTMLCollectionImpl _anchors; + + + /** + * Holds HTMLCollectionImpl object with live collection of all + * forms in document. This reference is on demand only once. + */ + private HTMLCollectionImpl _forms; + + + /** + * Holds HTMLCollectionImpl object with live collection of all + * images in document. This reference is on demand only once. + */ + private HTMLCollectionImpl _images; + + + /** + * Holds HTMLCollectionImpl object with live collection of all + * links in document. This reference is on demand only once. + */ + private HTMLCollectionImpl _links; + + + /** + * Holds HTMLCollectionImpl object with live collection of all + * applets in document. This reference is on demand only once. + */ + private HTMLCollectionImpl _applets; + + + /** + * Holds string writer used by direct manipulation operation ({@link #open}. + * {@link #write}, etc) to write new contents into the document and parse + * that text into a document tree. + */ + private StringWriter _writer; + + + /** + * Holds names and classes of HTML element types. When an element with a + * particular tag name is created, the matching {@link java.lang.Class} + * is used to create the element object. For example, <A> matches + * {@link HTMLAnchorElementImpl}. This static table is shared across all + * HTML documents. + * + * @see #createElement + */ + private static Hashtable _elementTypesHTML; + + + /** + * Signature used to locate constructor of HTML element classes. This + * static array is shared across all HTML documents. + * + * @see #createElement + */ + private static final Class[] _elemClassSigHTML = + new Class[] { HTMLDocumentImpl.class, String.class }; + + + /** + */ + public HTMLDocumentImpl() + { + super(); + populateElementTypes(); + } + + + public synchronized Element getDocumentElement() + { + Node html; + Node child; + Node next; + + // The document element is the top-level HTML element of the HTML + // document. Only this element should exist at the top level. + // If the HTML element is found, all other elements that might + // precede it are placed inside the HTML element. + html = getFirstChild(); + while ( html != null ) + { + if ( html instanceof HTMLHtmlElement ) + { + // REVISIT: [Q] Why is this code even here? In fact, the + // original code is in error because it will + // try to move ALL nodes to be children of the + // HTML tag. This is not the intended behavior + // for comments and processing instructions + // outside the root element; it will throw a + // hierarchy request error exception for doctype + // nodes; *and* this code shouldn't even be + // needed because the parser should never build + // a document that contains more than a single + // root element, anyway! -Ac + /*** + synchronized ( html ) + { + child = getFirstChild(); + while ( child != null && child != html ) + { + next = child.getNextSibling(); + html.appendChild( child ); + child = next; + } + } + /***/ + return (HTMLElement) html; + } + html = html.getNextSibling(); + } + + // HTML element must exist. Create a new element and dump the + // entire contents of the document into it in the same order as + // they appear now. + html = new HTMLHtmlElementImpl( this, "HTML" ); + child = getFirstChild(); + while ( child != null ) + { + next = child.getNextSibling(); + html.appendChild( child ); + child = next; + } + appendChild( html ); + return (HTMLElement) html; + } + + + /** + * Obtains the <HEAD> element in the document, creating one if does + * not exist before. The <HEAD> element is the first element in the + * <HTML> in the document. The <HTML> element is obtained by + * calling {@link #getDocumentElement}. If the element does not exist, one + * is created. + *

+ * Called by {@link #getTitle}, {@link #setTitle}, {@link #getBody} and + * {@link #setBody} to assure the document has the <HEAD> element + * correctly placed. + * + * @return The <HEAD> element + */ + public synchronized HTMLElement getHead() + { + Node head; + Node html; + Node child; + Node next; + + // Call getDocumentElement() to get the HTML element that is also the + // top-level element in the document. Get the first element in the + // document that is called HEAD. Work with that. + html = getDocumentElement(); + synchronized ( html ) + { + head = html.getFirstChild(); + while ( head != null && ! ( head instanceof HTMLHeadElement ) ) + head = head.getNextSibling(); + // HEAD exists but might not be first element in HTML: make sure + // it is and return it. + if ( head != null ) + { + synchronized ( head ) + { + child = html.getFirstChild(); + while ( child != null && child != head ) + { + next = child.getNextSibling(); + head.insertBefore( child, head.getFirstChild() ); + child = next; + } + } + return (HTMLElement) head; + } + + // Head does not exist, create a new one, place it at the top of the + // HTML element and return it. + head = new HTMLHeadElementImpl( this, "HEAD" ); + html.insertBefore( head, html.getFirstChild() ); + } + return (HTMLElement) head; + } + + + public synchronized String getTitle() + { + HTMLElement head; + NodeList list; + Node title; + + // Get the HEAD element and look for the TITLE element within. + // When found, make sure the TITLE is a direct child of HEAD, + // and return the title's text (the Text node contained within). + head = getHead(); + list = head.getElementsByTagName( "TITLE" ); + if ( list.getLength() > 0 ) { + title = list.item( 0 ); + return ( (HTMLTitleElement) title ).getText(); + } + // No TITLE found, return an empty string. + return ""; + } + + + public synchronized void setTitle( String newTitle ) + { + HTMLElement head; + NodeList list; + Node title; + + // Get the HEAD element and look for the TITLE element within. + // When found, make sure the TITLE is a direct child of HEAD, + // and set the title's text (the Text node contained within). + head = getHead(); + list = head.getElementsByTagName( "TITLE" ); + if ( list.getLength() > 0 ) { + title = list.item( 0 ); + if ( title.getParentNode() != head ) + head.appendChild( title ); + ( (HTMLTitleElement) title ).setText( newTitle ); + } + else + { + // No TITLE found, create a new element and place it at the end + // of the HEAD element. + title = new HTMLTitleElementImpl( this, "TITLE" ); + ( (HTMLTitleElement) title ).setText( newTitle ); + head.appendChild( title ); + } + } + + + public synchronized HTMLElement getBody() + { + Node html; + Node head; + Node body; + Node child; + Node next; + + // Call getDocumentElement() to get the HTML element that is also the + // top-level element in the document. Get the first element in the + // document that is called BODY. Work with that. + html = getDocumentElement(); + head = getHead(); + synchronized ( html ) + { + body = head.getNextSibling(); + while ( body != null && ! ( body instanceof HTMLBodyElement ) + && ! ( body instanceof HTMLFrameSetElement ) ) + body = body.getNextSibling(); + + // BODY/FRAMESET exists but might not be second element in HTML + // (after HEAD): make sure it is and return it. + if ( body != null ) + { + synchronized ( body ) + { + child = head.getNextSibling(); + while ( child != null && child != body ) + { + next = child.getNextSibling(); + body.insertBefore( child, body.getFirstChild() ); + child = next; + } + } + return (HTMLElement) body; + } + + // BODY does not exist, create a new one, place it in the HTML element + // right after the HEAD and return it. + body = new HTMLBodyElementImpl( this, "BODY" ); + html.appendChild( body ); + } + return (HTMLElement) body; + } + + + public synchronized void setBody( HTMLElement newBody ) + { + Node html; + Node body; + Node head; + Node child; + NodeList list; + + synchronized ( newBody ) + { + // Call getDocumentElement() to get the HTML element that is also the + // top-level element in the document. Get the first element in the + // document that is called BODY. Work with that. + html = getDocumentElement(); + head = getHead(); + synchronized ( html ) + { + list = this.getElementsByTagName( "BODY" ); + if ( list.getLength() > 0 ) { + // BODY exists but might not follow HEAD in HTML. If not, + // make it so and replce it. Start with the HEAD and make + // sure the BODY is the first element after the HEAD. + body = list.item( 0 ); + synchronized ( body ) + { + child = head; + while ( child != null ) + { + if ( child instanceof Element ) + { + if ( child != body ) + html.insertBefore( newBody, child ); + else + html.replaceChild( newBody, body ); + return; + } + child = child.getNextSibling(); + } + html.appendChild( newBody ); + } + return; + } + // BODY does not exist, place it in the HTML element + // right after the HEAD. + html.appendChild( newBody ); + } + } + } + + + public synchronized Element getElementById( String elementId ) + { + Element idElement = super.getElementById(elementId); + if (idElement != null) { + return idElement; + } + return getElementById( elementId, this ); + } + + + public NodeList getElementsByName( String elementName ) + { + return new NameNodeListImpl( this, elementName ); + } + + + public final NodeList getElementsByTagName( String tagName ) + { + return super.getElementsByTagName( tagName.toUpperCase(Locale.ENGLISH) ); + } + + + public final NodeList getElementsByTagNameNS( String namespaceURI, + String localName ) + { + if ( namespaceURI != null && namespaceURI.length() > 0 ) { + return super.getElementsByTagNameNS( namespaceURI, localName.toUpperCase(Locale.ENGLISH) ); + } + return super.getElementsByTagName( localName.toUpperCase(Locale.ENGLISH) ); + } + + + /** + * Xerces-specific constructor. "localName" is passed in, so we don't need + * to create a new String for it. + * + * @param namespaceURI The namespace URI of the element to + * create. + * @param qualifiedName The qualified name of the element type to + * instantiate. + * @param localpart The local name of the element to instantiate. + * @return Element A new Element object with the following attributes: + * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified + * name contains an invalid character. + */ + public Element createElementNS(String namespaceURI, String qualifiedName, + String localpart) + throws DOMException + { + return createElementNS(namespaceURI, qualifiedName); + } + + public Element createElementNS( String namespaceURI, String qualifiedName ) + { + if ( namespaceURI == null || namespaceURI.length() == 0 ) { + return createElement( qualifiedName ); + } + return super.createElementNS( namespaceURI, qualifiedName ); + } + + + public Element createElement( String tagName ) + throws DOMException + { + Class elemClass; + Constructor cnst; + + // First, make sure tag name is all upper case, next get the associated + // element class. If no class is found, generate a generic HTML element. + // Do so also if an unexpected exception occurs. + tagName = tagName.toUpperCase(Locale.ENGLISH); + elemClass = (Class) _elementTypesHTML.get( tagName ); + if ( elemClass != null ) + { + // Get the constructor for the element. The signature specifies an + // owner document and a tag name. Use the constructor to instantiate + // a new object and return it. + try + { + cnst = elemClass.getConstructor( _elemClassSigHTML ); + return (Element) cnst.newInstance( new Object[] { this, tagName } ); + } + catch ( Exception except ) + { + /* + Throwable thrw; + + if ( except instanceof java.lang.reflect.InvocationTargetException ) + thrw = ( (java.lang.reflect.InvocationTargetException) except ).getTargetException(); + else + thrw = except; + System.out.println( "Exception " + thrw.getClass().getName() ); + System.out.println( thrw.getMessage() ); + */ + throw new IllegalStateException( "HTM15 Tag '" + tagName + "' associated with an Element class that failed to construct.\n" + tagName); + } + } + return new HTMLElementImpl( this, tagName ); + } + + + /** + * Creates an Attribute having this Document as its OwnerDoc. + * Overrides {@link DocumentImpl#createAttribute} and returns + * and attribute whose name is lower case. + * + * @param name The name of the attribute + * @return An attribute whose name is all lower case + * @throws DOMException(INVALID_NAME_ERR) if the attribute name + * is not acceptable + */ + public Attr createAttribute( String name ) + throws DOMException + { + return super.createAttribute( name.toLowerCase(Locale.ENGLISH) ); + } + + + public String getReferrer() + { + // Information not available on server side. + return null; + } + + + public String getDomain() + { + // Information not available on server side. + return null; + } + + + public String getURL() + { + // Information not available on server side. + return null; + } + + + public String getCookie() + { + // Information not available on server side. + return null; + } + + + public void setCookie( String cookie ) + { + // Information not available on server side. + } + + + public HTMLCollection getImages() + { + // For more information see HTMLCollection#collectionMatch + if ( _images == null ) + _images = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.IMAGE ); + return _images; + } + + + public HTMLCollection getApplets() + { + // For more information see HTMLCollection#collectionMatch + if ( _applets == null ) + _applets = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.APPLET ); + return _applets; + } + + + public HTMLCollection getLinks() + { + // For more information see HTMLCollection#collectionMatch + if ( _links == null ) + _links = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.LINK ); + return _links; + } + + + public HTMLCollection getForms() + { + // For more information see HTMLCollection#collectionMatch + if ( _forms == null ) + _forms = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.FORM ); + return _forms; + } + + + public HTMLCollection getAnchors() + { + // For more information see HTMLCollection#collectionMatch + if ( _anchors == null ) + _anchors = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.ANCHOR ); + return _anchors; + } + + + public void open() + { + // When called an in-memory is prepared. The document tree is still + // accessible the old way, until this writer is closed. + if ( _writer == null ) + _writer = new StringWriter(); + } + + + public void close() + { + // ! NOT IMPLEMENTED, REQUIRES PARSER ! + if ( _writer != null ) + { + _writer = null; + } + } + + + public void write( String text ) + { + // Write a string into the in-memory writer. + if ( _writer != null ) + _writer.write( text ); + } + + + public void writeln( String text ) + { + // Write a line into the in-memory writer. + if ( _writer != null ) + _writer.write( text + "\n" ); + } + + + public Node cloneNode( boolean deep ) + { + HTMLDocumentImpl newdoc = new HTMLDocumentImpl(); + callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED); + cloneNode(newdoc, deep); + return newdoc; + } + + + /* (non-Javadoc) + * @see CoreDocumentImpl#canRenameElements() + */ + protected boolean canRenameElements(String newNamespaceURI, String newNodeName, ElementImpl el) { + if (el.getNamespaceURI() != null) { + // element is not HTML: + // can be renamed if not changed to HTML + return newNamespaceURI != null; + } + + // check whether a class change is required + Class newClass = (Class) _elementTypesHTML.get(newNodeName.toUpperCase(Locale.ENGLISH)); + Class oldClass = (Class) _elementTypesHTML.get(el.getTagName()); + return newClass == oldClass; + } + + + /** + * Recursive method retreives an element by its id attribute. + * Called by {@link #getElementById(String)}. + * + * @param elementId The id value to look for + * @return The node in which to look for + */ + private Element getElementById( String elementId, Node node ) + { + Node child; + Element result; + + child = node.getFirstChild(); + while ( child != null ) + { + if ( child instanceof Element ) + { + if ( elementId.equals( ( (Element) child ).getAttribute( "id" ) ) ) + return (Element) child; + result = getElementById( elementId, child ); + if ( result != null ) + return result; + } + child = child.getNextSibling(); + } + return null; + } + + + /** + * Called by the constructor to populate the element types list (see {@link + * #_elementTypesHTML}). Will be called multiple times but populate the list + * only the first time. Replacement for static constructor. + */ + private synchronized static void populateElementTypes() + { + // This class looks like it is due to some strange + // (read: inconsistent) JVM bugs. + // Initially all this code was placed in the static constructor, + // but that caused some early JVMs (1.1) to go mad, and if a + // class could not be found (as happened during development), + // the JVM would die. + // Bertrand Delacretaz pointed out + // several configurations where HTMLAnchorElementImpl.class + // failed, forcing me to revert back to Class.forName(). + + if ( _elementTypesHTML != null ) + return; + _elementTypesHTML = new Hashtable( 63 ); + populateElementType( "A", "HTMLAnchorElementImpl" ); + populateElementType( "APPLET", "HTMLAppletElementImpl" ); + populateElementType( "AREA", "HTMLAreaElementImpl" ); + populateElementType( "BASE", "HTMLBaseElementImpl" ); + populateElementType( "BASEFONT", "HTMLBaseFontElementImpl" ); + populateElementType( "BLOCKQUOTE", "HTMLQuoteElementImpl" ); + populateElementType( "BODY", "HTMLBodyElementImpl" ); + populateElementType( "BR", "HTMLBRElementImpl" ); + populateElementType( "BUTTON", "HTMLButtonElementImpl" ); + populateElementType( "DEL", "HTMLModElementImpl" ); + populateElementType( "DIR", "HTMLDirectoryElementImpl" ); + populateElementType( "DIV", "HTMLDivElementImpl" ); + populateElementType( "DL", "HTMLDListElementImpl" ); + populateElementType( "FIELDSET", "HTMLFieldSetElementImpl" ); + populateElementType( "FONT", "HTMLFontElementImpl" ); + populateElementType( "FORM", "HTMLFormElementImpl" ); + populateElementType( "FRAME","HTMLFrameElementImpl" ); + populateElementType( "FRAMESET", "HTMLFrameSetElementImpl" ); + populateElementType( "HEAD", "HTMLHeadElementImpl" ); + populateElementType( "H1", "HTMLHeadingElementImpl" ); + populateElementType( "H2", "HTMLHeadingElementImpl" ); + populateElementType( "H3", "HTMLHeadingElementImpl" ); + populateElementType( "H4", "HTMLHeadingElementImpl" ); + populateElementType( "H5", "HTMLHeadingElementImpl" ); + populateElementType( "H6", "HTMLHeadingElementImpl" ); + populateElementType( "HR", "HTMLHRElementImpl" ); + populateElementType( "HTML", "HTMLHtmlElementImpl" ); + populateElementType( "IFRAME", "HTMLIFrameElementImpl" ); + populateElementType( "IMG", "HTMLImageElementImpl" ); + populateElementType( "INPUT", "HTMLInputElementImpl" ); + populateElementType( "INS", "HTMLModElementImpl" ); + populateElementType( "ISINDEX", "HTMLIsIndexElementImpl" ); + populateElementType( "LABEL", "HTMLLabelElementImpl" ); + populateElementType( "LEGEND", "HTMLLegendElementImpl" ); + populateElementType( "LI", "HTMLLIElementImpl" ); + populateElementType( "LINK", "HTMLLinkElementImpl" ); + populateElementType( "MAP", "HTMLMapElementImpl" ); + populateElementType( "MENU", "HTMLMenuElementImpl" ); + populateElementType( "META", "HTMLMetaElementImpl" ); + populateElementType( "OBJECT", "HTMLObjectElementImpl" ); + populateElementType( "OL", "HTMLOListElementImpl" ); + populateElementType( "OPTGROUP", "HTMLOptGroupElementImpl" ); + populateElementType( "OPTION", "HTMLOptionElementImpl" ); + populateElementType( "P", "HTMLParagraphElementImpl" ); + populateElementType( "PARAM", "HTMLParamElementImpl" ); + populateElementType( "PRE", "HTMLPreElementImpl" ); + populateElementType( "Q", "HTMLQuoteElementImpl" ); + populateElementType( "SCRIPT", "HTMLScriptElementImpl" ); + populateElementType( "SELECT", "HTMLSelectElementImpl" ); + populateElementType( "STYLE", "HTMLStyleElementImpl" ); + populateElementType( "TABLE", "HTMLTableElementImpl" ); + populateElementType( "CAPTION", "HTMLTableCaptionElementImpl" ); + populateElementType( "TD", "HTMLTableCellElementImpl" ); + populateElementType( "TH", "HTMLTableCellElementImpl" ); + populateElementType( "COL", "HTMLTableColElementImpl" ); + populateElementType( "COLGROUP", "HTMLTableColElementImpl" ); + populateElementType( "TR", "HTMLTableRowElementImpl" ); + populateElementType( "TBODY", "HTMLTableSectionElementImpl" ); + populateElementType( "THEAD", "HTMLTableSectionElementImpl" ); + populateElementType( "TFOOT", "HTMLTableSectionElementImpl" ); + populateElementType( "TEXTAREA", "HTMLTextAreaElementImpl" ); + populateElementType( "TITLE", "HTMLTitleElementImpl" ); + populateElementType( "UL", "HTMLUListElementImpl" ); + } + + + private static void populateElementType( String tagName, String className ) + { + try { + _elementTypesHTML.put( tagName, + ObjectFactory.findProviderClass("org.apache.html.dom." + className, + HTMLDocumentImpl.class.getClassLoader(), true) ); + } catch ( Exception except ) { + throw new RuntimeException( "HTM019 OpenXML Error: Could not find or execute class " + className + " implementing HTML element " + tagName + + "\n" + className + "\t" + tagName); + } + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLElementImpl.java new file mode 100644 index 0000000..e4f6a80 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLElementImpl.java @@ -0,0 +1,257 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import java.util.Locale; + +import org.apache.xerces.dom.ElementImpl; +import org.w3c.dom.Attr; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLFormElement; + +/** + * Implements an HTML-specific element, an {@link org.w3c.dom.Element} that + * will only appear inside HTML documents. This element extends {@link + * org.apache.xerces.dom.ElementImpl} by adding methods for directly + * manipulating HTML-specific attributes. All HTML elements gain access to + * the id, title, lang, + * dir and class attributes. Other elements + * add their own specific attributes. + * + * @xerces.internal + * + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLElement + */ +public class HTMLElementImpl + extends ElementImpl + implements HTMLElement +{ + + private static final long serialVersionUID = 5283925246324423495L; + + /** + * Constructor required owner document and element tag name. Will be called + * by the constructor of specific element types but with a known tag name. + * Assures that the owner document is an HTML element. + * + * @param owner The owner HTML document + * @param tagName The element's tag name + */ + public HTMLElementImpl( HTMLDocumentImpl owner, String tagName ) { + super( owner, tagName.toUpperCase(Locale.ENGLISH) ); + } + + public String getId() { + return getAttribute( "id" ); + } + + public void setId( String id ) { + setAttribute( "id", id ); + } + + public String getTitle() { + return getAttribute( "title" ); + } + + public void setTitle( String title ) { + setAttribute( "title", title ); + } + + public String getLang() { + return getAttribute( "lang" ); + } + + public void setLang( String lang ) { + setAttribute( "lang", lang ); + } + + public String getDir() { + return getAttribute( "dir" ); + } + + public void setDir( String dir ) { + setAttribute( "dir", dir ); + } + + public String getClassName() { + return getAttribute( "class" ); + } + + public void setClassName( String className ) { + setAttribute( "class", className ); + } + + /** + * Convenience method used to translate an attribute value into an integer + * value. Returns the integer value or zero if the attribute is not a + * valid numeric string. + * + * @param value The value of the attribute + * @return The integer value, or zero if not a valid numeric string + */ + int getInteger( String value ) { + try { + return Integer.parseInt( value ); + } + catch ( NumberFormatException except ) { + return 0; + } + } + + /** + * Convenience method used to translate an attribute value into a boolean + * value. If the attribute has an associated value (even an empty string), + * it is set and true is returned. If the attribute does not exist, false + * is returend. + * + * @param value The value of the attribute + * @return True or false depending on whether the attribute has been set + */ + boolean getBinary( String name ) { + return ( getAttributeNode( name ) != null ); + } + + /** + * Convenience method used to set a boolean attribute. If the value is true, + * the attribute is set to an empty string. If the value is false, the attribute + * is removed. HTML 4.0 understands empty strings as set attributes. + * + * @param name The name of the attribute + * @param value The value of the attribute + */ + void setAttribute( String name, boolean value ) { + if ( value ) { + setAttribute( name, name ); + } + else { + removeAttribute( name ); + } + } + + public Attr getAttributeNode( String attrName ) { + return super.getAttributeNode( attrName.toLowerCase(Locale.ENGLISH) ); + } + + public Attr getAttributeNodeNS( String namespaceURI, + String localName ) { + if ( namespaceURI != null && namespaceURI.length() > 0 ) { + return super.getAttributeNodeNS( namespaceURI, localName ); + } + return super.getAttributeNode( localName.toLowerCase(Locale.ENGLISH) ); + } + + public String getAttribute( String attrName ) { + return super.getAttribute( attrName.toLowerCase(Locale.ENGLISH) ); + } + + public String getAttributeNS( String namespaceURI, + String localName ) { + if ( namespaceURI != null && namespaceURI.length() > 0 ) { + return super.getAttributeNS( namespaceURI, localName ); + } + return super.getAttribute( localName.toLowerCase(Locale.ENGLISH) ); + } + + public final NodeList getElementsByTagName( String tagName ) { + return super.getElementsByTagName( tagName.toUpperCase(Locale.ENGLISH) ); + } + + public final NodeList getElementsByTagNameNS( String namespaceURI, + String localName ) { + if ( namespaceURI != null && namespaceURI.length() > 0 ) { + return super.getElementsByTagNameNS( namespaceURI, localName.toUpperCase(Locale.ENGLISH) ); + } + return super.getElementsByTagName( localName.toUpperCase(Locale.ENGLISH) ); + } + + /** + * Convenience method used to capitalize a one-off attribute value before it + * is returned. For example, the align values "LEFT" and "left" will both + * return as "Left". + * + * @param value The value of the attribute + * @return The capitalized value + */ + String capitalize( String value ) { + + char[] chars; + int i; + + // Convert string to charactares. Convert the first one to upper case, + // the other characters to lower case, and return the converted string. + chars = value.toCharArray(); + if ( chars.length > 0 ) { + chars[ 0 ] = Character.toUpperCase( chars[ 0 ] ); + for ( i = 1 ; i < chars.length ; ++i ) { + chars[ i ] = Character.toLowerCase( chars[ i ] ); + } + return String.valueOf( chars ); + } + return value; + } + + /** + * Convenience method used to capitalize a one-off attribute value before it + * is returned. For example, the align values "LEFT" and "left" will both + * return as "Left". + * + * @param name The name of the attribute + * @return The capitalized value + */ + String getCapitalized( String name ) { + String value; + char[] chars; + int i; + + value = getAttribute( name ); + if ( value != null ) { + // Convert string to charactares. Convert the first one to upper case, + // the other characters to lower case, and return the converted string. + chars = value.toCharArray(); + if ( chars.length > 0 ) { + chars[ 0 ] = Character.toUpperCase( chars[ 0 ] ); + for ( i = 1 ; i < chars.length ; ++i ) { + chars[ i ] = Character.toLowerCase( chars[ i ] ); + } + return String.valueOf( chars ); + } + } + return value; + } + + + /** + * Convenience method returns the form in which this form element is contained. + * This method is exposed for form elements through the DOM API, but other + * elements have no access to it through the API. + */ + public HTMLFormElement getForm() { + Node parent = getParentNode(); + while ( parent != null ) { + if ( parent instanceof HTMLFormElement ) { + return (HTMLFormElement) parent; + } + parent = parent.getParentNode(); + } + return null; + } + +} diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLFieldSetElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLFieldSetElementImpl.java new file mode 100644 index 0000000..b82e1c4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLFieldSetElementImpl.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLFieldSetElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLFieldSetElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLFieldSetElementImpl + extends HTMLElementImpl + implements HTMLFieldSetElement, HTMLFormControl +{ + + private static final long serialVersionUID = 1146145578073441343L; + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLFieldSetElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLFontElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLFontElementImpl.java new file mode 100644 index 0000000..bd1c5de --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLFontElementImpl.java @@ -0,0 +1,77 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLFontElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLFontElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLFontElementImpl + extends HTMLElementImpl + implements HTMLFontElement +{ + + private static final long serialVersionUID = -415914342045846318L; + + public String getColor() + { + return capitalize( getAttribute( "color" ) ); + } + + + public void setColor( String color ) + { + setAttribute( "color", color ); + } + + + public String getFace() + { + return capitalize( getAttribute( "face" ) ); + } + + + public void setFace( String face ) + { + setAttribute( "face", face ); + } + + + public String getSize() + { + return getAttribute( "size" ); + } + + + public void setSize( String size ) + { + setAttribute( "size", size ); + } + + + public HTMLFontElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLFormControl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLFormControl.java new file mode 100644 index 0000000..1135cbc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLFormControl.java @@ -0,0 +1,30 @@ +/* + * 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. + */ +package org.apache.html.dom; + + +/** + * Identifies control in a form, so they may be collected in a form elements + * collection. All form control elements implement this empty interface. + * + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + */ +public interface HTMLFormControl +{ +} diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLFormElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLFormElementImpl.java new file mode 100644 index 0000000..b297386 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLFormElementImpl.java @@ -0,0 +1,170 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLFormElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLFormElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLFormElementImpl + extends HTMLElementImpl + implements HTMLFormElement +{ + + private static final long serialVersionUID = -7324749629151493210L; + + public HTMLCollection getElements() + { + if ( _elements == null ) + _elements = new HTMLCollectionImpl( this, HTMLCollectionImpl.ELEMENT ); + return _elements; + } + + + public int getLength() + { + return getElements().getLength(); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public String getAcceptCharset() + { + return getAttribute( "accept-charset" ); + } + + + public void setAcceptCharset( String acceptCharset ) + { + setAttribute( "accept-charset", acceptCharset ); + } + + + public String getAction() + { + return getAttribute( "action" ); + } + + + public void setAction( String action ) + { + setAttribute( "action", action ); + } + + + public String getEnctype() + { + return getAttribute( "enctype" ); + } + + + public void setEnctype( String enctype ) + { + setAttribute( "enctype", enctype ); + } + + + public String getMethod() + { + return capitalize( getAttribute( "method" ) ); + } + + + public void setMethod( String method ) + { + setAttribute( "method", method ); + } + + + public String getTarget() + { + return getAttribute( "target" ); + } + + + public void setTarget( String target ) + { + setAttribute( "target", target ); + } + + + public void submit() + { + // No scripting in server-side DOM. This method is moot. + } + + + public void reset() + { + // No scripting in server-side DOM. This method is moot. + } + + /* + * Explicit implementation of getChildNodes() to avoid problems with + * overriding the getLength() method hidden in the super class. + */ + public NodeList getChildNodes() { + return getChildNodesUnoptimized(); + } + + /** + * Explicit implementation of cloneNode() to ensure that cache used + * for getElements() gets cleared. + */ + public Node cloneNode( boolean deep ) { + HTMLFormElementImpl clonedNode = (HTMLFormElementImpl)super.cloneNode( deep ); + clonedNode._elements = null; + return clonedNode; + } + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLFormElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + + /** + * Collection of all elements contained in this FORM. + */ + private HTMLCollectionImpl _elements; + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLFrameElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLFrameElementImpl.java new file mode 100644 index 0000000..913c6ba --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLFrameElementImpl.java @@ -0,0 +1,143 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLFrameElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLFrameElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLFrameElementImpl + extends HTMLElementImpl + implements HTMLFrameElement +{ + + private static final long serialVersionUID = 635237057173695984L; + + public String getFrameBorder() + { + return getAttribute( "frameborder" ); + } + + + public void setFrameBorder( String frameBorder ) + { + setAttribute( "frameborder", frameBorder ); + } + + + public String getLongDesc() + { + return getAttribute( "longdesc" ); + } + + + public void setLongDesc( String longDesc ) + { + setAttribute( "longdesc", longDesc ); + } + + + public String getMarginHeight() + { + return getAttribute( "marginheight" ); + } + + + public void setMarginHeight( String marginHeight ) + { + setAttribute( "marginheight", marginHeight ); + } + + + public String getMarginWidth() + { + return getAttribute( "marginwidth" ); + } + + + public void setMarginWidth( String marginWidth ) + { + setAttribute( "marginwidth", marginWidth ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public boolean getNoResize() + { + return getBinary( "noresize" ); + } + + + public void setNoResize( boolean noResize ) + { + setAttribute( "noresize", noResize ); + } + + + public String getScrolling() + { + return capitalize( getAttribute( "scrolling" ) ); + } + + + public void setScrolling( String scrolling ) + { + setAttribute( "scrolling", scrolling ); + } + + + public String getSrc() + { + return getAttribute( "src" ); + } + + + public void setSrc( String src ) + { + setAttribute( "src", src ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLFrameElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLFrameSetElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLFrameSetElementImpl.java new file mode 100644 index 0000000..1670130 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLFrameSetElementImpl.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLFrameSetElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLFrameSetElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLFrameSetElementImpl + extends HTMLElementImpl + implements HTMLFrameSetElement +{ + + private static final long serialVersionUID = 8403143821972586708L; + + public String getCols() + { + return getAttribute( "cols" ); + } + + + public void setCols( String cols ) + { + setAttribute( "cols", cols ); + } + + + public String getRows() + { + return getAttribute( "rows" ); + } + + + public void setRows( String rows ) + { + setAttribute( "rows", rows ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLFrameSetElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLHRElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLHRElementImpl.java new file mode 100644 index 0000000..6d29c10 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLHRElementImpl.java @@ -0,0 +1,95 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLHRElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLHRElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLHRElementImpl + extends HTMLElementImpl + implements HTMLHRElement +{ + + private static final long serialVersionUID = -4210053417678939270L; + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public boolean getNoShade() + { + return getBinary( "noshade" ); + } + + + public void setNoShade( boolean noShade ) + { + setAttribute( "noshade", noShade ); + } + + + public String getSize() + { + return getAttribute( "size" ); + } + + + public void setSize( String size ) + { + setAttribute( "size", size ); + } + + + public String getWidth() + { + return getAttribute( "width" ); + } + + + public void setWidth( String width ) + { + setAttribute( "width", width ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLHRElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLHeadElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLHeadElementImpl.java new file mode 100644 index 0000000..8bda2cd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLHeadElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLHeadElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLHeadElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLHeadElementImpl + extends HTMLElementImpl + implements HTMLHeadElement +{ + + private static final long serialVersionUID = 6438668473721292232L; + + public String getProfile() + { + return getAttribute( "profile" ); + } + + + public void setProfile( String profile ) + { + setAttribute( "profile", profile ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLHeadElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLHeadingElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLHeadingElementImpl.java new file mode 100644 index 0000000..b977ab2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLHeadingElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLHeadingElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLHeadingElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLHeadingElementImpl + extends HTMLElementImpl + implements HTMLHeadingElement +{ + + private static final long serialVersionUID = 6605827989383069095L; + + public String getAlign() + { + return getCapitalized( "align" ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLHeadingElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLHtmlElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLHtmlElementImpl.java new file mode 100644 index 0000000..bc640e9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLHtmlElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLHtmlElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLHtmlElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLHtmlElementImpl + extends HTMLElementImpl + implements HTMLHtmlElement +{ + + private static final long serialVersionUID = -4489734201536616166L; + + public String getVersion() + { + return capitalize( getAttribute( "version" ) ); + } + + + public void setVersion( String version ) + { + setAttribute( "version", version ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLHtmlElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLIFrameElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLIFrameElementImpl.java new file mode 100644 index 0000000..ab01942 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLIFrameElementImpl.java @@ -0,0 +1,166 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLIFrameElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLIFrameElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLIFrameElementImpl + extends HTMLElementImpl + implements HTMLIFrameElement +{ + + private static final long serialVersionUID = 2393622754706230429L; + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getFrameBorder() + { + return getAttribute( "frameborder" ); + } + + + public void setFrameBorder( String frameBorder ) + { + setAttribute( "frameborder", frameBorder ); + } + + + public String getHeight() + { + return getAttribute( "height" ); + } + + + public void setHeight( String height ) + { + setAttribute( "height", height ); + } + + public String getLongDesc() + { + return getAttribute( "longdesc" ); + } + + + public void setLongDesc( String longDesc ) + { + setAttribute( "longdesc", longDesc ); + } + + + public String getMarginHeight() + { + return getAttribute( "marginheight" ); + } + + + public void setMarginHeight( String marginHeight ) + { + setAttribute( "marginheight", marginHeight ); + } + + + public String getMarginWidth() + { + return getAttribute( "marginwidth" ); + } + + + public void setMarginWidth( String marginWidth ) + { + setAttribute( "marginwidth", marginWidth ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public String getScrolling() + { + return capitalize( getAttribute( "scrolling" ) ); + } + + + public void setScrolling( String scrolling ) + { + setAttribute( "scrolling", scrolling ); + } + + + public String getSrc() + { + return getAttribute( "src" ); + } + + + public void setSrc( String src ) + { + setAttribute( "src", src ); + } + + + public String getWidth() + { + return getAttribute( "width" ); + } + + + public void setWidth( String width ) + { + setAttribute( "width", width ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLIFrameElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLImageElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLImageElementImpl.java new file mode 100644 index 0000000..8862482 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLImageElementImpl.java @@ -0,0 +1,203 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLImageElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLImageElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLImageElementImpl + extends HTMLElementImpl + implements HTMLImageElement +{ + + private static final long serialVersionUID = 1424360710977241315L; + + public String getLowSrc() + { + return getAttribute( "lowsrc" ); + } + + + public void setLowSrc( String lowSrc ) + { + setAttribute( "lowsrc", lowSrc ); + } + + + public String getSrc() + { + return getAttribute( "src" ); + } + + + public void setSrc( String src ) + { + setAttribute( "src", src ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getAlt() + { + return getAttribute( "alt" ); + } + + + public void setAlt( String alt ) + { + setAttribute( "alt", alt ); + } + + + public String getBorder() + { + return getAttribute( "border" ); + } + + + public void setBorder( String border ) + { + setAttribute( "border", border ); + } + + + public String getHeight() + { + return getAttribute( "height" ); + } + + + public void setHeight( String height ) + { + setAttribute( "height", height ); + } + + + public String getHspace() + { + return getAttribute( "hspace" ); + } + + + public void setHspace( String hspace ) + { + setAttribute( "hspace", hspace ); + } + + + public boolean getIsMap() + { + return getBinary( "ismap" ); + } + + + public void setIsMap( boolean isMap ) + { + setAttribute( "ismap", isMap ); + } + + + public String getLongDesc() + { + return getAttribute( "longdesc" ); + } + + + public void setLongDesc( String longDesc ) + { + setAttribute( "longdesc", longDesc ); + } + + + public String getUseMap() + { + return getAttribute( "useMap" ); + } + + + public void setUseMap( String useMap ) + { + setAttribute( "useMap", useMap ); + } + + + public String getVspace() + { + return getAttribute( "vspace" ); + } + + + public void setVspace( String vspace ) + { + setAttribute( "vspace", vspace ); + } + + + public String getWidth() + { + return getAttribute( "width" ); + } + + + public void setWidth( String width ) + { + setAttribute( "width", width ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLImageElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLInputElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLInputElementImpl.java new file mode 100644 index 0000000..1a1fcd2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLInputElementImpl.java @@ -0,0 +1,290 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLInputElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLInputElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLInputElementImpl + extends HTMLElementImpl + implements HTMLInputElement, HTMLFormControl +{ + + private static final long serialVersionUID = 640139325394332007L; + + public String getDefaultValue() + { + // ! NOT FULLY IMPLEMENTED ! + return getAttribute( "defaultValue" ); + } + + + public void setDefaultValue( String defaultValue ) + { + // ! NOT FULLY IMPLEMENTED ! + setAttribute( "defaultValue", defaultValue ); + } + + + public boolean getDefaultChecked() + { + // ! NOT FULLY IMPLEMENTED ! + return getBinary( "defaultChecked" ); + } + + + public void setDefaultChecked( boolean defaultChecked ) + { + // ! NOT FULLY IMPLEMENTED ! + setAttribute( "defaultChecked", defaultChecked ); + } + + + public String getAccept() + { + return getAttribute( "accept" ); + } + + + public void setAccept( String accept ) + { + setAttribute( "accept", accept ); + } + + + public String getAccessKey() + { + String accessKey; + + // Make sure that the access key is a single character. + accessKey = getAttribute( "accesskey" ); + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + return accessKey; + } + + + public void setAccessKey( String accessKey ) + { + // Make sure that the access key is a single character. + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + setAttribute( "accesskey", accessKey ); + } + + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getAlt() + { + return getAttribute( "alt" ); + } + + + public void setAlt( String alt ) + { + setAttribute( "alt", alt ); + } + + + public boolean getChecked() + { + return getBinary( "checked" ); + } + + + public void setChecked( boolean checked ) + { + setAttribute( "checked", checked ); + } + + + public boolean getDisabled() + { + return getBinary( "disabled" ); + } + + + public void setDisabled( boolean disabled ) + { + setAttribute( "disabled", disabled ); + } + + + public int getMaxLength() + { + return getInteger( getAttribute( "maxlength" ) ); + } + + + public void setMaxLength( int maxLength ) + { + setAttribute( "maxlength", String.valueOf( maxLength ) ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public boolean getReadOnly() + { + return getBinary( "readonly" ); + } + + + public void setReadOnly( boolean readOnly ) + { + setAttribute( "readonly", readOnly ); + } + + + public String getSize() + { + return getAttribute( "size" ); + } + + + public void setSize( String size ) + { + setAttribute( "size", size ); + } + + + public String getSrc() + { + return getAttribute( "src" ); + } + + + public void setSrc( String src ) + { + setAttribute( "src", src ); + } + + + public int getTabIndex() + { + try + { + return Integer.parseInt( getAttribute( "tabindex" ) ); + } + catch ( NumberFormatException except ) + { + return 0; + } + } + + + public void setTabIndex( int tabIndex ) + { + setAttribute( "tabindex", String.valueOf( tabIndex ) ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public String getUseMap() + { + return getAttribute( "useMap" ); + } + + + public void setUseMap( String useMap ) + { + setAttribute( "useMap", useMap ); + } + + + public String getValue() + { + return getAttribute( "value" ); + } + + + public void setValue( String value ) + { + setAttribute( "value", value ); + } + + + public void blur() + { + // No scripting in server-side DOM. This method is moot. + } + + + public void focus() + { + // No scripting in server-side DOM. This method is moot. + } + + + public void select() + { + // No scripting in server-side DOM. This method is moot. + } + + + public void click() + { + // No scripting in server-side DOM. This method is moot. + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLInputElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLIsIndexElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLIsIndexElementImpl.java new file mode 100644 index 0000000..0cdd50b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLIsIndexElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLIsIndexElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLIsIndexElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLIsIndexElementImpl + extends HTMLElementImpl + implements HTMLIsIndexElement +{ + + private static final long serialVersionUID = 3073521742049689699L; + + public String getPrompt() + { + return getAttribute( "prompt" ); + } + + + public void setPrompt( String prompt ) + { + setAttribute( "prompt", prompt ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLIsIndexElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLLIElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLLIElementImpl.java new file mode 100644 index 0000000..a523d5e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLLIElementImpl.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLLIElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLLIElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLLIElementImpl + extends HTMLElementImpl + implements HTMLLIElement +{ + + private static final long serialVersionUID = -8987309345926701831L; + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + public int getValue() + { + return getInteger( getAttribute( "value" ) ); + } + + + public void setValue( int value ) + { + setAttribute( "value", String.valueOf( value ) ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLLIElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLLabelElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLLabelElementImpl.java new file mode 100644 index 0000000..6888607 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLLabelElementImpl.java @@ -0,0 +1,80 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLLabelElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLLabelElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLLabelElementImpl + extends HTMLElementImpl + implements HTMLLabelElement, HTMLFormControl +{ + + private static final long serialVersionUID = 5774388295313199380L; + + public String getAccessKey() + { + String accessKey; + + // Make sure that the access key is a single character. + accessKey = getAttribute( "accesskey" ); + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + return accessKey; + } + + + public void setAccessKey( String accessKey ) + { + // Make sure that the access key is a single character. + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + setAttribute( "accesskey", accessKey ); + } + + + public String getHtmlFor() + { + return getAttribute( "for" ); + } + + + public void setHtmlFor( String htmlFor ) + { + setAttribute( "for", htmlFor ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLLabelElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLLegendElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLLegendElementImpl.java new file mode 100644 index 0000000..730df73 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLLegendElementImpl.java @@ -0,0 +1,80 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLLegendElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLLegendElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLLegendElementImpl + extends HTMLElementImpl + implements HTMLLegendElement +{ + + private static final long serialVersionUID = -621849164029630762L; + + public String getAccessKey() + { + String accessKey; + + // Make sure that the access key is a single character. + accessKey = getAttribute( "accesskey" ); + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + return accessKey; + } + + + public void setAccessKey( String accessKey ) + { + // Make sure that the access key is a single character. + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + setAttribute( "accesskey", accessKey ); + } + + + public String getAlign() + { + return getAttribute( "align" ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLLegendElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLLinkElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLLinkElementImpl.java new file mode 100644 index 0000000..e2f2449 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLLinkElementImpl.java @@ -0,0 +1,155 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLLinkElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLLinkElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLLinkElementImpl + extends HTMLElementImpl + implements HTMLLinkElement +{ + + private static final long serialVersionUID = 874345520063418879L; + + public boolean getDisabled() + { + return getBinary( "disabled" ); + } + + + public void setDisabled( boolean disabled ) + { + setAttribute( "disabled", disabled ); + } + + + public String getCharset() + { + return getAttribute( "charset" ); + } + + + public void setCharset( String charset ) + { + setAttribute( "charset", charset ); + } + + + public String getHref() + { + return getAttribute( "href" ); + } + + + public void setHref( String href ) + { + setAttribute( "href", href ); + } + + + public String getHreflang() + { + return getAttribute( "hreflang" ); + } + + + public void setHreflang( String hreflang ) + { + setAttribute( "hreflang", hreflang ); + } + + + public String getMedia() + { + return getAttribute( "media" ); + } + + + public void setMedia( String media ) + { + setAttribute( "media", media ); + } + + + public String getRel() + { + return getAttribute( "rel" ); + } + + + public void setRel( String rel ) + { + setAttribute( "rel", rel ); + } + + + public String getRev() + { + return getAttribute( "rev" ); + } + + + public void setRev( String rev ) + { + setAttribute( "rev", rev ); + } + + + public String getTarget() + { + return getAttribute( "target" ); + } + + + public void setTarget( String target ) + { + setAttribute( "target", target ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLLinkElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLMapElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLMapElementImpl.java new file mode 100644 index 0000000..a25cead --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLMapElementImpl.java @@ -0,0 +1,82 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLMapElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLMapElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLMapElementImpl + extends HTMLElementImpl + implements HTMLMapElement +{ + + private static final long serialVersionUID = 7520887584251976392L; + + public HTMLCollection getAreas() + { + if ( _areas == null ) + _areas = new HTMLCollectionImpl( this, HTMLCollectionImpl.AREA ); + return _areas; + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + /** + * Explicit implementation of cloneNode() to ensure that cache used + * for getAreas() gets cleared. + */ + public Node cloneNode( boolean deep ) + { + HTMLMapElementImpl clonedNode = (HTMLMapElementImpl)super.cloneNode( deep ); + clonedNode._areas = null; + return clonedNode; + } + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLMapElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + + private HTMLCollection _areas; + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLMenuElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLMenuElementImpl.java new file mode 100644 index 0000000..5010064 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLMenuElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLMenuElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLMenuElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLMenuElementImpl + extends HTMLElementImpl + implements HTMLMenuElement +{ + + private static final long serialVersionUID = -1489696654903916901L; + + public boolean getCompact() + { + return getBinary( "compact" ); + } + + + public void setCompact( boolean compact ) + { + setAttribute( "compact", compact ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLMenuElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLMetaElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLMetaElementImpl.java new file mode 100644 index 0000000..47c2e62 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLMetaElementImpl.java @@ -0,0 +1,96 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLMetaElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLMetaElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLMetaElementImpl + extends HTMLElementImpl + implements HTMLMetaElement +{ + + private static final long serialVersionUID = -2401961905874264272L; + + public String getContent() + { + return getAttribute( "content" ); + } + + + public void setContent( String content ) + { + setAttribute( "content", content ); + } + + + + public String getHttpEquiv() + { + return getAttribute( "http-equiv" ); + } + + + public void setHttpEquiv( String httpEquiv ) + { + setAttribute( "http-equiv", httpEquiv ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public String getScheme() + { + return getAttribute( "scheme" ); + } + + + public void setScheme( String scheme ) + { + setAttribute( "scheme", scheme ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLMetaElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLModElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLModElementImpl.java new file mode 100644 index 0000000..cf1211d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLModElementImpl.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLModElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLModElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLModElementImpl + extends HTMLElementImpl + implements HTMLModElement +{ + + private static final long serialVersionUID = 6424581972706750120L; + + public String getCite() + { + return getAttribute( "cite" ); + } + + + public void setCite( String cite ) + { + setAttribute( "cite", cite ); + } + + + public String getDateTime() + { + return getAttribute( "datetime" ); + } + + + public void setDateTime( String dateTime ) + { + setAttribute( "datetime", dateTime ); + } + + + /** + * Constructor requires owner document and tag name. + * + * @param owner The owner HTML document + */ + public HTMLModElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLOListElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLOListElementImpl.java new file mode 100644 index 0000000..5941956 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLOListElementImpl.java @@ -0,0 +1,83 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLOListElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLOListElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLOListElementImpl + extends HTMLElementImpl + implements HTMLOListElement +{ + + private static final long serialVersionUID = 1293750546025862146L; + + public boolean getCompact() + { + return getBinary( "compact" ); + } + + + public void setCompact( boolean compact ) + { + setAttribute( "compact", compact ); + } + + + public int getStart() + { + return getInteger( getAttribute( "start" ) ); + } + + + public void setStart( int start ) + { + setAttribute( "start", String.valueOf( start ) ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLOListElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLObjectElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLObjectElementImpl.java new file mode 100644 index 0000000..cc31952 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLObjectElementImpl.java @@ -0,0 +1,256 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLObjectElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLObjectElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLObjectElementImpl + extends HTMLElementImpl + implements HTMLObjectElement, HTMLFormControl +{ + + private static final long serialVersionUID = 2276953229932965067L; + + public String getCode() + { + return getAttribute( "code" ); + } + + + public void setCode( String code ) + { + setAttribute( "code", code ); + } + + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getArchive() + { + return getAttribute( "archive" ); + } + + + public void setArchive( String archive ) + { + setAttribute( "archive", archive ); + } + + public String getBorder() + { + return getAttribute( "border" ); + } + + + public void setBorder( String border ) + { + setAttribute( "border", border ); + } + + + public String getCodeBase() + { + return getAttribute( "codebase" ); + } + + + public void setCodeBase( String codeBase ) + { + setAttribute( "codebase", codeBase ); + } + + + public String getCodeType() + { + return getAttribute( "codetype" ); + } + + + public void setCodeType( String codeType ) + { + setAttribute( "codetype", codeType ); + } + + + public String getData() + { + return getAttribute( "data" ); + } + + + public void setData( String data ) + { + setAttribute( "data", data ); + } + + + public boolean getDeclare() + { + return getBinary( "declare" ); + } + + + public void setDeclare( boolean declare ) + { + setAttribute( "declare", declare ); + } + + + public String getHeight() + { + return getAttribute( "height" ); + } + + + public void setHeight( String height ) + { + setAttribute( "height", height ); + } + + + public String getHspace() + { + return getAttribute( "hspace" ); + } + + + public void setHspace( String hspace ) + { + setAttribute( "hspace", hspace ); + } + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public String getStandby() + { + return getAttribute( "standby" ); + } + + + public void setStandby( String standby ) + { + setAttribute( "standby", standby ); + } + + public int getTabIndex() + { + try + { + return Integer.parseInt( getAttribute( "tabindex" ) ); + } + catch ( NumberFormatException except ) + { + return 0; + } + } + + + public void setTabIndex( int tabIndex ) + { + setAttribute( "tabindex", String.valueOf( tabIndex ) ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + public String getUseMap() + { + return getAttribute( "useMap" ); + } + + + public void setUseMap( String useMap ) + { + setAttribute( "useMap", useMap ); + } + + + public String getVspace() + { + return getAttribute( "vspace" ); + } + + + public void setVspace( String vspace ) + { + setAttribute( "vspace", vspace ); + } + + + public String getWidth() + { + return getAttribute( "width" ); + } + + + public void setWidth( String width ) + { + setAttribute( "width", width ); + } + + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLObjectElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLOptGroupElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLOptGroupElementImpl.java new file mode 100644 index 0000000..0463c67 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLOptGroupElementImpl.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLOptGroupElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLOptGroupElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLOptGroupElementImpl + extends HTMLElementImpl + implements HTMLOptGroupElement +{ + + private static final long serialVersionUID = -8807098641226171501L; + + public boolean getDisabled() + { + return getBinary( "disabled" ); + } + + + public void setDisabled( boolean disabled ) + { + setAttribute( "disabled", disabled ); + } + + + public String getLabel() + { + return capitalize( getAttribute( "label" ) ); + } + + + public void setLabel( String label ) + { + setAttribute( "label", label ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLOptGroupElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLOptionElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLOptionElementImpl.java new file mode 100644 index 0000000..75ce3b2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLOptionElementImpl.java @@ -0,0 +1,209 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLOptionElement; +import org.w3c.dom.html.HTMLSelectElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLOptionElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLOptionElementImpl + extends HTMLElementImpl + implements HTMLOptionElement +{ + + private static final long serialVersionUID = -4486774554137530907L; + + public boolean getDefaultSelected() + { + // ! NOT FULLY IMPLEMENTED ! + return getBinary( "default-selected" ); + } + + + public void setDefaultSelected( boolean defaultSelected ) + { + // ! NOT FULLY IMPLEMENTED ! + setAttribute( "default-selected", defaultSelected ); + } + + + public String getText() + { + Node child; + StringBuffer text = new StringBuffer(); + + // Find the Text nodes contained within this element and return their + // concatenated value. Required to go around comments, entities, etc. + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof Text ) { + text.append(( (Text) child ).getData()); + } + child = child.getNextSibling(); + } + return text.toString(); + } + + + public void setText( String text ) + { + Node child; + Node next; + + // Delete all the nodes and replace them with a single Text node. + // This is the only approach that can handle comments and other nodes. + child = getFirstChild(); + while ( child != null ) + { + next = child.getNextSibling(); + removeChild( child ); + child = next; + } + insertBefore( getOwnerDocument().createTextNode( text ), getFirstChild() ); + } + + + public int getIndex() + { + Node parent; + NodeList options; + int i; + + // Locate the parent SELECT. Note that this OPTION might be inside a + // OPTGROUP inside the SELECT. Or it might not have a parent SELECT. + // Everything is possible. If no parent is found, return -1. + parent = getParentNode(); + while ( parent != null && ! ( parent instanceof HTMLSelectElement ) ) + parent = parent.getParentNode(); + if ( parent != null ) + { + // Use getElementsByTagName() which creates a snapshot of all the + // OPTION elements under the SELECT. Access to the returned NodeList + // is very fast and the snapshot solves many synchronization problems. + options = ( (HTMLElement) parent ).getElementsByTagName( "OPTION" ); + for ( i = 0 ; i < options.getLength() ; ++i ) + if ( options.item( i ) == this ) + return i; + } + return -1; + } + + + public void setIndex( int index ) + { + Node parent; + NodeList options; + Node item; + + // Locate the parent SELECT. Note that this OPTION might be inside a + // OPTGROUP inside the SELECT. Or it might not have a parent SELECT. + // Everything is possible. If no parent is found, just return. + parent = getParentNode(); + while ( parent != null && ! ( parent instanceof HTMLSelectElement ) ) + parent = parent.getParentNode(); + if ( parent != null ) + { + // Use getElementsByTagName() which creates a snapshot of all the + // OPTION elements under the SELECT. Access to the returned NodeList + // is very fast and the snapshot solves many synchronization problems. + // Make sure this OPTION is not replacing itself. + options = ( (HTMLElement) parent ).getElementsByTagName( "OPTION" ); + if ( options.item( index ) != this ) + { + // Remove this OPTION from its parent. Place this OPTION right + // before indexed OPTION underneath it's direct parent (might + // be an OPTGROUP). + getParentNode().removeChild( this ); + item = options.item( index ); + item.getParentNode().insertBefore( this, item ); + } + } + } + + + public boolean getDisabled() + { + return getBinary( "disabled" ); + } + + + public void setDisabled( boolean disabled ) + { + setAttribute( "disabled", disabled ); + } + + + public String getLabel() + { + return capitalize( getAttribute( "label" ) ); + } + + + public void setLabel( String label ) + { + setAttribute( "label", label ); + } + + + public boolean getSelected() + { + return getBinary( "selected" ); + } + + + public void setSelected( boolean selected ) + { + setAttribute( "selected", selected ); + } + + + public String getValue() + { + return getAttribute( "value" ); + } + + + public void setValue( String value ) + { + setAttribute( "value", value ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLOptionElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLParagraphElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLParagraphElementImpl.java new file mode 100644 index 0000000..c3e21f5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLParagraphElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLParagraphElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLParagraphElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLParagraphElementImpl + extends HTMLElementImpl + implements HTMLParagraphElement +{ + + private static final long serialVersionUID = 8075287150683866287L; + + public String getAlign() + { + return getAttribute( "align" ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLParagraphElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLParamElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLParamElementImpl.java new file mode 100644 index 0000000..03cf192 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLParamElementImpl.java @@ -0,0 +1,95 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLParamElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLParamElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLParamElementImpl + extends HTMLElementImpl + implements HTMLParamElement +{ + + private static final long serialVersionUID = -8513050483880341412L; + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + public String getValue() + { + return getAttribute( "value" ); + } + + + public void setValue( String value ) + { + setAttribute( "value", value ); + } + + + public String getValueType() + { + return capitalize( getAttribute( "valuetype" ) ); + } + + + public void setValueType( String valueType ) + { + setAttribute( "valuetype", valueType ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLParamElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLPreElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLPreElementImpl.java new file mode 100644 index 0000000..63f4f6e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLPreElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLPreElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLPreElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLPreElementImpl + extends HTMLElementImpl + implements HTMLPreElement +{ + + private static final long serialVersionUID = -4195360849946217644L; + + public int getWidth() + { + return getInteger( getAttribute( "width" ) ); + } + + + public void setWidth( int width ) + { + setAttribute( "width", String.valueOf( width ) ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLPreElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLQuoteElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLQuoteElementImpl.java new file mode 100644 index 0000000..3a50b56 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLQuoteElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLQuoteElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLQuoteElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLQuoteElementImpl + extends HTMLElementImpl + implements HTMLQuoteElement +{ + + private static final long serialVersionUID = -67544811597906132L; + + public String getCite() + { + return getAttribute( "cite" ); + } + + + public void setCite( String cite ) + { + setAttribute( "cite", cite ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLQuoteElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLScriptElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLScriptElementImpl.java new file mode 100644 index 0000000..75acfc9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLScriptElementImpl.java @@ -0,0 +1,157 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.w3c.dom.html.HTMLScriptElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLScriptElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLScriptElementImpl + extends HTMLElementImpl + implements HTMLScriptElement +{ + + private static final long serialVersionUID = 5090330049085326558L; + + public String getText() + { + Node child; + StringBuffer text = new StringBuffer(); + + // Find the Text nodes contained within this element and return their + // concatenated value. Required to go around comments, entities, etc. + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof Text ) { + text.append(( (Text) child ).getData()); + } + child = child.getNextSibling(); + } + return text.toString(); + } + + + public void setText( String text ) + { + Node child; + Node next; + + // Delete all the nodes and replace them with a single Text node. + // This is the only approach that can handle comments and other nodes. + child = getFirstChild(); + while ( child != null ) + { + next = child.getNextSibling(); + removeChild( child ); + child = next; + } + insertBefore( getOwnerDocument().createTextNode( text ), getFirstChild() ); + } + + + public String getHtmlFor() + { + return getAttribute( "for" ); + } + + + public void setHtmlFor( String htmlFor ) + { + setAttribute( "for", htmlFor ); + } + + + public String getEvent() + { + return getAttribute( "event" ); + } + + + public void setEvent( String event ) + { + setAttribute( "event", event ); + } + + public String getCharset() + { + return getAttribute( "charset" ); + } + + + public void setCharset( String charset ) + { + setAttribute( "charset", charset ); + } + + + public boolean getDefer() + { + return getBinary( "defer" ); + } + + + public void setDefer( boolean defer ) + { + setAttribute( "defer", defer ); + } + + + public String getSrc() + { + return getAttribute( "src" ); + } + + + public void setSrc( String src ) + { + setAttribute( "src", src ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLScriptElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLSelectElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLSelectElementImpl.java new file mode 100644 index 0000000..8095f02 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLSelectElementImpl.java @@ -0,0 +1,233 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLOptionElement; +import org.w3c.dom.html.HTMLSelectElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLSelectElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLSelectElementImpl + extends HTMLElementImpl + implements HTMLSelectElement, HTMLFormControl +{ + + private static final long serialVersionUID = -6998282711006968187L; + + public String getType() + { + return getAttribute( "type" ); + } + + + public String getValue() + { + return getAttribute( "value" ); + } + + + public void setValue( String value ) + { + setAttribute( "value", value ); + } + + + public int getSelectedIndex() + { + NodeList options; + int i; + + // Use getElementsByTagName() which creates a snapshot of all the + // OPTION elements under this SELECT. Access to the returned NodeList + // is very fast and the snapshot solves many synchronization problems. + // Locate the first selected OPTION and return its index. Note that + // the OPTION might be under an OPTGROUP. + options = getElementsByTagName( "OPTION" ); + for ( i = 0 ; i < options.getLength() ; ++i ) + if ( ( (HTMLOptionElement) options.item( i ) ).getSelected() ) + return i; + return -1; + } + + + public void setSelectedIndex( int selectedIndex ) + { + NodeList options; + int i; + + // Use getElementsByTagName() which creates a snapshot of all the + // OPTION elements under this SELECT. Access to the returned NodeList + // is very fast and the snapshot solves many synchronization problems. + // Change the select so all OPTIONs are off, except for the + // selectIndex-th one. + options = getElementsByTagName( "OPTION" ); + for ( i = 0 ; i < options.getLength() ; ++i ) + ( (HTMLOptionElementImpl) options.item( i ) ).setSelected( i == selectedIndex ); + } + + + public HTMLCollection getOptions() + { + if ( _options == null ) + _options = new HTMLCollectionImpl( this, HTMLCollectionImpl.OPTION ); + return _options; + } + + + public int getLength() + { + return getOptions().getLength(); + } + + + public boolean getDisabled() + { + return getBinary( "disabled" ); + } + + + public void setDisabled( boolean disabled ) + { + setAttribute( "disabled", disabled ); + } + + + public boolean getMultiple() + { + return getBinary( "multiple" ); + } + + + public void setMultiple( boolean multiple ) + { + setAttribute( "multiple", multiple ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public int getSize() + { + return getInteger( getAttribute( "size" ) ); + } + + + public void setSize( int size ) + { + setAttribute( "size", String.valueOf( size ) ); + } + + + public int getTabIndex() + { + return getInteger( getAttribute( "tabindex" ) ); + } + + + public void setTabIndex( int tabIndex ) + { + setAttribute( "tabindex", String.valueOf( tabIndex ) ); + } + + + public void add( HTMLElement element, HTMLElement before ) + { + insertBefore( element, before ); + } + + + public void remove( int index ) + { + NodeList options; + Node removed; + + // Use getElementsByTagName() which creates a snapshot of all the + // OPTION elements under this SELECT. Access to the returned NodeList + // is very fast and the snapshot solves many synchronization problems. + // Remove the indexed OPTION from it's parent, this might be this + // SELECT or an OPTGROUP. + options = getElementsByTagName( "OPTION" ); + removed = options.item( index ); + if ( removed != null ) + removed.getParentNode().removeChild ( removed ); + } + + + public void blur() + { + // No scripting in server-side DOM. This method is moot. + } + + + public void focus() + { + // No scripting in server-side DOM. This method is moot. + } + + /** + * Explicit implementation of getChildNodes() to avoid problems with + * overriding the getLength() method hidden in the super class. + */ + public NodeList getChildNodes() { + return getChildNodesUnoptimized(); + } + + /** + * Explicit implementation of cloneNode() to ensure that cache used + * for getOptions() gets cleared. + */ + public Node cloneNode(boolean deep) { + HTMLSelectElementImpl clonedNode = (HTMLSelectElementImpl)super.cloneNode( deep ); + clonedNode._options = null; + return clonedNode; + } + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLSelectElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + + private HTMLCollection _options; + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLStyleElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLStyleElementImpl.java new file mode 100644 index 0000000..3ce4b69 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLStyleElementImpl.java @@ -0,0 +1,83 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLStyleElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLStyleElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLStyleElementImpl + extends HTMLElementImpl + implements HTMLStyleElement +{ + + private static final long serialVersionUID = -9001815754196124532L; + + public boolean getDisabled() + { + return getBinary( "disabled" ); + } + + + public void setDisabled( boolean disabled ) + { + setAttribute( "disabled", disabled ); + } + + + public String getMedia() + { + return getAttribute( "media" ); + } + + + public void setMedia( String media ) + { + setAttribute( "media", media ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLStyleElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLTableCaptionElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableCaptionElementImpl.java new file mode 100644 index 0000000..f604f62 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableCaptionElementImpl.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLTableCaptionElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLTableCaptionElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLTableCaptionElementImpl + extends HTMLElementImpl + implements HTMLTableCaptionElement +{ + + private static final long serialVersionUID = 183703024771848940L; + + public String getAlign() + { + return getAttribute( "align" ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLTableCaptionElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLTableCellElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableCellElementImpl.java new file mode 100644 index 0000000..cd4df94 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableCellElementImpl.java @@ -0,0 +1,278 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.html.HTMLTableCellElement; +import org.w3c.dom.html.HTMLTableRowElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLTableCellElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLTableCellElementImpl + extends HTMLElementImpl + implements HTMLTableCellElement +{ + + private static final long serialVersionUID = -2406518157464313922L; + + public int getCellIndex() + { + Node parent; + Node child; + int index; + + parent = getParentNode(); + index = 0; + if ( parent instanceof HTMLTableRowElement ) + { + child = parent.getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableCellElement ) + { + if ( child == this ) + return index; + ++ index; + } + child = child.getNextSibling(); + } + } + return -1; + } + + + public void setCellIndex( int cellIndex ) + { + Node parent; + Node child; + + parent = getParentNode(); + if ( parent instanceof HTMLTableRowElement ) + { + child = parent.getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableCellElement ) + { + if ( cellIndex == 0 ) + { + if ( this != child ) + parent.insertBefore( this, child ); + return; + } + -- cellIndex; + } + child = child.getNextSibling(); + } + } + parent.appendChild( this ); + } + + + public String getAbbr() + { + return getAttribute( "abbr" ); + } + + + public void setAbbr( String abbr ) + { + setAttribute( "abbr", abbr ); + } + + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getAxis() + { + return getAttribute( "axis" ); + } + + + public void setAxis( String axis ) + { + setAttribute( "axis", axis ); + } + + public String getBgColor() + { + return getAttribute( "bgcolor" ); + } + + + public void setBgColor( String bgColor ) + { + setAttribute( "bgcolor", bgColor ); + } + + + public String getCh() + { + String ch; + + // Make sure that the access key is a single character. + ch = getAttribute( "char" ); + if ( ch != null && ch.length() > 1 ) + ch = ch.substring( 0, 1 ); + return ch; + } + + + public void setCh( String ch ) + { + // Make sure that the access key is a single character. + if ( ch != null && ch.length() > 1 ) + ch = ch.substring( 0, 1 ); + setAttribute( "char", ch ); + } + + + public String getChOff() + { + return getAttribute( "charoff" ); + } + + + public void setChOff( String chOff ) + { + setAttribute( "charoff", chOff ); + } + + + public int getColSpan() + { + return getInteger( getAttribute( "colspan" ) ); + } + + + public void setColSpan( int colspan ) + { + setAttribute( "colspan", String.valueOf( colspan ) ); + } + + + public String getHeaders() + { + return getAttribute( "headers" ); + } + + + public void setHeaders( String headers ) + { + setAttribute( "headers", headers ); + } + + + public String getHeight() + { + return getAttribute( "height" ); + } + + + public void setHeight( String height ) + { + setAttribute( "height", height ); + } + + + public boolean getNoWrap() + { + return getBinary( "nowrap" ); + } + + + public void setNoWrap( boolean noWrap ) + { + setAttribute( "nowrap", noWrap ); + } + + public int getRowSpan() + { + return getInteger( getAttribute( "rowspan" ) ); + } + + + public void setRowSpan( int rowspan ) + { + setAttribute( "rowspan", String.valueOf( rowspan ) ); + } + + + public String getScope() + { + return getAttribute( "scope" ); + } + + + public void setScope( String scope ) + { + setAttribute( "scope", scope ); + } + + + public String getVAlign() + { + return capitalize( getAttribute( "valign" ) ); + } + + + public void setVAlign( String vAlign ) + { + setAttribute( "valign", vAlign ); + } + + + public String getWidth() + { + return getAttribute( "width" ); + } + + + public void setWidth( String width ) + { + setAttribute( "width", width ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLTableCellElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLTableColElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableColElementImpl.java new file mode 100644 index 0000000..ce7d1d9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableColElementImpl.java @@ -0,0 +1,127 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLTableColElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLTableColElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLTableColElementImpl + extends HTMLElementImpl + implements HTMLTableColElement +{ + + private static final long serialVersionUID = -6189626162811911792L; + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getCh() + { + String ch; + + // Make sure that the access key is a single character. + ch = getAttribute( "char" ); + if ( ch != null && ch.length() > 1 ) + ch = ch.substring( 0, 1 ); + return ch; + } + + + public void setCh( String ch ) + { + // Make sure that the access key is a single character. + if ( ch != null && ch.length() > 1 ) + ch = ch.substring( 0, 1 ); + setAttribute( "char", ch ); + } + + + public String getChOff() + { + return getAttribute( "charoff" ); + } + + + public void setChOff( String chOff ) + { + setAttribute( "charoff", chOff ); + } + + + public int getSpan() + { + return getInteger( getAttribute( "span" ) ); + } + + + public void setSpan( int span ) + { + setAttribute( "span", String.valueOf( span ) ); + } + + + public String getVAlign() + { + return capitalize( getAttribute( "valign" ) ); + } + + + public void setVAlign( String vAlign ) + { + setAttribute( "valign", vAlign ); + } + + public String getWidth() + { + return getAttribute( "width" ); + } + + + public void setWidth( String width ) + { + setAttribute( "width", width ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLTableColElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLTableElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableElementImpl.java new file mode 100644 index 0000000..b3cc95e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableElementImpl.java @@ -0,0 +1,409 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLTableCaptionElement; +import org.w3c.dom.html.HTMLTableElement; +import org.w3c.dom.html.HTMLTableRowElement; +import org.w3c.dom.html.HTMLTableSectionElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLAnchorElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLTableElementImpl + extends HTMLElementImpl + implements HTMLTableElement +{ + + private static final long serialVersionUID = -1824053099870917532L; + + public synchronized HTMLTableCaptionElement getCaption() + { + Node child; + + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableCaptionElement && + child.getNodeName().equals( "CAPTION" ) ) + return (HTMLTableCaptionElement) child; + child = child.getNextSibling(); + } + return null; + } + + + public synchronized void setCaption( HTMLTableCaptionElement caption ) + { + if ( caption != null && ! caption.getTagName().equals( "CAPTION" ) ) + throw new IllegalArgumentException( "HTM016 Argument 'caption' is not an element of type ." ); + deleteCaption(); + if ( caption != null ) + appendChild( caption ); + } + + + public synchronized HTMLElement createCaption() + { + HTMLElement section; + + section = getCaption(); + if ( section != null ) + return section; + section = new HTMLTableCaptionElementImpl( (HTMLDocumentImpl) getOwnerDocument(), "CAPTION" ); + appendChild( section ); + return section; + } + + + public synchronized void deleteCaption() + { + Node old; + + old = getCaption(); + if ( old != null ) + removeChild ( old ); + } + + public synchronized HTMLTableSectionElement getTHead() + { + Node child; + + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableSectionElement && + child.getNodeName().equals( "THEAD" ) ) + return (HTMLTableSectionElement) child; + child = child.getNextSibling(); + } + return null; + } + + + public synchronized void setTHead( HTMLTableSectionElement tHead ) + { + if ( tHead != null && ! tHead.getTagName().equals( "THEAD" ) ) + throw new IllegalArgumentException( "HTM017 Argument 'tHead' is not an element of type ." ); + deleteTHead(); + if ( tHead != null ) + appendChild( tHead ); + } + + + public synchronized HTMLElement createTHead() + { + HTMLElement section; + + section = getTHead(); + if ( section != null ) + return section; + section = new HTMLTableSectionElementImpl( (HTMLDocumentImpl) getOwnerDocument(), "THEAD" ); + appendChild( section ); + return section; + } + + + public synchronized void deleteTHead() + { + Node old; + + old = getTHead(); + if ( old != null ) + removeChild ( old ); + } + + public synchronized HTMLTableSectionElement getTFoot() + { + Node child; + + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableSectionElement && + child.getNodeName().equals( "TFOOT" ) ) + return (HTMLTableSectionElement) child; + child = child.getNextSibling(); + } + return null; + } + + + public synchronized void setTFoot( HTMLTableSectionElement tFoot ) + { + if ( tFoot != null && ! tFoot.getTagName().equals( "TFOOT" ) ) + throw new IllegalArgumentException( "HTM018 Argument 'tFoot' is not an element of type ." ); + deleteTFoot(); + if ( tFoot != null ) + appendChild( tFoot ); + } + + + public synchronized HTMLElement createTFoot() + { + HTMLElement section; + + section = getTFoot(); + if ( section != null ) + return section; + section = new HTMLTableSectionElementImpl( (HTMLDocumentImpl) getOwnerDocument(), "TFOOT" ); + appendChild( section ); + return section; + } + + + public synchronized void deleteTFoot() + { + Node old; + + old = getTFoot(); + if ( old != null ) + removeChild ( old ); + } + + public HTMLCollection getRows() + { + if ( _rows == null ) + _rows = new HTMLCollectionImpl( this, HTMLCollectionImpl.ROW ); + return _rows; + } + + + public HTMLCollection getTBodies() + { + if ( _bodies == null ) + _bodies = new HTMLCollectionImpl( this, HTMLCollectionImpl.TBODY ); + return _bodies; + } + + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getBgColor() + { + return getAttribute( "bgcolor" ); + } + + + public void setBgColor( String bgColor ) + { + setAttribute( "bgcolor", bgColor ); + } + + + public String getBorder() + { + return getAttribute( "border" ); + } + + + public void setBorder( String border ) + { + setAttribute( "border", border ); + } + + + public String getCellPadding() + { + return getAttribute( "cellpadding" ); + } + + + public void setCellPadding( String cellPadding ) + { + setAttribute( "cellpadding", cellPadding ); + } + + + public String getCellSpacing() + { + return getAttribute( "cellspacing" ); + } + + + public void setCellSpacing( String cellSpacing ) + { + setAttribute( "cellspacing", cellSpacing ); + } + + + public String getFrame() + { + return capitalize( getAttribute( "frame" ) ); + } + + + public void setFrame( String frame ) + { + setAttribute( "frame", frame ); + } + + + public String getRules() + { + return capitalize( getAttribute( "rules" ) ); + } + + + public void setRules( String rules ) + { + setAttribute( "rules", rules ); + } + + + public String getSummary() + { + return getAttribute( "summary" ); + } + + + public void setSummary( String summary ) + { + setAttribute( "summary", summary ); + } + + + public String getWidth() + { + return getAttribute( "width" ); + } + + + public void setWidth( String width ) + { + setAttribute( "width", width ); + } + + + public HTMLElement insertRow( int index ) + { + HTMLTableRowElementImpl newRow; + + newRow = new HTMLTableRowElementImpl( (HTMLDocumentImpl) getOwnerDocument(), "TR" ); + //newRow.insertCell( 0 ); + insertRowX( index, newRow ); + return newRow; + } + + + void insertRowX( int index, HTMLTableRowElementImpl newRow ) + { + Node child; + Node lastSection = null; + + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableRowElement ) + { + if ( index == 0 ) + { + insertBefore( newRow, child ); + return; + } + } + else + if ( child instanceof HTMLTableSectionElementImpl ) + { + lastSection = child; + index = ( (HTMLTableSectionElementImpl) child ).insertRowX( index, newRow ); + if ( index < 0 ) + return; + } + child = child.getNextSibling(); + } + if ( lastSection != null ) + lastSection.appendChild( newRow ); + else + appendChild( newRow ); + } + + + public synchronized void deleteRow( int index ) + { + Node child; + + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableRowElement ) + { + if ( index == 0 ) + { + removeChild ( child ); + return; + } + --index; + } + else + if ( child instanceof HTMLTableSectionElementImpl ) + { + index = ( (HTMLTableSectionElementImpl) child ).deleteRowX( index ); + if ( index < 0 ) + return; + } + child = child.getNextSibling(); + } + } + + /** + * Explicit implementation of cloneNode() to ensure that cache used + * for getRows() and getTBodies() gets cleared. + */ + public Node cloneNode( boolean deep ) { + HTMLTableElementImpl clonedNode = (HTMLTableElementImpl)super.cloneNode( deep ); + clonedNode._rows = null; + clonedNode._bodies = null; + return clonedNode; + } + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLTableElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + + private HTMLCollectionImpl _rows; + + + private HTMLCollectionImpl _bodies; + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLTableRowElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableRowElementImpl.java new file mode 100644 index 0000000..b021c1f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableRowElementImpl.java @@ -0,0 +1,276 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLTableCellElement; +import org.w3c.dom.html.HTMLTableElement; +import org.w3c.dom.html.HTMLTableRowElement; +import org.w3c.dom.html.HTMLTableSectionElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLTableRowElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLTableRowElementImpl + extends HTMLElementImpl + implements HTMLTableRowElement +{ + + private static final long serialVersionUID = 5409562635656244263L; + + public int getRowIndex() + { + Node parent; + + parent = getParentNode(); + if ( parent instanceof HTMLTableSectionElement ) { + parent = parent.getParentNode(); + } + if ( parent instanceof HTMLTableElement ) { + return getRowIndex( parent ); + } + return -1; + } + + + public void setRowIndex( int rowIndex ) + { + Node parent; + + parent = getParentNode(); + if ( parent instanceof HTMLTableSectionElement ) { + parent = parent.getParentNode(); + } + if ( parent instanceof HTMLTableElement ) { + ( (HTMLTableElementImpl) parent ).insertRowX( rowIndex, this ); + } + } + + + public int getSectionRowIndex() + { + Node parent; + + parent = getParentNode(); + if ( parent instanceof HTMLTableSectionElement ) { + return getRowIndex( parent ); + } + return -1; + } + + + public void setSectionRowIndex( int sectionRowIndex ) + { + Node parent; + + parent = getParentNode(); + if ( parent instanceof HTMLTableSectionElement ) { + ( (HTMLTableSectionElementImpl) parent ).insertRowX( sectionRowIndex, this ); + } + } + + + int getRowIndex( Node parent ) + { + NodeList rows; + int i; + + // Use getElementsByTagName() which creates a snapshot of all the + // TR elements under the TABLE/section. Access to the returned NodeList + // is very fast and the snapshot solves many synchronization problems. + rows = ( (HTMLElement) parent ).getElementsByTagName( "TR" ); + for ( i = 0 ; i < rows.getLength() ; ++i ) { + if ( rows.item( i ) == this ) { + return i; + } + } + return -1; + } + + + public HTMLCollection getCells() + { + if ( _cells == null ) { + _cells = new HTMLCollectionImpl( this, HTMLCollectionImpl.CELL ); + } + return _cells; + } + + + public void setCells( HTMLCollection cells ) + { + Node child; + int i; + + child = getFirstChild(); + while ( child != null ) { + removeChild( child ); + child = child.getNextSibling(); + } + i = 0; + child = cells.item( i ); + while ( child != null ) { + appendChild ( child ); + ++i; + child = cells.item( i ); + } + } + + + public HTMLElement insertCell( int index ) + { + Node child; + HTMLElement newCell; + + newCell = new HTMLTableCellElementImpl( (HTMLDocumentImpl) getOwnerDocument(), "TD" ); + child = getFirstChild(); + while ( child != null ) { + if ( child instanceof HTMLTableCellElement ) { + if ( index == 0 ) { + insertBefore( newCell, child ); + return newCell; + } + --index; + } + child = child.getNextSibling(); + } + appendChild( newCell ); + return newCell; + } + + + public void deleteCell( int index ) + { + Node child; + + child = getFirstChild(); + while ( child != null ) { + if ( child instanceof HTMLTableCellElement ) { + if ( index == 0 ) { + removeChild ( child ); + return; + } + --index; + } + child = child.getNextSibling(); + } + } + + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getBgColor() + { + return getAttribute( "bgcolor" ); + } + + + public void setBgColor( String bgColor ) + { + setAttribute( "bgcolor", bgColor ); + } + + + public String getCh() + { + String ch; + + // Make sure that the access key is a single character. + ch = getAttribute( "char" ); + if ( ch != null && ch.length() > 1 ) { + ch = ch.substring( 0, 1 ); + } + return ch; + } + + + public void setCh( String ch ) + { + // Make sure that the access key is a single character. + if ( ch != null && ch.length() > 1 ) { + ch = ch.substring( 0, 1 ); + } + setAttribute( "char", ch ); + } + + + public String getChOff() + { + return getAttribute( "charoff" ); + } + + + public void setChOff( String chOff ) + { + setAttribute( "charoff", chOff ); + } + + + public String getVAlign() + { + return capitalize( getAttribute( "valign" ) ); + } + + + public void setVAlign( String vAlign ) + { + setAttribute( "valign", vAlign ); + } + + /** + * Explicit implementation of cloneNode() to ensure that cache used + * for getCells() gets cleared. + */ + public Node cloneNode( boolean deep ) { + HTMLTableRowElementImpl clonedNode = (HTMLTableRowElementImpl)super.cloneNode( deep ); + clonedNode._cells = null; + return clonedNode; + } + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLTableRowElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + + HTMLCollection _cells; + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLTableSectionElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableSectionElementImpl.java new file mode 100644 index 0000000..030ab08 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLTableSectionElementImpl.java @@ -0,0 +1,190 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.html.HTMLCollection; +import org.w3c.dom.html.HTMLElement; +import org.w3c.dom.html.HTMLTableRowElement; +import org.w3c.dom.html.HTMLTableSectionElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLTableSectionElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLTableSectionElementImpl + extends HTMLElementImpl + implements HTMLTableSectionElement +{ + + private static final long serialVersionUID = 1016412997716618027L; + + public String getAlign() + { + return capitalize( getAttribute( "align" ) ); + } + + + public void setAlign( String align ) + { + setAttribute( "align", align ); + } + + + public String getCh() + { + String ch; + + // Make sure that the access key is a single character. + ch = getAttribute( "char" ); + if ( ch != null && ch.length() > 1 ) + ch = ch.substring( 0, 1 ); + return ch; + } + + + public void setCh( String ch ) + { + // Make sure that the access key is a single character. + if ( ch != null && ch.length() > 1 ) + ch = ch.substring( 0, 1 ); + setAttribute( "char", ch ); + } + + + public String getChOff() + { + return getAttribute( "charoff" ); + } + + + public void setChOff( String chOff ) + { + setAttribute( "charoff", chOff ); + } + + + public String getVAlign() + { + return capitalize( getAttribute( "valign" ) ); + } + + + public void setVAlign( String vAlign ) + { + setAttribute( "valign", vAlign ); + } + + + public HTMLCollection getRows() + { + if ( _rows == null ) + _rows = new HTMLCollectionImpl( this, HTMLCollectionImpl.ROW ); + return _rows; + } + + + public HTMLElement insertRow( int index ) + { + HTMLTableRowElementImpl newRow; + + newRow = new HTMLTableRowElementImpl( (HTMLDocumentImpl) getOwnerDocument(), "TR" ); + newRow.insertCell( 0 ); + if ( insertRowX( index, newRow ) >= 0 ) + appendChild( newRow ); + return newRow; + } + + + int insertRowX( int index, HTMLTableRowElementImpl newRow ) + { + Node child; + + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableRowElement ) + { + if ( index == 0 ) + { + insertBefore( newRow, child ); + return -1; + } + --index; + } + child = child.getNextSibling(); + } + return index; + } + + + public void deleteRow( int index ) + { + deleteRowX( index ); + } + + + int deleteRowX( int index ) + { + Node child; + + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof HTMLTableRowElement ) + { + if ( index == 0 ) + { + removeChild ( child ); + return -1; + } + --index; + } + child = child.getNextSibling(); + } + return index; + } + + /** + * Explicit implementation of cloneNode() to ensure that cache used + * for getRows() gets cleared. + */ + public Node cloneNode( boolean deep ) { + HTMLTableSectionElementImpl clonedNode = (HTMLTableSectionElementImpl)super.cloneNode( deep ); + clonedNode._rows = null; + return clonedNode; + } + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLTableSectionElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + + private HTMLCollectionImpl _rows; + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLTextAreaElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLTextAreaElementImpl.java new file mode 100644 index 0000000..2837a2e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLTextAreaElementImpl.java @@ -0,0 +1,191 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLTextAreaElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLTextAreaElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLTextAreaElementImpl + extends HTMLElementImpl + implements HTMLTextAreaElement, HTMLFormControl +{ + + private static final long serialVersionUID = -6737778308542678104L; + + public String getDefaultValue() + { + // ! NOT FULLY IMPLEMENTED ! + return getAttribute( "default-value" ); + } + + + public void setDefaultValue( String defaultValue ) + { + // ! NOT FULLY IMPLEMENTED ! + setAttribute( "default-value", defaultValue ); + } + + + + public String getAccessKey() + { + String accessKey; + + // Make sure that the access key is a single character. + accessKey = getAttribute( "accesskey" ); + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + return accessKey; + } + + + public void setAccessKey( String accessKey ) + { + // Make sure that the access key is a single character. + if ( accessKey != null && accessKey.length() > 1 ) + accessKey = accessKey.substring( 0, 1 ); + setAttribute( "accesskey", accessKey ); + } + + + public int getCols() + { + return getInteger( getAttribute( "cols" ) ); + } + + + public void setCols( int cols ) + { + setAttribute( "cols", String.valueOf( cols ) ); + } + + + public boolean getDisabled() + { + return getBinary( "disabled" ); + } + + + public void setDisabled( boolean disabled ) + { + setAttribute( "disabled", disabled ); + } + + + public String getName() + { + return getAttribute( "name" ); + } + + + public void setName( String name ) + { + setAttribute( "name", name ); + } + + + public boolean getReadOnly() + { + return getBinary( "readonly" ); + } + + + public void setReadOnly( boolean readOnly ) + { + setAttribute( "readonly", readOnly ); + } + + + public int getRows() + { + return getInteger( getAttribute( "rows" ) ); + } + + + public void setRows( int rows ) + { + setAttribute( "rows", String.valueOf( rows ) ); + } + + + public int getTabIndex() + { + return getInteger( getAttribute( "tabindex" ) ); + } + + + public void setTabIndex( int tabIndex ) + { + setAttribute( "tabindex", String.valueOf( tabIndex ) ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public String getValue() + { + return getAttribute( "value" ); + } + + + public void setValue( String value ) + { + setAttribute( "value", value ); + } + + + public void blur() + { + // No scripting in server-side DOM. This method is moot. + } + + + public void focus() + { + // No scripting in server-side DOM. This method is moot. + } + + + public void select() + { + // No scripting in server-side DOM. This method is moot. + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLTextAreaElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLTitleElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLTitleElementImpl.java new file mode 100644 index 0000000..0e7bb3a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLTitleElementImpl.java @@ -0,0 +1,86 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.w3c.dom.html.HTMLTitleElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLTitleElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLTitleElementImpl + extends HTMLElementImpl + implements HTMLTitleElement +{ + + private static final long serialVersionUID = 879646303512367875L; + + public String getText() + { + Node child; + StringBuffer text = new StringBuffer(); + + // Find the Text nodes contained within this element and return their + // concatenated value. Required to go around comments, entities, etc. + child = getFirstChild(); + while ( child != null ) + { + if ( child instanceof Text ) { + text.append(( (Text) child ).getData()); + } + child = child.getNextSibling(); + } + return text.toString(); + } + + + public void setText( String text ) + { + Node child; + Node next; + + // Delete all the nodes and replace them with a single Text node. + // This is the only approach that can handle comments and other nodes. + child = getFirstChild(); + while ( child != null ) + { + next = child.getNextSibling(); + removeChild( child ); + child = next; + } + insertBefore( getOwnerDocument().createTextNode( text ), getFirstChild() ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLTitleElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/HTMLUListElementImpl.java b/resources/xerces2-j-src/org/apache/html/dom/HTMLUListElementImpl.java new file mode 100644 index 0000000..ebb84d8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/HTMLUListElementImpl.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package org.apache.html.dom; + +import org.w3c.dom.html.HTMLUListElement; + +/** + * @xerces.internal + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see org.w3c.dom.html.HTMLUListElement + * @see org.apache.xerces.dom.ElementImpl + */ +public class HTMLUListElementImpl + extends HTMLElementImpl + implements HTMLUListElement +{ + + private static final long serialVersionUID = -3220401442015109211L; + + public boolean getCompact() + { + return getBinary( "compact" ); + } + + + public void setCompact( boolean compact ) + { + setAttribute( "compact", compact ); + } + + + public String getType() + { + return getAttribute( "type" ); + } + + + public void setType( String type ) + { + setAttribute( "type", type ); + } + + + /** + * Constructor requires owner document. + * + * @param owner The owner HTML document + */ + public HTMLUListElementImpl( HTMLDocumentImpl owner, String name ) + { + super( owner, name ); + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/html/dom/NameNodeListImpl.java b/resources/xerces2-j-src/org/apache/html/dom/NameNodeListImpl.java new file mode 100644 index 0000000..225c07d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/NameNodeListImpl.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +package org.apache.html.dom; + +import org.apache.xerces.dom.DeepNodeListImpl; +import org.apache.xerces.dom.ElementImpl; +import org.apache.xerces.dom.NodeImpl; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * This class implements the DOM's NodeList behavior for + * HTMLDocuemnt.getElementsByName(). + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + * @see DeepNodeListImpl + */ +public class NameNodeListImpl + extends DeepNodeListImpl + implements NodeList { + + + /** Constructor. */ + public NameNodeListImpl(NodeImpl rootNode, String tagName) { + super( rootNode, tagName ); + } + + + /** + * Iterative tree-walker. When you have a Parent link, there's often no + * need to resort to recursion. NOTE THAT only Element nodes are matched + * since we're specifically supporting getElementsByTagName(). + */ + protected Node nextMatchingElementAfter(Node current) { + + Node next; + while (current != null) { + // Look down to first child. + if (current.hasChildNodes()) { + current = (current.getFirstChild()); + } + + // Look right to sibling (but not from root!) + else if (current != rootNode && null != (next = current.getNextSibling())) { + current = next; + } + + // Look up and right (but not past root!) + else { + next = null; + for (; current != rootNode; // Stop when we return to starting point + current = current.getParentNode()) { + + next = current.getNextSibling(); + if (next != null) + break; + } + current = next; + } + + // Have we found an Element with the right tagName? + // ("*" matches anything.) + if (current != rootNode && current != null + && current.getNodeType() == Node.ELEMENT_NODE ) { + String name = ((ElementImpl) current).getAttribute( "name" ); + if ( name.equals("*") || name.equals(tagName)) + return current; + } + + // Otherwise continue walking the tree + } + + // Fell out of tree-walk; no more instances found + return null; + + } // nextMatchingElementAfter(int):Node + +} // class NameNodeListImpl diff --git a/resources/xerces2-j-src/org/apache/html/dom/ObjectFactory.java b/resources/xerces2-j-src/org/apache/html/dom/ObjectFactory.java new file mode 100644 index 0000000..7a04cbe --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/ObjectFactory.java @@ -0,0 +1,545 @@ +/* + * 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. + */ + +package org.apache.html.dom; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; + +/** + * This class is duplicated for each JAXP subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of the JAXP + * API. + *

+ * This code is designed to implement the JAXP 1.1 spec pluggability + * feature and is designed to run on JDK version 1.1 and + * later, and to compile on JDK 1.2 and onward. + * The code also runs both as part of an unbundled jar file and + * when bundled as part of the JDK. + *

+ * + * @xerces.internal + * + * @version $Id$ + */ +final class ObjectFactory { + + // + // Constants + // + + // name of default properties file to look for in JDK's jre/lib directory + private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties"; + + /** Set to true for debugging */ + private static final boolean DEBUG = isDebugEnabled(); + + /** + * Default columns per line. + */ + private static final int DEFAULT_LINE_LENGTH = 80; + + /** cache the contents of the xerces.properties file. + * Until an attempt has been made to read this file, this will + * be null; if the file does not exist or we encounter some other error + * during the read, this will be empty. + */ + private static Properties fXercesProperties = null; + + /*** + * Cache the time stamp of the xerces.properties file so + * that we know if it's been modified and can invalidate + * the cache when necessary. + */ + private static long fLastModified = -1; + + // + // static methods + // + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *

    + *
  1. query the system property using System.getProperty + *
  2. read META-INF/services/factoryId file + *
  3. use fallback classname + *
+ * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, String fallbackClassName) + throws ConfigurationError { + return createObject(factoryId, null, fallbackClassName); + } // createObject(String,String):Object + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *
    + *
  1. query the system property using System.getProperty + *
  2. read $java.home/lib/propertiesFilename file + *
  3. read META-INF/services/factoryId file + *
  4. use fallback classname + *
+ * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param propertiesFilename The filename in the $java.home/lib directory + * of the properties file. If none specified, + * ${java.home}/lib/xerces.properties will be used. + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, + String propertiesFilename, + String fallbackClassName) + throws ConfigurationError + { + if (DEBUG) debugPrintln("debug is on"); + + ClassLoader cl = findClassLoader(); + + // Use the system property first + try { + String systemProp = SecuritySupport.getSystemProperty(factoryId); + if (systemProp != null && systemProp.length() > 0) { + if (DEBUG) debugPrintln("found system property, value=" + systemProp); + return newInstance(systemProp, cl, true); + } + } catch (SecurityException se) { + // Ignore and continue w/ next location + } + + // Try to read from propertiesFilename, or $java.home/lib/xerces.properties + String factoryClassName = null; + // no properties file name specified; use $JAVA_HOME/lib/xerces.properties: + if (propertiesFilename == null) { + File propertiesFile = null; + boolean propertiesFileExists = false; + try { + String javah = SecuritySupport.getSystemProperty("java.home"); + propertiesFilename = javah + File.separator + + "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME; + propertiesFile = new File(propertiesFilename); + propertiesFileExists = SecuritySupport.getFileExists(propertiesFile); + } catch (SecurityException e) { + // try again... + fLastModified = -1; + fXercesProperties = null; + } + + synchronized (ObjectFactory.class) { + boolean loadProperties = false; + FileInputStream fis = null; + try { + // file existed last time + if(fLastModified >= 0) { + if(propertiesFileExists && + (fLastModified < (fLastModified = SecuritySupport.getLastModified(propertiesFile)))) { + loadProperties = true; + } else { + // file has stopped existing... + if(!propertiesFileExists) { + fLastModified = -1; + fXercesProperties = null; + } // else, file wasn't modified! + } + } else { + // file has started to exist: + if(propertiesFileExists) { + loadProperties = true; + fLastModified = SecuritySupport.getLastModified(propertiesFile); + } // else, nothing's changed + } + if(loadProperties) { + // must never have attempted to read xerces.properties before (or it's outdeated) + fXercesProperties = new Properties(); + fis = SecuritySupport.getFileInputStream(propertiesFile); + fXercesProperties.load(fis); + } + } catch (Exception x) { + fXercesProperties = null; + fLastModified = -1; + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if(fXercesProperties != null) { + factoryClassName = fXercesProperties.getProperty(factoryId); + } + } else { + FileInputStream fis = null; + try { + fis = SecuritySupport.getFileInputStream(new File(propertiesFilename)); + Properties props = new Properties(); + props.load(fis); + factoryClassName = props.getProperty(factoryId); + } catch (Exception x) { + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if (factoryClassName != null) { + if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName); + return newInstance(factoryClassName, cl, true); + } + + // Try Jar Service Provider Mechanism + Object provider = findJarServiceProvider(factoryId); + if (provider != null) { + return provider; + } + + if (fallbackClassName == null) { + throw new ConfigurationError( + "Provider for " + factoryId + " cannot be found", null); + } + + if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); + return newInstance(fallbackClassName, cl, true); + } // createObject(String,String,String):Object + + // + // Private static methods + // + + /** Returns true if debug has been enabled. */ + private static boolean isDebugEnabled() { + try { + String val = SecuritySupport.getSystemProperty("xerces.debug"); + // Allow simply setting the prop to turn on debug + return (val != null && (!"false".equals(val))); + } + catch (SecurityException se) {} + return false; + } // isDebugEnabled() + + /** Prints a message to standard error if debugging is enabled. */ + private static void debugPrintln(String msg) { + if (DEBUG) { + System.err.println("XERCES: " + msg); + } + } // debugPrintln(String) + + /** + * Figure out which ClassLoader to use. For JDK 1.2 and later use + * the context ClassLoader. + */ + static ClassLoader findClassLoader() + throws ConfigurationError + { + // Figure out which ClassLoader to use for loading the provider + // class. If there is a Context ClassLoader then use it. + ClassLoader context = SecuritySupport.getContextClassLoader(); + ClassLoader system = SecuritySupport.getSystemClassLoader(); + + ClassLoader chain = system; + while (true) { + if (context == chain) { + // Assert: we are on JDK 1.1 or we have no Context ClassLoader + // or any Context ClassLoader in chain of system classloader + // (including extension ClassLoader) so extend to widest + // ClassLoader (always look in system ClassLoader if Xerces + // is in boot/extension/system classpath and in current + // ClassLoader otherwise); normal classloaders delegate + // back to system ClassLoader first so this widening doesn't + // change the fact that context ClassLoader will be consulted + ClassLoader current = ObjectFactory.class.getClassLoader(); + + chain = system; + while (true) { + if (current == chain) { + // Assert: Current ClassLoader in chain of + // boot/extension/system ClassLoaders + return system; + } + if (chain == null) { + break; + } + chain = SecuritySupport.getParentClassLoader(chain); + } + + // Assert: Current ClassLoader not in chain of + // boot/extension/system ClassLoaders + return current; + } + + if (chain == null) { + // boot ClassLoader reached + break; + } + + // Check for any extension ClassLoaders in chain up to + // boot ClassLoader + chain = SecuritySupport.getParentClassLoader(chain); + }; + + // Assert: Context ClassLoader not in chain of + // boot/extension/system ClassLoaders + return context; + } // findClassLoader():ClassLoader + + /** + * Create an instance of a class using the specified ClassLoader + */ + static Object newInstance(String className, ClassLoader cl, + boolean doFallback) + throws ConfigurationError + { + // assert(className != null); + try{ + Class providerClass = findProviderClass(className, cl, doFallback); + Object instance = providerClass.newInstance(); + if (DEBUG) debugPrintln("created new instance of " + providerClass + + " using ClassLoader: " + cl); + return instance; + } catch (ClassNotFoundException x) { + throw new ConfigurationError( + "Provider " + className + " not found", x); + } catch (Exception x) { + throw new ConfigurationError( + "Provider " + className + " could not be instantiated: " + x, + x); + } + } + + /** + * Find a Class using the specified ClassLoader + */ + static Class findProviderClass(String className, ClassLoader cl, + boolean doFallback) + throws ClassNotFoundException, ConfigurationError + { + //throw security exception if the calling thread is not allowed to access the package + //restrict the access to package as specified in java.security policy + SecurityManager security = System.getSecurityManager(); + if (security != null) { + final int lastDot = className.lastIndexOf('.'); + String packageName = className; + if (lastDot != -1) packageName = className.substring(0, lastDot); + security.checkPackageAccess(packageName); + } + Class providerClass; + if (cl == null) { + // XXX Use the bootstrap ClassLoader. There is no way to + // load a class using the bootstrap ClassLoader that works + // in both JDK 1.1 and Java 2. However, this should still + // work b/c the following should be true: + // + // (cl == null) iff current ClassLoader == null + // + // Thus Class.forName(String) will use the current + // ClassLoader which will be the bootstrap ClassLoader. + providerClass = Class.forName(className); + } else { + try { + providerClass = cl.loadClass(className); + } catch (ClassNotFoundException x) { + if (doFallback) { + // Fall back to current classloader + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (current == null) { + providerClass = Class.forName(className); + } else if (cl != current) { + cl = current; + providerClass = cl.loadClass(className); + } else { + throw x; + } + } else { + throw x; + } + } + } + + return providerClass; + } + + /* + * Try to find provider using Jar Service Provider Mechanism + * + * @return instance of provider class if found or null + */ + private static Object findJarServiceProvider(String factoryId) + throws ConfigurationError + { + String serviceId = "META-INF/services/" + factoryId; + InputStream is = null; + + // First try the Context ClassLoader + ClassLoader cl = findClassLoader(); + + is = SecuritySupport.getResourceAsStream(cl, serviceId); + + // If no provider found then try the current ClassLoader + if (is == null) { + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (cl != current) { + cl = current; + is = SecuritySupport.getResourceAsStream(cl, serviceId); + } + } + + if (is == null) { + // No provider found + return null; + } + + if (DEBUG) debugPrintln("found jar resource=" + serviceId + + " using ClassLoader: " + cl); + + // Read the service provider name in UTF-8 as specified in + // the jar spec. Unfortunately this fails in Microsoft + // VJ++, which does not implement the UTF-8 + // encoding. Theoretically, we should simply let it fail in + // that case, since the JVM is obviously broken if it + // doesn't support such a basic standard. But since there + // are still some users attempting to use VJ++ for + // development, we have dropped in a fallback which makes a + // second attempt using the platform's default encoding. In + // VJ++ this is apparently ASCII, which is a subset of + // UTF-8... and since the strings we'll be reading here are + // also primarily limited to the 7-bit ASCII range (at + // least, in English versions), this should work well + // enough to keep us on the air until we're ready to + // officially decommit from VJ++. [Edited comment from + // jkesselm] + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); + } catch (java.io.UnsupportedEncodingException e) { + rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); + } + + String factoryClassName = null; + try { + // XXX Does not handle all possible input as specified by the + // Jar Service Provider specification + factoryClassName = rd.readLine(); + } catch (IOException x) { + // No provider found + return null; + } + finally { + try { + // try to close the reader. + rd.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + + if (factoryClassName != null && + ! "".equals(factoryClassName)) { + if (DEBUG) debugPrintln("found in resource, value=" + + factoryClassName); + + // Note: here we do not want to fall back to the current + // ClassLoader because we want to avoid the case where the + // resource file was found using one ClassLoader and the + // provider class was instantiated using a different one. + return newInstance(factoryClassName, cl, false); + } + + // No provider found + return null; + } + + // + // Classes + // + + /** + * A configuration error. + */ + static final class ConfigurationError + extends Error { + + /** Serialization version. */ + static final long serialVersionUID = 2646822752226280048L; + + // + // Data + // + + /** Exception. */ + private Exception exception; + + // + // Constructors + // + + /** + * Construct a new instance with the specified detail string and + * exception. + */ + ConfigurationError(String msg, Exception x) { + super(msg); + this.exception = x; + } // (String,Exception) + + // + // methods + // + + /** Returns the exception associated to this error. */ + Exception getException() { + return exception; + } // getException():Exception + + } // class ConfigurationError + +} // class ObjectFactory diff --git a/resources/xerces2-j-src/org/apache/html/dom/SecuritySupport.java b/resources/xerces2-j-src/org/apache/html/dom/SecuritySupport.java new file mode 100644 index 0000000..07bdfce --- /dev/null +++ b/resources/xerces2-j-src/org/apache/html/dom/SecuritySupport.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.html.dom; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * This class is duplicated for each subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of any API. + * + * @xerces.internal + * + * @version $Id$ + */ +final class SecuritySupport { + + static ClassLoader getContextClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (SecurityException ex) { } + return cl; + } + }); + } + + static ClassLoader getSystemClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (SecurityException ex) {} + return cl; + } + }); + } + + static ClassLoader getParentClassLoader(final ClassLoader cl) { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader parent = null; + try { + parent = cl.getParent(); + } catch (SecurityException ex) {} + + // eliminate loops in case of the boot + // ClassLoader returning itself as a parent + return (parent == cl) ? null : parent; + } + }); + } + + static String getSystemProperty(final String propName) { + return (String) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(propName); + } + }); + } + + static FileInputStream getFileInputStream(final File file) + throws FileNotFoundException + { + try { + return (FileInputStream) + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws FileNotFoundException { + return new FileInputStream(file); + } + }); + } catch (PrivilegedActionException e) { + throw (FileNotFoundException)e.getException(); + } + } + + static InputStream getResourceAsStream(final ClassLoader cl, + final String name) + { + return (InputStream) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + InputStream ris; + if (cl == null) { + ris = ClassLoader.getSystemResourceAsStream(name); + } else { + ris = cl.getResourceAsStream(name); + } + return ris; + } + }); + } + + static boolean getFileExists(final File f) { + return ((Boolean) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return f.exists() ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + } + + static long getLastModified(final File f) { + return ((Long) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return new Long(f.lastModified()); + } + })).longValue(); + } + + private SecuritySupport () {} +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLAElement.java b/resources/xerces2-j-src/org/apache/wml/WMLAElement.java new file mode 100644 index 0000000..bbb20f7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLAElement.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLAElement extends WMLElement { + + public void setHref(String newValue); + public String getHref(); + + public void setTitle(String newValue); + public String getTitle(); + + public void setId(String newValue); + public String getId(); + + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLAccessElement.java b/resources/xerces2-j-src/org/apache/wml/WMLAccessElement.java new file mode 100644 index 0000000..6c39c20 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLAccessElement.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'access' element specifics the access control for the entire deck + * (Section 11.3.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLAccessElement extends WMLElement { + + /** + * A deck's domain and path attributes specify which deck may + * access it. + * + * domain attribute is suffix-matched against the domain name + * portion of the referring URI + */ + public void setDomain(String newValue); + public String getDomain(); + + /** + * path attribute is prefix-matched against the path portion of + * the referring URI + */ + public void setPath(String newValue); + public String getPath(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLAnchorElement.java b/resources/xerces2-j-src/org/apache/wml/WMLAnchorElement.java new file mode 100644 index 0000000..8f8e31d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLAnchorElement.java @@ -0,0 +1,41 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLAnchorElement extends WMLElement { + + public void setTitle(String newValue); + public String getTitle(); + + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLBElement.java b/resources/xerces2-j-src/org/apache/wml/WMLBElement.java new file mode 100644 index 0000000..5e67174 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLBElement.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'b' element boldface the text + * (Section 11.8.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLBElement extends WMLElement { + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLBigElement.java b/resources/xerces2-j-src/org/apache/wml/WMLBigElement.java new file mode 100644 index 0000000..28a96af --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLBigElement.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'big' element renders the text with big font + * (Section 11.8.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLBigElement extends WMLElement { + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLBrElement.java b/resources/xerces2-j-src/org/apache/wml/WMLBrElement.java new file mode 100644 index 0000000..adb6af5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLBrElement.java @@ -0,0 +1,39 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'br' element starts a new line

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLBrElement extends WMLElement { + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLCardElement.java b/resources/xerces2-j-src/org/apache/wml/WMLCardElement.java new file mode 100644 index 0000000..de15b9a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLCardElement.java @@ -0,0 +1,88 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'card' element is the basic display unit of WML. A WML decks + * contains a collection of cards. + * (Section 11.5, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLCardElement extends WMLElement { + + /** + * 'onenterbackward' specifies the event to occur when a user + * agent into a card using a 'go' task + * (Section 11.5.1, WAP WML Version 16-Jun-1999) + */ + public void setOnEnterBackward(String href); + public String getOnEnterBackward(); + + /** + * 'onenterforward' specifies the event to occur when a user + * agent into a card using a 'prev' task + * (Section 11.5.1, WAP WML Version 16-Jun-1999) + */ + public void setOnEnterForward(String href); + public String getOnEnterForward(); + + /** + * 'onenterbackward' specifies the event to occur when a timer expires + * (Section 11.5.1, WAP WML Version 16-Jun-1999) + */ + public void setOnTimer(String href); + public String getOnTimer(); + + /** + * 'title' specifies a advisory info about the card + * (Section 11.5.2, WAP WML Version 16-Jun-1999) + */ + public void setTitle(String newValue); + public String getTitle(); + + /** + * 'newcontext' specifies whether a browser context should be + * re-initialized upon entering the card. Default to be false. + * (Section 11.5.2, WAP WML Version 16-Jun-1999) + */ + public void setNewContext(boolean newValue); + public boolean getNewContext(); + + /** + * 'ordered' attribute specifies a hit to user agent about the + * organization of the card's content + * (Section 11.5.2, WAP WML Version 16-Jun-1999) + */ + public void setOrdered(boolean newValue); + public boolean getOrdered(); + + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLDOMImplementation.java b/resources/xerces2-j-src/org/apache/wml/WMLDOMImplementation.java new file mode 100644 index 0000000..07517e5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLDOMImplementation.java @@ -0,0 +1,31 @@ +/* + * 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. + */ +package org.apache.wml; + +import org.w3c.dom.DOMImplementation; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ +public interface WMLDOMImplementation extends DOMImplementation { +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLDoElement.java b/resources/xerces2-j-src/org/apache/wml/WMLDoElement.java new file mode 100644 index 0000000..a1cb03a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLDoElement.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLDoElement extends WMLElement { + + public void setOptional(String newValue); + public String getOptional(); + + public void setLabel(String newValue); + public String getLabel(); + + public void setType(String newValue); + public String getType(); + + public void setName(String newValue); + public String getName(); + + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLDocument.java b/resources/xerces2-j-src/org/apache/wml/WMLDocument.java new file mode 100644 index 0000000..b09b59d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLDocument.java @@ -0,0 +1,32 @@ +/* + * 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. + */ +package org.apache.wml; + +import org.w3c.dom.Document; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLDocument extends Document { +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLElement.java b/resources/xerces2-j-src/org/apache/wml/WMLElement.java new file mode 100644 index 0000000..20da15a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLElement.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package org.apache.wml; + +import org.w3c.dom.Element; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

All WML Elements are derived from this class that contains two + * core attributes defined in the DTD.

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLElement extends Element { + + /** + * The element's identifier which is unique in a single deck. + * (Section 8.9, WAP WML Version 16-Jun-1999) + */ + public void setId(String newValue); + public String getId(); + + /** + * The 'class' attribute of a element that affiliates an elements + * with one or more elements. + * (Section 8.9, WAP WML Version 16-Jun-1999) + */ + public void setClassName(String newValue); + public String getClassName(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLEmElement.java b/resources/xerces2-j-src/org/apache/wml/WMLEmElement.java new file mode 100644 index 0000000..3f93825 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLEmElement.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'em' element emphasis the text + * (Section 11.8.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLEmElement extends WMLElement { + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLFieldsetElement.java b/resources/xerces2-j-src/org/apache/wml/WMLFieldsetElement.java new file mode 100644 index 0000000..34e7338 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLFieldsetElement.java @@ -0,0 +1,46 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'fieldset' element groups related fields and tet + * (Section 11.6.4, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ +public interface WMLFieldsetElement extends WMLElement { + + /** + * 'title' specifies a title for this element + */ + public void setTitle(String newValue); + public String getTitle(); + + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLGoElement.java b/resources/xerces2-j-src/org/apache/wml/WMLGoElement.java new file mode 100644 index 0000000..2f7e791 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLGoElement.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLGoElement extends WMLElement { + + public void setSendreferer(String newValue); + + public String getSendreferer(); + + public void setAcceptCharset(String newValue); + + public String getAcceptCharset(); + + public void setHref(String newValue); + + public String getHref(); + + public void setMethod(String newValue); + + public String getMethod(); + +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLHeadElement.java b/resources/xerces2-j-src/org/apache/wml/WMLHeadElement.java new file mode 100644 index 0000000..e197e60 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLHeadElement.java @@ -0,0 +1,33 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

The head element contains information about a deck. + * (Section 11.3, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLHeadElement extends WMLElement { +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLIElement.java b/resources/xerces2-j-src/org/apache/wml/WMLIElement.java new file mode 100644 index 0000000..9ecc546 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLIElement.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'i' italic the text + * (Section 11.8.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLIElement extends WMLElement { + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLImgElement.java b/resources/xerces2-j-src/org/apache/wml/WMLImgElement.java new file mode 100644 index 0000000..b8abb1f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLImgElement.java @@ -0,0 +1,100 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'img' specifies an image in a text flow + * (Section 11.9, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ +public interface WMLImgElement extends WMLElement { + + /** + * 'alt' specifies an alternative text for the image + * (Section 11.9, WAP WML Version 16-Jun-1999) + */ + public void setAlt(String newValue); + public String getAlt(); + + /** + * 'src' specifies URI for the source images + * (Section 11.9, WAP WML Version 16-Jun-1999) + */ + public void setSrc(String newValue); + public String getSrc(); + + /** + * 'localsrc' specifies an alternative internal representation of + * the image. + * (Section 11.9, WAP WML Version 16-Jun-1999) + */ + public void setLocalSrc(String newValue); + public String getLocalSrc(); + + /** + * 'vspace' specifies the abount of white space to be inserted + * above and below + * (Section 11.9, WAP WML Version 16-Jun-1999) + */ + public void setVspace(String newValue); + public String getVspace(); + + /** + * 'hspace' specifies the abount of white space to be inserted + * left and right + * (Section 11.9, WAP WML Version 16-Jun-1999) + */ + public void setHspace(String newValue); + public String getHspace(); + + /** + * 'align' specifies the alignment of the image within the text + * flow. + * (Section 11.8, WAP WML Version 16-Jun-1999) + */ + public void setAlign(String newValue); + public String getAlign(); + + /** + * 'width' specifies the width of an image. + * (Section 11.9, WAP WML Version 16-Jun-1999) + */ + public void setWidth(String newValue); + public String getWidth(); + + /** + * 'height' specifies the height of an image. + * (Section 11.9, WAP WML Version 16-Jun-1999) + */ + public void setHeight(String newValue); + public String getHeight(); + + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLInputElement.java b/resources/xerces2-j-src/org/apache/wml/WMLInputElement.java new file mode 100644 index 0000000..33c21cc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLInputElement.java @@ -0,0 +1,107 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'input' element specifies a text entry object. + * (Section 11.6.3, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLInputElement extends WMLElement { + + /** + * 'name' specifies the name of a variable after the user enters the text. + * (Section 11.6.3, WAP WML Version 16-Jun-1999) + */ + public void setName(String newValue); + public String getName(); + + /** + * 'value' specifies the default value of the variable in 'name' attribute + * (Section 11.6.3, WAP WML Version 16-Jun-1999) + */ + public void setValue(String newValue); + public String getValue(); + + /** + * 'type' specifies the type of text input area. + * Two values are allowed: 'text' and 'password' and default is 'text' + * (Section 11.6.3, WAP WML Version 16-Jun-1999) + */ + public void setType(String newValue); + public String getType(); + + /** + * 'format' specifies the input mask for user input. + * (Section 11.6.3, WAP WML Version 16-Jun-1999) + */ + public void setFormat(String newValue); + public String getFormat(); + + /** + * 'emptyok' specifies whether a empty input is allowed when a + * non-empty 'format' is specified. Default to be 'false' + * (Section 11.6.3, WAP WML Version 16-Jun-1999) + */ + public void setEmptyOk(boolean newValue); + public boolean getEmptyOk(); + + /** + * 'size' specifies the width of the input in characters + * (Section 11.6.3, WAP WML Version 16-Jun-1999) + */ + public void setSize(int newValue); + public int getSize(); + + /** + * 'maxlength' specifies the maximum number of characters to be + * enter. + * (Section 11.6.3, WAP WML Version 16-Jun-1999) + */ + public void setMaxLength(int newValue); + public int getMaxLength(); + + /** + * 'title' specifies a title for this element + * (Section 11.6.3, WAP WML Version 16-Jun-1999) + */ + public void setTitle(String newValue); + public String getTitle(); + + /** + * 'tabindex' specifies the tabbing position of the element + * (Section 11.6.1, WAP WML Version 16-Jun-1999) + */ + public void setTabIndex(int newValue); + public int getTabIndex(); + + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLMetaElement.java b/resources/xerces2-j-src/org/apache/wml/WMLMetaElement.java new file mode 100644 index 0000000..71224ee --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLMetaElement.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

The meta element contains meta-info of an WML deck + * (Section 11.3.2, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ +public interface WMLMetaElement extends WMLElement { + + /** + * 'name' attribute specific the property name + */ + public void setName(String newValue); + public String getName(); + + /** + * 'http-equiv' attribute indicates the property should be + * interpret as HTTP header. + */ + public void setHttpEquiv(String newValue); + public String getHttpEquiv(); + + /** + * 'forua' attribute specifies whether a intermediate agent should + * remove this meta element. A value of false means the + * intermediate agent must remove the element. + */ + public void setForua(boolean newValue); + public boolean getForua(); + + /** + * 'scheme' attribute specifies a form that may be used to + * interpret the property value + */ + public void setScheme(String newValue); + public String getScheme(); + + /** + * 'content' attribute specifies the property value + */ + public void setContent(String newValue); + public String getContent(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLNoopElement.java b/resources/xerces2-j-src/org/apache/wml/WMLNoopElement.java new file mode 100644 index 0000000..be77756 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLNoopElement.java @@ -0,0 +1,29 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ +public interface WMLNoopElement extends WMLElement { +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLOneventElement.java b/resources/xerces2-j-src/org/apache/wml/WMLOneventElement.java new file mode 100644 index 0000000..06ed515 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLOneventElement.java @@ -0,0 +1,35 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLOneventElement extends WMLElement { + + public void setType(String newValue); + + public String getType(); + +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLOptgroupElement.java b/resources/xerces2-j-src/org/apache/wml/WMLOptgroupElement.java new file mode 100644 index 0000000..02e16e4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLOptgroupElement.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'optgroup' element groups related 'option' elements into a + * hierarchy. (Section 11.6.2.2, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLOptgroupElement extends WMLElement { + + /** + * 'title' specifies the title of this element + * (Section 11.6.2.3, WAP WML Version 16-Jun-1999) + */ + public void setTitle(String newValue); + public String getTitle(); + + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLOptionElement.java b/resources/xerces2-j-src/org/apache/wml/WMLOptionElement.java new file mode 100644 index 0000000..943a860 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLOptionElement.java @@ -0,0 +1,61 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'option' element specifies a choice in a 'select' element

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLOptionElement extends WMLElement { + + /** + * 'value' specifies the value to used to set the 'name' variable + * (Section 11.6.2.2, WAP WML Version 16-Jun-1999) + */ + public void setValue(String newValue); + public String getValue(); + + /** + * 'title' specifies a title for this element. + * (Section 11.6.2.2, WAP WML Version 16-Jun-1999) + */ + public void setTitle(String newValue); + public String getTitle(); + + /** + * 'onpick' specifies a event to occur when a user select and + * disselect this choice. + * (Section 11.6.2.2, WAP WML Version 16-Jun-1999) */ + public void setOnPick(String href); + public String getOnPick(); + + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLPElement.java b/resources/xerces2-j-src/org/apache/wml/WMLPElement.java new file mode 100644 index 0000000..f8f6b0d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLPElement.java @@ -0,0 +1,57 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'p' element specifies a paragraph + * (Section 11.8.3, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLPElement extends WMLElement { + + /** + * 'mode' specifies the wrapping mode of the paragraph. + * The legal values are 'wrap' and 'nowrap' + * (Section 11.8.3, WAP WML Version 16-Jun-1999) + */ + public void setMode(String newValue); + public String getMode(); + + /** + * 'align' specifies the align of teh paragraph + * The legal values are 'left,' 'center,' and 'right' + * (Section 11.8.3, WAP WML Version 16-Jun-1999) + */ + public void setAlign(String newValue); + public String getAlign(); + + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLPostfieldElement.java b/resources/xerces2-j-src/org/apache/wml/WMLPostfieldElement.java new file mode 100644 index 0000000..f6de42c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLPostfieldElement.java @@ -0,0 +1,39 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLPostfieldElement extends WMLElement { + + public void setValue(String newValue); + + public String getValue(); + + public void setName(String newValue); + + public String getName(); + +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLPrevElement.java b/resources/xerces2-j-src/org/apache/wml/WMLPrevElement.java new file mode 100644 index 0000000..c9a38a5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLPrevElement.java @@ -0,0 +1,30 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLPrevElement extends WMLElement { +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLRefreshElement.java b/resources/xerces2-j-src/org/apache/wml/WMLRefreshElement.java new file mode 100644 index 0000000..74d9a8e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLRefreshElement.java @@ -0,0 +1,30 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLRefreshElement extends WMLElement { +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLSelectElement.java b/resources/xerces2-j-src/org/apache/wml/WMLSelectElement.java new file mode 100644 index 0000000..68cf57d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLSelectElement.java @@ -0,0 +1,89 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'select' element lets user pick from a list of options. + * (Section 11.6.2.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ +public interface WMLSelectElement extends WMLElement { + + /** + * 'tabindex' specifies the tabbing position of the element + * (Section 11.6.1, WAP WML Version 16-Jun-1999) + */ + public void setTabIndex(int newValue); + public int getTabIndex(); + + /** + * 'multiple' indicates whether a list accept multiple selection + * (Section 11.6.2.1, WAP WML Version 16-Jun-1999) + */ + public void setMultiple(boolean newValue); + public boolean getMultiple(); + + /** + * 'name' specifies the name of variable to be set. + * (Section 11.6.2.1, WAP WML Version 16-Jun-1999) + */ + public void setName(String newValue); + public String getName(); + + /** + * 'value' specifics the default value of the variable of 'name' + * (Section 11.6.2.1, WAP WML Version 16-Jun-1999) + */ + public void setValue(String newValue); + public String getValue(); + + /** + * 'title' specifies a title for this element + * (Section 11.6.2.1, WAP WML Version 16-Jun-1999) + */ + public void setTitle(String newValue); + public String getTitle(); + + /** + * 'iname' specifies name of variable to be set with the index + * result of selection. + * (Section 11.6.2.1, WAP WML Version 16-Jun-1999) + */ + public void setIName(String newValue); + public String getIName(); + + /** + * 'ivalue' specifies the default of the variable 'iname' + */ + public void setIValue(String newValue); + public String getIValue(); + + /** + * 'xml:lang' specifics the natural or formal language in which + * the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLSetvarElement.java b/resources/xerces2-j-src/org/apache/wml/WMLSetvarElement.java new file mode 100644 index 0000000..87600b1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLSetvarElement.java @@ -0,0 +1,39 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLSetvarElement extends WMLElement { + + public void setValue(String newValue); + + public String getValue(); + + public void setName(String newValue); + + public String getName(); + +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLSmallElement.java b/resources/xerces2-j-src/org/apache/wml/WMLSmallElement.java new file mode 100644 index 0000000..aece9ba --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLSmallElement.java @@ -0,0 +1,39 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'small' render the text with small font + * (Section 11.8.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ +public interface WMLSmallElement extends WMLElement { + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLStrongElement.java b/resources/xerces2-j-src/org/apache/wml/WMLStrongElement.java new file mode 100644 index 0000000..9434bbf --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLStrongElement.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'strong' strongly emphasis the text + * (Section 11.8.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLStrongElement extends WMLElement { + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLTableElement.java b/resources/xerces2-j-src/org/apache/wml/WMLTableElement.java new file mode 100644 index 0000000..f1e8605 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLTableElement.java @@ -0,0 +1,62 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'table' create a set of aligned columns of text and images. + * (Section 11.8.5, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLTableElement extends WMLElement { + + /** + * 'title' specifies a title for the table + * (Section 11.8.5, WAP WML Version 16-Jun-1999) + */ + public void setTitle(String newValue); + public String getTitle(); + + /** + * 'align' set the align of the table + * (Section 11.8.5, WAP WML Version 16-Jun-1999) + */ + public void setAlign(String newValue); + public String getAlign(); + + /** + * 'columns' specifies the number of columns + * (Section 11.8.5, WAP WML Version 16-Jun-1999) + */ + public void setColumns(int newValue); + public int getColumns(); + + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLTdElement.java b/resources/xerces2-j-src/org/apache/wml/WMLTdElement.java new file mode 100644 index 0000000..27b91ca --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLTdElement.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'td' specifies a single table cell with in a row + * (Section 11.8.6, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLTdElement extends WMLElement { + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLTemplateElement.java b/resources/xerces2-j-src/org/apache/wml/WMLTemplateElement.java new file mode 100644 index 0000000..15f9af0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLTemplateElement.java @@ -0,0 +1,41 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

The 'template' element declares a template for the cards in the deck.

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLTemplateElement extends WMLElement { + + public void setOnTimer(String newValue); + public String getOnTimer(); + + public void setOnEnterBackward(String newValue); + public String getOnEnterBackward(); + + public void setOnEnterForward(String newValue); + public String getOnEnterForward(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLTimerElement.java b/resources/xerces2-j-src/org/apache/wml/WMLTimerElement.java new file mode 100644 index 0000000..00efdee --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLTimerElement.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'timer' elements declares a card timer. + * (Section 11.6.7, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLTimerElement extends WMLElement { + /** + * 'name' specifies the name of variable ot be set with the value + * of the timer. + * (Section 11.6.7, WAP WML Version 16-Jun-1999) + */ + public void setName(String newValue); + public String getName(); + + /** + * 'value' indicates teh default of the variable 'name' + * (Section 11.6.7, WAP WML Version 16-Jun-1999) + */ + public void setValue(String newValue); + public String getValue(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLTrElement.java b/resources/xerces2-j-src/org/apache/wml/WMLTrElement.java new file mode 100644 index 0000000..bad2e7e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLTrElement.java @@ -0,0 +1,33 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'tr' specifies a single row + * (Section 11.8.6, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLTrElement extends WMLElement { +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLUElement.java b/resources/xerces2-j-src/org/apache/wml/WMLUElement.java new file mode 100644 index 0000000..89d71f9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLUElement.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'u' underline the text + * (Section 11.8.1, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLUElement extends WMLElement { + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/WMLWmlElement.java b/resources/xerces2-j-src/org/apache/wml/WMLWmlElement.java new file mode 100644 index 0000000..8fab453 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/WMLWmlElement.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +package org.apache.wml; + +/** + *

The interface is modeled after DOM1 Spec for HTML from W3C. + * The DTD used in this DOM model is from + * + * http://www.wapforum.org/DTD/wml_1.1.xml

+ * + *

'wml' is the root oot of a WML document. + * (Section 11.2, WAP WML Version 16-Jun-1999)

+ * + * @version $Id$ + * @author David Li + */ + +public interface WMLWmlElement extends WMLElement { + /** + * The xml:lang that specifics the natural or formal language in + * which the document is written. + * (Section 8.8, WAP WML Version 16-Jun-1999) + */ + public void setXmlLang(String newValue); + public String getXmlLang(); +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLAElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLAElementImpl.java new file mode 100644 index 0000000..70be9c8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLAElementImpl.java @@ -0,0 +1,74 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLAElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLAElementImpl extends WMLElementImpl implements WMLAElement { + + private static final long serialVersionUID = 2628169803370301255L; + + public WMLAElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setHref(String newValue) { + setAttribute("href", newValue); + } + + public String getHref() { + return getAttribute("href"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLAccessElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLAccessElementImpl.java new file mode 100644 index 0000000..48dab9c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLAccessElementImpl.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLAccessElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLAccessElementImpl extends WMLElementImpl implements WMLAccessElement { + + private static final long serialVersionUID = -235627181817012806L; + + public WMLAccessElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setDomain(String newValue) { + setAttribute("domain", newValue); + } + + public String getDomain() { + return getAttribute("domain"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setPath(String newValue) { + setAttribute("path", newValue); + } + + public String getPath() { + return getAttribute("path"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLAnchorElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLAnchorElementImpl.java new file mode 100644 index 0000000..7a71bf4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLAnchorElementImpl.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLAnchorElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLAnchorElementImpl extends WMLElementImpl implements WMLAnchorElement { + + private static final long serialVersionUID = 5720492496046133176L; + + public WMLAnchorElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLBElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLBElementImpl.java new file mode 100644 index 0000000..fbac978 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLBElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLBElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLBElementImpl extends WMLElementImpl implements WMLBElement { + + private static final long serialVersionUID = -758504371498228671L; + + public WMLBElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLBigElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLBigElementImpl.java new file mode 100644 index 0000000..bf51756 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLBigElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLBigElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLBigElementImpl extends WMLElementImpl implements WMLBigElement { + + private static final long serialVersionUID = -8826061369691668904L; + + public WMLBigElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLBrElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLBrElementImpl.java new file mode 100644 index 0000000..9ef2345 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLBrElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLBrElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLBrElementImpl extends WMLElementImpl implements WMLBrElement { + + private static final long serialVersionUID = -5047802409550691268L; + + public WMLBrElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLCardElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLCardElementImpl.java new file mode 100644 index 0000000..efbb53e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLCardElementImpl.java @@ -0,0 +1,106 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLCardElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLCardElementImpl extends WMLElementImpl implements WMLCardElement { + + private static final long serialVersionUID = -3571126568344328924L; + + public WMLCardElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setOnTimer(String newValue) { + setAttribute("ontimer", newValue); + } + + public String getOnTimer() { + return getAttribute("ontimer"); + } + + public void setOrdered(boolean newValue) { + setAttribute("ordered", newValue); + } + + public boolean getOrdered() { + return getAttribute("ordered", true); + } + + public void setOnEnterBackward(String newValue) { + setAttribute("onenterbackward", newValue); + } + + public String getOnEnterBackward() { + return getAttribute("onenterbackward"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setNewContext(boolean newValue) { + setAttribute("newcontext", newValue); + } + + public boolean getNewContext() { + return getAttribute("newcontext", false); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setOnEnterForward(String newValue) { + setAttribute("onenterforward", newValue); + } + + public String getOnEnterForward() { + return getAttribute("onenterforward"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLDOMImplementationImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLDOMImplementationImpl.java new file mode 100644 index 0000000..be5b4d6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLDOMImplementationImpl.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.wml.dom; + +import org.apache.wml.WMLDOMImplementation; +import org.apache.xerces.dom.CoreDocumentImpl; +import org.apache.xerces.dom.DOMImplementationImpl; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DocumentType; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLDOMImplementationImpl extends DOMImplementationImpl implements WMLDOMImplementation { + + static final DOMImplementationImpl singleton = new WMLDOMImplementationImpl(); + + /** NON-DOM: Obtain and return the single shared object */ + public static DOMImplementation getDOMImplementation() { + return singleton; + } + + // + // Protected methods + // + + protected CoreDocumentImpl createDocument(DocumentType doctype) { + return new WMLDocumentImpl(doctype); + } +} + diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLDoElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLDoElementImpl.java new file mode 100644 index 0000000..68fe14a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLDoElementImpl.java @@ -0,0 +1,90 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLDoElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLDoElementImpl extends WMLElementImpl implements WMLDoElement { + + private static final long serialVersionUID = 7755861458464251322L; + + public WMLDoElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setOptional(String newValue) { + setAttribute("optional", newValue); + } + + public String getOptional() { + return getAttribute("optional"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setLabel(String newValue) { + setAttribute("label", newValue); + } + + public String getLabel() { + return getAttribute("label"); + } + + public void setType(String newValue) { + setAttribute("type", newValue); + } + + public String getType() { + return getAttribute("type"); + } + + public void setName(String newValue) { + setAttribute("name", newValue); + } + + public String getName() { + return getAttribute("name"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLDocumentImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLDocumentImpl.java new file mode 100644 index 0000000..ffadafe --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLDocumentImpl.java @@ -0,0 +1,120 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import java.lang.reflect.Constructor; +import java.util.Hashtable; + +import org.apache.wml.WMLDocument; +import org.apache.xerces.dom.DocumentImpl; +import org.apache.xerces.dom.ElementImpl; +import org.w3c.dom.DOMException; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLDocumentImpl extends DocumentImpl implements WMLDocument { + + private static final long serialVersionUID = -6582904849512384104L; + + private static Hashtable _elementTypesWML; + private static final Class[] _elemClassSigWML = + new Class[] { WMLDocumentImpl.class, String.class }; + + public Element createElement( String tagName ) throws DOMException + { + Class elemClass; + Constructor cnst; + + elemClass = (Class) _elementTypesWML.get( tagName ); + if ( elemClass != null ) { + try { + cnst = elemClass.getConstructor( _elemClassSigWML ); + return (Element) cnst.newInstance( new Object[] { this, tagName } ); + } catch ( Exception except ) { + Throwable thrw; + + if ( except instanceof java.lang.reflect.InvocationTargetException ) + thrw = ( (java.lang.reflect.InvocationTargetException) except ).getTargetException(); + else + thrw = except; + + System.out.println( "Exception " + thrw.getClass().getName() ); + System.out.println( thrw.getMessage() ); + + throw new IllegalStateException( "Tag '" + tagName + "' associated with an Element class that failed to construct." ); + } + } + return new WMLElementImpl( this, tagName ); + } + + /* (non-Javadoc) + * @see CoreDocumentImpl#canRenameElements() + */ + protected boolean canRenameElements(String newNamespaceURI, String newNodeName, ElementImpl el) { + // check whether a class change is required + return _elementTypesWML.get(newNodeName) == _elementTypesWML.get(el.getTagName()); + } + + static { + _elementTypesWML = new Hashtable(); + _elementTypesWML.put("b", WMLBElementImpl.class); + _elementTypesWML.put("noop", WMLNoopElementImpl.class); + _elementTypesWML.put("a", WMLAElementImpl.class); + _elementTypesWML.put("setvar", WMLSetvarElementImpl.class); + _elementTypesWML.put("access", WMLAccessElementImpl.class); + _elementTypesWML.put("strong", WMLStrongElementImpl.class); + _elementTypesWML.put("postfield", WMLPostfieldElementImpl.class); + _elementTypesWML.put("do", WMLDoElementImpl.class); + _elementTypesWML.put("wml", WMLWmlElementImpl.class); + _elementTypesWML.put("tr", WMLTrElementImpl.class); + _elementTypesWML.put("go", WMLGoElementImpl.class); + _elementTypesWML.put("big", WMLBigElementImpl.class); + _elementTypesWML.put("anchor", WMLAnchorElementImpl.class); + _elementTypesWML.put("timer", WMLTimerElementImpl.class); + _elementTypesWML.put("small", WMLSmallElementImpl.class); + _elementTypesWML.put("optgroup", WMLOptgroupElementImpl.class); + _elementTypesWML.put("head", WMLHeadElementImpl.class); + _elementTypesWML.put("td", WMLTdElementImpl.class); + _elementTypesWML.put("fieldset", WMLFieldsetElementImpl.class); + _elementTypesWML.put("img", WMLImgElementImpl.class); + _elementTypesWML.put("refresh", WMLRefreshElementImpl.class); + _elementTypesWML.put("onevent", WMLOneventElementImpl.class); + _elementTypesWML.put("input", WMLInputElementImpl.class); + _elementTypesWML.put("prev", WMLPrevElementImpl.class); + _elementTypesWML.put("table", WMLTableElementImpl.class); + _elementTypesWML.put("meta", WMLMetaElementImpl.class); + _elementTypesWML.put("template", WMLTemplateElementImpl.class); + _elementTypesWML.put("br", WMLBrElementImpl.class); + _elementTypesWML.put("option", WMLOptionElementImpl.class); + _elementTypesWML.put("u", WMLUElementImpl.class); + _elementTypesWML.put("p", WMLPElementImpl.class); + _elementTypesWML.put("select", WMLSelectElementImpl.class); + _elementTypesWML.put("em", WMLEmElementImpl.class); + _elementTypesWML.put("i", WMLIElementImpl.class); + _elementTypesWML.put("card", WMLCardElementImpl.class); + } + + /* DOM level 2 */ + public WMLDocumentImpl(DocumentType doctype) { + super(doctype, false); + } +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLElementImpl.java new file mode 100644 index 0000000..a613ea0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLElementImpl.java @@ -0,0 +1,83 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLElement; +import org.apache.xerces.dom.ElementImpl; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLElementImpl extends ElementImpl implements WMLElement { + + private static final long serialVersionUID = 3440984702956371604L; + + public WMLElementImpl (WMLDocumentImpl owner, String tagName) { + super(owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + void setAttribute(String attr, boolean value) { + setAttribute(attr, value ? "true" : "false"); + } + + boolean getAttribute(String attr, boolean defaultValue) { + boolean ret = defaultValue; + String value; + if (((value = getAttribute("emptyok")) != null) + && value.equals("true")) + ret = true; + return ret; + } + + void setAttribute(String attr, int value) { + setAttribute(attr, value + ""); + } + + int getAttribute(String attr, int defaultValue) { + int ret = defaultValue; + String value; + if ((value = getAttribute("emptyok")) != null) + ret = Integer.parseInt(value); + return ret; + } +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLEmElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLEmElementImpl.java new file mode 100644 index 0000000..0b16686 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLEmElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLEmElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLEmElementImpl extends WMLElementImpl implements WMLEmElement { + + private static final long serialVersionUID = 7962278391619830801L; + + public WMLEmElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLFieldsetElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLFieldsetElementImpl.java new file mode 100644 index 0000000..d51efee --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLFieldsetElementImpl.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLFieldsetElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLFieldsetElementImpl extends WMLElementImpl implements WMLFieldsetElement { + + private static final long serialVersionUID = 6941811812235840705L; + + public WMLFieldsetElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLGoElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLGoElementImpl.java new file mode 100644 index 0000000..020149f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLGoElementImpl.java @@ -0,0 +1,82 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLGoElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLGoElementImpl extends WMLElementImpl implements WMLGoElement { + + private static final long serialVersionUID = -2052250142899797905L; + + public WMLGoElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setSendreferer(String newValue) { + setAttribute("sendreferer", newValue); + } + + public String getSendreferer() { + return getAttribute("sendreferer"); + } + + public void setAcceptCharset(String newValue) { + setAttribute("accept-charset", newValue); + } + + public String getAcceptCharset() { + return getAttribute("accept-charset"); + } + + public void setHref(String newValue) { + setAttribute("href", newValue); + } + + public String getHref() { + return getAttribute("href"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setMethod(String newValue) { + setAttribute("method", newValue); + } + + public String getMethod() { + return getAttribute("method"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLHeadElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLHeadElementImpl.java new file mode 100644 index 0000000..68a6b2a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLHeadElementImpl.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLHeadElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLHeadElementImpl extends WMLElementImpl implements WMLHeadElement { + + private static final long serialVersionUID = 3311307374813188908L; + + public WMLHeadElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLIElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLIElementImpl.java new file mode 100644 index 0000000..0709aa5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLIElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLIElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLIElementImpl extends WMLElementImpl implements WMLIElement { + + private static final long serialVersionUID = 5008873415065802109L; + + public WMLIElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLImgElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLImgElementImpl.java new file mode 100644 index 0000000..609d268 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLImgElementImpl.java @@ -0,0 +1,122 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLImgElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLImgElementImpl extends WMLElementImpl implements WMLImgElement { + + private static final long serialVersionUID = -500092034867051550L; + + public WMLImgElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setWidth(String newValue) { + setAttribute("width", newValue); + } + + public String getWidth() { + return getAttribute("width"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setLocalSrc(String newValue) { + setAttribute("localsrc", newValue); + } + + public String getLocalSrc() { + return getAttribute("localsrc"); + } + + public void setHeight(String newValue) { + setAttribute("height", newValue); + } + + public String getHeight() { + return getAttribute("height"); + } + + public void setAlign(String newValue) { + setAttribute("align", newValue); + } + + public String getAlign() { + return getAttribute("align"); + } + + public void setVspace(String newValue) { + setAttribute("vspace", newValue); + } + + public String getVspace() { + return getAttribute("vspace"); + } + + public void setAlt(String newValue) { + setAttribute("alt", newValue); + } + + public String getAlt() { + return getAttribute("alt"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setHspace(String newValue) { + setAttribute("hspace", newValue); + } + + public String getHspace() { + return getAttribute("hspace"); + } + + public void setSrc(String newValue) { + setAttribute("src", newValue); + } + + public String getSrc() { + return getAttribute("src"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLInputElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLInputElementImpl.java new file mode 100644 index 0000000..fc041bb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLInputElementImpl.java @@ -0,0 +1,130 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLInputElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLInputElementImpl extends WMLElementImpl implements WMLInputElement { + + private static final long serialVersionUID = 2897319793637966619L; + + public WMLInputElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setSize(int newValue) { + setAttribute("size", newValue); + } + + public int getSize() { + return getAttribute("size", 0); + } + + public void setFormat(String newValue) { + setAttribute("format", newValue); + } + + public String getFormat() { + return getAttribute("format"); + } + + public void setValue(String newValue) { + setAttribute("value", newValue); + } + + public String getValue() { + return getAttribute("value"); + } + + public void setMaxLength(int newValue) { + setAttribute("maxlength", newValue); + } + + public int getMaxLength() { + return getAttribute("maxlength", 0); + } + + public void setTabIndex(int newValue) { + setAttribute("tabindex", newValue); + } + + public int getTabIndex() { + return getAttribute("tabindex", 0); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setEmptyOk(boolean newValue) { + setAttribute("emptyok", newValue); + } + + public boolean getEmptyOk() { + return getAttribute("emptyok", false); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setType(String newValue) { + setAttribute("type", newValue); + } + + public String getType() { + return getAttribute("type"); + } + + public void setName(String newValue) { + setAttribute("name", newValue); + } + + public String getName() { + return getAttribute("name"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLMetaElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLMetaElementImpl.java new file mode 100644 index 0000000..8877b14 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLMetaElementImpl.java @@ -0,0 +1,89 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLMetaElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLMetaElementImpl extends WMLElementImpl implements WMLMetaElement { + + private static final long serialVersionUID = -2791663042188681846L; + + public WMLMetaElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setForua(boolean newValue) { + setAttribute("forua", newValue); + } + + public boolean getForua() { + return getAttribute("forua", false); + } + + public void setScheme(String newValue) { + setAttribute("scheme", newValue); + } + + public String getScheme() { + return getAttribute("scheme"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setHttpEquiv(String newValue) { + setAttribute("http-equiv", newValue); + } + + public String getHttpEquiv() { + return getAttribute("http-equiv"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setContent(String newValue) { + setAttribute("content", newValue); + } + + public String getContent() { + return getAttribute("content"); + } + + public void setName(String newValue) { + setAttribute("name", newValue); + } + + public String getName() { + return getAttribute("name"); + } +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLNoopElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLNoopElementImpl.java new file mode 100644 index 0000000..f8e90ab --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLNoopElementImpl.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLNoopElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLNoopElementImpl extends WMLElementImpl implements WMLNoopElement { + + private static final long serialVersionUID = -1581314434256075931L; + + public WMLNoopElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLOneventElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLOneventElementImpl.java new file mode 100644 index 0000000..3fab7ee --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLOneventElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLOneventElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLOneventElementImpl extends WMLElementImpl implements WMLOneventElement { + + private static final long serialVersionUID = -4279215241146570871L; + + public WMLOneventElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setType(String newValue) { + setAttribute("type", newValue); + } + + public String getType() { + return getAttribute("type"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLOptgroupElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLOptgroupElementImpl.java new file mode 100644 index 0000000..9d45d52 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLOptgroupElementImpl.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLOptgroupElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLOptgroupElementImpl extends WMLElementImpl implements WMLOptgroupElement { + + private static final long serialVersionUID = 1592761119479339142L; + + public WMLOptgroupElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLOptionElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLOptionElementImpl.java new file mode 100644 index 0000000..0486988 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLOptionElementImpl.java @@ -0,0 +1,82 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLOptionElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLOptionElementImpl extends WMLElementImpl implements WMLOptionElement { + + private static final long serialVersionUID = -3432299264888771937L; + + public WMLOptionElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setValue(String newValue) { + setAttribute("value", newValue); + } + + public String getValue() { + return getAttribute("value"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setOnPick(String newValue) { + setAttribute("onpick", newValue); + } + + public String getOnPick() { + return getAttribute("onpick"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLPElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLPElementImpl.java new file mode 100644 index 0000000..5690303 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLPElementImpl.java @@ -0,0 +1,74 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLPElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLPElementImpl extends WMLElementImpl implements WMLPElement { + + private static final long serialVersionUID = 4263257796458499960L; + + public WMLPElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setMode(String newValue) { + setAttribute("mode", newValue); + } + + public String getMode() { + return getAttribute("mode"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setAlign(String newValue) { + setAttribute("align", newValue); + } + + public String getAlign() { + return getAttribute("align"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLPostfieldElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLPostfieldElementImpl.java new file mode 100644 index 0000000..d660725 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLPostfieldElementImpl.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLPostfieldElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLPostfieldElementImpl extends WMLElementImpl implements WMLPostfieldElement { + + private static final long serialVersionUID = -1169432003991642980L; + + public WMLPostfieldElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setValue(String newValue) { + setAttribute("value", newValue); + } + + public String getValue() { + return getAttribute("value"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setName(String newValue) { + setAttribute("name", newValue); + } + + public String getName() { + return getAttribute("name"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLPrevElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLPrevElementImpl.java new file mode 100644 index 0000000..bdb9cec --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLPrevElementImpl.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLPrevElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLPrevElementImpl extends WMLElementImpl implements WMLPrevElement { + + private static final long serialVersionUID = -1545713716925433554L; + + public WMLPrevElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLRefreshElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLRefreshElementImpl.java new file mode 100644 index 0000000..b306685 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLRefreshElementImpl.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLRefreshElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLRefreshElementImpl extends WMLElementImpl implements WMLRefreshElement { + + private static final long serialVersionUID = 8781837880806459398L; + + public WMLRefreshElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLSelectElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLSelectElementImpl.java new file mode 100644 index 0000000..758277a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLSelectElementImpl.java @@ -0,0 +1,113 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLSelectElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLSelectElementImpl extends WMLElementImpl implements WMLSelectElement { + + private static final long serialVersionUID = 6489112443257247261L; + + public WMLSelectElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setMultiple(boolean newValue) { + setAttribute("multiple", newValue); + } + + public boolean getMultiple() { + return getAttribute("multiple", false); + } + + public void setValue(String newValue) { + setAttribute("value", newValue); + } + + public String getValue() { + return getAttribute("value"); + } + + public void setTabIndex(int newValue) { + setAttribute("tabindex", newValue); + } + + public int getTabIndex() { + return getAttribute("tabindex", 0); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setIValue(String newValue) { + setAttribute("ivalue", newValue); + } + + public String getIValue() { + return getAttribute("ivalue"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setIName(String newValue) { + setAttribute("iname", newValue); + } + + public String getIName() { + return getAttribute("iname"); + } + + public void setName(String newValue) { + setAttribute("name", newValue); + } + + public String getName() { + return getAttribute("name"); + } +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLSetvarElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLSetvarElementImpl.java new file mode 100644 index 0000000..ff044e2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLSetvarElementImpl.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLSetvarElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLSetvarElementImpl extends WMLElementImpl implements WMLSetvarElement { + + private static final long serialVersionUID = -1944519734782236471L; + + public WMLSetvarElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setValue(String newValue) { + setAttribute("value", newValue); + } + + public String getValue() { + return getAttribute("value"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setName(String newValue) { + setAttribute("name", newValue); + } + + public String getName() { + return getAttribute("name"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLSmallElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLSmallElementImpl.java new file mode 100644 index 0000000..baf9351 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLSmallElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLSmallElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLSmallElementImpl extends WMLElementImpl implements WMLSmallElement { + + private static final long serialVersionUID = 2654490940644799492L; + + public WMLSmallElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLStrongElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLStrongElementImpl.java new file mode 100644 index 0000000..08fcd57 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLStrongElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLStrongElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLStrongElementImpl extends WMLElementImpl implements WMLStrongElement { + + private static final long serialVersionUID = 8451363815747099580L; + + public WMLStrongElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLTableElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLTableElementImpl.java new file mode 100644 index 0000000..16ea366 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLTableElementImpl.java @@ -0,0 +1,82 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLTableElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLTableElementImpl extends WMLElementImpl implements WMLTableElement { + + private static final long serialVersionUID = 7676208849347355339L; + + public WMLTableElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setColumns(int newValue) { + setAttribute("columns", newValue); + } + + public int getColumns() { + return getAttribute("columns", 0); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setAlign(String newValue) { + setAttribute("align", newValue); + } + + public String getAlign() { + return getAttribute("align"); + } + + public void setTitle(String newValue) { + setAttribute("title", newValue); + } + + public String getTitle() { + return getAttribute("title"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLTdElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLTdElementImpl.java new file mode 100644 index 0000000..ea52071 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLTdElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLTdElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLTdElementImpl extends WMLElementImpl implements WMLTdElement { + + private static final long serialVersionUID = 6074218675876025710L; + + public WMLTdElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLTemplateElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLTemplateElementImpl.java new file mode 100644 index 0000000..e8440ae --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLTemplateElementImpl.java @@ -0,0 +1,74 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLTemplateElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLTemplateElementImpl extends WMLElementImpl implements WMLTemplateElement { + + private static final long serialVersionUID = 4231732841621131049L; + + public WMLTemplateElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setOnTimer(String newValue) { + setAttribute("ontimer", newValue); + } + + public String getOnTimer() { + return getAttribute("ontimer"); + } + + public void setOnEnterBackward(String newValue) { + setAttribute("onenterbackward", newValue); + } + + public String getOnEnterBackward() { + return getAttribute("onenterbackward"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setOnEnterForward(String newValue) { + setAttribute("onenterforward", newValue); + } + + public String getOnEnterForward() { + return getAttribute("onenterforward"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLTimerElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLTimerElementImpl.java new file mode 100644 index 0000000..8e96ebc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLTimerElementImpl.java @@ -0,0 +1,66 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLTimerElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLTimerElementImpl extends WMLElementImpl implements WMLTimerElement { + + private static final long serialVersionUID = 9055622169756832726L; + + public WMLTimerElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setValue(String newValue) { + setAttribute("value", newValue); + } + + public String getValue() { + return getAttribute("value"); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + + public void setName(String newValue) { + setAttribute("name", newValue); + } + + public String getName() { + return getAttribute("name"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLTrElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLTrElementImpl.java new file mode 100644 index 0000000..6a8eaed --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLTrElementImpl.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLTrElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLTrElementImpl extends WMLElementImpl implements WMLTrElement { + + private static final long serialVersionUID = -4304021232051604343L; + + public WMLTrElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLUElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLUElementImpl.java new file mode 100644 index 0000000..9553c48 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLUElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLUElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLUElementImpl extends WMLElementImpl implements WMLUElement { + + private static final long serialVersionUID = 6350194387815102797L; + + public WMLUElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/wml/dom/WMLWmlElementImpl.java b/resources/xerces2-j-src/org/apache/wml/dom/WMLWmlElementImpl.java new file mode 100644 index 0000000..817fd48 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/wml/dom/WMLWmlElementImpl.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.wml.dom; + +import org.apache.wml.WMLWmlElement; + +/** + * @xerces.internal + * @version $Id$ + * @author David Li + */ +public class WMLWmlElementImpl extends WMLElementImpl implements WMLWmlElement { + + private static final long serialVersionUID = -7008023851895920651L; + + public WMLWmlElementImpl (WMLDocumentImpl owner, String tagName) { + super( owner, tagName); + } + + public void setClassName(String newValue) { + setAttribute("class", newValue); + } + + public String getClassName() { + return getAttribute("class"); + } + + public void setXmlLang(String newValue) { + setAttribute("xml:lang", newValue); + } + + public String getXmlLang() { + return getAttribute("xml:lang"); + } + + public void setId(String newValue) { + setAttribute("id", newValue); + } + + public String getId() { + return getAttribute("id"); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ASDOMImplementationImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/ASDOMImplementationImpl.java new file mode 100644 index 0000000..2239154 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ASDOMImplementationImpl.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.apache.xerces.dom3.as.ASModel; +import org.apache.xerces.dom3.as.DOMASBuilder; +import org.apache.xerces.dom3.as.DOMASWriter; +import org.apache.xerces.dom3.as.DOMImplementationAS; +import org.apache.xerces.parsers.DOMASBuilderImpl; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; + + + +/** + * The DOMImplementation class is description of a particular + * implementation of the Document Object Model. As such its data is + * static, shared by all instances of this implementation. + *

+ * The DOM API requires that it be a real object rather than static + * methods. However, there's nothing that says it can't be a singleton, + * so that's how I've implemented it. + *

+ * This particular class, along with DocumentImpl, supports the DOM + * Core, DOM Level 2 optional mofules, and Abstract Schemas (Experimental). + * @deprecated + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class ASDOMImplementationImpl extends DOMImplementationImpl + implements DOMImplementationAS { + + + // static + + /** Dom implementation singleton. */ + static final ASDOMImplementationImpl singleton = new ASDOMImplementationImpl(); + + + // + // Public methods + // + + /** NON-DOM: Obtain and return the single shared object */ + public static DOMImplementation getDOMImplementation() { + return singleton; + } + + // + // DOM L3 Abstract Schemas: + // REVISIT: implement hasFeature() + // + + /** + * DOM Level 3 WD - Experimental. + * Creates an ASModel. + * @param isNamespaceAware Allow creation of ASModel with + * this attribute set to a specific value. + * @return A null return indicates failure.what is a + * failure? Could be a system error. + */ + public ASModel createAS(boolean isNamespaceAware){ + return new ASModelImpl(isNamespaceAware); + } + + /** + * DOM Level 3 WD - Experimental. + * Creates an DOMASBuilder.Do we need the method since we + * already have DOMImplementationLS.createDOMParser? + * @return DOMASBuilder + */ + public DOMASBuilder createDOMASBuilder(){ + return new DOMASBuilderImpl(); + } + + + /** + * DOM Level 3 WD - Experimental. + * Creates an DOMASWriter. + * @return a DOMASWriter + */ + public DOMASWriter createDOMASWriter(){ + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + + +} // class DOMImplementationImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ASModelImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/ASModelImpl.java new file mode 100644 index 0000000..c1b0f99 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ASModelImpl.java @@ -0,0 +1,498 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.Vector; + +import org.apache.xerces.dom3.as.ASAttributeDeclaration; +import org.apache.xerces.dom3.as.ASContentModel; +import org.apache.xerces.dom3.as.ASElementDeclaration; +import org.apache.xerces.dom3.as.ASEntityDeclaration; +import org.apache.xerces.dom3.as.ASModel; +import org.apache.xerces.dom3.as.ASNamedObjectMap; +import org.apache.xerces.dom3.as.ASNotationDeclaration; +import org.apache.xerces.dom3.as.ASObject; +import org.apache.xerces.dom3.as.ASObjectList; +import org.apache.xerces.dom3.as.DOMASException; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.w3c.dom.DOMException; + +/** + * To begin with, an abstract schema is a generic structure that could + * contain both internal and external subsets. An ASModel is an + * abstract object that could map to a DTD , an XML Schema , a database + * schema, etc. An ASModel could represent either an internal + * or an external subset; hence an abstract schema could be composed of an + * ASModel representing the internal subset and an + * ASModel representing the external subset. Note that the + * ASModel representing the external subset could consult the + * ASModel representing the internal subset. Furthermore, the + * ASModel representing the internal subset could be set to + * null by the setInternalAS method as a mechanism for + * "removal". In addition, only one ASModel representing the + * external subset can be specified as "active" and it is possible that none + * are "active". Finally, the ASModel contains the factory + * methods needed to create a various types of ASObjects like + * ASElementDeclaration, ASAttributeDeclaration, + * etc. + *

See also the + * Document Object Model (DOM) Level 3 Abstract Schemas and Load and Save Specification. + * @deprecated + * @author Pavani Mukthipudi + * @author Neil Graham + * @version $Id$ + */ +public class ASModelImpl implements ASModel { + + // + // Data + // + boolean fNamespaceAware = true; + + // conceptually, an ASModel may contain grammar information and/or + // other ASModels. These two fields divide that function. + protected Vector fASModels; + protected SchemaGrammar fGrammar = null; + + // + // Constructors + // + + public ASModelImpl() { + fASModels = new Vector(); + } + + public ASModelImpl(boolean isNamespaceAware) { + fASModels = new Vector(); + fNamespaceAware = isNamespaceAware; + } + + // + // ASObject methods + // + + /** + * A code representing the underlying object as defined above. + */ + public short getAsNodeType() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The ASModel object associated with this + * ASObject. For a node of type AS_MODEL, this + * is null. + */ + public ASModel getOwnerASModel() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The ASModel object associated with this + * ASObject. For a node of type AS_MODEL, this + * is null. + */ + public void setOwnerASModel(ASModel ownerASModel) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The name of this ASObject depending on the + * ASObject type. + */ + public String getNodeName() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The name of this ASObject depending on the + * ASObject type. + */ + public void setNodeName(String nodeName) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The namespace prefix of this node, or null if it is + * unspecified. + */ + public String getPrefix() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The namespace prefix of this node, or null if it is + * unspecified. + */ + public void setPrefix(String prefix) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Returns the local part of the qualified name of this + * ASObject. + */ + public String getLocalName() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Returns the local part of the qualified name of this + * ASObject. + */ + public void setLocalName(String localName) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespaceURI() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public void setNamespaceURI(String namespaceURI) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Creates a copy of this ASObject. See text for + * cloneNode off of Node but substitute AS + * functionality. + * @param deep Setting the deep flag on, causes the whole + * subtree to be duplicated. Setting it to false only + * duplicates its immediate child nodes. + * @return Cloned ASObject. + */ + public ASObject cloneASObject(boolean deep) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + // + // ASModel methods + // + + /** + * true if this ASModel defines the document + * structure in terms of namespaces and local names ; false + * if the document structure is defined only in terms of + * QNames. + */ + public boolean getIsNamespaceAware() { + return fNamespaceAware; + } + + /** + * 0 if used internally, 1 if used externally, 2 if not all. An exception + * will be raised if it is incompatibly shared or in use as an internal + * subset. + */ + public short getUsageLocation() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The URI reference. + */ + public String getAsLocation() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The URI reference. + */ + public void setAsLocation(String asLocation) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The hint to locating an ASModel. + */ + public String getAsHint() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * The hint to locating an ASModel. + */ + public void setAsHint(String asHint) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * If usage is EXTERNAL_SUBSET or NOT_USED, and the + * ASModel is simply a container of other ASModels. + */ + public boolean getContainer() { + return (fGrammar != null); + } + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global" + * element declarations. If one attempts to add, set, or remove a node + * type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getElementDeclarations() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global" + * attribute declarations. If one attempts to add, set, or remove a node + * type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getAttributeDeclarations() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global" + * notation declarations. If one attempts to add, set, or remove a node + * type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getNotationDeclarations() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global" + * entity declarations. If one attempts to add, set, or remove a node + * type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getEntityDeclarations() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global + * content model declarations. If one attempts to add, set, or remove a + * node type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getContentModelDeclarations() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * This method will allow the nesting or "importation" of ASModels. + * @param abstractSchema ASModel to be set. Subsequent calls will nest + * the ASModels within the specified ownerASModel. + */ + public void addASModel(ASModel abstractSchema) { + fASModels.addElement(abstractSchema); + } + + /** + * To retrieve a list of nested ASModels without reference to names. + * @return A list of ASModels. + */ + public ASObjectList getASModels() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Removes only the specified ASModel from the list of + * ASModels. + * @param as AS to be removed. + */ + public void removeAS(ASModel as) { + fASModels.removeElement(as); + } + + /** + * Determines if an ASModel itself is valid, i.e., confirming + * that it's well-formed and valid per its own formal grammar. + * @return true if the ASModel is valid, + * false otherwise. + */ + public boolean validate() { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Imports ASObject into ASModel. + * @param asobject ASObject to be imported. + */ + public void importASObject(ASObject asobject) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Inserts ASObject into ASModel. + * @param asobject ASObject to be inserted. + */ + public void insertASObject(ASObject asobject) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Creates an element declaration for the element type specified. + * @param namespaceURI The namespace URI of the element type + * being declared. + * @param name The name of the element. The format of the name could be + * an NCName as defined by XML Namespaces or a Name as defined by XML + * 1.0; it's ASModel-dependent. + * @return A new ASElementDeclaration object with + * name attribute set to tagname and + * namespaceURI set to systemId. Other + * attributes of the element declaration are set through + * ASElementDeclaration interface methods. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the specified name contains an + * illegal character. + */ + public ASElementDeclaration createASElementDeclaration(String namespaceURI, + String name) + throws DOMException { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Creates an attribute declaration. + * @param namespaceURI The namespace URI of the attribute being declared. + * @param name The name of the attribute. The format of the name could be + * an NCName as defined by XML Namespaces or a Name as defined by XML + * 1.0; it's ASModel-dependent. + * @return A new ASAttributeDeclaration object with + * appropriate attributes set by input parameters. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the input name + * parameter contains an illegal character. + */ + public ASAttributeDeclaration createASAttributeDeclaration(String namespaceURI, + String name) + throws DOMException { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Creates a new notation declaration. + * @param namespaceURI The namespace URI of the notation being declared. + * @param name The name of the notation. The format of the name could be + * an NCName as defined by XML Namespaces or a Name as defined by XML + * 1.0; it's ASModel-dependent. + * @param systemId The system identifier for the notation declaration. + * @param publicId The public identifier for the notation declaration. + * @return A new ASNotationDeclaration object with + * notationName attribute set to name and + * publicId and systemId set to the + * corresponding fields. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the specified name contains an + * illegal character. + */ + public ASNotationDeclaration createASNotationDeclaration(String namespaceURI, String name, + String systemId, String publicId) + throws DOMException { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Creates an ASEntityDeclaration. + * @param name The name of the entity being declared. + * @return A new ASEntityDeclaration object with + * entityName attribute set to name. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the specified name contains an + * illegal character. + */ + public ASEntityDeclaration createASEntityDeclaration(String name) + throws DOMException { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + /** + * Creates an object which describes part of an + * ASElementDeclaration's content model. + * @param minOccurs The minimum occurrence for the subModels of this + * ASContentModel. + * @param maxOccurs The maximum occurrence for the subModels of this + * ASContentModel. + * @param operator operator of type AS_CHOICE, + * AS_SEQUENCE, AS_ALL or + * AS_NONE. + * @return A new ASContentModel object. + * @exception DOMASException + * A DOMASException, e.g., minOccurs > maxOccurs. + */ + public ASContentModel createASContentModel(int minOccurs, int maxOccurs, + short operator) throws DOMASException { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + + // convenience methods + public SchemaGrammar getGrammar() { + return fGrammar; + } + public void setGrammar(SchemaGrammar grammar) { + fGrammar = grammar; + } + + public Vector getInternalASModels() { + return fASModels; + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/AttrImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/AttrImpl.java new file mode 100644 index 0000000..5166148 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/AttrImpl.java @@ -0,0 +1,1237 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.TypeInfo; + +/** + * Attribute represents an XML-style attribute of an + * Element. Typically, the allowable values are controlled by its + * declaration in the Document Type Definition (DTD) governing this + * kind of document. + *

+ * If the attribute has not been explicitly assigned a value, but has + * been declared in the DTD, it will exist and have that default. Only + * if neither the document nor the DTD specifies a value will the + * Attribute really be considered absent and have no value; in that + * case, querying the attribute will return null. + *

+ * Attributes may have multiple children that contain their data. (XML + * allows attributes to contain entity references, and tokenized + * attribute types such as NMTOKENS may have a child for each token.) + * For convenience, the Attribute object's getValue() method returns + * the string version of the attribute's value. + *

+ * Attributes are not children of the Elements they belong to, in the + * usual sense, and have no valid Parent reference. However, the spec + * says they _do_ belong to a specific Element, and an INUSE exception + * is to be thrown if the user attempts to explicitly share them + * between elements. + *

+ * Note that Elements do not permit attributes to appear to be shared + * (see the INUSE exception), so this object's mutability is + * officially not an issue. + *

+ * Note: The ownerNode attribute is used to store the Element the Attr + * node is associated with. Attr nodes do not have parent nodes. + * Besides, the getOwnerElement() method can be used to get the element node + * this attribute is associated with. + *

+ * AttrImpl does not support Namespaces. AttrNSImpl, which inherits from + * it, does. + * + *

AttrImpl used to inherit from ParentNode. It now directly inherits from + * NodeImpl and provide its own implementation of the ParentNode's behavior. + * The reason is that we now try and avoid to always create a Text node to + * hold the value of an attribute. The DOM spec requires it, so we still have + * to do it in case getFirstChild() is called for instance. The reason + * attribute values are stored as a list of nodes is so that they can carry + * more than a simple string. They can also contain EntityReference nodes. + * However, most of the times people only have a single string that they only + * set and get through Element.set/getAttribute or Attr.set/getValue. In this + * new version, the Attr node has a value pointer which can either be the + * String directly or a pointer to the first ChildNode. A flag tells which one + * it currently is. Note that while we try to stick with the direct String as + * much as possible once we've switched to a node there is no going back. This + * is because we have no way to know whether the application keeps referring to + * the node we once returned. + *

The gain in memory varies on the density of attributes in the document. + * But in the tests I've run I've seen up to 12% of memory gain. And the good + * thing is that it also leads to a slight gain in speed because we allocate + * fewer objects! I mean, that's until we have to actually create the node... + *

+ * To avoid too much duplicated code, I got rid of ParentNode and renamed + * ChildAndParentNode, which I never really liked, to ParentNode for + * simplicity, this doesn't make much of a difference in memory usage because + * there are only very few objects that are only a Parent. This is only true + * now because AttrImpl now inherits directly from NodeImpl and has its own + * implementation of the ParentNode's node behavior. So there is still some + * duplicated code there. + *

+ * This class doesn't directly support mutation events, however, it notifies + * the document when mutations are performed so that the document class do so. + * + *

WARNING: Some of the code here is partially duplicated in + * ParentNode, be careful to keep these two classes in sync! + * + * @xerces.internal + * + * @see AttrNSImpl + * + * @author Arnaud Le Hors, IBM + * @author Joe Kesselman, IBM + * @author Andy Clark, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + * + */ +public class AttrImpl + extends NodeImpl + implements Attr, TypeInfo{ + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 7277707688218972102L; + + /** DTD namespace. **/ + static final String DTD_URI = "http://www.w3.org/TR/REC-xml"; + + // + // Data + // + + /** This can either be a String or the first child node. */ + protected Object value = null; + + /** Attribute name. */ + protected String name; + + /** Type information */ + // REVISIT: we are losing the type information in DOM during serialization + transient Object type; + + // + // Constructors + // + + /** + * Attribute has no public constructor. Please use the factory + * method in the Document class. + */ + protected AttrImpl(CoreDocumentImpl ownerDocument, String name) { + super(ownerDocument); + this.name = name; + /** False for default attributes. */ + isSpecified(true); + hasStringValue(true); + } + + // for AttrNSImpl + protected AttrImpl() {} + + // Support for DOM Level 3 renameNode method. + // Note: This only deals with part of the pb. It is expected to be + // called after the Attr has been detached for one thing. + // CoreDocumentImpl does all the work. + void rename(String name) { + if (needsSyncData()) { + synchronizeData(); + } + this.name = name; + } + + // create a real text node as child if we don't have one yet + protected void makeChildNode() { + if (hasStringValue()) { + if (value != null) { + TextImpl text = + (TextImpl) ownerDocument().createTextNode((String) value); + value = text; + text.isFirstChild(true); + text.previousSibling = text; + text.ownerNode = this; + text.isOwned(true); + } + hasStringValue(false); + } + } + + /** + * NON-DOM + * set the ownerDocument of this node and its children + */ + protected void setOwnerDocument(CoreDocumentImpl doc) { + if (needsSyncChildren()) { + synchronizeChildren(); + } + super.setOwnerDocument(doc); + if (!hasStringValue()) { + for (ChildNode child = (ChildNode) value; + child != null; child = child.nextSibling) { + child.setOwnerDocument(doc); + } + } + } + + /** + * NON-DOM: set the type of this attribute to be ID type. + * + * @param id + */ + public void setIdAttribute(boolean id){ + if (needsSyncData()) { + synchronizeData(); + } + isIdAttribute(id); + } + /** DOM Level 3: isId*/ + public boolean isId(){ + // REVISIT: should an attribute that is not in the tree return + // isID true? + return isIdAttribute(); + } + + + // + // Node methods + // + + public Node cloneNode(boolean deep) { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + AttrImpl clone = (AttrImpl) super.cloneNode(deep); + + // take care of case where there are kids + if (!clone.hasStringValue()) { + + // Need to break the association w/ original kids + clone.value = null; + + // Cloning an Attribute always clones its children, + // since they represent its value, no matter whether this + // is a deep clone or not + for (Node child = (Node) value; child != null; + child = child.getNextSibling()) { + clone.appendChild(child.cloneNode(true)); + } + } + clone.isSpecified(true); + return clone; + } + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.ATTRIBUTE_NODE; + } + + /** + * Returns the attribute name + */ + public String getNodeName() { + if (needsSyncData()) { + synchronizeData(); + } + return name; + } + + /** + * Implicit in the rerouting of getNodeValue to getValue is the + * need to redefine setNodeValue, for symmetry's sake. Note that + * since we're explicitly providing a value, Specified should be set + * true.... even if that value equals the default. + */ + public void setNodeValue(String value) throws DOMException { + setValue(value); + } + + /** + * @see org.w3c.dom.TypeInfo#getTypeName() + */ + public String getTypeName() { + return (String)type; + } + + /** + * @see org.w3c.dom.TypeInfo#getTypeNamespace() + */ + public String getTypeNamespace() { + if (type != null) { + return DTD_URI; + } + return null; + } + + /** + * Method getSchemaTypeInfo. + * @return TypeInfo + */ + public TypeInfo getSchemaTypeInfo(){ + return this; + } + + /** + * In Attribute objects, NodeValue is considered a synonym for + * Value. + * + * @see #getValue() + */ + public String getNodeValue() { + return getValue(); + } + + // + // Attr methods + // + + /** + * In Attributes, NodeName is considered a synonym for the + * attribute's Name + */ + public String getName() { + + if (needsSyncData()) { + synchronizeData(); + } + return name; + + } // getName():String + + /** + * The DOM doesn't clearly define what setValue(null) means. I've taken it + * as "remove all children", which from outside should appear + * similar to setting it to the empty string. + */ + public void setValue(String newvalue) { + + CoreDocumentImpl ownerDocument = ownerDocument(); + + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + Element ownerElement = getOwnerElement(); + String oldvalue = ""; + TextImpl textNode = null; + + if (needsSyncData()) { + synchronizeData(); + } + if (needsSyncChildren()) { + synchronizeChildren(); + } + if (value != null) { + if (ownerDocument.getMutationEvents()) { + // Can no longer just discard the kids; they may have + // event listeners waiting for them to disconnect. + if (hasStringValue()) { + oldvalue = (String) value; + // create an actual text node as our child so + // that we can use it in the event + textNode = (TextImpl) ownerDocument.createTextNode((String) value); + value = textNode; + textNode.isFirstChild(true); + textNode.previousSibling = textNode; + textNode.ownerNode = this; + textNode.isOwned(true); + hasStringValue(false); + internalRemoveChild(textNode, true); + } + else { + oldvalue = getValue(); + while (value != null) { + internalRemoveChild((Node) value, true); + } + } + } + else { + if (hasStringValue()) { + oldvalue = (String) value; + } + else { + // simply discard children if any + oldvalue = getValue(); + // remove ref from first child to last child + ChildNode firstChild = (ChildNode) value; + firstChild.previousSibling = null; + firstChild.isFirstChild(false); + firstChild.ownerNode = ownerDocument; + } + // then remove ref to current value + value = null; + needsSyncChildren(false); + } + if (isIdAttribute() && ownerElement != null) { + ownerDocument.removeIdentifier(oldvalue); + } + } + + // Create and add the new one, generating only non-aggregate events + // (There are no listeners on the new Text, but there may be + // capture/bubble listeners on the Attr. + // Note that aggregate events are NOT dispatched here, + // since we need to combine the remove and insert. + isSpecified(true); + if (ownerDocument.getMutationEvents()) { + // if there are any event handlers create a real node or + // reuse the one we synthesized for the remove notifications + // if it exists. + if (textNode == null) { + textNode = (TextImpl) ownerDocument.createTextNode(newvalue); + } + else { + textNode.data = newvalue; + } + internalInsertBefore(textNode, null, true); + hasStringValue(false); + // notify document + ownerDocument.modifiedAttrValue(this, oldvalue); + } else { + // directly store the string + value = newvalue; + hasStringValue(true); + changed(); + } + if (isIdAttribute() && ownerElement != null) { + ownerDocument.putIdentifier(newvalue, ownerElement); + } + + } // setValue(String) + + /** + * The "string value" of an Attribute is its text representation, + * which in turn is a concatenation of the string values of its children. + */ + public String getValue() { + + if (needsSyncData()) { + synchronizeData(); + } + if (needsSyncChildren()) { + synchronizeChildren(); + } + if (value == null) { + return ""; + } + if (hasStringValue()) { + return (String) value; + } + + ChildNode firstChild = ((ChildNode) value); + + String data = null; + if (firstChild.getNodeType() == Node.ENTITY_REFERENCE_NODE){ + data = ((EntityReferenceImpl)firstChild).getEntityRefValue(); + } + else { + data = firstChild.getNodeValue(); + } + + ChildNode node = firstChild.nextSibling; + + if (node == null || data == null) return (data == null)?"":data; + + StringBuffer value = new StringBuffer(data); + while (node != null) { + if (node.getNodeType() == Node.ENTITY_REFERENCE_NODE){ + data = ((EntityReferenceImpl)node).getEntityRefValue(); + if (data == null) return ""; + value.append(data); + } + else { + value.append(node.getNodeValue()); + } + node = node.nextSibling; + } + return value.toString(); + + } // getValue():String + + + /** + * The "specified" flag is true if and only if this attribute's + * value was explicitly specified in the original document. Note that + * the implementation, not the user, is in charge of this + * property. If the user asserts an Attribute value (even if it ends + * up having the same value as the default), it is considered a + * specified attribute. If you really want to revert to the default, + * delete the attribute from the Element, and the Implementation will + * re-assert the default (if any) in its place, with the appropriate + * specified=false setting. + */ + public boolean getSpecified() { + + if (needsSyncData()) { + synchronizeData(); + } + return isSpecified(); + + } // getSpecified():boolean + + // + // Attr2 methods + // + + /** + * Returns the element node that this attribute is associated with, + * or null if the attribute has not been added to an element. + * + * @see #getOwnerElement + * + * @deprecated Previous working draft of DOM Level 2. New method + * is getOwnerElement(). + */ + public Element getElement() { + // if we have an owner, ownerNode is our ownerElement, otherwise it's + // our ownerDocument and we don't have an ownerElement + return (Element) (isOwned() ? ownerNode : null); + } + + /** + * Returns the element node that this attribute is associated with, + * or null if the attribute has not been added to an element. + * + * @since WD-DOM-Level-2-19990719 + */ + public Element getOwnerElement() { + // if we have an owner, ownerNode is our ownerElement, otherwise it's + // our ownerDocument and we don't have an ownerElement + return (Element) (isOwned() ? ownerNode : null); + } + + public void normalize() { + + // No need to normalize if already normalized or + // if value is kept as a String. + if (isNormalized() || hasStringValue()) + return; + + Node kid, next; + ChildNode firstChild = (ChildNode)value; + for (kid = firstChild; kid != null; kid = next) { + next = kid.getNextSibling(); + + // If kid is a text node, we need to check for one of two + // conditions: + // 1) There is an adjacent text node + // 2) There is no adjacent text node, but kid is + // an empty text node. + if ( kid.getNodeType() == Node.TEXT_NODE ) + { + // If an adjacent text node, merge it with kid + if ( next!=null && next.getNodeType() == Node.TEXT_NODE ) + { + ((Text)kid).appendData(next.getNodeValue()); + removeChild( next ); + next = kid; // Don't advance; there might be another. + } + else + { + // If kid is empty, remove it + if ( kid.getNodeValue() == null || kid.getNodeValue().length() == 0 ) { + removeChild( kid ); + } + } + } + } + + isNormalized(true); + } // normalize() + + // + // Public methods + // + + /** NON-DOM, for use by parser */ + public void setSpecified(boolean arg) { + + if (needsSyncData()) { + synchronizeData(); + } + isSpecified(arg); + + } // setSpecified(boolean) + + /** + * NON-DOM: used by the parser + * @param type + */ + public void setType (Object type){ + this.type = type; + } + + // + // Object methods + // + + /** NON-DOM method for debugging convenience */ + public String toString() { + return getName() + "=" + "\"" + getValue() + "\""; + } + + /** + * Test whether this node has any children. Convenience shorthand + * for (Node.getFirstChild()!=null) + */ + public boolean hasChildNodes() { + if (needsSyncChildren()) { + synchronizeChildren(); + } + return value != null; + } + + /** + * Obtain a NodeList enumerating all children of this node. If there + * are none, an (initially) empty NodeList is returned. + *

+ * NodeLists are "live"; as children are added/removed the NodeList + * will immediately reflect those changes. Also, the NodeList refers + * to the actual nodes, so changes to those nodes made via the DOM tree + * will be reflected in the NodeList and vice versa. + *

+ * In this implementation, Nodes implement the NodeList interface and + * provide their own getChildNodes() support. Other DOMs may solve this + * differently. + */ + public NodeList getChildNodes() { + // JKESS: KNOWN ISSUE HERE + + if (needsSyncChildren()) { + synchronizeChildren(); + } + return this; + + } // getChildNodes():NodeList + + /** The first child of this Node, or null if none. */ + public Node getFirstChild() { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + makeChildNode(); + return (Node) value; + + } // getFirstChild():Node + + /** The last child of this Node, or null if none. */ + public Node getLastChild() { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + return lastChild(); + + } // getLastChild():Node + + final ChildNode lastChild() { + // last child is stored as the previous sibling of first child + makeChildNode(); + return value != null ? ((ChildNode) value).previousSibling : null; + } + + final void lastChild(ChildNode node) { + // store lastChild as previous sibling of first child + if (value != null) { + ((ChildNode) value).previousSibling = node; + } + } + + /** + * Move one or more node(s) to our list of children. Note that this + * implicitly removes them from their previous parent. + * + * @param newChild The Node to be moved to our subtree. As a + * convenience feature, inserting a DocumentNode will instead insert + * all its children. + * + * @param refChild Current child which newChild should be placed + * immediately before. If refChild is null, the insertion occurs + * after all existing Nodes, like appendChild(). + * + * @return newChild, in its new state (relocated, or emptied in the case of + * DocumentNode.) + * + * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a + * type that shouldn't be a child of this node, or if newChild is an + * ancestor of this node. + * + * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a + * different owner document than we do. + * + * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node insertBefore(Node newChild, Node refChild) + throws DOMException { + // Tail-call; optimizer should be able to do good things with. + return internalInsertBefore(newChild, refChild, false); + } // insertBefore(Node,Node):Node + + /** NON-DOM INTERNAL: Within DOM actions,we sometimes need to be able + * to control which mutation events are spawned. This version of the + * insertBefore operation allows us to do so. It is not intended + * for use by application programs. + */ + Node internalInsertBefore(Node newChild, Node refChild, boolean replace) + throws DOMException { + + CoreDocumentImpl ownerDocument = ownerDocument(); + boolean errorChecking = ownerDocument.errorChecking; + + if (newChild.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { + // SLOW BUT SAFE: We could insert the whole subtree without + // juggling so many next/previous pointers. (Wipe out the + // parent's child-list, patch the parent pointers, set the + // ends of the list.) But we know some subclasses have special- + // case behavior they add to insertBefore(), so we don't risk it. + // This approch also takes fewer bytecodes. + + // NOTE: If one of the children is not a legal child of this + // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children + // have been transferred. (Alternative behaviors would be to + // reparent up to the first failure point or reparent all those + // which are acceptable to the target node, neither of which is + // as robust. PR-DOM-0818 isn't entirely clear on which it + // recommends????? + + // No need to check kids for right-document; if they weren't, + // they wouldn't be kids of that DocFrag. + if (errorChecking) { + for (Node kid = newChild.getFirstChild(); // Prescan + kid != null; kid = kid.getNextSibling()) { + + if (!ownerDocument.isKidOK(this, kid)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null); + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg); + } + } + } + + while (newChild.hasChildNodes()) { + insertBefore(newChild.getFirstChild(), refChild); + } + return newChild; + } + + if (newChild == refChild) { + // stupid case that must be handled as a no-op triggering events... + refChild = refChild.getNextSibling(); + removeChild(newChild); + insertBefore(newChild, refChild); + return newChild; + } + + if (needsSyncChildren()) { + synchronizeChildren(); + } + + if (errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + if (newChild.getOwnerDocument() != ownerDocument) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + if (!ownerDocument.isKidOK(this, newChild)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null); + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg); + } + // refChild must be a child of this node (or null) + if (refChild != null && refChild.getParentNode() != this) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + + // Prevent cycles in the tree + // newChild cannot be ancestor of this Node, + // and actually cannot be this + boolean treeSafe = true; + for (NodeImpl a = this; treeSafe && a != null; a = a.parentNode()) + { + treeSafe = newChild != a; + } + if (!treeSafe) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null); + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg); + } + } + + makeChildNode(); // make sure we have a node and not a string + + // notify document + ownerDocument.insertingNode(this, replace); + + // Convert to internal type, to avoid repeated casting + ChildNode newInternal = (ChildNode)newChild; + + Node oldparent = newInternal.parentNode(); + if (oldparent != null) { + oldparent.removeChild(newInternal); + } + + // Convert to internal type, to avoid repeated casting + ChildNode refInternal = (ChildNode) refChild; + + // Attach up + newInternal.ownerNode = this; + newInternal.isOwned(true); + + // Attach before and after + // Note: firstChild.previousSibling == lastChild!! + ChildNode firstChild = (ChildNode) value; + if (firstChild == null) { + // this our first and only child + value = newInternal; // firstchild = newInternal; + newInternal.isFirstChild(true); + newInternal.previousSibling = newInternal; + } + else { + if (refInternal == null) { + // this is an append + ChildNode lastChild = firstChild.previousSibling; + lastChild.nextSibling = newInternal; + newInternal.previousSibling = lastChild; + firstChild.previousSibling = newInternal; + } + else { + // this is an insert + if (refChild == firstChild) { + // at the head of the list + firstChild.isFirstChild(false); + newInternal.nextSibling = firstChild; + newInternal.previousSibling = firstChild.previousSibling; + firstChild.previousSibling = newInternal; + value = newInternal; // firstChild = newInternal; + newInternal.isFirstChild(true); + } + else { + // somewhere in the middle + ChildNode prev = refInternal.previousSibling; + newInternal.nextSibling = refInternal; + prev.nextSibling = newInternal; + refInternal.previousSibling = newInternal; + newInternal.previousSibling = prev; + } + } + } + + changed(); + + // notify document + ownerDocument.insertedNode(this, newInternal, replace); + + checkNormalizationAfterInsert(newInternal); + + return newChild; + + } // internalInsertBefore(Node,Node,int):Node + + /** + * Remove a child from this Node. The removed child's subtree + * remains intact so it may be re-inserted elsewhere. + * + * @return oldChild, in its new state (removed). + * + * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node removeChild(Node oldChild) + throws DOMException { + // Tail-call, should be optimizable + if (hasStringValue()) { + // we don't have any child per say so it can't be one of them! + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + return internalRemoveChild(oldChild, false); + } // removeChild(Node) :Node + + /** NON-DOM INTERNAL: Within DOM actions,we sometimes need to be able + * to control which mutation events are spawned. This version of the + * removeChild operation allows us to do so. It is not intended + * for use by application programs. + */ + Node internalRemoveChild(Node oldChild, boolean replace) + throws DOMException { + + CoreDocumentImpl ownerDocument = ownerDocument(); + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + if (oldChild != null && oldChild.getParentNode() != this) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + } + + ChildNode oldInternal = (ChildNode) oldChild; + + // notify document + ownerDocument.removingNode(this, oldInternal, replace); + + // Patch linked list around oldChild + // Note: lastChild == firstChild.previousSibling + if (oldInternal == value) { // oldInternal == firstChild + // removing first child + oldInternal.isFirstChild(false); + // next line is: firstChild = oldInternal.nextSibling + value = oldInternal.nextSibling; + ChildNode firstChild = (ChildNode) value; + if (firstChild != null) { + firstChild.isFirstChild(true); + firstChild.previousSibling = oldInternal.previousSibling; + } + } else { + ChildNode prev = oldInternal.previousSibling; + ChildNode next = oldInternal.nextSibling; + prev.nextSibling = next; + if (next == null) { + // removing last child + ChildNode firstChild = (ChildNode) value; + firstChild.previousSibling = prev; + } else { + // removing some other child in the middle + next.previousSibling = prev; + } + } + + // Save previous sibling for normalization checking. + ChildNode oldPreviousSibling = oldInternal.previousSibling(); + + // Remove oldInternal's references to tree + oldInternal.ownerNode = ownerDocument; + oldInternal.isOwned(false); + oldInternal.nextSibling = null; + oldInternal.previousSibling = null; + + changed(); + + // notify document + ownerDocument.removedNode(this, replace); + + checkNormalizationAfterRemove(oldPreviousSibling); + + return oldInternal; + + } // internalRemoveChild(Node,int):Node + + /** + * Make newChild occupy the location that oldChild used to + * have. Note that newChild will first be removed from its previous + * parent, if any. Equivalent to inserting newChild before oldChild, + * then removing oldChild. + * + * @return oldChild, in its new state (removed). + * + * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a + * type that shouldn't be a child of this node, or if newChild is + * one of our ancestors. + * + * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a + * different owner document than we do. + * + * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node replaceChild(Node newChild, Node oldChild) + throws DOMException { + + makeChildNode(); + + // If Mutation Events are being generated, this operation might + // throw aggregate events twice when modifying an Attr -- once + // on insertion and once on removal. DOM Level 2 does not specify + // this as either desirable or undesirable, but hints that + // aggregations should be issued only once per user request. + + // notify document + CoreDocumentImpl ownerDocument = ownerDocument(); + ownerDocument.replacingNode(this); + + internalInsertBefore(newChild, oldChild, true); + if (newChild != oldChild) { + internalRemoveChild(oldChild, true); + } + + // notify document + ownerDocument.replacedNode(this); + + return oldChild; + } + + // + // NodeList methods + // + + /** + * NodeList method: Count the immediate children of this node + * @return int + */ + public int getLength() { + + if (hasStringValue()) { + return 1; + } + ChildNode node = (ChildNode) value; + int length = 0; + for (; node != null; node = node.nextSibling) { + length++; + } + return length; + + } // getLength():int + + /** + * NodeList method: Return the Nth immediate child of this node, or + * null if the index is out of bounds. + * @return org.w3c.dom.Node + * @param index int + */ + public Node item(int index) { + + if (hasStringValue()) { + if (index != 0 || value == null) { + return null; + } + else { + makeChildNode(); + return (Node) value; + } + } + if (index < 0) { + return null; + } + ChildNode node = (ChildNode) value; + for (int i = 0; i < index && node != null; i++) { + node = node.nextSibling; + } + return node; + + } // item(int):Node + + // + // DOM3 + // + + /** + * DOM Level 3 WD- Experimental. + * Override inherited behavior from ParentNode to support deep equal. + * isEqualNode is always deep on Attr nodes. + */ + public boolean isEqualNode(Node arg) { + return super.isEqualNode(arg); + } + + /** + * Introduced in DOM Level 3.

+ * Checks if a type is derived from another by restriction. See: + * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom + * + * @param typeNamespaceArg + * The namspace of the ancestor type declaration + * @param typeNameArg + * The name of the ancestor type declaration + * @param derivationMethod + * The derivation method + * + * @return boolean True if the type is derived by restriciton for the + * reference type + */ + public boolean isDerivedFrom(String typeNamespaceArg, + String typeNameArg, + int derivationMethod) { + + return false; + } + + + // + // Public methods + // + + /** + * Override default behavior so that if deep is true, children are also + * toggled. + * @see Node + *

+ * Note: this will not change the state of an EntityReference or its + * children, which are always read-only. + */ + public void setReadOnly(boolean readOnly, boolean deep) { + + super.setReadOnly(readOnly, deep); + + if (deep) { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + + if (hasStringValue()) { + return; + } + // Recursively set kids + for (ChildNode mykid = (ChildNode) value; + mykid != null; + mykid = mykid.nextSibling) { + if (mykid.getNodeType() != Node.ENTITY_REFERENCE_NODE) { + mykid.setReadOnly(readOnly,true); + } + } + } + } // setReadOnly(boolean,boolean) + + // + // Protected methods + // + + /** + * Override this method in subclass to hook in efficient + * internal data structure. + */ + protected void synchronizeChildren() { + // By default just change the flag to avoid calling this method again + needsSyncChildren(false); + } + + /** + * Checks the normalized state of this node after inserting a child. + * If the inserted child causes this node to be unnormalized, then this + * node is flagged accordingly. + * The conditions for changing the normalized state are: + *

    + *
  • The inserted child is a text node and one of its adjacent siblings + * is also a text node. + *
  • The inserted child is is itself unnormalized. + *
+ * + * @param insertedChild the child node that was inserted into this node + * + * @throws NullPointerException if the inserted child is null + */ + void checkNormalizationAfterInsert(ChildNode insertedChild) { + // See if insertion caused this node to be unnormalized. + if (insertedChild.getNodeType() == Node.TEXT_NODE) { + ChildNode prev = insertedChild.previousSibling(); + ChildNode next = insertedChild.nextSibling; + // If an adjacent sibling of the new child is a text node, + // flag this node as unnormalized. + if ((prev != null && prev.getNodeType() == Node.TEXT_NODE) || + (next != null && next.getNodeType() == Node.TEXT_NODE)) { + isNormalized(false); + } + } + else { + // If the new child is not normalized, + // then this node is inherently not normalized. + if (!insertedChild.isNormalized()) { + isNormalized(false); + } + } + } // checkNormalizationAfterInsert(ChildNode) + + /** + * Checks the normalized of this node after removing a child. + * If the removed child causes this node to be unnormalized, then this + * node is flagged accordingly. + * The conditions for changing the normalized state are: + *
    + *
  • The removed child had two adjacent siblings that were text nodes. + *
+ * + * @param previousSibling the previous sibling of the removed child, or + * null + */ + void checkNormalizationAfterRemove(ChildNode previousSibling) { + // See if removal caused this node to be unnormalized. + // If the adjacent siblings of the removed child were both text nodes, + // flag this node as unnormalized. + if (previousSibling != null && + previousSibling.getNodeType() == Node.TEXT_NODE) { + + ChildNode next = previousSibling.nextSibling; + if (next != null && next.getNodeType() == Node.TEXT_NODE) { + isNormalized(false); + } + } + } // checkNormalizationAfterRemove(ChildNode) + + // + // Serialization methods + // + + /** Serialize object. */ + private void writeObject(ObjectOutputStream out) throws IOException { + + // synchronize chilren + if (needsSyncChildren()) { + synchronizeChildren(); + } + // write object + out.defaultWriteObject(); + + } // writeObject(ObjectOutputStream) + + /** Deserialize object. */ + private void readObject(ObjectInputStream ois) + throws ClassNotFoundException, IOException { + + // perform default deseralization + ois.defaultReadObject(); + + // hardset synchildren - so we don't try to sync - + // it does not make any sense to try to synchildren when we just + // deserialize object. + needsSyncChildren(false); + + } // readObject(ObjectInputStream) + + +} // class AttrImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/AttrNSImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/AttrNSImpl.java new file mode 100644 index 0000000..4582d51 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/AttrNSImpl.java @@ -0,0 +1,324 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.xni.NamespaceContext; +import org.w3c.dom.DOMException; + +/** + * AttrNSImpl inherits from AttrImpl and adds namespace support. + *

+ * The qualified name is the node name, and we store localName which is also + * used in all queries. On the other hand we recompute the prefix when + * necessary. + * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * @author Ralf Pfeiffer, IBM + * @version $Id$ + */ +public class AttrNSImpl + extends AttrImpl { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -781906615369795414L; + + static final String xmlnsURI = "http://www.w3.org/2000/xmlns/"; + static final String xmlURI = "http://www.w3.org/XML/1998/namespace"; + + // + // Data + // + + /** DOM2: Namespace URI. */ + protected String namespaceURI; + + /** DOM2: localName. */ + protected String localName; + + /* + * Default constructor + */ + public AttrNSImpl(){} + + /** + * DOM2: Constructor for Namespace implementation. + */ + protected AttrNSImpl(CoreDocumentImpl ownerDocument, + String namespaceURI, + String qualifiedName) { + + super(ownerDocument, qualifiedName); + setName(namespaceURI, qualifiedName); + } + + private void setName(String namespaceURI, String qname){ + CoreDocumentImpl ownerDocument = ownerDocument(); + String prefix; + // DOM Level 3: namespace URI is never empty string. + this.namespaceURI = namespaceURI; + if (namespaceURI !=null) { + this.namespaceURI = (namespaceURI.length() == 0)? null + : namespaceURI; + + } + int colon1 = qname.indexOf(':'); + int colon2 = qname.lastIndexOf(':'); + ownerDocument.checkNamespaceWF(qname, colon1, colon2); + if (colon1 < 0) { + // there is no prefix + localName = qname; + if (ownerDocument.errorChecking) { + ownerDocument.checkQName(null, localName); + + if (qname.equals("xmlns") && (namespaceURI == null + || !namespaceURI.equals(NamespaceContext.XMLNS_URI)) + || (namespaceURI!=null && namespaceURI.equals(NamespaceContext.XMLNS_URI) + && !qname.equals("xmlns"))) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + } + } + else { + prefix = qname.substring(0, colon1); + localName = qname.substring(colon2+1); + ownerDocument.checkQName(prefix, localName); + ownerDocument.checkDOMNSErr(prefix, namespaceURI); + } + } + + // when local name is known + public AttrNSImpl(CoreDocumentImpl ownerDocument, + String namespaceURI, + String qualifiedName, + String localName) { + super(ownerDocument, qualifiedName); + + this.localName = localName; + this.namespaceURI = namespaceURI; + } + + // for DeferredAttrImpl + protected AttrNSImpl(CoreDocumentImpl ownerDocument, + String value) { + super(ownerDocument, value); + } + + // Support for DOM Level 3 renameNode method. + // Note: This only deals with part of the pb. It is expected to be + // called after the Attr has been detached for one thing. + // CoreDocumentImpl does all the work. + void rename(String namespaceURI, String qualifiedName) { + if (needsSyncData()) { + synchronizeData(); + } + this.name = qualifiedName; + setName(namespaceURI, qualifiedName); + } + + // + // DOM2: Namespace methods + // + + /** + * Introduced in DOM Level 2.

+ * + * 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 created with a DOM Level 1 method, such as createElement + * from the Document interface, this is null. + * @since WD-DOM-Level-2-19990923 + */ + public String getNamespaceURI() + { + if (needsSyncData()) { + synchronizeData(); + } + // REVIST: This code could/should be done at a lower-level, such that + // the namespaceURI is set properly upon creation. However, there still + // seems to be some DOM spec interpretation grey-area. + return namespaceURI; + } + + /** + * Introduced in DOM Level 2.

+ * + * The namespace prefix of this node, or null if it is unspecified.

+ * + * For nodes created with a DOM Level 1 method, such as createElement + * from the Document interface, this is null.

+ * + * @since WD-DOM-Level-2-19990923 + */ + public String getPrefix() + { + if (needsSyncData()) { + synchronizeData(); + } + int index = name.indexOf(':'); + return index < 0 ? null : name.substring(0, index); + } + + /** + * Introduced in DOM Level 2.

+ * + * Note that setting this attribute changes the nodeName attribute, which + * holds the qualified name, as well as the tagName and name attributes of + * the Element and Attr interfaces, when applicable.

+ * + * @param prefix The namespace prefix of this node, or null(empty string) if it is unspecified. + * + * @exception INVALID_CHARACTER_ERR + * Raised if the specified + * prefix contains an invalid character. + * @exception DOMException + * @since WD-DOM-Level-2-19990923 + */ + public void setPrefix(String prefix) + throws DOMException + { + if (needsSyncData()) { + synchronizeData(); + } + if (ownerDocument().errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + if (prefix != null && prefix.length() != 0) { + + if (!CoreDocumentImpl.isXMLName(prefix,ownerDocument().isXML11Version())) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + if (namespaceURI == null || prefix.indexOf(':') >=0) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + + } + if (prefix.equals("xmlns")) { + if (!namespaceURI.equals(xmlnsURI)){ + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + } else if (prefix.equals("xml")) { + if (!namespaceURI.equals(xmlURI)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + }else if (name.equals("xmlns")) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + } + } + + // update node name with new qualifiedName + if (prefix !=null && prefix.length() != 0) { + name = prefix + ":" + localName; + } + else { + name = localName; + } + } + + /** + * Introduced in DOM Level 2.

+ * + * Returns the local part of the qualified name of this node. + * @since WD-DOM-Level-2-19990923 + */ + public String getLocalName() + { + if (needsSyncData()) { + synchronizeData(); + } + return localName; + } + + + /** + * @see org.w3c.dom.TypeInfo#getTypeName() + */ + public String getTypeName() { + if (type !=null){ + if (type instanceof XSSimpleTypeDecl){ + return ((XSSimpleTypeDecl)type).getName(); + } + return (String)type; + } + return null; + } + + /** + * Introduced in DOM Level 3.

+ * Checks if a type is derived from another by restriction. See: + * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom + * + * @param typeNamespaceArg + * The namspace of the ancestor type declaration + * @param typeNameArg + * The name of the ancestor type declaration + * @param derivationMethod + * The derivation method + * + * @return boolean True if the type is derived by restriciton for the + * reference type + */ + public boolean isDerivedFrom(String typeNamespaceArg, + String typeNameArg, + int derivationMethod) { + if (type != null) { + if (type instanceof XSSimpleTypeDecl) { + return ((XSSimpleTypeDecl) type).isDOMDerivedFrom( + typeNamespaceArg, typeNameArg, derivationMethod); + } + } + return false; + } + + /** + * @see org.w3c.dom.TypeInfo#getTypeNamespace() + */ + public String getTypeNamespace() { + if (type !=null) { + if (type instanceof XSSimpleTypeDecl){ + return ((XSSimpleTypeDecl)type).getNamespace(); + } + return DTD_URI; + } + return null; + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/AttributeMap.java b/resources/xerces2-j-src/org/apache/xerces/dom/AttributeMap.java new file mode 100644 index 0000000..136bf60 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/AttributeMap.java @@ -0,0 +1,603 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + * AttributeMap inherits from NamedNodeMapImpl and extends it to deal with the + * specifics of storing attributes. These are: + *

    + *
  • managing ownership of attribute nodes + *
  • managing default attributes + *
  • firing mutation events + *
+ *

+ * This class doesn't directly support mutation events, however, it notifies + * the document when mutations are performed so that the document class do so. + * + * @xerces.internal + * + * @version $Id$ + */ +public class AttributeMap extends NamedNodeMapImpl { + + /** Serialization version. */ + static final long serialVersionUID = 8872606282138665383L; + + // + // Constructors + // + + /** Constructs a named node map. */ + protected AttributeMap(ElementImpl ownerNode, NamedNodeMapImpl defaults) { + super(ownerNode); + if (defaults != null) { + // initialize map with the defaults + cloneContent(defaults); + if (nodes != null) { + hasDefaults(true); + } + } + } + + /** + * Adds an attribute using its nodeName attribute. + * @see org.w3c.dom.NamedNodeMap#setNamedItem + * @return If the new Node replaces an existing node the replaced Node is + * returned, otherwise null is returned. + * @param arg + * An Attr node to store in this map. + * @exception org.w3c.dom.DOMException The exception description. + */ + public Node setNamedItem(Node arg) + throws DOMException { + + boolean errCheck = ownerNode.ownerDocument().errorChecking; + if (errCheck) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + if (arg.getOwnerDocument() != ownerNode.ownerDocument()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + if (arg.getNodeType() != Node.ATTRIBUTE_NODE) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null); + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg); + } + } + AttrImpl argn = (AttrImpl)arg; + + if (argn.isOwned()){ + if (errCheck && argn.getOwnerElement() != ownerNode) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INUSE_ATTRIBUTE_ERR", null); + throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, msg); + } + // replacing an Attribute with itself does nothing + return arg; + } + + + // set owner + argn.ownerNode = ownerNode; + argn.isOwned(true); + + int i = findNamePoint(argn.getNodeName(),0); + AttrImpl previous = null; + if (i >= 0) { + previous = (AttrImpl) nodes.get(i); + nodes.set(i, arg); + previous.ownerNode = ownerNode.ownerDocument(); + previous.isOwned(false); + // make sure it won't be mistaken with defaults in case it's reused + previous.isSpecified(true); + } else { + i = -1 - i; // Insert point (may be end of list) + if (null == nodes) { + nodes = new ArrayList(5); + } + nodes.add(i, arg); + } + + // notify document + ownerNode.ownerDocument().setAttrNode(argn, previous); + + // If the new attribute is not normalized, + // the owning element is inherently not normalized. + if (!argn.isNormalized()) { + ownerNode.isNormalized(false); + } + return previous; + + } // setNamedItem(Node):Node + + /** + * Adds an attribute using its namespaceURI and localName. + * @see org.w3c.dom.NamedNodeMap#setNamedItem + * @return If the new Node replaces an existing node the replaced Node is + * returned, otherwise null is returned. + * @param arg A node to store in a named node map. + */ + public Node setNamedItemNS(Node arg) + throws DOMException { + + boolean errCheck = ownerNode.ownerDocument().errorChecking; + if (errCheck) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + if(arg.getOwnerDocument() != ownerNode.ownerDocument()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + if (arg.getNodeType() != Node.ATTRIBUTE_NODE) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null); + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg); + } + } + AttrImpl argn = (AttrImpl)arg; + + if (argn.isOwned()){ + if (errCheck && argn.getOwnerElement() != ownerNode) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INUSE_ATTRIBUTE_ERR", null); + throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, msg); + } + // replacing an Attribute with itself does nothing + return arg; + } + + // set owner + argn.ownerNode = ownerNode; + argn.isOwned(true); + + int i = findNamePoint(argn.getNamespaceURI(), argn.getLocalName()); + AttrImpl previous = null; + if (i >= 0) { + previous = (AttrImpl) nodes.get(i); + nodes.set(i, arg); + previous.ownerNode = ownerNode.ownerDocument(); + previous.isOwned(false); + // make sure it won't be mistaken with defaults in case it's reused + previous.isSpecified(true); + } else { + // If we can't find by namespaceURI, localName, then we find by + // nodeName so we know where to insert. + i = findNamePoint(arg.getNodeName(),0); + if (i >=0) { + previous = (AttrImpl) nodes.get(i); + nodes.add(i, arg); + } else { + i = -1 - i; // Insert point (may be end of list) + if (null == nodes) { + nodes = new ArrayList(5); + } + nodes.add(i, arg); + } + } + // changed(true); + + // notify document + ownerNode.ownerDocument().setAttrNode(argn, previous); + + // If the new attribute is not normalized, + // the owning element is inherently not normalized. + if (!argn.isNormalized()) { + ownerNode.isNormalized(false); + } + return previous; + + } // setNamedItemNS(Node):Node + + /** + * Removes an attribute specified by name. + * @param name + * The name of a node to remove. If the + * removed attribute is known to have a default value, an + * attribute immediately appears containing the default value + * as well as the corresponding namespace URI, local name, + * and prefix when applicable. + * @return The node removed from the map if a node with such a name exists. + * @throws NOT_FOUND_ERR: Raised if there is no node named + * name in the map. + */ + /***/ + public Node removeNamedItem(String name) + throws DOMException { + return internalRemoveNamedItem(name, true); + } + + /** + * Same as removeNamedItem except that it simply returns null if the + * specified name is not found. + */ + Node safeRemoveNamedItem(String name) { + return internalRemoveNamedItem(name, false); + } + + + /** + * NON-DOM: Remove the node object + * + * NOTE: Specifically removes THIS NODE -- not the node with this + * name, nor the node with these contents. If node does not belong to + * this named node map, we throw a DOMException. + * + * @param item The node to remove + * @param addDefault true -- magically add default attribute + * @return Removed node + * @exception DOMException + */ + protected Node removeItem(Node item, boolean addDefault) + throws DOMException { + + int index = -1; + if (nodes != null) { + final int size = nodes.size(); + for (int i = 0; i < size; ++i) { + if (nodes.get(i) == item) { + index = i; + break; + } + } + } + if (index < 0) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + + return remove((AttrImpl)item, index, addDefault); + } + + /** + * Internal removeNamedItem method allowing to specify whether an exception + * must be thrown if the specified name is not found. + */ + final protected Node internalRemoveNamedItem(String name, boolean raiseEx){ + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + int i = findNamePoint(name,0); + if (i < 0) { + if (raiseEx) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } else { + return null; + } + } + + return remove((AttrImpl)nodes.get(i), i, true); + + } // internalRemoveNamedItem(String,boolean):Node + + private final Node remove(AttrImpl attr, int index, + boolean addDefault) { + + CoreDocumentImpl ownerDocument = ownerNode.ownerDocument(); + String name = attr.getNodeName(); + if (attr.isIdAttribute()) { + ownerDocument.removeIdentifier(attr.getValue()); + } + + if (hasDefaults() && addDefault) { + // If there's a default, add it instead + NamedNodeMapImpl defaults = + ((ElementImpl) ownerNode).getDefaultAttributes(); + + Node d; + if (defaults != null && + (d = defaults.getNamedItem(name)) != null && + findNamePoint(name, index+1) < 0) { + NodeImpl clone = (NodeImpl)d.cloneNode(true); + if (d.getLocalName() !=null){ + // we must rely on the name to find a default attribute + // ("test:attr"), but while copying it from the DOCTYPE + // we should not loose namespace URI that was assigned + // to the attribute in the instance document. + ((AttrNSImpl)clone).namespaceURI = attr.getNamespaceURI(); + } + clone.ownerNode = ownerNode; + clone.isOwned(true); + clone.isSpecified(false); + + nodes.set(index, clone); + if (attr.isIdAttribute()) { + ownerDocument.putIdentifier(clone.getNodeValue(), + (ElementImpl)ownerNode); + } + } else { + nodes.remove(index); + } + } else { + nodes.remove(index); + } + + // changed(true); + + // remove reference to owner + attr.ownerNode = ownerDocument; + attr.isOwned(false); + + // make sure it won't be mistaken with defaults in case it's + // reused + attr.isSpecified(true); + attr.isIdAttribute(false); + + // notify document + ownerDocument.removedAttrNode(attr, ownerNode, name); + + return attr; + } + + /** + * Introduced in DOM Level 2.

+ * Removes an attribute specified by local name and namespace URI. + * @param namespaceURI + * The namespace URI of the node to remove. + * When it is null or an empty string, this + * method behaves like removeNamedItem. + * @param name The local name of the node to remove. If the + * removed attribute is known to have a default + * value, an attribute immediately appears + * containing the default value. + * @return Node The node removed from the map if a node with such + * a local name and namespace URI exists. + * @throws NOT_FOUND_ERR: Raised if there is no node named + * name in the map. + */ + public Node removeNamedItemNS(String namespaceURI, String name) + throws DOMException { + return internalRemoveNamedItemNS(namespaceURI, name, true); + } + + /** + * Same as removeNamedItem except that it simply returns null if the + * specified local name and namespace URI is not found. + */ + Node safeRemoveNamedItemNS(String namespaceURI, String name) { + return internalRemoveNamedItemNS(namespaceURI, name, false); + } + + /** + * Internal removeNamedItemNS method allowing to specify whether an + * exception must be thrown if the specified local name and namespace URI + * is not found. + */ + final protected Node internalRemoveNamedItemNS(String namespaceURI, + String name, + boolean raiseEx) { + + CoreDocumentImpl ownerDocument = ownerNode.ownerDocument(); + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + int i = findNamePoint(namespaceURI, name); + if (i < 0) { + if (raiseEx) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } else { + return null; + } + } + + AttrImpl n = (AttrImpl)nodes.get(i); + + if (n.isIdAttribute()) { + ownerDocument.removeIdentifier(n.getValue()); + } + // If there's a default, add it instead + String nodeName = n.getNodeName(); + if (hasDefaults()) { + NamedNodeMapImpl defaults = ((ElementImpl) ownerNode).getDefaultAttributes(); + Node d; + if (defaults != null + && (d = defaults.getNamedItem(nodeName)) != null) + { + int j = findNamePoint(nodeName,0); + if (j>=0 && findNamePoint(nodeName, j+1) < 0) { + NodeImpl clone = (NodeImpl)d.cloneNode(true); + clone.ownerNode = ownerNode; + if (d.getLocalName() != null) { + // we must rely on the name to find a default attribute + // ("test:attr"), but while copying it from the DOCTYPE + // we should not loose namespace URI that was assigned + // to the attribute in the instance document. + ((AttrNSImpl)clone).namespaceURI = namespaceURI; + } + clone.isOwned(true); + clone.isSpecified(false); + nodes.set(i, clone); + if (clone.isIdAttribute()) { + ownerDocument.putIdentifier(clone.getNodeValue(), + (ElementImpl)ownerNode); + } + } else { + nodes.remove(i); + } + } else { + nodes.remove(i); + } + } else { + nodes.remove(i); + } + + // changed(true); + + // remove reference to owner + n.ownerNode = ownerDocument; + n.isOwned(false); + // make sure it won't be mistaken with defaults in case it's + // reused + n.isSpecified(true); + // update id table if needed + n.isIdAttribute(false); + + // notify document + ownerDocument.removedAttrNode(n, ownerNode, name); + + return n; + + } // internalRemoveNamedItemNS(String,String,boolean):Node + + // + // Public methods + // + + /** + * Cloning a NamedNodeMap is a DEEP OPERATION; it always clones + * all the nodes contained in the map. + */ + + public NamedNodeMapImpl cloneMap(NodeImpl ownerNode) { + AttributeMap newmap = + new AttributeMap((ElementImpl) ownerNode, null); + newmap.hasDefaults(hasDefaults()); + newmap.cloneContent(this); + return newmap; + } // cloneMap():AttributeMap + + /** + * Override parent's method to set the ownerNode correctly + */ + protected void cloneContent(NamedNodeMapImpl srcmap) { + List srcnodes = srcmap.nodes; + if (srcnodes != null) { + int size = srcnodes.size(); + if (size != 0) { + if (nodes == null) { + nodes = new ArrayList(size); + } + else { + nodes.clear(); + } + for (int i = 0; i < size; ++i) { + NodeImpl n = (NodeImpl) srcnodes.get(i); + NodeImpl clone = (NodeImpl) n.cloneNode(true); + clone.isSpecified(n.isSpecified()); + nodes.add(clone); + clone.ownerNode = ownerNode; + clone.isOwned(true); + } + } + } + } // cloneContent():AttributeMap + + + /** + * Move specified attributes from the given map to this one + */ + void moveSpecifiedAttributes(AttributeMap srcmap) { + int nsize = (srcmap.nodes != null) ? srcmap.nodes.size() : 0; + for (int i = nsize - 1; i >= 0; i--) { + AttrImpl attr = (AttrImpl) srcmap.nodes.get(i); + if (attr.isSpecified()) { + srcmap.remove(attr, i, false); + if (attr.getLocalName() != null) { + setNamedItem(attr); + } + else { + setNamedItemNS(attr); + } + } + } + } // moveSpecifiedAttributes(AttributeMap):void + + + /** + * Get this AttributeMap in sync with the given "defaults" map. + * @param defaults The default attributes map to sync with. + */ + protected void reconcileDefaults(NamedNodeMapImpl defaults) { + + // remove any existing default + int nsize = (nodes != null) ? nodes.size() : 0; + for (int i = nsize - 1; i >= 0; --i) { + AttrImpl attr = (AttrImpl) nodes.get(i); + if (!attr.isSpecified()) { + remove(attr, i, false); + } + } + // add the new defaults + if (defaults == null) { + return; + } + if (nodes == null || nodes.size() == 0) { + cloneContent(defaults); + } + else { + int dsize = defaults.nodes.size(); + for (int n = 0; n < dsize; ++n) { + AttrImpl d = (AttrImpl) defaults.nodes.get(n); + int i = findNamePoint(d.getNodeName(), 0); + if (i < 0) { + i = -1 - i; + NodeImpl clone = (NodeImpl) d.cloneNode(true); + clone.ownerNode = ownerNode; + clone.isOwned(true); + clone.isSpecified(false); + nodes.add(i, clone); + } + } + } + + } // reconcileDefaults() + + protected final int addItem (Node arg) { + + final AttrImpl argn = (AttrImpl) arg; + + // set owner + argn.ownerNode = ownerNode; + argn.isOwned(true); + + int i = findNamePoint(argn.getNamespaceURI(), argn.getLocalName()); + if (i >= 0) { + nodes.set(i, arg); + } + else { + // If we can't find by namespaceURI, localName, then we find by + // nodeName so we know where to insert. + i = findNamePoint(argn.getNodeName(),0); + if (i >= 0) { + nodes.add(i, arg); + } + else { + i = -1 - i; // Insert point (may be end of list) + if (null == nodes) { + nodes = new ArrayList(5); + } + nodes.add(i, arg); + } + } + + // notify document + ownerNode.ownerDocument().setAttrNode(argn, null); + return i; + } + +} // class AttributeMap diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/CDATASectionImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/CDATASectionImpl.java new file mode 100644 index 0000000..514f948 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/CDATASectionImpl.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.CDATASection; +import org.w3c.dom.Node; + +/** + * XML provides the CDATA markup to allow a region of text in which + * most of the XML delimiter recognition does not take place. This is + * intended to ease the task of quoting XML fragments and other + * programmatic information in a document's text without needing to + * escape these special characters. It's primarily a convenience feature + * for those who are hand-editing XML. + *

+ * CDATASection is an Extended DOM feature, and is not used in HTML + * contexts. + *

+ * Within the DOM, CDATASections are treated essentially as Text + * blocks. Their distinct type is retained in order to allow us to + * properly recreate the XML syntax when we write them out. + *

+ * Reminder: CDATA IS NOT A COMPLETELY GENERAL SOLUTION; it can't + * quote its own end-of-block marking. If you need to write out a + * CDATA that contains the ]]> sequence, it's your responsibility to + * split that string over two successive CDATAs at that time. + *

+ * CDATA does not participate in Element.normalize() processing. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class CDATASectionImpl + extends TextImpl + implements CDATASection { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 2372071297878177780L; + + // + // Constructors + // + + /** Factory constructor for creating a CDATA section. */ + public CDATASectionImpl(CoreDocumentImpl ownerDoc, String data) { + super(ownerDoc, data); + } + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.CDATA_SECTION_NODE; + } + + /** Returns the node name. */ + public String getNodeName() { + return "#cdata-section"; + } + +} // class CDATASectionImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/CharacterDataImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/CharacterDataImpl.java new file mode 100644 index 0000000..eb02ac3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/CharacterDataImpl.java @@ -0,0 +1,423 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * CharacterData is an abstract Node that can carry character data as its + * Value. It provides shared behavior for Text, CData, and + * possibly other node types. All offsets are 0-based. + *

+ * Since ProcessingInstructionImpl inherits from this class to reuse the + * setNodeValue method, this class isn't declared as implementing the interface + * CharacterData. This is done by relevant subclasses (TexImpl, CommentImpl). + *

+ * This class doesn't directly support mutation events, however, it notifies + * the document when mutations are performed so that the document class do so. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public abstract class CharacterDataImpl + extends ChildNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 7931170150428474230L; + + // + // Data + // + + protected String data; + + /** Empty child nodes. */ + private static final transient NodeList singletonNodeList = new NodeList() { + public Node item(int index) { return null; } + public int getLength() { return 0; } + }; + + // + // Constructors + // + + public CharacterDataImpl(){} + + /** Factory constructor. */ + protected CharacterDataImpl(CoreDocumentImpl ownerDocument, String data) { + super(ownerDocument); + this.data = data; + } + + // + // Node methods + // + + /** Returns an empty node list. */ + public NodeList getChildNodes() { + return singletonNodeList; + } + + /* + * returns the content of this node + */ + public String getNodeValue() { + if (needsSyncData()) { + synchronizeData(); + } + return data; + } + + /** Convenience wrapper for calling setNodeValueInternal when + * we are not performing a replacement operation + */ + protected void setNodeValueInternal (String value) { + setNodeValueInternal(value, false); + } + + /** This function added so that we can distinguish whether + * setNodeValue has been called from some other DOM functions. + * or by the client.

+ * This is important, because we do one type of Range fix-up, + * from the high-level functions in CharacterData, and another + * type if the client simply calls setNodeValue(value). + */ + protected void setNodeValueInternal(String value, boolean replace) { + + CoreDocumentImpl ownerDocument = ownerDocument(); + + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + // revisit: may want to set the value in ownerDocument. + // Default behavior, overridden in some subclasses + if (needsSyncData()) { + synchronizeData(); + } + + // keep old value for document notification + String oldvalue = this.data; + + // notify document + ownerDocument.modifyingCharacterData(this, replace); + + this.data = value; + + // notify document + ownerDocument.modifiedCharacterData(this, oldvalue, value, replace); + } + + /** + * Sets the content, possibly firing related events, + * and updating ranges (via notification to the document) + */ + public void setNodeValue(String value) { + + setNodeValueInternal(value); + + // notify document + ownerDocument().replacedText(this); + } + + // + // CharacterData methods + // + + /** + * Retrieve character data currently stored in this node. + * + * @throws DOMExcpetion(DOMSTRING_SIZE_ERR) In some implementations, + * the stored data may exceed the permitted length of strings. If so, + * getData() will throw this DOMException advising the user to + * instead retrieve the data in chunks via the substring() operation. + */ + public String getData() { + if (needsSyncData()) { + synchronizeData(); + } + return data; + } + + /** + * Report number of characters currently stored in this node's + * data. It may be 0, meaning that the value is an empty string. + */ + public int getLength() { + if (needsSyncData()) { + synchronizeData(); + } + return data.length(); + } + + /** + * Concatenate additional characters onto the end of the data + * stored in this node. Note that this, and insert(), are the paths + * by which a DOM could wind up accumulating more data than the + * language's strings can easily handle. (See above discussion.) + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly. + */ + public void appendData(String data) { + + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + if (data == null) { + return; + } + if (needsSyncData()) { + synchronizeData(); + } + + setNodeValue(this.data + data); + + } // appendData(String) + + /** + * Remove a range of characters from the node's value. Throws a + * DOMException if the offset is beyond the end of the + * string. However, a deletion _count_ that exceeds the available + * data is accepted as a delete-to-end request. + * + * @throws DOMException(INDEX_SIZE_ERR) if offset is negative or + * greater than length, or if count is negative. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is + * readonly. + */ + public void deleteData(int offset, int count) + throws DOMException { + + internalDeleteData(offset, count, false); + } // deleteData(int,int) + + + /** NON-DOM INTERNAL: Within DOM actions, we sometimes need to be able + * to control which mutation events are spawned. This version of the + * deleteData operation allows us to do so. It is not intended + * for use by application programs. + */ + void internalDeleteData (int offset, int count, boolean replace) + throws DOMException { + + CoreDocumentImpl ownerDocument = ownerDocument(); + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + if (count < 0) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null); + throw new DOMException(DOMException.INDEX_SIZE_ERR, msg); + } + } + + if (needsSyncData()) { + synchronizeData(); + } + int tailLength = Math.max(data.length() - count - offset, 0); + try { + String value = data.substring(0, offset) + + (tailLength > 0 ? data.substring(offset + count, offset + count + tailLength) : ""); + + setNodeValueInternal(value, replace); + + // notify document + ownerDocument.deletedText(this, offset, count); + } + catch (StringIndexOutOfBoundsException e) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null); + throw new DOMException(DOMException.INDEX_SIZE_ERR, msg); + } + + } // internalDeleteData(int,int,boolean) + + /** + * Insert additional characters into the data stored in this node, + * at the offset specified. + * + * @throws DOMException(INDEX_SIZE_ERR) if offset is negative or + * greater than length. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly. + */ + public void insertData(int offset, String data) + throws DOMException { + + internalInsertData(offset, data, false); + + } // insertData(int,int) + + + + /** NON-DOM INTERNAL: Within DOM actions, we sometimes need to be able + * to control which mutation events are spawned. This version of the + * insertData operation allows us to do so. It is not intended + * for use by application programs. + */ + void internalInsertData (int offset, String data, boolean replace) + throws DOMException { + + CoreDocumentImpl ownerDocument = ownerDocument(); + + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + if (needsSyncData()) { + synchronizeData(); + } + try { + String value = + new StringBuffer(this.data).insert(offset, data).toString(); + + + setNodeValueInternal(value, replace); + + // notify document + ownerDocument.insertedText(this, offset, data.length()); + } + catch (StringIndexOutOfBoundsException e) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null); + throw new DOMException(DOMException.INDEX_SIZE_ERR, msg); + } + + } // internalInsertData(int,String,boolean) + + + + /** + * Replace a series of characters at the specified (zero-based) + * offset with a new string, NOT necessarily of the same + * length. Convenience method, equivalent to a delete followed by an + * insert. Throws a DOMException if the specified offset is beyond + * the end of the existing data. + * + * @param offset The offset at which to begin replacing. + * + * @param count The number of characters to remove, + * interpreted as in the delete() method. + * + * @param data The new string to be inserted at offset in place of + * the removed data. Note that the entire string will + * be inserted -- the count parameter does not affect + * insertion, and the new data may be longer or shorter + * than the substring it replaces. + * + * @throws DOMException(INDEX_SIZE_ERR) if offset is negative or + * greater than length, or if count is negative. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is + * readonly. + */ + public void replaceData(int offset, int count, String data) + throws DOMException { + + CoreDocumentImpl ownerDocument = ownerDocument(); + + // The read-only check is done by deleteData() + // ***** This could be more efficient w/r/t Mutation Events, + // specifically by aggregating DOMAttrModified and + // DOMSubtreeModified. But mutation events are + // underspecified; I don't feel compelled + // to deal with it right now. + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + if (needsSyncData()) { + synchronizeData(); + } + + //notify document + ownerDocument.replacingData(this); + + // keep old value for document notification + String oldvalue = this.data; + + internalDeleteData(offset, count, true); + internalInsertData(offset, data, true); + + ownerDocument.replacedCharacterData(this, oldvalue, this.data); + + } // replaceData(int,int,String) + + /** + * Store character data into this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly. + */ + public void setData(String value) + throws DOMException { + setNodeValue(value); + } + + /** + * Substring is more than a convenience function. In some + * implementations of the DOM, where the stored data may exceed the + * length that can be returned in a single string, the only way to + * read it all is to extract it in chunks via this method. + * + * @param offset Zero-based offset of first character to retrieve. + * @param count Number of characters to retrieve. + * + * If the sum of offset and count exceeds the length, all characters + * to end of data are returned. + * + * @throws DOMException(INDEX_SIZE_ERR) if offset is negative or + * greater than length, or if count is negative. + * + * @throws DOMException(WSTRING_SIZE_ERR) In some implementations, + * count may exceed the permitted length of strings. If so, + * substring() will throw this DOMException advising the user to + * instead retrieve the data in smaller chunks. + */ + public String substringData(int offset, int count) + throws DOMException { + + if (needsSyncData()) { + synchronizeData(); + } + + int length = data.length(); + if (count < 0 || offset < 0 || offset > length - 1) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null); + throw new DOMException(DOMException.INDEX_SIZE_ERR, msg); + } + + int tailIndex = Math.min(offset + count, length); + + return data.substring(offset, tailIndex); + + } // substringData(int,int):String + +} // class CharacterDataImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ChildNode.java b/resources/xerces2-j-src/org/apache/xerces/dom/ChildNode.java new file mode 100644 index 0000000..c9ba429 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ChildNode.java @@ -0,0 +1,146 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.Node; + +/** + * ChildNode inherits from NodeImpl and adds the capability of being a child by + * having references to its previous and next siblings. + * + * @xerces.internal + * + * @version $Id$ + */ +public abstract class ChildNode + extends NodeImpl { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -6112455738802414002L; + + // + // Data + // + + /** Previous sibling. */ + protected ChildNode previousSibling; + + /** Next sibling. */ + protected ChildNode nextSibling; + + // + // Constructors + // + + /** + * No public constructor; only subclasses of Node should be + * instantiated, and those normally via a Document's factory methods + *

+ * Every Node knows what Document it belongs to. + */ + protected ChildNode(CoreDocumentImpl ownerDocument) { + super(ownerDocument); + } // (CoreDocumentImpl) + + /** Constructor for serialization. */ + public ChildNode() {} + + // + // Node methods + // + + /** + * Returns a duplicate of a given node. You can consider this a + * generic "copy constructor" for nodes. The newly returned object should + * be completely independent of the source object's subtree, so changes + * in one after the clone has been made will not affect the other. + *

+ * Note: since we never have any children deep is meaningless here, + * ParentNode overrides this behavior. + * @see ParentNode + * + *

+ * Example: Cloning a Text node will copy both the node and the text it + * contains. + *

+ * Example: Cloning something that has children -- Element or Attr, for + * example -- will _not_ clone those children unless a "deep clone" + * has been requested. A shallow clone of an Attr node will yield an + * empty Attr of the same name. + *

+ * NOTE: Clones will always be read/write, even if the node being cloned + * is read-only, to permit applications using only the DOM API to obtain + * editable copies of locked portions of the tree. + */ + public Node cloneNode(boolean deep) { + + ChildNode newnode = (ChildNode) super.cloneNode(deep); + + // Need to break the association w/ original kids + newnode.previousSibling = null; + newnode.nextSibling = null; + newnode.isFirstChild(false); + + return newnode; + + } // cloneNode(boolean):Node + + /** + * Returns the parent node of this node + */ + public Node getParentNode() { + // if we have an owner, ownerNode is our parent, otherwise it's + // our ownerDocument and we don't have a parent + return isOwned() ? ownerNode : null; + } + + /* + * same as above but returns internal type + */ + final NodeImpl parentNode() { + // if we have an owner, ownerNode is our parent, otherwise it's + // our ownerDocument and we don't have a parent + return isOwned() ? ownerNode : null; + } + + /** The next child of this node's parent, or null if none */ + public Node getNextSibling() { + return nextSibling; + } + + /** The previous child of this node's parent, or null if none */ + public Node getPreviousSibling() { + // if we are the firstChild, previousSibling actually refers to our + // parent's lastChild, but we hide that + return isFirstChild() ? null : previousSibling; + } + + /* + * same as above but returns internal type + */ + final ChildNode previousSibling() { + // if we are the firstChild, previousSibling actually refers to our + // parent's lastChild, but we hide that + return isFirstChild() ? null : previousSibling; + } + +} // class ChildNode diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/CommentImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/CommentImpl.java new file mode 100644 index 0000000..6bb0d59 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/CommentImpl.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.Comment; +import org.w3c.dom.Node; + +/** + * Represents an XML (or HTML) comment. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class CommentImpl + extends CharacterDataImpl + implements CharacterData, Comment { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -2685736833408134044L; + + // + // Constructors + // + + /** Factory constructor. */ + public CommentImpl(CoreDocumentImpl ownerDoc, String data) { + super(ownerDoc, data); + } + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.COMMENT_NODE; + } + + /** Returns the node name. */ + public String getNodeName() { + return "#comment"; + } + +} // class CommentImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/CoreDOMImplementationImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/CoreDOMImplementationImpl.java new file mode 100644 index 0000000..041db5b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/CoreDOMImplementationImpl.java @@ -0,0 +1,712 @@ +/* + * 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. + */ +package org.apache.xerces.dom; + +import java.lang.ref.SoftReference; + +import org.apache.xerces.impl.RevalidationHandler; +import org.apache.xerces.impl.dtd.XMLDTDLoader; +import org.apache.xerces.parsers.DOMParserImpl; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xml.serialize.DOMSerializerImpl; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSSerializer; + +/** + * The DOMImplementation class is description of a particular + * implementation of the Document Object Model. As such its data is + * static, shared by all instances of this implementation. + *

+ * The DOM API requires that it be a real object rather than static + * methods. However, there's nothing that says it can't be a singleton, + * so that's how I've implemented it. + *

+ * This particular class, along with CoreDocumentImpl, supports the DOM + * Core and Load/Save (Experimental). Optional modules are supported by + * the more complete DOMImplementation class along with DocumentImpl. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class CoreDOMImplementationImpl + implements DOMImplementation, DOMImplementationLS { + + // + // Data + // + + // validator pools + private static final int SIZE = 2; + + private SoftReference schemaValidators[] = new SoftReference[SIZE]; + private SoftReference xml10DTDValidators[] = new SoftReference[SIZE]; + private SoftReference xml11DTDValidators[] = new SoftReference[SIZE]; + + private int freeSchemaValidatorIndex = -1; + private int freeXML10DTDValidatorIndex = -1; + private int freeXML11DTDValidatorIndex = -1; + + private int schemaValidatorsCurrentSize = SIZE; + private int xml10DTDValidatorsCurrentSize = SIZE; + private int xml11DTDValidatorsCurrentSize = SIZE; + + private SoftReference xml10DTDLoaders[] = new SoftReference[SIZE]; + private SoftReference xml11DTDLoaders[] = new SoftReference[SIZE]; + + private int freeXML10DTDLoaderIndex = -1; + private int freeXML11DTDLoaderIndex = -1; + + private int xml10DTDLoaderCurrentSize = SIZE; + private int xml11DTDLoaderCurrentSize = SIZE; + + // Document and doctype counter. Used to assign order to documents and + // doctypes without owners, on an demand basis. Used for + // compareDocumentPosition + private int docAndDoctypeCounter = 0; + + // static + /** Dom implementation singleton. */ + static final CoreDOMImplementationImpl singleton = new CoreDOMImplementationImpl(); + + // + // Public methods + // + /** NON-DOM: Obtain and return the single shared object */ + public static DOMImplementation getDOMImplementation() { + return singleton; + } + // + // DOMImplementation methods + // + /** + * Test if the DOM implementation supports a specific "feature" -- + * currently meaning language and level thereof. + * + * @param feature The package name of the feature to test. + * In Level 1, supported values are "HTML" and "XML" (case-insensitive). + * At this writing, org.apache.xerces.dom supports only XML. + * + * @param version The version number of the feature being tested. + * This is interpreted as "Version of the DOM API supported for the + * specified Feature", and in Level 1 should be "1.0" + * + * @return true iff this implementation is compatible with the specified + * feature and version. + */ + public boolean hasFeature(String feature, String version) { + + boolean anyVersion = version == null || version.length() == 0; + + // check if Xalan implementation is around and if yes report true for supporting + // XPath API + // if a plus sign "+" is prepended to any feature name, implementations + // are considered in which the specified feature may not be directly + // castable DOMImplementation.getFeature(feature, version). Without a + // plus, only features whose interfaces are directly castable are considered. + if ((feature.equalsIgnoreCase("+XPath")) + && (anyVersion || version.equals("3.0"))) { + try { + Class xpathClass = ObjectFactory.findProviderClass( + "org.apache.xpath.domapi.XPathEvaluatorImpl", + ObjectFactory.findClassLoader(), true); + + // Check if the DOM XPath implementation implements + // the interface org.w3c.dom.XPathEvaluator + Class interfaces[] = xpathClass.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + if (interfaces[i].getName().equals( + "org.w3c.dom.xpath.XPathEvaluator")) { + return true; + } + } + } catch (Exception e) { + return false; + } + return true; + } + if (feature.startsWith("+")) { + feature = feature.substring(1); + } + return ( + feature.equalsIgnoreCase("Core") + && (anyVersion + || version.equals("1.0") + || version.equals("2.0") + || version.equals("3.0"))) + || (feature.equalsIgnoreCase("XML") + && (anyVersion + || version.equals("1.0") + || version.equals("2.0") + || version.equals("3.0"))) + || (feature.equalsIgnoreCase("XMLVersion") + && (anyVersion + || version.equals("1.0") + || version.equals("1.1"))) + || (feature.equalsIgnoreCase("LS") + && (anyVersion + || version.equals("3.0"))) + || (feature.equalsIgnoreCase("ElementTraversal") + && (anyVersion + || version.equals("1.0"))); + } // hasFeature(String,String):boolean + + + /** + * Introduced in DOM Level 2.

+ * + * Creates an empty DocumentType node. + * + * @param qualifiedName The qualified name of the document type to be created. + * @param publicID The document type public identifier. + * @param systemID The document type system identifier. + * @since WD-DOM-Level-2-19990923 + */ + public DocumentType createDocumentType( String qualifiedName, + String publicID, String systemID) { + // REVISIT: this might allow creation of invalid name for DOCTYPE + // xmlns prefix. + // also there is no way for a user to turn off error checking. + checkQName(qualifiedName); + return new DocumentTypeImpl(null, qualifiedName, publicID, systemID); + } + + final void checkQName(String qname){ + int index = qname.indexOf(':'); + int lastIndex = qname.lastIndexOf(':'); + int length = qname.length(); + + // it is an error for NCName to have more than one ':' + // check if it is valid QName [Namespace in XML production 6] + if (index == 0 || index == length - 1 || lastIndex != index) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + int start = 0; + // Namespace in XML production [6] + if (index > 0) { + // check that prefix is NCName + if (!XMLChar.isNCNameStart(qname.charAt(start))) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "INVALID_CHARACTER_ERR", + null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + for (int i = 1; i < index; i++) { + if (!XMLChar.isNCName(qname.charAt(i))) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "INVALID_CHARACTER_ERR", + null); + throw new DOMException( + DOMException.INVALID_CHARACTER_ERR, + msg); + } + } + start = index + 1; + } + + // check local part + if (!XMLChar.isNCNameStart(qname.charAt(start))) { + // REVISIT: add qname parameter to the message + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "INVALID_CHARACTER_ERR", + null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + for (int i = start + 1; i < length; i++) { + if (!XMLChar.isNCName(qname.charAt(i))) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "INVALID_CHARACTER_ERR", + null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + } + } + + + /** + * Introduced in DOM Level 2.

+ * + * Creates an XML Document object of the specified type with its document + * element. + * + * @param namespaceURI The namespace URI of the document + * element to create, or null. + * @param qualifiedName The qualified name of the document + * element to create. + * @param doctype The type of document to be created or null.

+ * + * When doctype is not null, its + * Node.ownerDocument attribute is set to + * the document being created. + * @return Document A new Document object. + * @throws DOMException WRONG_DOCUMENT_ERR: Raised if doctype has + * already been used with a different document. + * @since WD-DOM-Level-2-19990923 + */ + public Document createDocument( + String namespaceURI, + String qualifiedName, + DocumentType doctype) + throws DOMException { + if (doctype != null && doctype.getOwnerDocument() != null) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "WRONG_DOCUMENT_ERR", + null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + CoreDocumentImpl doc = createDocument(doctype); + // If namespaceURI and qualifiedName are null return a Document with no document element. + if (qualifiedName != null || namespaceURI != null) { + Element e = doc.createElementNS(namespaceURI, qualifiedName); + doc.appendChild(e); + } + return doc; + } + + protected CoreDocumentImpl createDocument(DocumentType doctype) { + return new CoreDocumentImpl(doctype); + } + + /** + * DOM Level 3 WD - Experimental. + */ + public Object getFeature(String feature, String version) { + if (singleton.hasFeature(feature, version)) { + if ((feature.equalsIgnoreCase("+XPath"))) { + try { + Class xpathClass = ObjectFactory.findProviderClass( + "org.apache.xpath.domapi.XPathEvaluatorImpl", + ObjectFactory.findClassLoader(), true); + + // Check if the DOM XPath implementation implements + // the interface org.w3c.dom.XPathEvaluator + Class interfaces[] = xpathClass.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + if (interfaces[i].getName().equals( + "org.w3c.dom.xpath.XPathEvaluator")) { + return xpathClass.newInstance(); + } + } + } catch (Exception e) { + return null; + } + } else { + return singleton; + } + } + return null; + } + + // DOM L3 LS + + /** + * DOM Level 3 LS CR - Experimental. + * Create a new LSParser. The newly constructed parser may + * then be configured by means of its DOMConfiguration + * object, and used to parse documents by means of its parse + * method. + * @param mode The mode argument is either + * MODE_SYNCHRONOUS or MODE_ASYNCHRONOUS, if + * mode is MODE_SYNCHRONOUS then the + * LSParser that is created will operate in synchronous + * mode, if it's MODE_ASYNCHRONOUS then the + * LSParser that is created will operate in asynchronous + * mode. + * @param schemaType An absolute URI representing the type of the schema + * language used during the load of a Document using the + * newly created LSParser. Note that no lexical checking + * is done on the absolute URI. In order to create a + * LSParser for any kind of schema types (i.e. the + * LSParser will be free to use any schema found), use the value + * null. + *

Note: For W3C XML Schema [XML Schema Part 1] + * , applications must use the value + * "http://www.w3.org/2001/XMLSchema". For XML DTD [XML 1.0], + * applications must use the value + * "http://www.w3.org/TR/REC-xml". Other Schema languages + * are outside the scope of the W3C and therefore should recommend an + * absolute URI in order to use this method. + * @return The newly created LSParser object. This + * LSParser is either synchronous or asynchronous + * depending on the value of the mode argument. + *

Note: By default, the newly created LSParser + * does not contain a DOMErrorHandler, i.e. the value of + * the " + * error-handler" configuration parameter is null. However, implementations + * may provide a default error handler at creation time. In that case, + * the initial value of the "error-handler" configuration + * parameter on the new created LSParser contains a + * reference to the default error handler. + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised if the requested mode or schema type is + * not supported. + */ + public LSParser createLSParser(short mode, String schemaType) + throws DOMException { + if (mode != DOMImplementationLS.MODE_SYNCHRONOUS || (schemaType !=null && + !"http://www.w3.org/2001/XMLSchema".equals(schemaType) && + !"http://www.w3.org/TR/REC-xml".equals(schemaType))) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NOT_SUPPORTED_ERR", + null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + if (schemaType != null + && schemaType.equals("http://www.w3.org/TR/REC-xml")) { + return new DOMParserImpl( + "org.apache.xerces.parsers.XML11DTDConfiguration", + schemaType); + } + else { + // create default parser configuration validating against XMLSchemas + return new DOMParserImpl( + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration", + schemaType); + } + } + + /** + * DOM Level 3 LS CR - Experimental. + * Create a new LSSerializer object. + * @return The newly created LSSerializer object. + *

Note: By default, the newly created + * LSSerializer has no DOMErrorHandler, + * i.e. the value of the "error-handler" configuration + * parameter is null. However, implementations may + * provide a default error handler at creation time. In that case, the + * initial value of the "error-handler" configuration + * parameter on the new created LSSerializer contains a + * reference to the default error handler. + */ + public LSSerializer createLSSerializer() { + try { + Class serializerClass = ObjectFactory.findProviderClass( + "org.apache.xml.serializer.dom3.LSSerializerImpl", + ObjectFactory.findClassLoader(), true); + return (LSSerializer) serializerClass.newInstance(); + } + catch (Exception e) {} + // Fall back to Xerces' deprecated serializer if + // the Xalan based serializer is unavailable. + return new DOMSerializerImpl(); + } + + /** + * DOM Level 3 LS CR - Experimental. + * Create a new empty input source. + * @return The newly created input object. + */ + public LSInput createLSInput() { + return new DOMInputImpl(); + } + + // + // Protected methods + // + /** NON-DOM: retrieve validator. */ + synchronized RevalidationHandler getValidator(String schemaType, String xmlVersion) { + if (schemaType == XMLGrammarDescription.XML_SCHEMA) { + // create new validator - we should not attempt + // to restrict the number of validation handlers being + // requested + while (freeSchemaValidatorIndex >= 0) { + // return first available validator + SoftReference ref = schemaValidators[freeSchemaValidatorIndex]; + RevalidationHandlerHolder holder = (RevalidationHandlerHolder) ref.get(); + if (holder != null && holder.handler != null) { + RevalidationHandler val = holder.handler; + holder.handler = null; + --freeSchemaValidatorIndex; + return val; + } + schemaValidators[freeSchemaValidatorIndex--] = null; + } + return (RevalidationHandler) (ObjectFactory + .newInstance( + "org.apache.xerces.impl.xs.XMLSchemaValidator", + ObjectFactory.findClassLoader(), + true)); + } + else if(schemaType == XMLGrammarDescription.XML_DTD) { + // return an instance of XML11DTDValidator + if ("1.1".equals(xmlVersion)) { + while (freeXML11DTDValidatorIndex >= 0) { + // return first available validator + SoftReference ref = xml11DTDValidators[freeXML11DTDValidatorIndex]; + RevalidationHandlerHolder holder = (RevalidationHandlerHolder) ref.get(); + if (holder != null && holder.handler != null) { + RevalidationHandler val = holder.handler; + holder.handler = null; + --freeXML11DTDValidatorIndex; + return val; + } + xml11DTDValidators[freeXML11DTDValidatorIndex--] = null; + } + return (RevalidationHandler) (ObjectFactory + .newInstance( + "org.apache.xerces.impl.dtd.XML11DTDValidator", + ObjectFactory.findClassLoader(), + true)); + } + // return an instance of XMLDTDValidator + else { + while (freeXML10DTDValidatorIndex >= 0) { + // return first available validator + SoftReference ref = xml10DTDValidators[freeXML10DTDValidatorIndex]; + RevalidationHandlerHolder holder = (RevalidationHandlerHolder) ref.get(); + if (holder != null && holder.handler != null) { + RevalidationHandler val = holder.handler; + holder.handler = null; + --freeXML10DTDValidatorIndex; + return val; + } + xml10DTDValidators[freeXML10DTDValidatorIndex--] = null; + } + return (RevalidationHandler) (ObjectFactory + .newInstance( + "org.apache.xerces.impl.dtd.XMLDTDValidator", + ObjectFactory.findClassLoader(), + true)); + } + } + return null; + } + + /** NON-DOM: release validator */ + synchronized void releaseValidator(String schemaType, String xmlVersion, + RevalidationHandler validator) { + if (schemaType == XMLGrammarDescription.XML_SCHEMA) { + ++freeSchemaValidatorIndex; + if (schemaValidators.length == freeSchemaValidatorIndex) { + // resize size of the validators + schemaValidatorsCurrentSize += SIZE; + SoftReference newarray[] = new SoftReference[schemaValidatorsCurrentSize]; + System.arraycopy(schemaValidators, 0, newarray, 0, schemaValidators.length); + schemaValidators = newarray; + } + SoftReference ref = schemaValidators[freeSchemaValidatorIndex]; + if (ref != null) { + RevalidationHandlerHolder holder = (RevalidationHandlerHolder) ref.get(); + if (holder != null) { + holder.handler = validator; + return; + } + } + schemaValidators[freeSchemaValidatorIndex] = new SoftReference(new RevalidationHandlerHolder(validator)); + } + else if (schemaType == XMLGrammarDescription.XML_DTD) { + // release an instance of XML11DTDValidator + if ("1.1".equals(xmlVersion)) { + ++freeXML11DTDValidatorIndex; + if (xml11DTDValidators.length == freeXML11DTDValidatorIndex) { + // resize size of the validators + xml11DTDValidatorsCurrentSize += SIZE; + SoftReference [] newarray = new SoftReference[xml11DTDValidatorsCurrentSize]; + System.arraycopy(xml11DTDValidators, 0, newarray, 0, xml11DTDValidators.length); + xml11DTDValidators = newarray; + } + SoftReference ref = xml11DTDValidators[freeXML11DTDValidatorIndex]; + if (ref != null) { + RevalidationHandlerHolder holder = (RevalidationHandlerHolder) ref.get(); + if (holder != null) { + holder.handler = validator; + return; + } + } + xml11DTDValidators[freeXML11DTDValidatorIndex] = new SoftReference(new RevalidationHandlerHolder(validator)); + } + // release an instance of XMLDTDValidator + else { + ++freeXML10DTDValidatorIndex; + if (xml10DTDValidators.length == freeXML10DTDValidatorIndex) { + // resize size of the validators + xml10DTDValidatorsCurrentSize += SIZE; + SoftReference [] newarray = new SoftReference[xml10DTDValidatorsCurrentSize]; + System.arraycopy(xml10DTDValidators, 0, newarray, 0, xml10DTDValidators.length); + xml10DTDValidators = newarray; + } + SoftReference ref = xml10DTDValidators[freeXML10DTDValidatorIndex]; + if (ref != null) { + RevalidationHandlerHolder holder = (RevalidationHandlerHolder) ref.get(); + if (holder != null) { + holder.handler = validator; + return; + } + } + xml10DTDValidators[freeXML10DTDValidatorIndex] = new SoftReference(new RevalidationHandlerHolder(validator)); + } + } + } + + /** NON-DOM: retrieve DTD loader */ + synchronized final XMLDTDLoader getDTDLoader(String xmlVersion) { + // return an instance of XML11DTDProcessor + if ("1.1".equals(xmlVersion)) { + while (freeXML11DTDLoaderIndex >= 0) { + // return first available DTD loader + SoftReference ref = xml11DTDLoaders[freeXML11DTDLoaderIndex]; + XMLDTDLoaderHolder holder = (XMLDTDLoaderHolder) ref.get(); + if (holder != null && holder.loader != null) { + XMLDTDLoader val = holder.loader; + holder.loader = null; + --freeXML11DTDLoaderIndex; + return val; + } + xml11DTDLoaders[freeXML11DTDLoaderIndex--] = null; + } + return (XMLDTDLoader) (ObjectFactory + .newInstance( + "org.apache.xerces.impl.dtd.XML11DTDProcessor", + ObjectFactory.findClassLoader(), + true)); + } + // return an instance of XMLDTDLoader + else { + while (freeXML10DTDLoaderIndex >= 0) { + // return first available DTD loader + SoftReference ref = xml10DTDLoaders[freeXML10DTDLoaderIndex]; + XMLDTDLoaderHolder holder = (XMLDTDLoaderHolder) ref.get(); + if (holder != null && holder.loader != null) { + XMLDTDLoader val = holder.loader; + holder.loader = null; + --freeXML10DTDLoaderIndex; + return val; + } + xml10DTDLoaders[freeXML10DTDLoaderIndex--] = null; + } + return new XMLDTDLoader(); + } + } + + /** NON-DOM: release DTD loader */ + synchronized final void releaseDTDLoader(String xmlVersion, XMLDTDLoader loader) { + // release an instance of XMLDTDLoader + if ("1.1".equals(xmlVersion)) { + ++freeXML11DTDLoaderIndex; + if (xml11DTDLoaders.length == freeXML11DTDLoaderIndex) { + // resize size of the DTD loaders + xml11DTDLoaderCurrentSize += SIZE; + SoftReference [] newarray = new SoftReference[xml11DTDLoaderCurrentSize]; + System.arraycopy(xml11DTDLoaders, 0, newarray, 0, xml11DTDLoaders.length); + xml11DTDLoaders = newarray; + } + SoftReference ref = xml11DTDLoaders[freeXML11DTDLoaderIndex]; + if (ref != null) { + XMLDTDLoaderHolder holder = (XMLDTDLoaderHolder) ref.get(); + if (holder != null) { + holder.loader = loader; + return; + } + } + xml11DTDLoaders[freeXML11DTDLoaderIndex] = new SoftReference(new XMLDTDLoaderHolder(loader)); + } + // release an instance of XMLDTDLoader + else { + ++freeXML10DTDLoaderIndex; + if (xml10DTDLoaders.length == freeXML10DTDLoaderIndex) { + // resize size of the DTD loaders + xml10DTDLoaderCurrentSize += SIZE; + SoftReference [] newarray = new SoftReference[xml10DTDLoaderCurrentSize]; + System.arraycopy(xml10DTDLoaders, 0, newarray, 0, xml10DTDLoaders.length); + xml10DTDLoaders = newarray; + } + SoftReference ref = xml10DTDLoaders[freeXML10DTDLoaderIndex]; + if (ref != null) { + XMLDTDLoaderHolder holder = (XMLDTDLoaderHolder) ref.get(); + if (holder != null) { + holder.loader = loader; + return; + } + } + xml10DTDLoaders[freeXML10DTDLoaderIndex] = new SoftReference(new XMLDTDLoaderHolder(loader)); + } + } + + /** NON-DOM: increment document/doctype counter */ + protected synchronized int assignDocumentNumber() { + return ++docAndDoctypeCounter; + } + + /** NON-DOM: increment document/doctype counter */ + protected synchronized int assignDocTypeNumber() { + return ++docAndDoctypeCounter; + } + + /** + * DOM Level 3 LS CR - Experimental. + * + * Create a new empty output destination object where + * LSOutput.characterStream, + * LSOutput.byteStream, LSOutput.systemId, + * LSOutput.encoding are null. + * @return The newly created output object. + */ + public LSOutput createLSOutput() { + return new DOMOutputImpl(); + } + + /** + * A holder for RevalidationHandlers. This allows us to reuse + * SoftReferences which haven't yet been cleared by the garbage + * collector. + */ + static final class RevalidationHandlerHolder { + RevalidationHandlerHolder(RevalidationHandler handler) { + this.handler = handler; + } + RevalidationHandler handler; + } + + /** + * A holder for XMLDTDLoaders. This allows us to reuse SoftReferences + * which haven't yet been cleared by the garbage collector. + */ + static final class XMLDTDLoaderHolder { + XMLDTDLoaderHolder(XMLDTDLoader loader) { + this.loader = loader; + } + XMLDTDLoader loader; + } + +} // class DOMImplementationImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/CoreDocumentImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/CoreDocumentImpl.java new file mode 100644 index 0000000..0646520 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/CoreDocumentImpl.java @@ -0,0 +1,2815 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Constructor; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + +import org.apache.xerces.util.URI; +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.NamespaceContext; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Notation; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSSerializer; + +/** + * The Document interface represents the entire HTML or XML document. + * Conceptually, it is the root of the document tree, and provides the + * primary access to the document's data. + *

+ * Since elements, text nodes, comments, processing instructions, + * etc. cannot exist outside the context of a Document, the Document + * interface also contains the factory methods needed to create these + * objects. The Node objects created have a ownerDocument attribute + * which associates them with the Document within whose context they + * were created. + *

+ * The CoreDocumentImpl class only implements the DOM Core. Additional modules + * are supported by the more complete DocumentImpl subclass. + *

+ * Note: When any node in the document is serialized, the + * entire document is serialized along with it. + * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Joe Kesselman, IBM + * @author Andy Clark, IBM + * @author Ralf Pfeiffer, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ + + +public class CoreDocumentImpl +extends ParentNode implements Document { + + /**TODO:: + * 1. Change XML11Char method names similar to XMLChar. That will prevent lot + * of dirty version checking code. + * + * 2. IMO during cloneNode qname/isXMLName check should not be made. + */ + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 0; + + // + // Data + // + + // document information + + /** Document type. */ + protected DocumentTypeImpl docType; + + /** Document element. */ + protected ElementImpl docElement; + + /** NodeListCache free list */ + transient NodeListCache fFreeNLCache; + + /**Experimental DOM Level 3 feature: Document encoding */ + protected String encoding; + + /**Experimental DOM Level 3 feature: Document actualEncoding */ + protected String actualEncoding; + + /**Experimental DOM Level 3 feature: Document version */ + protected String version; + + /**Experimental DOM Level 3 feature: Document standalone */ + protected boolean standalone; + + /**Experimental DOM Level 3 feature: documentURI */ + protected String fDocumentURI; + + /** Table for user data attached to this document nodes. */ + protected Map userData; // serialized as Hashtable + + /** Identifiers. */ + protected Hashtable identifiers; + + // DOM Level 3: normalizeDocument + transient DOMNormalizer domNormalizer = null; + transient DOMConfigurationImpl fConfiguration = null; + + // support of XPath API + transient Object fXPathEvaluator = null; + + /** Table for quick check of child insertion. */ + private final static int[] kidOK; + + /** + * Number of alterations made to this document since its creation. + * Serves as a "dirty bit" so that live objects such as NodeList can + * recognize when an alteration has been made and discard its cached + * state information. + *

+ * Any method that alters the tree structure MUST cause or be + * accompanied by a call to changed(), to inform it that any outstanding + * NodeLists may have to be updated. + *

+ * (Required because NodeList is simultaneously "live" and integer- + * indexed -- a bad decision in the DOM's design.) + *

+ * Note that changes which do not affect the tree's structure -- changing + * the node's name, for example -- do _not_ have to call changed(). + *

+ * Alternative implementation would be to use a cryptographic + * Digest value rather than a count. This would have the advantage that + * "harmless" changes (those producing equal() trees) would not force + * NodeList to resynchronize. Disadvantage is that it's slightly more prone + * to "false negatives", though that's the difference between "wildly + * unlikely" and "absurdly unlikely". IF we start maintaining digests, + * we should consider taking advantage of them. + * + * Note: This used to be done a node basis, so that we knew what + * subtree changed. But since only DeepNodeList really use this today, + * the gain appears to be really small compared to the cost of having + * an int on every (parent) node plus having to walk up the tree all the + * way to the root to mark the branch as changed everytime a node is + * changed. + * So we now have a single counter global to the document. It means that + * some objects may flush their cache more often than necessary, but this + * makes nodes smaller and only the document needs to be marked as changed. + */ + protected int changes = 0; + + // experimental + + /** Allow grammar access. */ + protected boolean allowGrammarAccess; + + /** Bypass error checking. */ + protected boolean errorChecking = true; + + //Did version change at any point when the document was created ? + //this field helps us to optimize when normalizingDocument. + protected boolean xmlVersionChanged = false ; + + /** The following are required for compareDocumentPosition + */ + // Document number. Documents are ordered across the implementation using + // positive integer values. Documents are assigned numbers on demand. + private int documentNumber=0; + // Node counter and table. Used to assign numbers to nodes for this + // document. Node number values are negative integers. Nodes are + // assigned numbers on demand. + private int nodeCounter = 0; + private Map nodeTable; // serialized as Hashtable + private boolean xml11Version = false; //by default 1.0 + // + // Static initialization + // + + static { + + kidOK = new int[13]; + + kidOK[DOCUMENT_NODE] = + 1 << ELEMENT_NODE | 1 << PROCESSING_INSTRUCTION_NODE | + 1 << COMMENT_NODE | 1 << DOCUMENT_TYPE_NODE; + + kidOK[DOCUMENT_FRAGMENT_NODE] = + kidOK[ENTITY_NODE] = + kidOK[ENTITY_REFERENCE_NODE] = + kidOK[ELEMENT_NODE] = + 1 << ELEMENT_NODE | 1 << PROCESSING_INSTRUCTION_NODE | + 1 << COMMENT_NODE | 1 << TEXT_NODE | + 1 << CDATA_SECTION_NODE | 1 << ENTITY_REFERENCE_NODE ; + + + kidOK[ATTRIBUTE_NODE] = + 1 << TEXT_NODE | 1 << ENTITY_REFERENCE_NODE; + + kidOK[DOCUMENT_TYPE_NODE] = + kidOK[PROCESSING_INSTRUCTION_NODE] = + kidOK[COMMENT_NODE] = + kidOK[TEXT_NODE] = + kidOK[CDATA_SECTION_NODE] = + kidOK[NOTATION_NODE] = + 0; + + } // static + + // + // Constructors + // + + /** + * NON-DOM: Actually creating a Document is outside the DOM's spec, + * since it has to operate in terms of a particular implementation. + */ + public CoreDocumentImpl() { + this(false); + } + + /** Constructor. */ + public CoreDocumentImpl(boolean grammarAccess) { + super(null); + ownerDocument = this; + allowGrammarAccess = grammarAccess; + } + + /** + * For DOM2 support. + * The createDocument factory method is in DOMImplementation. + */ + public CoreDocumentImpl(DocumentType doctype) { + this(doctype, false); + } + + /** For DOM2 support. */ + public CoreDocumentImpl(DocumentType doctype, boolean grammarAccess) { + this(grammarAccess); + if (doctype != null) { + DocumentTypeImpl doctypeImpl; + try { + doctypeImpl = (DocumentTypeImpl) doctype; + } catch (ClassCastException e) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + doctypeImpl.ownerDocument = this; + appendChild(doctype); + } + } + + // + // Node methods + // + + // even though ownerDocument refers to this in this implementation + // the DOM Level 2 spec says it must be null, so make it appear so + final public Document getOwnerDocument() { + return null; + } + + /** Returns the node type. */ + public short getNodeType() { + return Node.DOCUMENT_NODE; + } + + /** Returns the node name. */ + public String getNodeName() { + return "#document"; + } + + /** + * Deep-clone a document, including fixing ownerDoc for the cloned + * children. Note that this requires bypassing the WRONG_DOCUMENT_ERR + * protection. I've chosen to implement it by calling importNode + * which is DOM Level 2. + * + * @return org.w3c.dom.Node + * @param deep boolean, iff true replicate children + */ + public Node cloneNode(boolean deep) { + + CoreDocumentImpl newdoc = new CoreDocumentImpl(); + callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED); + cloneNode(newdoc, deep); + + return newdoc; + + } // cloneNode(boolean):Node + + + /** + * internal method to share code with subclass + **/ + protected void cloneNode(CoreDocumentImpl newdoc, boolean deep) { + + // clone the children by importing them + if (needsSyncChildren()) { + synchronizeChildren(); + } + + if (deep) { + HashMap reversedIdentifiers = null; + if (identifiers != null) { + // Build a reverse mapping from element to identifier. + reversedIdentifiers = new HashMap(); + Iterator entries = identifiers.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + Object elementId = entry.getKey(); + Object elementNode = entry.getValue(); + reversedIdentifiers.put(elementNode, elementId); + } + } + + // Copy children into new document. + for (ChildNode kid = firstChild; kid != null; + kid = kid.nextSibling) { + newdoc.appendChild(newdoc.importNode(kid, true, true, + reversedIdentifiers)); + } + } + + // experimental + newdoc.allowGrammarAccess = allowGrammarAccess; + newdoc.errorChecking = errorChecking; + + } // cloneNode(CoreDocumentImpl,boolean):void + + /** + * Since a Document may contain at most one top-level Element child, + * and at most one DocumentType declaraction, we need to subclass our + * add-children methods to implement this constraint. + * Since appendChild() is implemented as insertBefore(,null), + * altering the latter fixes both. + *

+ * While I'm doing so, I've taken advantage of the opportunity to + * cache documentElement and docType so we don't have to + * search for them. + * + * REVISIT: According to the spec it is not allowed to alter neither the + * document element nor the document type in any way + */ + public Node insertBefore(Node newChild, Node refChild) + throws DOMException { + + // Only one such child permitted + int type = newChild.getNodeType(); + if (errorChecking) { + if (needsSyncChildren()) { + synchronizeChildren(); + } + if((type == Node.ELEMENT_NODE && docElement != null) || + (type == Node.DOCUMENT_TYPE_NODE && docType != null)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null); + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg); + } + } + // Adopt orphan doctypes + if (newChild.getOwnerDocument() == null && + newChild instanceof DocumentTypeImpl) { + ((DocumentTypeImpl) newChild).ownerDocument = this; + } + super.insertBefore(newChild,refChild); + + // If insert succeeded, cache the kid appropriately + if (type == Node.ELEMENT_NODE) { + docElement = (ElementImpl)newChild; + } + else if (type == Node.DOCUMENT_TYPE_NODE) { + docType = (DocumentTypeImpl)newChild; + } + + return newChild; + + } // insertBefore(Node,Node):Node + + /** + * Since insertBefore caches the docElement (and, currently, docType), + * removeChild has to know how to undo the cache + * + * REVISIT: According to the spec it is not allowed to alter neither the + * document element nor the document type in any way + */ + public Node removeChild(Node oldChild) throws DOMException { + + super.removeChild(oldChild); + + // If remove succeeded, un-cache the kid appropriately + int type = oldChild.getNodeType(); + if(type == Node.ELEMENT_NODE) { + docElement = null; + } + else if (type == Node.DOCUMENT_TYPE_NODE) { + docType = null; + } + + return oldChild; + + } // removeChild(Node):Node + + /** + * Since we cache the docElement (and, currently, docType), + * replaceChild has to update the cache + * + * REVISIT: According to the spec it is not allowed to alter neither the + * document element nor the document type in any way + */ + public Node replaceChild(Node newChild, Node oldChild) + throws DOMException { + + // Adopt orphan doctypes + if (newChild.getOwnerDocument() == null && + newChild instanceof DocumentTypeImpl) { + ((DocumentTypeImpl) newChild).ownerDocument = this; + } + + if (errorChecking &&((docType != null && + oldChild.getNodeType() != Node.DOCUMENT_TYPE_NODE && + newChild.getNodeType() == Node.DOCUMENT_TYPE_NODE) + || (docElement != null && + oldChild.getNodeType() != Node.ELEMENT_NODE && + newChild.getNodeType() == Node.ELEMENT_NODE))) { + + throw new DOMException( + DOMException.HIERARCHY_REQUEST_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + } + super.replaceChild(newChild, oldChild); + + int type = oldChild.getNodeType(); + if(type == Node.ELEMENT_NODE) { + docElement = (ElementImpl)newChild; + } + else if (type == Node.DOCUMENT_TYPE_NODE) { + docType = (DocumentTypeImpl)newChild; + } + return oldChild; + } // replaceChild(Node,Node):Node + + /* + * Get Node text content + * @since DOM Level 3 + */ + public String getTextContent() throws DOMException { + return null; + } + + /* + * Set Node text content + * @since DOM Level 3 + */ + public void setTextContent(String textContent) + throws DOMException { + // no-op + } + + /** + * @since DOM Level 3 + */ + public Object getFeature(String feature, String version) { + + boolean anyVersion = version == null || version.length() == 0; + + // if a plus sign "+" is prepended to any feature name, implementations + // are considered in which the specified feature may not be directly + // castable DOMImplementation.getFeature(feature, version). Without a + // plus, only features whose interfaces are directly castable are + // considered. + if ((feature.equalsIgnoreCase("+XPath")) + && (anyVersion || version.equals("3.0"))) { + + // If an XPathEvaluator was created previously + // return it otherwise create a new one. + if (fXPathEvaluator != null) { + return fXPathEvaluator; + } + + try { + Class xpathClass = ObjectFactory.findProviderClass( + "org.apache.xpath.domapi.XPathEvaluatorImpl", + ObjectFactory.findClassLoader(), true); + Constructor xpathClassConstr = + xpathClass.getConstructor(new Class[] { Document.class }); + + // Check if the DOM XPath implementation implements + // the interface org.w3c.dom.XPathEvaluator + Class interfaces[] = xpathClass.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + if (interfaces[i].getName().equals( + "org.w3c.dom.xpath.XPathEvaluator")) { + fXPathEvaluator = xpathClassConstr.newInstance(new Object[] { this }); + return fXPathEvaluator; + } + } + return null; + } catch (Exception e) { + return null; + } + } + return super.getFeature(feature, version); + } + + // + // Document methods + // + + // factory methods + + /** + * Factory method; creates an Attribute having this Document as its + * OwnerDoc. + * + * @param name The name of the attribute. Note that the attribute's value is + * _not_ established at the factory; remember to set it! + * + * @throws DOMException(INVALID_NAME_ERR) + * if the attribute name is not acceptable. + */ + public Attr createAttribute(String name) + throws DOMException { + + if (errorChecking && !isXMLName(name,xml11Version)) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "INVALID_CHARACTER_ERR", + null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + return new AttrImpl(this, name); + + } // createAttribute(String):Attr + + /** + * Factory method; creates a CDATASection having this Document as + * its OwnerDoc. + * + * @param data The initial contents of the CDATA + * + * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents. (HTML + * not yet implemented.) + */ + public CDATASection createCDATASection(String data) + throws DOMException { + return new CDATASectionImpl(this, data); + } + + /** + * Factory method; creates a Comment having this Document as its + * OwnerDoc. + * + * @param data The initial contents of the Comment. */ + public Comment createComment(String data) { + return new CommentImpl(this, data); + } + + /** + * Factory method; creates a DocumentFragment having this Document + * as its OwnerDoc. + */ + public DocumentFragment createDocumentFragment() { + return new DocumentFragmentImpl(this); + } + + /** + * Factory method; creates an Element having this Document + * as its OwnerDoc. + * + * @param tagName The name of the element type to instantiate. For + * XML, this is case-sensitive. For HTML, the tagName parameter may + * be provided in any case, but it must be mapped to the canonical + * uppercase form by the DOM implementation. + * + * @throws DOMException(INVALID_NAME_ERR) if the tag name is not + * acceptable. + */ + public Element createElement(String tagName) + throws DOMException { + + if (errorChecking && !isXMLName(tagName,xml11Version)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + return new ElementImpl(this, tagName); + + } // createElement(String):Element + + /** + * Factory method; creates an EntityReference having this Document + * as its OwnerDoc. + * + * @param name The name of the Entity we wish to refer to + * + * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where + * nonstandard entities are not permitted. (HTML not yet + * implemented.) + */ + public EntityReference createEntityReference(String name) + throws DOMException { + + if (errorChecking && !isXMLName(name,xml11Version)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + return new EntityReferenceImpl(this, name); + + } // createEntityReference(String):EntityReference + + /** + * Factory method; creates a ProcessingInstruction having this Document + * as its OwnerDoc. + * + * @param target The target "processor channel" + * @param data Parameter string to be passed to the target. + * + * @throws DOMException(INVALID_NAME_ERR) if the target name is not + * acceptable. + * + * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents. (HTML + * not yet implemented.) + */ + public ProcessingInstruction createProcessingInstruction(String target, + String data) + throws DOMException { + + if (errorChecking && !isXMLName(target,xml11Version)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + return new ProcessingInstructionImpl(this, target, data); + + } // createProcessingInstruction(String,String):ProcessingInstruction + + /** + * Factory method; creates a Text node having this Document as its + * OwnerDoc. + * + * @param data The initial contents of the Text. + */ + public Text createTextNode(String data) { + return new TextImpl(this, data); + } + + // other document methods + + /** + * For XML, this provides access to the Document Type Definition. + * For HTML documents, and XML documents which don't specify a DTD, + * it will be null. + */ + public DocumentType getDoctype() { + if (needsSyncChildren()) { + synchronizeChildren(); + } + return docType; + } + + + /** + * Convenience method, allowing direct access to the child node + * which is considered the root of the actual document content. For + * HTML, where it is legal to have more than one Element at the top + * level of the document, we pick the one with the tagName + * "HTML". For XML there should be only one top-level + * + * (HTML not yet supported.) + */ + public Element getDocumentElement() { + if (needsSyncChildren()) { + synchronizeChildren(); + } + return docElement; + } + + /** + * Return a live collection of all descendent Elements (not just + * immediate children) having the specified tag name. + * + * @param tagname The type of Element we want to gather. "*" will be + * taken as a wildcard, meaning "all elements in the document." + * + * @see DeepNodeListImpl + */ + public NodeList getElementsByTagName(String tagname) { + return new DeepNodeListImpl(this,tagname); + } + + /** + * Retrieve information describing the abilities of this particular + * DOM implementation. Intended to support applications that may be + * using DOMs retrieved from several different sources, potentially + * with different underlying representations. + */ + public DOMImplementation getImplementation() { + // Currently implemented as a singleton, since it's hardcoded + // information anyway. + return CoreDOMImplementationImpl.getDOMImplementation(); + } + + // + // Public methods + // + + // properties + + /** + * Sets whether the DOM implementation performs error checking + * upon operations. Turning off error checking only affects + * the following DOM checks: + *

    + *
  • Checking strings to make sure that all characters are + * legal XML characters + *
  • Hierarchy checking such as allowed children, checks for + * cycles, etc. + *
+ *

+ * Turning off error checking does not turn off the + * following checks: + *

    + *
  • Read only checks + *
  • Checks related to DOM events + *
+ */ + + public void setErrorChecking(boolean check) { + errorChecking = check; + } + + /* + * DOM Level 3 WD - Experimental. + */ + public void setStrictErrorChecking(boolean check) { + errorChecking = check; + } + + /** + * Returns true if the DOM implementation performs error checking. + */ + public boolean getErrorChecking() { + return errorChecking; + } + + /* + * DOM Level 3 WD - Experimental. + */ + public boolean getStrictErrorChecking() { + return errorChecking; + } + + + /** + * DOM Level 3 CR - Experimental. (Was getActualEncoding) + * + * 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 actualEncoding; + } + + /** + * DOM Internal + * (Was a DOM L3 Core WD public interface method setActualEncoding ) + * + * An attribute specifying the actual encoding of this document. This is + * null otherwise. + *
This attribute represents the property [character encoding scheme] + * defined in . + */ + public void setInputEncoding(String value) { + actualEncoding = value; + } + + /** + * DOM Internal + * (Was a DOM L3 Core WD public interface method setXMLEncoding ) + * + * An attribute specifying, as part of the XML declaration, + * the encoding of this document. This is null when unspecified. + */ + public void setXmlEncoding(String value) { + encoding = value; + } + + /** + * @deprecated This method is internal and only exists for + * compatibility with older applications. New applications + * should never call this method. + */ + public void setEncoding(String value) { + setXmlEncoding(value); + } + + /** + * DOM Level 3 WD - Experimental. + * The encoding of this document (part of XML Declaration) + */ + public String getXmlEncoding() { + return encoding; + } + + /** + * @deprecated This method is internal and only exists for + * compatibility with older applications. New applications + * should never call this method. + */ + public String getEncoding() { + return getXmlEncoding(); + } + + /** + * DOM Level 3 CR - Experimental. + * version - An attribute specifying, as part of the XML declaration, + * the version number of this document. + */ + public void setXmlVersion(String value) { + if(value.equals("1.0") || value.equals("1.1")){ + //we need to change the flag value only -- + // when the version set is different than already set. + if(!getXmlVersion().equals(value)){ + xmlVersionChanged = true ; + //change the normalization value back to false + isNormalized(false); + version = value; + } + } + else{ + //NOT_SUPPORTED_ERR: Raised if the vesion is set to a value that is not supported by + //this document + //we dont support any other XML version + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + + } + if((getXmlVersion()).equals("1.1")){ + xml11Version = true; + } + else{ + xml11Version = false; + } + } + + /** + * @deprecated This method is internal and only exists for + * compatibility with older applications. New applications + * should never call this method. + */ + public void setVersion(String value) { + setXmlVersion(value); + } + + /** + * DOM Level 3 WD - Experimental. + * The version of this document (part of XML Declaration) + */ + public String getXmlVersion() { + return (version == null)?"1.0":version; + } + + /** + * @deprecated This method is internal and only exists for + * compatibility with older applications. New applications + * should never call this method. + */ + public String getVersion() { + return getXmlVersion(); + } + + /** + * DOM Level 3 CR - Experimental. + * + * Xmlstandalone - An attribute specifying, as part of the XML declaration, + * whether this document is standalone + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised if this document does not support the + * "XML" feature. + * @since DOM Level 3 + */ + public void setXmlStandalone(boolean value) + throws DOMException { + standalone = value; + } + + /** + * @deprecated This method is internal and only exists for + * compatibility with older applications. New applications + * should never call this method. + */ + public void setStandalone(boolean value) { + setXmlStandalone(value); + } + + /** + * DOM Level 3 WD - Experimental. + * standalone that specifies whether this document is standalone + * (part of XML Declaration) + */ + public boolean getXmlStandalone() { + return standalone; + } + + /** + * @deprecated This method is internal and only exists for + * compatibility with older applications. New applications + * should never call this method. + */ + public boolean getStandalone() { + return getXmlStandalone(); + } + + /** + * DOM Level 3 WD - Experimental. + * The location of the document or null if undefined. + *
Beware that when the Document supports the feature + * "HTML" , the href attribute of the HTML BASE element takes precedence + * over this attribute. + * @since DOM Level 3 + */ + public String getDocumentURI(){ + return fDocumentURI; + } + + + /* NON-DOM + * Used by DOM Level 3 WD remameNode. + * + * Some DOM implementations do not allow nodes to be renamed and require + * creating new elements. + * In this case this method should be overwritten. + * + * @return true if the given element can be renamed, false, if it must be replaced. + */ + protected boolean canRenameElements(String newNamespaceURI, String newNodeName, ElementImpl el) { + return true; + } + + /** + * DOM Level 3 WD - Experimental. + * Renaming node + */ + public Node renameNode(Node n,String namespaceURI,String name) + throws DOMException{ + + if (errorChecking && n.getOwnerDocument() != this && n != this) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + switch (n.getNodeType()) { + case ELEMENT_NODE: { + ElementImpl el = (ElementImpl) n; + if (el instanceof ElementNSImpl) { + if (canRenameElements(namespaceURI, name, el)) { + ((ElementNSImpl) el).rename(namespaceURI, name); + // fire user data NODE_RENAMED event + callUserDataHandlers(el, null, UserDataHandler.NODE_RENAMED); + } + else { + el = replaceRenameElement(el, namespaceURI, name); + } + } + else { + if (namespaceURI == null && canRenameElements(null, name, el)) { + el.rename(name); + // fire user data NODE_RENAMED event + callUserDataHandlers(el, null, UserDataHandler.NODE_RENAMED); + } + else { + el = replaceRenameElement(el, namespaceURI, name); + } + } + // fire ElementNameChanged event + renamedElement((Element) n, el); + return el; + } + case ATTRIBUTE_NODE: { + AttrImpl at = (AttrImpl) n; + + // detach attr from element + Element el = at.getOwnerElement(); + if (el != null) { + el.removeAttributeNode(at); + } + if (n instanceof AttrNSImpl) { + ((AttrNSImpl) at).rename(namespaceURI, name); + // reattach attr to element + if (el != null) { + el.setAttributeNodeNS(at); + } + + // fire user data NODE_RENAMED event + callUserDataHandlers(at, null, UserDataHandler.NODE_RENAMED); + } + else { + if (namespaceURI == null) { + at.rename(name); + // reattach attr to element + if (el != null) { + el.setAttributeNode(at); + } + + // fire user data NODE_RENAMED event + callUserDataHandlers(at, null, UserDataHandler.NODE_RENAMED); + } + else { + // we need to create a new object + AttrNSImpl nat = (AttrNSImpl) createAttributeNS(namespaceURI, name); + + // register event listeners on new node + copyEventListeners(at, nat); + + // remove user data from old node + Hashtable data = removeUserDataTable(at); + + // move children to new node + Node child = at.getFirstChild(); + while (child != null) { + at.removeChild(child); + nat.appendChild(child); + child = at.getFirstChild(); + } + + // attach user data to new node + setUserDataTable(nat, data); + + // and fire user data NODE_RENAMED event + callUserDataHandlers(at, nat, UserDataHandler.NODE_RENAMED); + + // reattach attr to element + if (el != null) { + el.setAttributeNode(nat); + } + at = nat; + } + } + // fire AttributeNameChanged event + renamedAttrNode((Attr) n, at); + + return at; + } + default: { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + } + + } + + private ElementImpl replaceRenameElement(ElementImpl el, String namespaceURI, String name) { + + // we need to create a new object + ElementNSImpl nel = (ElementNSImpl)createElementNS(namespaceURI, name); + + // register event listeners on new node + copyEventListeners(el, nel); + + // remove user data from old node + Hashtable data = removeUserDataTable(el); + + // remove old node from parent if any + Node parent = el.getParentNode(); + Node nextSib = el.getNextSibling(); + if (parent != null) { + parent.removeChild(el); + } + // move children to new node + Node child = el.getFirstChild(); + while (child != null) { + el.removeChild(child); + nel.appendChild(child); + child = el.getFirstChild(); + } + // move specified attributes to new node + nel.moveSpecifiedAttributes(el); + + // attach user data to new node + setUserDataTable(nel, data); + + // and fire user data NODE_RENAMED event + callUserDataHandlers(el, nel, + UserDataHandler.NODE_RENAMED); + + // insert new node where old one was + if (parent != null) { + parent.insertBefore(nel, nextSib); + } + return nel; + } + + + /** + * DOM Level 3 WD - Experimental + * Normalize document. + */ + public void normalizeDocument(){ + // No need to normalize if already normalized. + if (isNormalized() && !isNormalizeDocRequired()) { + return; + } + if (needsSyncChildren()) { + synchronizeChildren(); + } + + if (domNormalizer == null) { + domNormalizer = new DOMNormalizer(); + } + + if (fConfiguration == null) { + fConfiguration = new DOMConfigurationImpl(); + } + else { + fConfiguration.reset(); + } + + domNormalizer.normalizeDocument(this, fConfiguration); + isNormalized(true); + //set the XMLversion changed value to false -- once we have finished + //doing normalization + xmlVersionChanged = false ; + } + + + /** + * DOM Level 3 CR - Experimental + * + * The configuration used when Document.normalizeDocument is + * invoked. + * @since DOM Level 3 + */ + public DOMConfiguration getDomConfig(){ + if (fConfiguration == null) { + fConfiguration = new DOMConfigurationImpl(); + } + return fConfiguration; + } + + + /** + * Returns the absolute base URI of this node or null if the implementation + * wasn't able to obtain an absolute URI. Note: If the URI is malformed, a + * null is returned. + * + * @return The absolute base URI of this node or null. + * @since DOM Level 3 + */ + public String getBaseURI() { + if (fDocumentURI != null && fDocumentURI.length() != 0 ) {// attribute value is always empty string + try { + return new URI(fDocumentURI).toString(); + } + catch (org.apache.xerces.util.URI.MalformedURIException e){ + // REVISIT: what should happen in this case? + return null; + } + } + return fDocumentURI; + } + + /** + * DOM Level 3 WD - Experimental. + */ + public void setDocumentURI(String documentURI){ + fDocumentURI = documentURI; + } + + + // + // DOM L3 LS + // + /** + * DOM Level 3 WD - Experimental. + * Indicates whether the method load should be synchronous or + * asynchronous. When the async attribute is set to true + * the load method returns control to the caller before the document has + * completed loading. The default value of this property is + * false. + *
Setting the value of this attribute might throw NOT_SUPPORTED_ERR + * if the implementation doesn't support the mode the attribute is being + * set to. Should the DOM spec define the default value of this + * property? What if implementing both async and sync IO is impractical + * in some systems? 2001-09-14. default is false but we + * need to check with Mozilla and IE. + */ + public boolean getAsync() { + return false; + } + + /** + * DOM Level 3 WD - Experimental. + * Indicates whether the method load should be synchronous or + * asynchronous. When the async attribute is set to true + * the load method returns control to the caller before the document has + * completed loading. The default value of this property is + * false. + *
Setting the value of this attribute might throw NOT_SUPPORTED_ERR + * if the implementation doesn't support the mode the attribute is being + * set to. Should the DOM spec define the default value of this + * property? What if implementing both async and sync IO is impractical + * in some systems? 2001-09-14. default is false but we + * need to check with Mozilla and IE. + */ + public void setAsync(boolean async) { + if (async) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + } + /** + * DOM Level 3 WD - Experimental. + * If the document is currently being loaded as a result of the method + * load being invoked the loading and parsing is + * immediately aborted. The possibly partial result of parsing the + * document is discarded and the document is cleared. + */ + public void abort() { + } + + /** + * DOM Level 3 WD - Experimental. + * + * Replaces the content of the document with the result of parsing the + * given URI. Invoking this method will either block the caller or + * return to the caller immediately depending on the value of the async + * attribute. Once the document is fully loaded a "load" event (as + * defined in [DOM Level 3 Events] + * , except that the Event.targetNode will be the document, + * not an element) will be dispatched on the document. If an error + * occurs, an implementation dependent "error" event will be dispatched + * on the document. If this method is called on a document that is + * currently loading, the current load is interrupted and the new URI + * load is initiated. + *
When invoking this method the parameters used in the + * DOMParser interface are assumed to have their default + * values with the exception that the parameters "entities" + * , "normalize-characters", + * "check-character-normalization" are set to + * "false". + *
The result of a call to this method is the same the result of a + * call to DOMParser.parseWithContext with an input stream + * referencing the URI that was passed to this call, the document as the + * context node, and the action ACTION_REPLACE_CHILDREN. + * @param uri The URI reference for the XML file to be loaded. If this is + * a relative URI, the base URI used by the implementation is + * implementation dependent. + * @return If async is set to true load returns + * true if the document load was successfully initiated. + * If an error occurred when initiating the document load, + * load returns false.If async is set to + * false load returns true if + * the document was successfully loaded and parsed. If an error + * occurred when either loading or parsing the URI, load + * returns false. + */ + public boolean load(String uri) { + return false; + } + + /** + * DOM Level 3 WD - Experimental. + * Replace the content of the document with the result of parsing the + * input string, this method is always synchronous. + * @param source A string containing an XML document. + * @return true if parsing the input string succeeded + * without errors, otherwise false. + */ + public boolean loadXML(String source) { + return false; + } + + /** + * DOM Level 3 WD - Experimental. + * Save the document or the given node and all its descendants to a string + * (i.e. serialize the document or node). + *
The parameters used in the LSSerializer interface are + * assumed to have their default values when invoking this method. + *
The result of a call to this method is the same the result of a + * call to LSSerializer.writeToString with the document as + * the node to write. + * @param node Specifies what to serialize, if this parameter is + * null the whole document is serialized, if it's + * non-null the given node is serialized. + * @return The serialized document or null in case an error + * occurred. + * @exception DOMException + * WRONG_DOCUMENT_ERR: Raised if the node passed in as the node + * parameter is from an other document. + */ + public String saveXML(Node node) + throws DOMException { + if ( errorChecking && node != null && + this != node.getOwnerDocument() ) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + DOMImplementationLS domImplLS = (DOMImplementationLS)DOMImplementationImpl.getDOMImplementation(); + LSSerializer xmlWriter = domImplLS.createLSSerializer(); + if (node == null) { + node = this; + } + return xmlWriter.writeToString(node); + } + + /** + * Sets whether the DOM implementation generates mutation events + * upon operations. + */ + void setMutationEvents(boolean set) { + // does nothing by default - overidden in subclass + } + + /** + * Returns true if the DOM implementation generates mutation events. + */ + boolean getMutationEvents() { + // does nothing by default - overriden in subclass + return false; + } + + + + // non-DOM factory methods + + /** + * NON-DOM + * Factory method; creates a DocumentType having this Document + * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building + * DTD information unspecified.) + * + * @param qualifiedName + * @param publicID + * @param systemID + * + * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where + * DTDs are not permitted. (HTML not yet implemented.) + */ + public DocumentType createDocumentType(String qualifiedName, + String publicID, + String systemID) + throws DOMException { + + return new DocumentTypeImpl(this, qualifiedName, publicID, systemID); + + } // createDocumentType(String):DocumentType + + /** + * NON-DOM + * Factory method; creates an Entity having this Document + * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building + * DTD information unspecified.) + * + * @param name The name of the Entity we wish to provide a value for. + * + * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where + * nonstandard entities are not permitted. (HTML not yet + * implemented.) + */ + public Entity createEntity(String name) + throws DOMException { + + + if (errorChecking && !isXMLName(name,xml11Version)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + return new EntityImpl(this, name); + + } // createEntity(String):Entity + + /** + * NON-DOM + * Factory method; creates a Notation having this Document + * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building + * DTD information unspecified.) + * + * @param name The name of the Notation we wish to describe + * + * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where + * notations are not permitted. (HTML not yet + * implemented.) + */ + public Notation createNotation(String name) + throws DOMException { + + if (errorChecking && !isXMLName(name,xml11Version)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + return new NotationImpl(this, name); + + } // createNotation(String):Notation + + /** + * NON-DOM Factory method: creates an element definition. Element + * definitions hold default attribute values. + */ + public ElementDefinitionImpl createElementDefinition(String name) + throws DOMException { + + if (errorChecking && !isXMLName(name,xml11Version)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + return new ElementDefinitionImpl(this, name); + + } // createElementDefinition(String):ElementDefinitionImpl + + // other non-DOM methods + + /** NON-DOM: Get the number associated with this document. Used to + * order documents in the implementation. + */ + protected int getNodeNumber() { + if (documentNumber==0) { + + CoreDOMImplementationImpl cd = (CoreDOMImplementationImpl)CoreDOMImplementationImpl.getDOMImplementation(); + documentNumber = cd.assignDocumentNumber(); + } + return documentNumber; + } + + + /** NON-DOM: Get a number associated with a node created with respect + * to this document. Needed for compareDocumentPosition when nodes + * are disconnected. This is only used on demand. + */ + protected int getNodeNumber(Node node) { + + // Check if the node is already in the hash + // If so, retrieve the node number + // If not, assign a number to the node + // Node numbers are negative, from -1 to -n + int num; + if (nodeTable == null) { + nodeTable = new WeakHashMap(); + num = --nodeCounter; + nodeTable.put(node, new Integer(num)); + } + else { + Integer n = (Integer)nodeTable.get(node); + if (n== null) { + num = --nodeCounter; + nodeTable.put(node, new Integer(num)); + } + else + num = n.intValue(); + } + return num; + } + + /** + * Copies a node from another document to this document. The new nodes are + * created using this document's factory methods and are populated with the + * data from the source's accessor methods defined by the DOM interfaces. + * Its behavior is otherwise similar to that of cloneNode. + *

+ * According to the DOM specifications, document nodes cannot be imported + * and a NOT_SUPPORTED_ERR exception is thrown if attempted. + */ + public Node importNode(Node source, boolean deep) + throws DOMException { + return importNode(source, deep, false, null); + } // importNode(Node,boolean):Node + + /** + * Overloaded implementation of DOM's importNode method. This method + * provides the core functionality for the public importNode and cloneNode + * methods. + * + * The reversedIdentifiers parameter is provided for cloneNode to + * preserve the document's identifiers. The HashMap has Elements as the + * keys and their identifiers as the values. When an element is being + * imported, a check is done for an associated identifier. If one exists, + * the identifier is registered with the new, imported element. If + * reversedIdentifiers is null, the parameter is not applied. + */ + private Node importNode(Node source, boolean deep, boolean cloningDoc, + HashMap reversedIdentifiers) + throws DOMException { + Node newnode=null; + Hashtable userData = null; + + // Sigh. This doesn't work; too many nodes have private data that + // would have to be manually tweaked. May be able to add local + // shortcuts to each nodetype. Consider ????? + // if(source instanceof NodeImpl && + // !(source instanceof DocumentImpl)) + // { + // // Can't clone DocumentImpl since it invokes us... + // newnode=(NodeImpl)source.cloneNode(false); + // newnode.ownerDocument=this; + // } + // else + if(source instanceof NodeImpl) + userData = ((NodeImpl)source).getUserDataRecord(); + int type = source.getNodeType(); + switch (type) { + case ELEMENT_NODE: { + Element newElement; + boolean domLevel20 = source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0"); + // Create element according to namespace support/qualification. + if(domLevel20 == false || source.getLocalName() == null) + newElement = createElement(source.getNodeName()); + else + newElement = createElementNS(source.getNamespaceURI(), + source.getNodeName()); + + // Copy element's attributes, if any. + NamedNodeMap sourceAttrs = source.getAttributes(); + if (sourceAttrs != null) { + int length = sourceAttrs.getLength(); + for (int index = 0; index < length; index++) { + Attr attr = (Attr)sourceAttrs.item(index); + + // NOTE: this methods is used for both importingNode + // and cloning the document node. In case of the + // clonning default attributes should be copied. + // But for importNode defaults should be ignored. + if (attr.getSpecified() || cloningDoc) { + Attr newAttr = (Attr)importNode(attr, true, cloningDoc, + reversedIdentifiers); + + // Attach attribute according to namespace + // support/qualification. + if (domLevel20 == false || + attr.getLocalName() == null) + newElement.setAttributeNode(newAttr); + else + newElement.setAttributeNodeNS(newAttr); + } + } + } + + // Register element identifier. + if (reversedIdentifiers != null) { + // Does element have an associated identifier? + Object elementId = reversedIdentifiers.get(source); + if (elementId != null) { + if (identifiers == null) + identifiers = new Hashtable(); + + identifiers.put(elementId, newElement); + } + } + + newnode = newElement; + break; + } + + case ATTRIBUTE_NODE: { + + if( source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0") ){ + if (source.getLocalName() == null) { + newnode = createAttribute(source.getNodeName()); + } else { + newnode = createAttributeNS(source.getNamespaceURI(), + source.getNodeName()); + } + } + else { + newnode = createAttribute(source.getNodeName()); + } + // if source is an AttrImpl from this very same implementation + // avoid creating the child nodes if possible + if (source instanceof AttrImpl) { + AttrImpl attr = (AttrImpl) source; + if (attr.hasStringValue()) { + AttrImpl newattr = (AttrImpl) newnode; + newattr.setValue(attr.getValue()); + deep = false; + } + else { + deep = true; + } + } + else { + // According to the DOM spec the kids carry the value. + // However, there are non compliant implementations out + // there that fail to do so. To avoid ending up with no + // value at all, in this case we simply copy the text value + // directly. + if (source.getFirstChild() == null) { + newnode.setNodeValue(source.getNodeValue()); + deep = false; + } else { + deep = true; + } + } + break; + } + + case TEXT_NODE: { + newnode = createTextNode(source.getNodeValue()); + break; + } + + case CDATA_SECTION_NODE: { + newnode = createCDATASection(source.getNodeValue()); + break; + } + + case ENTITY_REFERENCE_NODE: { + newnode = createEntityReference(source.getNodeName()); + // the subtree is created according to this doc by the method + // above, so avoid carrying over original subtree + deep = false; + break; + } + + case ENTITY_NODE: { + Entity srcentity = (Entity)source; + EntityImpl newentity = + (EntityImpl)createEntity(source.getNodeName()); + newentity.setPublicId(srcentity.getPublicId()); + newentity.setSystemId(srcentity.getSystemId()); + newentity.setNotationName(srcentity.getNotationName()); + // Kids carry additional value, + // allow deep import temporarily + newentity.isReadOnly(false); + newnode = newentity; + break; + } + + case PROCESSING_INSTRUCTION_NODE: { + newnode = createProcessingInstruction(source.getNodeName(), + source.getNodeValue()); + break; + } + + case COMMENT_NODE: { + newnode = createComment(source.getNodeValue()); + break; + } + + case DOCUMENT_TYPE_NODE: { + // unless this is used as part of cloning a Document + // forbid it for the sake of being compliant to the DOM spec + if (!cloningDoc) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + DocumentType srcdoctype = (DocumentType)source; + DocumentTypeImpl newdoctype = (DocumentTypeImpl) + createDocumentType(srcdoctype.getNodeName(), + srcdoctype.getPublicId(), + srcdoctype.getSystemId()); + newdoctype.setInternalSubset(srcdoctype.getInternalSubset()); + // Values are on NamedNodeMaps + NamedNodeMap smap = srcdoctype.getEntities(); + NamedNodeMap tmap = newdoctype.getEntities(); + if(smap != null) { + for(int i = 0; i < smap.getLength(); i++) { + tmap.setNamedItem(importNode(smap.item(i), true, true, + reversedIdentifiers)); + } + } + smap = srcdoctype.getNotations(); + tmap = newdoctype.getNotations(); + if (smap != null) { + for(int i = 0; i < smap.getLength(); i++) { + tmap.setNamedItem(importNode(smap.item(i), true, true, + reversedIdentifiers)); + } + } + + // NOTE: At this time, the DOM definition of DocumentType + // doesn't cover Elements and their Attributes. domimpl's + // extentions in that area will not be preserved, even if + // copying from domimpl to domimpl. We could special-case + // that here. Arguably we should. Consider. ????? + newnode = newdoctype; + break; + } + + case DOCUMENT_FRAGMENT_NODE: { + newnode = createDocumentFragment(); + // No name, kids carry value + break; + } + + case NOTATION_NODE: { + Notation srcnotation = (Notation)source; + NotationImpl newnotation = + (NotationImpl)createNotation(source.getNodeName()); + newnotation.setPublicId(srcnotation.getPublicId()); + newnotation.setSystemId(srcnotation.getSystemId()); + // Kids carry additional value + newnode = newnotation; + // No name, no value + break; + } + case DOCUMENT_NODE : // Can't import document nodes + default: { // Unknown node type + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + } + + if(userData != null) + callUserDataHandlers(source, newnode, UserDataHandler.NODE_IMPORTED,userData); + + // If deep, replicate and attach the kids. + if (deep) { + for (Node srckid = source.getFirstChild(); + srckid != null; + srckid = srckid.getNextSibling()) { + newnode.appendChild(importNode(srckid, true, cloningDoc, + reversedIdentifiers)); + } + } + if (newnode.getNodeType() == Node.ENTITY_NODE) { + ((NodeImpl)newnode).setReadOnly(true, true); + } + return newnode; + + } // importNode(Node,boolean,boolean,Hashtable):Node + + /** + * DOM Level 3 WD - Experimental + * Change the node's ownerDocument, and its subtree, to this Document + * + * @param source The node to adopt. + * @see #importNode + **/ + public Node adoptNode(Node source) { + NodeImpl node; + Hashtable userData = null; + try { + node = (NodeImpl) source; + } catch (ClassCastException e) { + // source node comes from a different DOMImplementation + return null; + } + + // Return null if the source is null + + if (source == null) { + return null; + } + else if (source != null && source.getOwnerDocument() != null) { + + DOMImplementation thisImpl = this.getImplementation(); + DOMImplementation otherImpl = source.getOwnerDocument().getImplementation(); + + // when the source node comes from a different implementation. + if (thisImpl != otherImpl) { + // Adopting from a deferred DOM to a non-deferred DOM + if (thisImpl instanceof org.apache.xerces.dom.DOMImplementationImpl && + otherImpl instanceof org.apache.xerces.dom.DeferredDOMImplementationImpl) { + // traverse the DOM and expand deferred nodes and then allow adoption + undeferChildren (node); + } + else if ( thisImpl instanceof org.apache.xerces.dom.DeferredDOMImplementationImpl + && otherImpl instanceof org.apache.xerces.dom.DOMImplementationImpl) { + // Adopting from a non-deferred DOM into a deferred DOM, this should be okay + } + else { + // Adopting between two dissimilar DOMs is not allowed + return null; + } + } + // Adopting from a deferred DOM into another deferred DOM + else if (otherImpl instanceof org.apache.xerces.dom.DeferredDOMImplementationImpl) { + // traverse the DOM and expand deferred nodes and then allow adoption + undeferChildren (node); + } + } + + switch (node.getNodeType()) { + case ATTRIBUTE_NODE: { + AttrImpl attr = (AttrImpl) node; + // remove node from wherever it is + if( attr.getOwnerElement() != null){ + //1. owner element attribute is set to null + attr.getOwnerElement().removeAttributeNode(attr); + } + //2. specified flag is set to true + attr.isSpecified(true); + userData = node.getUserDataRecord(); + + //3. change ownership + attr.setOwnerDocument(this); + if(userData != null ) + setUserDataTable(node,userData); + break; + } + //entity, notation nodes are read only nodes.. so they can't be adopted. + //runtime will fall through to NOTATION_NODE + case ENTITY_NODE: + case NOTATION_NODE:{ + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + + } + //document, documentype nodes can't be adopted. + //runtime will fall through to DocumentTypeNode + case DOCUMENT_NODE: + case DOCUMENT_TYPE_NODE: { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + case ENTITY_REFERENCE_NODE: { + userData = node.getUserDataRecord(); + // remove node from wherever it is + Node parent = node.getParentNode(); + if (parent != null) { + parent.removeChild(source); + } + // discard its replacement value + Node child; + while ((child = node.getFirstChild()) != null) { + node.removeChild(child); + } + // change ownership + node.setOwnerDocument(this); + if(userData != null) + setUserDataTable(node,userData); + // set its new replacement value if any + if (docType == null) { + break; + } + NamedNodeMap entities = docType.getEntities(); + Node entityNode = entities.getNamedItem(node.getNodeName()); + if (entityNode == null) { + break; + } + for (child = entityNode.getFirstChild(); + child != null; child = child.getNextSibling()) { + Node childClone = child.cloneNode(true); + node.appendChild(childClone); + } + break; + } + case ELEMENT_NODE: { + userData = node.getUserDataRecord(); + // remove node from wherever it is + Node parent = node.getParentNode(); + if (parent != null) { + parent.removeChild(source); + } + // change ownership + node.setOwnerDocument(this); + if(userData != null) + setUserDataTable(node,userData); + // reconcile default attributes + ((ElementImpl)node).reconcileDefaultAttributes(); + break; + } + default: { + userData = node.getUserDataRecord(); + // remove node from wherever it is + Node parent = node.getParentNode(); + if (parent != null) { + parent.removeChild(source); + } + // change ownership + node.setOwnerDocument(this); + if(userData != null) + setUserDataTable(node,userData); + } + } + + //DOM L3 Core CR + //http://www.w3.org/TR/2003/CR-DOM-Level-3-Core-20031107/core.html#UserDataHandler-ADOPTED + if(userData != null) + callUserDataHandlers(source, null, UserDataHandler.NODE_ADOPTED,userData); + + return node; + } + + /** + * Traverses the DOM Tree and expands deferred nodes and their + * children. + * + */ + protected void undeferChildren(Node node) { + + Node top = node; + + while (null != node) { + + if (((NodeImpl)node).needsSyncData()) { + ((NodeImpl)node).synchronizeData(); + } + + NamedNodeMap attributes = node.getAttributes(); + if (attributes != null) { + int length = attributes.getLength(); + for (int i = 0; i < length; ++i) { + undeferChildren(attributes.item(i)); + } + } + + Node nextNode = null; + nextNode = node.getFirstChild(); + + while (null == nextNode) { + + if (top.equals(node)) + break; + + nextNode = node.getNextSibling(); + + if (null == nextNode) { + node = node.getParentNode(); + + if ((null == node) || (top.equals(node))) { + nextNode = null; + break; + } + } + } + + node = nextNode; + } + } + + // identifier maintenence + /** + * Introduced in DOM Level 2 + * Returns 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. + *

+ * Note: 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. + * @see #getIdentifier + */ + public Element getElementById(String elementId) { + return getIdentifier(elementId); + } + + /** + * Remove all identifiers from the ID table + */ + protected final void clearIdentifiers(){ + if (identifiers != null){ + identifiers.clear(); + } + } + + /** + * Registers an identifier name with a specified element node. + * If the identifier is already registered, the new element + * node replaces the previous node. If the specified element + * node is null, removeIdentifier() is called. + * + * @see #getIdentifier + * @see #removeIdentifier + */ + public void putIdentifier(String idName, Element element) { + + if (element == null) { + removeIdentifier(idName); + return; + } + + if (needsSyncData()) { + synchronizeData(); + } + + if (identifiers == null) { + identifiers = new Hashtable(); + } + + identifiers.put(idName, element); + + } // putIdentifier(String,Element) + + /** + * Returns a previously registered element with the specified + * identifier name, or null if no element is registered. + * + * @see #putIdentifier + * @see #removeIdentifier + */ + public Element getIdentifier(String idName) { + + if (needsSyncData()) { + synchronizeData(); + } + + if (identifiers == null) { + return null; + } + Element elem = (Element) identifiers.get(idName); + if (elem != null) { + // check that the element is in the tree + Node parent = elem.getParentNode(); + while (parent != null) { + if (parent == this) { + return elem; + } + parent = parent.getParentNode(); + } + } + return null; + } // getIdentifier(String):Element + + /** + * Removes a previously registered element with the specified + * identifier name. + * + * @see #putIdentifier + * @see #getIdentifier + */ + public void removeIdentifier(String idName) { + + if (needsSyncData()) { + synchronizeData(); + } + + if (identifiers == null) { + return; + } + + identifiers.remove(idName); + + } // removeIdentifier(String) + + /** Returns an enumeration registered of identifier names. */ + public Enumeration getIdentifiers() { + + if (needsSyncData()) { + synchronizeData(); + } + + if (identifiers == null) { + identifiers = new Hashtable(); + } + + return identifiers.keys(); + + } // getIdentifiers():Enumeration + + // + // DOM2: Namespace methods + // + + /** + * Introduced in DOM Level 2.

+ * Creates an element of the given qualified name and namespace URI. + * If the given namespaceURI is null or an empty string and the + * qualifiedName has a prefix that is "xml", the created element + * is bound to the predefined namespace + * "http://www.w3.org/XML/1998/namespace" [Namespaces]. + * @param namespaceURI The namespace URI of the element to + * create. + * @param qualifiedName The qualified name of the element type to + * instantiate. + * @return Element A new Element object with the following attributes: + * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified + * name contains an invalid character. + * @throws DOMException NAMESPACE_ERR: Raised if the qualifiedName has a + * prefix that is "xml" and the namespaceURI is + * neither null nor an empty string nor + * "http://www.w3.org/XML/1998/namespace", or + * if the qualifiedName has a prefix different + * from "xml" and the namespaceURI is null or an + * empty string. + * @since WD-DOM-Level-2-19990923 + */ + public Element createElementNS(String namespaceURI, String qualifiedName) + throws DOMException { + return new ElementNSImpl(this, namespaceURI, qualifiedName); + } + + /** + * NON-DOM: a factory method used by the Xerces DOM parser + * to create an element. + * + * @param namespaceURI The namespace URI of the element to + * create. + * @param qualifiedName The qualified name of the element type to + * instantiate. + * @param localpart The local name of the attribute to instantiate. + * + * @return Element A new Element object with the following attributes: + * @exception DOMException INVALID_CHARACTER_ERR: Raised if the specified + * name contains an invalid character. + */ + public Element createElementNS(String namespaceURI, String qualifiedName, + String localpart) + throws DOMException { + return new ElementNSImpl(this, namespaceURI, qualifiedName, localpart); + } + + /** + * Introduced in DOM Level 2.

+ * Creates an attribute of the given qualified name and namespace URI. + * If the given namespaceURI is null or an empty string and the + * qualifiedName has a prefix that is "xml", the created element + * is bound to the predefined namespace + * "http://www.w3.org/XML/1998/namespace" [Namespaces]. + * + * @param namespaceURI The namespace URI of the attribute to + * create. When it is null or an empty string, + * this method behaves like createAttribute. + * @param qualifiedName The qualified name of the attribute to + * instantiate. + * @return Attr A new Attr object. + * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified + * name contains an invalid character. + * @since WD-DOM-Level-2-19990923 + */ + public Attr createAttributeNS(String namespaceURI, String qualifiedName) + throws DOMException { + return new AttrNSImpl(this, namespaceURI, qualifiedName); + } + + /** + * NON-DOM: a factory method used by the Xerces DOM parser + * to create an element. + * + * @param namespaceURI The namespace URI of the attribute to + * create. When it is null or an empty string, + * this method behaves like createAttribute. + * @param qualifiedName The qualified name of the attribute to + * instantiate. + * @param localpart The local name of the attribute to instantiate. + * + * @return Attr A new Attr object. + * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified + * name contains an invalid character. + */ + public Attr createAttributeNS(String namespaceURI, String qualifiedName, + String localpart) + throws DOMException { + return new AttrNSImpl(this, namespaceURI, qualifiedName, localpart); + } + + /** + * Introduced in DOM Level 2.

+ * Returns a NodeList of all the Elements with a given local name and + * namespace URI in the order in which they would be encountered in a + * preorder traversal of the Document tree. + * @param namespaceURI The namespace URI of the elements to match + * on. The special value "*" matches all + * namespaces. When it is null or an empty + * string, this method behaves like + * getElementsByTagName. + * @param localName The local name of the elements to match on. + * The special value "*" matches all local names. + * @return NodeList A new NodeList object containing all the matched + * Elements. + * @since WD-DOM-Level-2-19990923 + */ + public NodeList getElementsByTagNameNS(String namespaceURI, + String localName) { + return new DeepNodeListImpl(this, namespaceURI, localName); + } + + // + // Object methods + // + + /** Clone. */ + public Object clone() throws CloneNotSupportedException { + CoreDocumentImpl newdoc = (CoreDocumentImpl) super.clone(); + newdoc.docType = null; + newdoc.docElement = null; + return newdoc; + } + + // + // Public static methods + // + + /** + * Check the string against XML's definition of acceptable names for + * elements and attributes and so on using the XMLCharacterProperties + * utility class + */ + + public static final boolean isXMLName(String s, boolean xml11Version) { + + if (s == null) { + return false; + } + if(!xml11Version) + return XMLChar.isValidName(s); + else + return XML11Char.isXML11ValidName(s); + + } // isXMLName(String):boolean + + /** + * Checks if the given qualified name is legal with respect + * to the version of XML to which this document must conform. + * + * @param prefix prefix of qualified name + * @param local local part of qualified name + */ + public static final boolean isValidQName(String prefix, String local, boolean xml11Version) { + + // check that both prefix and local part match NCName + if (local == null) return false; + boolean validNCName = false; + + if (!xml11Version) { + validNCName = (prefix == null || XMLChar.isValidNCName(prefix)) + && XMLChar.isValidNCName(local); + } + else { + validNCName = (prefix == null || XML11Char.isXML11ValidNCName(prefix)) + && XML11Char.isXML11ValidNCName(local); + } + + return validNCName; + } + // + // Protected methods + // + + /** + * Uses the kidOK lookup table to check whether the proposed + * tree structure is legal. + */ + protected boolean isKidOK(Node parent, Node child) { + if (allowGrammarAccess && + parent.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + return child.getNodeType() == Node.ELEMENT_NODE; + } + return 0 != (kidOK[parent.getNodeType()] & 1 << child.getNodeType()); + } + + /** + * Denotes that this node has changed. + */ + protected void changed() { + changes++; + } + + /** + * Returns the number of changes to this node. + */ + protected int changes() { + return changes; + } + + // NodeListCache pool + + /** + * Returns a NodeListCache for the given node. + */ + NodeListCache getNodeListCache(ParentNode owner) { + if (fFreeNLCache == null) { + return new NodeListCache(owner); + } + NodeListCache c = fFreeNLCache; + fFreeNLCache = fFreeNLCache.next; + c.fChild = null; + c.fChildIndex = -1; + c.fLength = -1; + // revoke previous ownership + if (c.fOwner != null) { + c.fOwner.fNodeListCache = null; + } + c.fOwner = owner; + // c.next = null; not necessary, except for confused people... + return c; + } + + /** + * Puts the given NodeListCache in the free list. + * Note: The owner node can keep using it until we reuse it + */ + void freeNodeListCache(NodeListCache c) { + c.next = fFreeNLCache; + fFreeNLCache = c; + } + + + + /** + * Associate an object to a key on this node. The object can later be + * retrieved from this node by calling getUserData with the + * same key. + * @param n The node to associate the object to. + * @param key The key to associate the object to. + * @param data The object to associate to the given key, or + * null to remove any existing association to that key. + * @param handler The handler to associate to that key, or + * null. + * @return Returns the DOMObject previously associated to + * the given key on this node, or null if there was none. + * @since DOM Level 3 + * + * REVISIT: we could use a free list of UserDataRecord here + */ + public Object setUserData(Node n, String key, + Object data, UserDataHandler handler) { + if (data == null) { + if (userData != null) { + Hashtable t = (Hashtable) userData.get(n); + if (t != null) { + Object o = t.remove(key); + if (o != null) { + UserDataRecord r = (UserDataRecord) o; + return r.fData; + } + } + } + return null; + } + else { + Hashtable t; + if (userData == null) { + userData = new WeakHashMap(); + t = new Hashtable(); + userData.put(n, t); + } + else { + t = (Hashtable) userData.get(n); + if (t == null) { + t = new Hashtable(); + userData.put(n, t); + } + } + Object o = t.put(key, new UserDataRecord(data, handler)); + if (o != null) { + UserDataRecord r = (UserDataRecord) o; + return r.fData; + } + return null; + } + } + + + /** + * Retrieves the object associated to a key on a this node. The object + * must first have been set to this node by calling + * setUserData with the same key. + * @param n The node the object is associated to. + * @param key The key the object is associated to. + * @return Returns the DOMObject associated to the given key + * on this node, or null if there was none. + * @since DOM Level 3 + */ + public Object getUserData(Node n, String key) { + if (userData == null) { + return null; + } + Hashtable t = (Hashtable) userData.get(n); + if (t == null) { + return null; + } + Object o = t.get(key); + if (o != null) { + UserDataRecord r = (UserDataRecord) o; + return r.fData; + } + return null; + } + + protected Hashtable getUserDataRecord(Node n){ + if (userData == null) { + return null; + } + Hashtable t = (Hashtable) userData.get(n); + if (t == null) { + return null; + } + return t; + } + + /** + * Remove user data table for the given node. + * @param n The node this operation applies to. + * @return The removed table. + */ + Hashtable removeUserDataTable(Node n) { + if (userData == null) { + return null; + } + return (Hashtable) userData.get(n); + } + + /** + * Set user data table for the given node. + * @param n The node this operation applies to. + * @param data The user data table. + */ + void setUserDataTable(Node n, Hashtable data) { + if (userData == null) { + userData = new WeakHashMap(); + } + if (data != null) { + userData.put(n, data); + } + } + + /** + * Call user data handlers when a node is deleted (finalized) + * @param n The node this operation applies to. + * @param c The copy node or null. + * @param operation The operation - import, clone, or delete. + */ + protected void callUserDataHandlers(Node n, Node c, short operation) { + if (userData == null) { + return; + } + //Hashtable t = (Hashtable) userData.get(n); + if(n instanceof NodeImpl){ + Hashtable t = ((NodeImpl)n).getUserDataRecord(); + if (t == null || t.isEmpty()) { + return; + } + callUserDataHandlers(n, c, operation,t); + } + } + + /** + * Call user data handlers when a node is deleted (finalized) + * @param n The node this operation applies to. + * @param c The copy node or null. + * @param operation The operation - import, clone, or delete. + * @param handlers Data associated with n. + */ + void callUserDataHandlers(Node n, Node c, short operation, Hashtable userData) { + if (userData == null || userData.isEmpty()) { + return; + } + Iterator entries = userData.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + String key = (String) entry.getKey(); + UserDataRecord r = (UserDataRecord) entry.getValue(); + if (r.fHandler != null) { + r.fHandler.handle(operation, key, r.fData, n, c); + } + } + } + + /** + * Call user data handlers to let them know the nodes they are related to + * are being deleted. The alternative would be to do that on Node but + * because the nodes are used as the keys we have a reference to them that + * prevents them from being gc'ed until the document is. At the same time, + * doing it here has the advantage of avoiding a finalize() method on Node, + * which would affect all nodes and not just the ones that have a user + * data. + */ + // Temporarily comment out this method, because + // 1. It seems that finalizers are not guaranteed to be called, so the + // functionality is not implemented. + // 2. It affects the performance greatly in multi-thread environment. + // -SG + /*public void finalize() { + if (userData == null) { + return; + } + Enumeration nodes = userData.keys(); + while (nodes.hasMoreElements()) { + Object node = nodes.nextElement(); + Hashtable t = (Hashtable) userData.get(node); + if (t != null && !t.isEmpty()) { + Enumeration keys = t.keys(); + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + UserDataRecord r = (UserDataRecord) t.get(key); + if (r.fHandler != null) { + r.fHandler.handle(UserDataHandler.NODE_DELETED, + key, r.fData, null, null); + } + } + } + } + }*/ + + protected final void checkNamespaceWF( String qname, int colon1, + int colon2) { + + if (!errorChecking) { + return; + } + // it is an error for NCName to have more than one ':' + // check if it is valid QName [Namespace in XML production 6] + // :camera , nikon:camera:minolta, camera: + if (colon1 == 0 || colon1 == qname.length() - 1 || colon2 != colon1) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + } + protected final void checkDOMNSErr(String prefix, + String namespace) { + if (errorChecking) { + if (namespace == null) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + else if (prefix.equals("xml") + && !namespace.equals(NamespaceContext.XML_URI)) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + else if ( + prefix.equals("xmlns") + && !namespace.equals(NamespaceContext.XMLNS_URI) + || (!prefix.equals("xmlns") + && namespace.equals(NamespaceContext.XMLNS_URI))) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + } + } + + /** + * Checks if the given qualified name is legal with respect + * to the version of XML to which this document must conform. + * + * @param prefix prefix of qualified name + * @param local local part of qualified name + */ + protected final void checkQName(String prefix, String local) { + if (!errorChecking) { + return; + } + + // check that both prefix and local part match NCName + boolean validNCName = false; + if (!xml11Version) { + validNCName = (prefix == null || XMLChar.isValidNCName(prefix)) + && XMLChar.isValidNCName(local); + } + else { + validNCName = (prefix == null || XML11Char.isXML11ValidNCName(prefix)) + && XML11Char.isXML11ValidNCName(local); + } + + if (!validNCName) { + // REVISIT: add qname parameter to the message + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "INVALID_CHARACTER_ERR", + null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + } + + /** + * We could have more xml versions in future , but for now we could + * do with this to handle XML 1.0 and 1.1 + */ + boolean isXML11Version(){ + return xml11Version; + } + + boolean isNormalizeDocRequired(){ + // REVISIT: Implement to optimize when normalization + // is required + return true; + } + + //we should be checking the (elements, attribute, entity etc.) names only when + //version of the document is changed. + boolean isXMLVersionChanged(){ + return xmlVersionChanged ; + } + /** + * NON-DOM: kept for backward compatibility + * Store user data related to a given node + * This is a place where we could use weak references! Indeed, the node + * here won't be GC'ed as long as some user data is attached to it, since + * the userData table will have a reference to the node. + */ + protected void setUserData(NodeImpl n, Object data) { + setUserData(n, "XERCES1DOMUSERDATA", data, null); + } + + /** + * NON-DOM: kept for backward compatibility + * Retreive user data related to a given node + */ + protected Object getUserData(NodeImpl n) { + return getUserData(n, "XERCES1DOMUSERDATA"); + } + + + // Event related methods overidden in subclass + + protected void addEventListener(NodeImpl node, String type, + EventListener listener, + boolean useCapture) { + // does nothing by default - overidden in subclass + } + + protected void removeEventListener(NodeImpl node, String type, + EventListener listener, + boolean useCapture) { + // does nothing by default - overidden in subclass + } + + protected void copyEventListeners(NodeImpl src, NodeImpl tgt) { + // does nothing by default - overidden in subclass + } + + protected boolean dispatchEvent(NodeImpl node, Event event) { + // does nothing by default - overidden in subclass + return false; + } + + // Notification methods overidden in subclasses + + /** + * A method to be called when some text was changed in a text node, + * so that live objects can be notified. + */ + void replacedText(CharacterDataImpl node) { + } + + /** + * A method to be called when some text was deleted from a text node, + * so that live objects can be notified. + */ + void deletedText(CharacterDataImpl node, int offset, int count) { + } + + /** + * A method to be called when some text was inserted into a text node, + * so that live objects can be notified. + */ + void insertedText(CharacterDataImpl node, int offset, int count) { + } + + /** + * A method to be called when a character data node is about to be modified + */ + void modifyingCharacterData(NodeImpl node, boolean replace) { + } + + /** + * A method to be called when a character data node has been modified + */ + void modifiedCharacterData(NodeImpl node, String oldvalue, String value, boolean replace) { + } + + /** + * A method to be called when a node is about to be inserted in the tree. + */ + void insertingNode(NodeImpl node, boolean replace) { + } + + /** + * A method to be called when a node has been inserted in the tree. + */ + void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) { + } + + /** + * A method to be called when a node is about to be removed from the tree. + */ + void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) { + } + + /** + * A method to be called when a node has been removed from the tree. + */ + void removedNode(NodeImpl node, boolean replace) { + } + + /** + * A method to be called when a node is about to be replaced in the tree. + */ + void replacingNode(NodeImpl node) { + } + + /** + * A method to be called when a node has been replaced in the tree. + */ + void replacedNode(NodeImpl node) { + } + + /** + * A method to be called when a character data node is about to be replaced + */ + void replacingData(NodeImpl node) { + } + + /** + * method to be called when a character data node has been replaced. + */ + void replacedCharacterData(NodeImpl node, String oldvalue, String value) { + } + + + /** + * A method to be called when an attribute value has been modified + */ + void modifiedAttrValue(AttrImpl attr, String oldvalue) { + } + + /** + * A method to be called when an attribute node has been set + */ + void setAttrNode(AttrImpl attr, AttrImpl previous) { + } + + /** + * A method to be called when an attribute node has been removed + */ + void removedAttrNode(AttrImpl attr, NodeImpl oldOwner, String name) { + } + + /** + * A method to be called when an attribute node has been renamed + */ + void renamedAttrNode(Attr oldAt, Attr newAt) { + } + + /** + * A method to be called when an element has been renamed + */ + void renamedElement(Element oldEl, Element newEl) { + } + + /** + * The serialized forms of the user data and node table + * maps are Hashtables. Convert them into WeakHashMaps + * on load. + */ + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + if (userData != null) { + userData = new WeakHashMap(userData); + } + if (nodeTable != null) { + nodeTable = new WeakHashMap(nodeTable); + } + } + + /** + * To allow DOM trees serialized by newer versions of Xerces + * to be read by older versions briefly move the user data + * and node table into Hashtables. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + // Keep references to the original objects for restoration after serialization + final Map oldUserData = this.userData; + final Map oldNodeTable = this.nodeTable; + try { + if (oldUserData != null) { + this.userData = new Hashtable(oldUserData); + } + if (oldNodeTable != null) { + nodeTable = new Hashtable(oldNodeTable); + } + out.defaultWriteObject(); + } + // If the write fails for some reason ensure + // that we restore the original objects. + finally { + this.userData = oldUserData; + this.nodeTable = oldNodeTable; + } + } + +} // class CoreDocumentImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMConfigurationImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMConfigurationImpl.java new file mode 100644 index 0000000..8058dd7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMConfigurationImpl.java @@ -0,0 +1,1220 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; +import java.util.StringTokenizer; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.util.DOMEntityResolverWrapper; +import org.apache.xerces.util.DOMErrorHandlerWrapper; +import org.apache.xerces.util.MessageFormatter; +import org.apache.xerces.util.ParserConfigurationSettings; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.ls.LSResourceResolver; + +/** + * Xerces implementation of DOMConfiguration that maintains a table of recognized parameters. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Neeraj Bajaj, Sun Microsystems. + * @version $Id$ + */ +public class DOMConfigurationImpl extends ParserConfigurationSettings + implements XMLParserConfiguration, DOMConfiguration { + + // + // Constants + // + + protected static final String XML11_DATATYPE_VALIDATOR_FACTORY = + "org.apache.xerces.impl.dv.dtd.XML11DTDDVFactoryImpl"; + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String XERCES_VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: namespaces. */ + protected static final String XERCES_NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + protected static final String SCHEMA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + protected static final String SCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + + protected static final String DYNAMIC_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; + + protected static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + + /** Feature identifier: send element default value via characters() */ + protected static final String SCHEMA_ELEMENT_DEFAULT = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; + + /** sending psvi in the pipeline */ + protected static final String SEND_PSVI = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; + + /** Feature: generate synthetic annotations */ + protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE; + + /** Feature identifier: validate annotations */ + protected static final String VALIDATE_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE; + + /** Feature identifier: honour all schemaLocations */ + protected static final String HONOUR_ALL_SCHEMALOCATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; + + /** Feature identifier: use grammar pool only */ + protected static final String USE_GRAMMAR_POOL_ONLY = + Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + + /** Feature identifier: load external DTD. */ + protected static final String DISALLOW_DOCTYPE_DECL_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE; + + /** Feature identifier: balance syntax trees. */ + protected static final String BALANCE_SYNTAX_TREES = + Constants.XERCES_FEATURE_PREFIX + Constants.BALANCE_SYNTAX_TREES; + + /** Feature identifier: warn on duplicate attribute definition. */ + protected static final String WARN_ON_DUPLICATE_ATTDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; + + /** Feature identifier: namespace growth */ + protected static final String NAMESPACE_GROWTH = + Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; + + protected static final String TOLERATE_DUPLICATES = + Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; + // property identifiers + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: xml string. */ + protected static final String XML_STRING = + Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY; + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property id: Grammar pool. */ + protected static final String GRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** property identifier: security manager. */ + protected static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: JAXP schema language / DOM schema-type. */ + protected static final String JAXP_SCHEMA_LANGUAGE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE; + + /** Property identifier: JAXP schema source/ DOM schema-location. */ + protected static final String JAXP_SCHEMA_SOURCE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; + + /** Property identifier: DTD validator. */ + protected final static String DTD_VALIDATOR_PROPERTY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; + + /** Property identifier: datatype validator factory. */ + protected static final String DTD_VALIDATOR_FACTORY_PROPERTY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; + + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: schema location. */ + protected static final String SCHEMA_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION; + + /** Property identifier: no namespace schema location. */ + protected static final String SCHEMA_NONS_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION; + + /** Property identifier: Schema DV Factory */ + protected static final String SCHEMA_DV_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY; + + // + // Data + // + XMLDocumentHandler fDocumentHandler; + + /** Normalization features*/ + protected short features = 0; + + protected final static short NAMESPACES = 0x1<<0; + protected final static short DTNORMALIZATION = 0x1<<1; + protected final static short ENTITIES = 0x1<<2; + protected final static short CDATA = 0x1<<3; + protected final static short SPLITCDATA = 0x1<<4; + protected final static short COMMENTS = 0x1<<5; + protected final static short VALIDATE = 0x1<<6; + protected final static short PSVI = 0x1<<7; + protected final static short WELLFORMED = 0x1<<8; + protected final static short NSDECL = 0x1<<9; + + protected final static short INFOSET_TRUE_PARAMS = NAMESPACES | COMMENTS | WELLFORMED | NSDECL; + protected final static short INFOSET_FALSE_PARAMS = ENTITIES | DTNORMALIZATION | CDATA; + protected final static short INFOSET_MASK = INFOSET_TRUE_PARAMS | INFOSET_FALSE_PARAMS; + + // components + + /** Symbol table. */ + protected SymbolTable fSymbolTable; + + /** Components. */ + protected ArrayList fComponents; + + protected ValidationManager fValidationManager; + + /** Locale. */ + protected Locale fLocale; + + /** Error reporter */ + protected XMLErrorReporter fErrorReporter; + + protected final DOMErrorHandlerWrapper fErrorHandlerWrapper = + new DOMErrorHandlerWrapper(); + + /** Current Datatype validator factory. */ + protected DTDDVFactory fCurrentDVFactory; + + /** The XML 1.0 Datatype validator factory. */ + protected DTDDVFactory fDatatypeValidatorFactory; + + /** The XML 1.1 Datatype validator factory. **/ + protected DTDDVFactory fXML11DatatypeFactory; + + // private data + + private String fSchemaLocation = null; + private DOMStringList fRecognizedParameters; + + // + // Constructors + // + + /** Default Constructor. */ + protected DOMConfigurationImpl() { + this(null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + protected DOMConfigurationImpl(SymbolTable symbolTable) { + this(symbolTable, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table + * and parent settings. + * + * @param symbolTable The symbol table to use. + * @param parentSettings The parent settings. + */ + protected DOMConfigurationImpl(SymbolTable symbolTable, + XMLComponentManager parentSettings) { + super(parentSettings); + + // create storage for recognized features and properties + fRecognizedFeatures = new ArrayList(); + fRecognizedProperties = new ArrayList(); + + // create table for features and properties + fFeatures = new HashMap(); + fProperties = new HashMap(); + + // add default recognized features + final String[] recognizedFeatures = { + XERCES_VALIDATION, + XERCES_NAMESPACES, + SCHEMA, + SCHEMA_FULL_CHECKING, + DYNAMIC_VALIDATION, + NORMALIZE_DATA, + SCHEMA_ELEMENT_DEFAULT, + SEND_PSVI, + GENERATE_SYNTHETIC_ANNOTATIONS, + VALIDATE_ANNOTATIONS, + HONOUR_ALL_SCHEMALOCATIONS, + USE_GRAMMAR_POOL_ONLY, + DISALLOW_DOCTYPE_DECL_FEATURE, + BALANCE_SYNTAX_TREES, + WARN_ON_DUPLICATE_ATTDEF, + PARSER_SETTINGS, + NAMESPACE_GROWTH, + TOLERATE_DUPLICATES + }; + addRecognizedFeatures(recognizedFeatures); + + // set state for default features + setFeature(XERCES_VALIDATION, false); + setFeature(SCHEMA, false); + setFeature(SCHEMA_FULL_CHECKING, false); + setFeature(DYNAMIC_VALIDATION, false); + setFeature(NORMALIZE_DATA, false); + setFeature(SCHEMA_ELEMENT_DEFAULT, false); + setFeature(XERCES_NAMESPACES, true); + setFeature(SEND_PSVI, true); + setFeature(GENERATE_SYNTHETIC_ANNOTATIONS, false); + setFeature(VALIDATE_ANNOTATIONS, false); + setFeature(HONOUR_ALL_SCHEMALOCATIONS, false); + setFeature(USE_GRAMMAR_POOL_ONLY, false); + setFeature(DISALLOW_DOCTYPE_DECL_FEATURE, false); + setFeature(BALANCE_SYNTAX_TREES, false); + setFeature(WARN_ON_DUPLICATE_ATTDEF, false); + setFeature(PARSER_SETTINGS, true); + setFeature(NAMESPACE_GROWTH, false); + setFeature(TOLERATE_DUPLICATES, false); + + // add default recognized properties + final String[] recognizedProperties = { + XML_STRING, + SYMBOL_TABLE, + ERROR_HANDLER, + ENTITY_RESOLVER, + ERROR_REPORTER, + ENTITY_MANAGER, + VALIDATION_MANAGER, + GRAMMAR_POOL, + SECURITY_MANAGER, + JAXP_SCHEMA_SOURCE, + JAXP_SCHEMA_LANGUAGE, + SCHEMA_LOCATION, + SCHEMA_NONS_LOCATION, + DTD_VALIDATOR_PROPERTY, + DTD_VALIDATOR_FACTORY_PROPERTY, + SCHEMA_DV_FACTORY + }; + addRecognizedProperties(recognizedProperties); + + // set default values for normalization features + features |= NAMESPACES; + features |= ENTITIES; + features |= COMMENTS; + features |= CDATA; + features |= SPLITCDATA; + features |= WELLFORMED; + features |= NSDECL; + + if (symbolTable == null) { + symbolTable = new SymbolTable(); + } + fSymbolTable = symbolTable; + + fComponents = new ArrayList(); + + setProperty(SYMBOL_TABLE, fSymbolTable); + fErrorReporter = new XMLErrorReporter(); + setProperty(ERROR_REPORTER, fErrorReporter); + addComponent(fErrorReporter); + + fDatatypeValidatorFactory = DTDDVFactory.getInstance(); + fXML11DatatypeFactory = DTDDVFactory.getInstance(XML11_DATATYPE_VALIDATOR_FACTORY); + fCurrentDVFactory = fDatatypeValidatorFactory; + setProperty(DTD_VALIDATOR_FACTORY_PROPERTY, fCurrentDVFactory); + + XMLEntityManager manager = new XMLEntityManager(); + setProperty(ENTITY_MANAGER, manager); + addComponent(manager); + + fValidationManager = createValidationManager(); + setProperty(VALIDATION_MANAGER, fValidationManager); + + + // add message formatters + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + + // REVISIT: try to include XML Schema formatter. + // This is a hack to allow DTD configuration to be build. + // + if (fErrorReporter.getMessageFormatter("http://www.w3.org/TR/xml-schema-1") == null) { + MessageFormatter xmft = null; + try { + xmft = (MessageFormatter)( + ObjectFactory.newInstance("org.apache.xerces.impl.xs.XSMessageFormatter", + ObjectFactory.findClassLoader(), true)); + } catch (Exception exception){ + } + + if (xmft != null) { + fErrorReporter.putMessageFormatter("http://www.w3.org/TR/xml-schema-1", xmft); + } + } + + + // set locale + try { + setLocale(Locale.getDefault()); + } + catch (XNIException e) { + // do nothing + // REVISIT: What is the right thing to do? -Ac + } + + + } // (SymbolTable) + + + // + // XMLParserConfiguration methods + // + + /** + * Parse an XML document. + *

+ * The parser can use this method to instruct this configuration + * to begin parsing an XML document from any valid input source + * (a character stream, a byte stream, or a URI). + *

+ * Parsers may not invoke this method while a parse is in progress. + * Once a parse is complete, the parser may then parse another XML + * document. + *

+ * This method is synchronous: it will not return until parsing + * has ended. If a client application wants to terminate + * parsing early, it should throw an exception. + * + * @param inputSource The input source for the top-level of the + * XML document. + * + * @exception XNIException Any XNI exception, possibly wrapping + * another exception. + * @exception IOException An IO exception from the parser, possibly + * from a byte stream or character stream + * supplied by the parser. + */ + public void parse(XMLInputSource inputSource) + throws XNIException, IOException{ + // no-op + } + + /** + * Sets the document handler on the last component in the pipeline + * to receive information about the document. + * + * @param documentHandler The document handler. + */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + } // setDocumentHandler(XMLDocumentHandler) + + /** Returns the registered document handler. */ + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } // getDocumentHandler():XMLDocumentHandler + + /** + * Sets the DTD handler. + * + * @param dtdHandler The DTD handler. + */ + public void setDTDHandler(XMLDTDHandler dtdHandler) { + //no-op + } // setDTDHandler(XMLDTDHandler) + + /** Returns the registered DTD handler. */ + public XMLDTDHandler getDTDHandler() { + return null; + } // getDTDHandler():XMLDTDHandler + + /** + * Sets the DTD content model handler. + * + * @param handler The DTD content model handler. + */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) { + //no-op + + } // setDTDContentModelHandler(XMLDTDContentModelHandler) + + /** Returns the registered DTD content model handler. */ + public XMLDTDContentModelHandler getDTDContentModelHandler() { + return null; + } // getDTDContentModelHandler():XMLDTDContentModelHandler + + /** + * Sets the resolver used to resolve external entities. The EntityResolver + * interface supports resolution of public and system identifiers. + * + * @param resolver The new entity resolver. Passing a null value will + * uninstall the currently installed resolver. + */ + public void setEntityResolver(XMLEntityResolver resolver) { + fProperties.put(ENTITY_RESOLVER, resolver); + } // setEntityResolver(XMLEntityResolver) + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public XMLEntityResolver getEntityResolver() { + return (XMLEntityResolver)fProperties.get(ENTITY_RESOLVER); + } // getEntityResolver():XMLEntityResolver + + /** + * 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 errorHandler The error handler. + * @exception java.lang.NullPointerException If the handler + * argument is null. + * @see #getErrorHandler + */ + public void setErrorHandler(XMLErrorHandler errorHandler) { + if (errorHandler != null) { + fProperties.put(ERROR_HANDLER, errorHandler); + } + } // setErrorHandler(XMLErrorHandler) + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public XMLErrorHandler getErrorHandler() { + return (XMLErrorHandler)fProperties.get(ERROR_HANDLER); + } // getErrorHandler():XMLErrorHandler + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * @return true if the feature is supported + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + if (featureId.equals(PARSER_SETTINGS)) { + return true; + } + return super.getFeature(featureId); + } + + /** + * Set the state of a feature. + * + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + + // save state if noone "objects" + super.setFeature(featureId, state); + + } // setFeature(String,boolean) + + /** + * setProperty + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // store value if noone "objects" + super.setProperty(propertyId, value); + + } // setProperty(String,Object) + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException { + fLocale = locale; + fErrorReporter.setLocale(locale); + + } // setLocale(Locale) + + /** Returns the locale. */ + public Locale getLocale() { + return fLocale; + } // getLocale():Locale + + /** + * DOM Level 3 WD - Experimental. + * setParameter + */ + public void setParameter(String name, Object value) throws DOMException { + boolean found = true; + + // REVISIT: Recognizes DOM L3 default features only. + // Does not yet recognize Xerces features. + if(value instanceof Boolean){ + boolean state = ((Boolean)value).booleanValue(); + + if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)) { + features = (short) (state ? features | COMMENTS : features & ~COMMENTS); + } + else if (name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION)) { + setFeature(NORMALIZE_DATA, state); + features = + (short) (state ? features | DTNORMALIZATION : features & ~DTNORMALIZATION); + if (state) { + features = (short) (features | VALIDATE); + } + } + else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) { + features = (short) (state ? features | NAMESPACES : features & ~NAMESPACES); + } + else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) { + features = (short) (state ? features | CDATA : features & ~CDATA); + } + else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)) { + features = (short) (state ? features | ENTITIES : features & ~ENTITIES); + } + else if (name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)) { + features = (short) (state ? features | SPLITCDATA : features & ~SPLITCDATA); + } + else if (name.equalsIgnoreCase(Constants.DOM_VALIDATE)) { + features = (short) (state ? features | VALIDATE : features & ~VALIDATE); + } + else if (name.equalsIgnoreCase(Constants.DOM_WELLFORMED)) { + features = (short) (state ? features | WELLFORMED : features & ~WELLFORMED ); + } + else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { + features = (short) (state ? features | NSDECL : features & ~NSDECL); + } + else if (name.equalsIgnoreCase(Constants.DOM_INFOSET)) { + // Setting to false has no effect. + if (state) { + features = (short) (features | INFOSET_TRUE_PARAMS); + features = (short) (features & ~INFOSET_FALSE_PARAMS); + setFeature(NORMALIZE_DATA, false); + } + } + else if (name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS) + || name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) + || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) + ) { + if (state) { // true is not supported + throw newFeatureNotSupportedError(name); + } + } + else if ( name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE)) { + if (!state) { // false is not supported + throw newFeatureNotSupportedError(name); + } + } + else if (name.equalsIgnoreCase(SEND_PSVI) ){ + // REVISIT: turning augmentation of PSVI is not support, + // because in this case we won't be able to retrieve element + // default value. + if (!state) { // false is not supported + throw newFeatureNotSupportedError(name); + } + } + else if (name.equalsIgnoreCase(Constants.DOM_PSVI)){ + features = (short) (state ? features | PSVI : features & ~PSVI); + } + else { + found = false; + /* + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[] { name }); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + */ + } + + } + + if (!found || !(value instanceof Boolean)) { // set properties + found = true; + + if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { + if (value instanceof DOMErrorHandler || value == null) { + fErrorHandlerWrapper.setErrorHandler((DOMErrorHandler)value); + setErrorHandler(fErrorHandlerWrapper); + } + else { + throw newTypeMismatchError(name); + } + } + else if (name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER)) { + if (value instanceof LSResourceResolver || value == null) { + try { + setEntityResolver(new DOMEntityResolverWrapper((LSResourceResolver) value)); + } + catch (XMLConfigurationException e) {} + } + else { + throw newTypeMismatchError(name); + } + } + else if (name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION)) { + if (value instanceof String || value == null) { + try { + if (value == null) { + fSchemaLocation = null; + setProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE, + null); + } + else { + fSchemaLocation = (String) value; + // map DOM schema-location to JAXP schemaSource property + // tokenize location string + StringTokenizer t = new StringTokenizer(fSchemaLocation, " \n\t\r"); + if (t.hasMoreTokens()) { + ArrayList locations = new ArrayList(); + locations.add(t.nextToken()); + while (t.hasMoreTokens()) { + locations.add (t.nextToken()); + } + setProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE, + locations.toArray(new String[locations.size()])); + } + else { + setProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE, + new String [] {(String) value}); + } + } + } + catch (XMLConfigurationException e) {} + } + else { + throw newTypeMismatchError(name); + } + } + else if (name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE)) { + if (value instanceof String || value == null) { + try { + if (value == null) { + setProperty( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, + null); + } + else if (value.equals(Constants.NS_XMLSCHEMA)) { + // REVISIT: when add support to DTD validation + setProperty( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, + Constants.NS_XMLSCHEMA); + } + else if (value.equals(Constants.NS_DTD)) { + // Added support for revalidation against DTDs + setProperty(Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, + Constants.NS_DTD); + } + } + catch (XMLConfigurationException e) {} + } + else { + throw newTypeMismatchError(name); + } + } + else if (name.equalsIgnoreCase(ENTITY_RESOLVER)) { + if (value instanceof XMLEntityResolver || value == null) { + try { + setEntityResolver((XMLEntityResolver) value); + } + catch (XMLConfigurationException e) {} + } + else { + throw newTypeMismatchError(name); + } + } + else if (name.equalsIgnoreCase(SYMBOL_TABLE)) { + // Xerces Symbol Table + if (value instanceof SymbolTable){ + setProperty(SYMBOL_TABLE, value); + } + else { + throw newTypeMismatchError(name); + } + } + else if (name.equalsIgnoreCase (GRAMMAR_POOL)) { + if (value instanceof XMLGrammarPool || value == null) { + setProperty(GRAMMAR_POOL, value); + } + else { + throw newTypeMismatchError(name); + } + } + else if (name.equalsIgnoreCase (SECURITY_MANAGER)) { + if (value instanceof org.apache.xerces.util.SecurityManager || value == null) { + setProperty(SECURITY_MANAGER, value); + } + else { + throw newTypeMismatchError(name); + } + } + else { + // REVISIT: check if this is a boolean parameter -- type mismatch should be thrown. + //parameter is not recognized + throw newFeatureNotFoundError(name); + } + } + } + + + /** + * DOM Level 3 WD - Experimental. + * getParameter + */ + public Object getParameter(String name) throws DOMException { + + // REVISIT: Recognizes DOM L3 default features only. + // Does not yet recognize Xerces features. + + if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)) { + return ((features & COMMENTS) != 0) ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) { + return (features & NAMESPACES) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION)) { + // REVISIT: datatype-normalization only takes effect if validation is on + return (features & DTNORMALIZATION) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) { + return (features & CDATA) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)) { + return (features & ENTITIES) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)) { + return (features & SPLITCDATA) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_VALIDATE)) { + return (features & VALIDATE) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_WELLFORMED)) { + return (features & WELLFORMED) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { + return (features & NSDECL) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_INFOSET)) { + return (features & INFOSET_MASK) == INFOSET_TRUE_PARAMS ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS) + || name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) + || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) + ) { + return Boolean.FALSE; + } + else if (name.equalsIgnoreCase(SEND_PSVI)) { + return Boolean.TRUE; + } + else if (name.equalsIgnoreCase(Constants.DOM_PSVI)) { + return (features & PSVI) != 0 ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE)) { + return Boolean.TRUE; + } + else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { + return fErrorHandlerWrapper.getErrorHandler(); + } + else if (name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER)) { + XMLEntityResolver entityResolver = getEntityResolver(); + if (entityResolver != null && entityResolver instanceof DOMEntityResolverWrapper) { + return ((DOMEntityResolverWrapper) entityResolver).getEntityResolver(); + } + return null; + } + else if (name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE)) { + return getProperty(Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE); + } + else if (name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION)) { + return fSchemaLocation; + } + else if (name.equalsIgnoreCase(ENTITY_RESOLVER)) { + return getEntityResolver(); + } + else if (name.equalsIgnoreCase(SYMBOL_TABLE)) { + return getProperty(SYMBOL_TABLE); + } + else if (name.equalsIgnoreCase(GRAMMAR_POOL)) { + return getProperty(GRAMMAR_POOL); + } + else if (name.equalsIgnoreCase(SECURITY_MANAGER)) { + return getProperty(SECURITY_MANAGER); + } + else { + throw newFeatureNotFoundError(name); + } + } + + /** + * DOM Level 3 WD - Experimental. + * Check if setting a parameter to a specific value is supported. + * + * @param name The name of the parameter to check. + * + * @param value An object. if null, the returned value is true. + * + * @return true if the parameter could be successfully set to the + * specified value, or false if the parameter is not recognized or + * the requested value is not supported. This does not change the + * current value of the parameter itself. + */ + public boolean canSetParameter(String name, Object value) { + + if (value == null){ + //if null, the returned value is true. + //REVISIT: I dont like this --- even for unrecognized parameter it would + //return 'true'. I think it should return false in that case. + // Application will be surprised to find that setParameter throws not + //recognized exception when canSetParameter returns 'true' Then what is the use + //of having canSetParameter ??? - nb. + return true ; + } + if( value instanceof Boolean ){ + //features whose parameter value can be set either 'true' or 'false' + // or they accept any boolean value -- so we just need to check that + // its a boolean value.. + if (name.equalsIgnoreCase(Constants.DOM_COMMENTS) + || name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION) + || name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS) + || name.equalsIgnoreCase(Constants.DOM_ENTITIES) + || name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA) + || name.equalsIgnoreCase(Constants.DOM_NAMESPACES) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE) + || name.equalsIgnoreCase(Constants.DOM_WELLFORMED) + || name.equalsIgnoreCase(Constants.DOM_INFOSET) + || name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS) + ) { + return true; + }//features whose parameter value can not be set to 'true' + else if ( + name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS) + || name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) + || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) + ) { + return (value.equals(Boolean.TRUE)) ? false : true; + }//features whose parameter value can not be set to 'false' + else if( name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) + || name.equalsIgnoreCase(SEND_PSVI) + ) { + return (value.equals(Boolean.TRUE)) ? true : false; + }// if name is not among the above listed above -- its not recognized. return false + else { + return false ; + } + } + else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { + return (value instanceof DOMErrorHandler) ? true : false ; + } + else if (name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER)) { + return (value instanceof LSResourceResolver) ? true : false ; + } + else if (name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION)) { + return (value instanceof String) ? true : false ; + } + else if (name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE)) { + // REVISIT: should null value be supported? + // as of now we are only supporting W3C XML Schema and DTD. + return ((value instanceof String) && + (value.equals(Constants.NS_XMLSCHEMA) || value.equals(Constants.NS_DTD))) ? true : false; + } + else if (name.equalsIgnoreCase(ENTITY_RESOLVER)) { + return (value instanceof XMLEntityResolver) ? true : false; + } + else if (name.equalsIgnoreCase(SYMBOL_TABLE)) { + // Xerces Symbol Table + return (value instanceof SymbolTable) ? true : false; + } + else if (name.equalsIgnoreCase (GRAMMAR_POOL)) { + return (value instanceof XMLGrammarPool) ? true : false; + } + else if (name.equalsIgnoreCase(SECURITY_MANAGER)) { + return (value instanceof org.apache.xerces.util.SecurityManager) ? true : false; + } + else { + //false if the parameter is not recognized or the requested value is not supported. + return false ; + } + + } //canSetParameter + + /** + * DOM Level 3 CR - Experimental. + * + * The list of the parameters supported by this + * DOMConfiguration object and for which at least one value + * can be set by the application. Note that this list can also contain + * parameter names defined outside this specification. + */ + public DOMStringList getParameterNames() { + if (fRecognizedParameters == null){ + ArrayList parameters = new ArrayList(); + + //Add DOM recognized parameters + //REVISIT: Would have been nice to have a list of + //recognized paramters. + parameters.add(Constants.DOM_COMMENTS); + parameters.add(Constants.DOM_DATATYPE_NORMALIZATION); + parameters.add(Constants.DOM_CDATA_SECTIONS); + parameters.add(Constants.DOM_ENTITIES); + parameters.add(Constants.DOM_SPLIT_CDATA); + parameters.add(Constants.DOM_NAMESPACES); + parameters.add(Constants.DOM_VALIDATE); + + parameters.add(Constants.DOM_INFOSET); + parameters.add(Constants.DOM_NORMALIZE_CHARACTERS); + parameters.add(Constants.DOM_CANONICAL_FORM); + parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA); + parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION); + parameters.add(Constants.DOM_WELLFORMED); + + parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS); + parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE); + + parameters.add(Constants.DOM_ERROR_HANDLER); + parameters.add(Constants.DOM_SCHEMA_TYPE); + parameters.add(Constants.DOM_SCHEMA_LOCATION); + parameters.add(Constants.DOM_RESOURCE_RESOLVER); + + //Add recognized xerces features and properties + parameters.add(ENTITY_RESOLVER); + parameters.add(GRAMMAR_POOL); + parameters.add(SECURITY_MANAGER); + parameters.add(SYMBOL_TABLE); + parameters.add(SEND_PSVI); + + fRecognizedParameters = new DOMStringListImpl(parameters); + + } + + return fRecognizedParameters; + }//getParameterNames + + // + // Protected methods + // + + /** + * reset all components before parsing + */ + protected void reset() throws XNIException { + + if (fValidationManager != null) + fValidationManager.reset(); + + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.reset(this); + } + + } // reset() + + /** + * Check a property. If the property is known and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known or supported. + */ + protected void checkProperty(String propertyId) + throws XMLConfigurationException { + + // special cases + if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); + + // + // http://xml.org/sax/properties/xml-string + // Value type: String + // Access: read-only + // Get the literal string of characters associated with the + // current event. If the parser recognises and supports this + // property but is not currently parsing text, it should return + // null (this is a good way to check for availability before the + // parse begins). + // + if (suffixLength == Constants.XML_STRING_PROPERTY.length() && + propertyId.endsWith(Constants.XML_STRING_PROPERTY)) { + // REVISIT - we should probably ask xml-dev for a precise + // definition of what this is actually supposed to return, and + // in exactly which circumstances. + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, propertyId); + } + } + + // check property + super.checkProperty(propertyId); + + } // checkProperty(String) + + + protected void addComponent(XMLComponent component) { + + // don't add a component more than once + if (fComponents.contains(component)) { + return; + } + fComponents.add(component); + + // register component's recognized features + String[] recognizedFeatures = component.getRecognizedFeatures(); + addRecognizedFeatures(recognizedFeatures); + + // register component's recognized properties + String[] recognizedProperties = component.getRecognizedProperties(); + addRecognizedProperties(recognizedProperties); + + } // addComponent(XMLComponent) + + protected ValidationManager createValidationManager(){ + return new ValidationManager(); + } + + protected final void setDTDValidatorFactory(String version) { + if ("1.1".equals(version)) { + if (fCurrentDVFactory != fXML11DatatypeFactory) { + fCurrentDVFactory = fXML11DatatypeFactory; + setProperty(DTD_VALIDATOR_FACTORY_PROPERTY, fCurrentDVFactory); + } + } + else if (fCurrentDVFactory != fDatatypeValidatorFactory) { + fCurrentDVFactory = fDatatypeValidatorFactory; + setProperty(DTD_VALIDATOR_FACTORY_PROPERTY, fCurrentDVFactory); + } + } + + private static DOMException newFeatureNotSupportedError(String name) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + return new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + private static DOMException newFeatureNotFoundError(String name) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[] { name }); + return new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + + private static DOMException newTypeMismatchError(String name) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "TYPE_MISMATCH_ERR", + new Object[] { name }); + return new DOMException(DOMException.TYPE_MISMATCH_ERR, msg); + } + +} // class DOMConfigurationImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMErrorImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMErrorImpl.java new file mode 100644 index 0000000..d9aa461 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMErrorImpl.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.apache.xerces.xni.parser.XMLParseException; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMLocator; + + +/** + * DOMErrorImpl is an implementation that describes an error. + * Note: The error object that describes the error + * might be reused by Xerces implementation, across multiple calls to the + * handleEvent method on DOMErrorHandler interface. + * + * + *

See also the Document Object Model (DOM) Level 3 Core Specification. + * + * @xerces.internal + * + * @author Gopal Sharma, SUN Microsystems Inc. + * @author Elena Litani, IBM + * + * @version $Id$ + */ + +// REVISIT: the implementation of ErrorReporter. +// we probably should not pass XMLParseException +// + +public class DOMErrorImpl implements DOMError { + + // + // Data + // + + public short fSeverity = DOMError.SEVERITY_WARNING; + public String fMessage = null; + public DOMLocatorImpl fLocator = new DOMLocatorImpl(); + public Exception fException = null; + public String fType; + public Object fRelatedData; + + + + // + // Constructors + // + + /** Default constructor. */ + public DOMErrorImpl () { + } + + /** Exctracts information from XMLParserException) */ + public DOMErrorImpl (short severity, XMLParseException exception) { + fSeverity = severity; + fException = exception; + fLocator = createDOMLocator (exception); + } + + /** + * The severity of the error, either SEVERITY_WARNING, + * SEVERITY_ERROR, or SEVERITY_FATAL_ERROR. + */ + + public short getSeverity() { + return fSeverity; + } + + /** + * An implementation specific string describing the error that occured. + */ + + public String getMessage() { + return fMessage; + } + + /** + * The location of the error. + */ + + public DOMLocator getLocation() { + return fLocator; + } + + // method to get the DOMLocator Object + private DOMLocatorImpl createDOMLocator(XMLParseException exception) { + // assuming DOMLocator wants the *expanded*, not the literal, URI of the doc... - neilg + return new DOMLocatorImpl(exception.getLineNumber(), + exception.getColumnNumber(), + exception.getCharacterOffset(), + exception.getExpandedSystemId()); + } // createDOMLocator() + + + /** + * The related platform dependent exception if any.exception is a reserved + * word, we need to rename it.Change to "relatedException". (F2F 26 Sep + * 2001) + */ + public Object getRelatedException(){ + return fException; + } + + public void reset(){ + fSeverity = DOMError.SEVERITY_WARNING; + fException = null; + } + + public String getType(){ + return fType; + } + + public Object getRelatedData(){ + return fRelatedData; + } + + +}// class DOMErrorImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationImpl.java new file mode 100644 index 0000000..d4fa6f6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationImpl.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DocumentType; + +/** + * The DOMImplementation class is description of a particular + * implementation of the Document Object Model. As such its data is + * static, shared by all instances of this implementation. + *

+ * The DOM API requires that it be a real object rather than static + * methods. However, there's nothing that says it can't be a singleton, + * so that's how I've implemented it. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DOMImplementationImpl extends CoreDOMImplementationImpl + implements DOMImplementation { + + // + // Data + // + + // static + + /** Dom implementation singleton. */ + static final DOMImplementationImpl singleton = new DOMImplementationImpl(); + + + // + // Public methods + // + + /** NON-DOM: Obtain and return the single shared object */ + public static DOMImplementation getDOMImplementation() { + return singleton; + } + + // + // DOMImplementation methods + // + + /** + * Test if the DOM implementation supports a specific "feature" -- + * currently meaning language and level thereof. + * + * @param feature The package name of the feature to test. + * In Level 1, supported values are "HTML" and "XML" (case-insensitive). + * At this writing, org.apache.xerces.dom supports only XML. + * + * @param version The version number of the feature being tested. + * This is interpreted as "Version of the DOM API supported for the + * specified Feature", and in Level 1 should be "1.0" + * + * @return true iff this implementation is compatable with the + * specified feature and version. + */ + public boolean hasFeature(String feature, String version) { + + boolean result = super.hasFeature(feature, version); + if (!result) { + boolean anyVersion = version == null || version.length() == 0; + if (feature.startsWith("+")) { + feature = feature.substring(1); + } + return ( + (feature.equalsIgnoreCase("Events") + && (anyVersion || version.equals("2.0"))) + || (feature.equalsIgnoreCase("MutationEvents") + && (anyVersion || version.equals("2.0"))) + || (feature.equalsIgnoreCase("Traversal") + && (anyVersion || version.equals("2.0"))) + || (feature.equalsIgnoreCase("Range") + && (anyVersion || version.equals("2.0"))) + || (feature.equalsIgnoreCase("MutationEvents") + && (anyVersion || version.equals("2.0")))); + } + return result; + } // hasFeature(String,String):boolean + + // + // Protected methods + // + + protected CoreDocumentImpl createDocument(DocumentType doctype) { + return new DocumentImpl(doctype); + } + +} // class DOMImplementationImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationListImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationListImpl.java new file mode 100644 index 0000000..ef54e12 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationListImpl.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.ArrayList; +import java.util.Vector; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMImplementationList; + +/** + *

This class implements the DOM Level 3 Core interface DOMImplementationList.

+ * + * @xerces.internal + * + * @author Neil Delima, IBM + * @since DOM Level 3 Core + */ +public class DOMImplementationListImpl implements DOMImplementationList { + + // A collection of DOMImplementations + private final ArrayList fImplementations; + + /** + * Construct an empty list of DOMImplementations + */ + public DOMImplementationListImpl() { + fImplementations = new ArrayList(); + } + + /** + * Construct a list of DOMImplementations from an ArrayList + */ + public DOMImplementationListImpl(ArrayList params) { + fImplementations = params; + } + + /** + * Construct a list of DOMImplementations from a Vector + */ + public DOMImplementationListImpl(Vector params) { + fImplementations = new ArrayList(params); + } + + /** + * Returns the indexth item in the collection. + * + * @param index The index of the DOMImplemetation from the list to return. + */ + public DOMImplementation item(int index) { + final int length = getLength(); + if (index >= 0 && index < length) { + return (DOMImplementation) fImplementations.get(index); + } + return null; + } + + /** + * Returns the number of DOMImplementations in the list. + * + * @return An integer indicating the number of DOMImplementations. + */ + public int getLength() { + return fImplementations.size(); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationSourceImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationSourceImpl.java new file mode 100644 index 0000000..883f73f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMImplementationSourceImpl.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.ArrayList; +import java.util.StringTokenizer; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMImplementationList; +import org.w3c.dom.DOMImplementationSource; + +/** + * Supply one the right implementation, based upon requested features. Each + * implemented DOMImplementationSource object is listed in the + * binding-specific list of available sources so that its + * DOMImplementation objects are made available. + * + *

See also the Document Object Model (DOM) Level 3 Core Specification. + * + * @xerces.internal + * + * @version $Id$ + */ +public class DOMImplementationSourceImpl + implements DOMImplementationSource { + + /** + * A method to request a DOM implementation. + * @param features A string that specifies which features are required. + * This is a space separated list in which each feature is specified + * by its name optionally followed by a space and a version number. + * This is something like: "XML 1.0 Traversal Events 2.0" + * @return An implementation that has the desired features, or + * null if this source has none. + */ + public DOMImplementation getDOMImplementation(String features) { + // first check whether the CoreDOMImplementation would do + DOMImplementation impl = + CoreDOMImplementationImpl.getDOMImplementation(); + if (testImpl(impl, features)) { + return impl; + } + // if not try the DOMImplementation + impl = DOMImplementationImpl.getDOMImplementation(); + if (testImpl(impl, features)) { + return impl; + } + + return null; + } + + /** + * A method to request a list of DOM implementations that support the + * specified features and versions, as specified in . + * @param features A string that specifies which features and versions + * are required. This is a space separated list in which each feature + * is specified by its name optionally followed by a space and a + * version number. This is something like: "XML 3.0 Traversal +Events + * 2.0" + * @return A list of DOM implementations that support the desired + * features. + */ + public DOMImplementationList getDOMImplementationList(String features) { + // first check whether the CoreDOMImplementation would do + DOMImplementation impl = CoreDOMImplementationImpl.getDOMImplementation(); + final ArrayList implementations = new ArrayList(); + if (testImpl(impl, features)) { + implementations.add(impl); + } + impl = DOMImplementationImpl.getDOMImplementation(); + if (testImpl(impl, features)) { + implementations.add(impl); + } + + return new DOMImplementationListImpl(implementations); + } + + boolean testImpl(DOMImplementation impl, String features) { + + StringTokenizer st = new StringTokenizer(features); + String feature = null; + String version = null; + + if (st.hasMoreTokens()) { + feature = st.nextToken(); + } + while (feature != null) { + boolean isVersion = false; + if (st.hasMoreTokens()) { + char c; + version = st.nextToken(); + c = version.charAt(0); + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + isVersion = true; + } + } else { + version = null; + } + if (isVersion) { + if (!impl.hasFeature(feature, version)) { + return false; + } + if (st.hasMoreTokens()) { + feature = st.nextToken(); + } else { + feature = null; + } + } else { + if (!impl.hasFeature(feature, null)) { + return false; + } + feature = version; + } + } + return true; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMInputImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMInputImpl.java new file mode 100644 index 0000000..5023702 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMInputImpl.java @@ -0,0 +1,389 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.InputStream; +import java.io.Reader; + +import org.w3c.dom.ls.LSInput; + +/** + * This Class DOMInputImpl represents a single input source for an XML entity. + *

This Class allows an application to encapsulate information about + * an input source in a single object, which may include a public + * identifier, a system identifier, a byte stream (possibly with a specified + * encoding), and/or a character stream. + *

The exact definitions of a byte stream and a character stream are + * binding dependent. + *

There are two places that the application will deliver this input + * source to the parser: as the argument to the parse method, + * or as the return value of the DOMResourceResolver.resolveEntity + * method. + *

The DOMParser will use the LSInput + * object to determine how to read XML input. If there is a character stream + * available, the parser will read that stream directly; if not, the parser + * will use a byte stream, if available; if neither a character stream nor a + * byte stream is available, the parser will attempt to open a URI + * connection to the resource identified by the system identifier. + *

An LSInput object belongs to the application: the + * parser shall never modify it in any way (it may modify a copy if + * necessary). Eventhough all attributes in this interface are writable the + * DOM implementation is expected to never mutate a LSInput. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + * + * @xerces.internal + * + * @author Gopal Sharma, SUN Microsystems Inc. + * @version $Id$ + */ + +// REVISIT: +// 1. it should be possible to do the following +// DOMInputImpl extends XMLInputSource implements LSInput +// 2. we probably need only the default constructor. -- el + +public class DOMInputImpl implements LSInput { + + // + // Data + // + + protected String fPublicId = null; + protected String fSystemId = null; + protected String fBaseSystemId = null; + + protected InputStream fByteStream = null; + protected Reader fCharStream = null; + protected String fData = null; + + protected String fEncoding = null; + + protected boolean fCertifiedText = false; + + /** + * Default Constructor, constructs an input source + * + * + */ + public DOMInputImpl() {} + + /** + * Constructs an input source from just the public and system + * identifiers, leaving resolution of the entity and opening of + * the input stream up to the caller. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + */ + + public DOMInputImpl(String publicId, String systemId, + String baseSystemId) { + + fPublicId = publicId; + fSystemId = systemId; + fBaseSystemId = baseSystemId; + + } // DOMInputImpl(String,String,String) + + /** + * Constructs an input source from a byte stream. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + * @param byteStream The byte stream. + * @param encoding The encoding of the byte stream, if known. + */ + + public DOMInputImpl(String publicId, String systemId, + String baseSystemId, InputStream byteStream, + String encoding) { + + fPublicId = publicId; + fSystemId = systemId; + fBaseSystemId = baseSystemId; + fByteStream = byteStream; + fEncoding = encoding; + + } // DOMInputImpl(String,String,String,InputStream,String) + + /** + * Constructs an input source from a character stream. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + * @param charStream The character stream. + * @param encoding The original encoding of the byte stream + * used by the reader, if known. + */ + + public DOMInputImpl(String publicId, String systemId, + String baseSystemId, Reader charStream, + String encoding) { + + fPublicId = publicId; + fSystemId = systemId; + fBaseSystemId = baseSystemId; + fCharStream = charStream; + fEncoding = encoding; + + } // DOMInputImpl(String,String,String,Reader,String) + + /** + * Constructs an input source from a String. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + * @param data The String Data. + * @param encoding The original encoding of the byte stream + * used by the reader, if known. + */ + + public DOMInputImpl(String publicId, String systemId, + String baseSystemId, String data, + String encoding) { + fPublicId = publicId; + fSystemId = systemId; + fBaseSystemId = baseSystemId; + fData = data; + fEncoding = encoding; + } // DOMInputImpl(String,String,String,String,String) + + /** + * An attribute of a language-binding dependent type that represents a + * stream of bytes. + *
The parser will ignore this if there is also a character stream + * specified, but it will use a byte stream in preference to opening a + * URI connection itself. + *
If the application knows the character encoding of the byte stream, + * it should set the encoding property. Setting the encoding in this way + * will override any encoding specified in the XML declaration itself. + */ + + public InputStream getByteStream(){ + return fByteStream; + } + + /** + * An attribute of a language-binding dependent type that represents a + * stream of bytes. + *
The parser will ignore this if there is also a character stream + * specified, but it will use a byte stream in preference to opening a + * URI connection itself. + *
If the application knows the character encoding of the byte stream, + * it should set the encoding property. Setting the encoding in this way + * will override any encoding specified in the XML declaration itself. + */ + + public void setByteStream(InputStream byteStream){ + fByteStream = byteStream; + } + + /** + * An attribute of a language-binding dependent type that represents a + * stream of 16-bit units. Application must encode the stream using + * UTF-16 (defined in and Amendment 1 of ). + *
If a character stream is specified, the parser will ignore any byte + * stream and will not attempt to open a URI connection to the system + * identifier. + */ + public Reader getCharacterStream(){ + return fCharStream; + } + /** + * An attribute of a language-binding dependent type that represents a + * stream of 16-bit units. Application must encode the stream using + * UTF-16 (defined in and Amendment 1 of ). + *
If a character stream is specified, the parser will ignore any byte + * stream and will not attempt to open a URI connection to the system + * identifier. + */ + + public void setCharacterStream(Reader characterStream){ + fCharStream = characterStream; + } + + /** + * A string attribute that represents a sequence of 16 bit units (utf-16 + * encoded characters). + *
If string data is available in the input source, the parser will + * ignore the character stream and the byte stream and will not attempt + * to open a URI connection to the system identifier. + */ + public String getStringData(){ + return fData; + } + + /** + * A string attribute that represents a sequence of 16 bit units (utf-16 + * encoded characters). + *
If string data is available in the input source, the parser will + * ignore the character stream and the byte stream and will not attempt + * to open a URI connection to the system identifier. + */ + + public void setStringData(String stringData){ + fData = stringData; + } + + /** + * The character encoding, if known. The encoding must be a string + * acceptable for an XML encoding declaration ( section 4.3.3 "Character + * Encoding in Entities"). + *
This attribute has no effect when the application provides a + * character stream. For other sources of input, an encoding specified + * by means of this attribute will override any encoding specified in + * the XML claration or the Text Declaration, or an encoding obtained + * from a higher level protocol, such as HTTP . + */ + + public String getEncoding(){ + return fEncoding; + } + + /** + * The character encoding, if known. The encoding must be a string + * acceptable for an XML encoding declaration ( section 4.3.3 "Character + * Encoding in Entities"). + *
This attribute has no effect when the application provides a + * character stream. For other sources of input, an encoding specified + * by means of this attribute will override any encoding specified in + * the XML claration or the Text Declaration, or an encoding obtained + * from a higher level protocol, such as HTTP . + */ + public void setEncoding(String encoding){ + fEncoding = encoding; + } + + /** + * The public identifier for this input source. The public identifier is + * always optional: if the application writer includes one, it will be + * provided as part of the location information. + */ + public String getPublicId(){ + return fPublicId; + } + /** + * The public identifier for this input source. The public identifier is + * always optional: if the application writer includes one, it will be + * provided as part of the location information. + */ + public void setPublicId(String publicId){ + fPublicId = publicId; + } + + /** + * The system identifier, a URI reference , for this input source. The + * system identifier is optional if there is a byte stream or a + * character stream, but it is still useful to provide one, since the + * application can use it to resolve relative URIs and can include it in + * error messages and warnings (the parser will attempt to fetch the + * ressource identifier by the URI reference only if there is no byte + * stream or character stream specified). + *
If the application knows the character encoding of the object + * pointed to by the system identifier, it can register the encoding by + * setting the encoding attribute. + *
If the system ID is a relative URI reference (see section 5 in ), + * the behavior is implementation dependent. + */ + public String getSystemId(){ + return fSystemId; + } + /** + * The system identifier, a URI reference , for this input source. The + * system identifier is optional if there is a byte stream or a + * character stream, but it is still useful to provide one, since the + * application can use it to resolve relative URIs and can include it in + * error messages and warnings (the parser will attempt to fetch the + * ressource identifier by the URI reference only if there is no byte + * stream or character stream specified). + *
If the application knows the character encoding of the object + * pointed to by the system identifier, it can register the encoding by + * setting the encoding attribute. + *
If the system ID is a relative URI reference (see section 5 in ), + * the behavior is implementation dependent. + */ + public void setSystemId(String systemId){ + fSystemId = systemId; + } + + /** + * The base URI to be used (see section 5.1.4 in ) for resolving relative + * URIs to absolute URIs. If the baseURI is itself a relative URI, the + * behavior is implementation dependent. + */ + public String getBaseURI(){ + return fBaseSystemId; + } + /** + * The base URI to be used (see section 5.1.4 in ) for resolving relative + * URIs to absolute URIs. If the baseURI is itself a relative URI, the + * behavior is implementation dependent. + */ + public void setBaseURI(String baseURI){ + fBaseSystemId = baseURI; + } + + /** + * If set to true, assume that the input is certified (see section 2.13 + * in [XML 1.1]) when + * parsing [XML 1.1]. + */ + public boolean getCertifiedText(){ + return fCertifiedText; + } + + /** + * If set to true, assume that the input is certified (see section 2.13 + * in [XML 1.1]) when + * parsing [XML 1.1]. + */ + + public void setCertifiedText(boolean certifiedText){ + fCertifiedText = certifiedText; + } + +}// class DOMInputImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMLocatorImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMLocatorImpl.java new file mode 100644 index 0000000..2def831 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMLocatorImpl.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.DOMLocator; +import org.w3c.dom.Node; + + +/** + * DOMLocatorImpl is an implementaion that describes a location (e.g. + * where an error occured). + *

See also the Document Object Model (DOM) Level 3 Core Specification. + * + * @xerces.internal + * + * @author Gopal Sharma, SUN Microsystems Inc. + * @version $Id$ + */ + +public class DOMLocatorImpl implements DOMLocator { + + // + // Data + // + + /** + * The column number where the error occured, + * or -1 if there is no column number available. + */ + public int fColumnNumber = -1; + + /** + * The line number where the error occured, + * or -1 if there is no line number available. + */ + public int fLineNumber = -1; + + /** related data node*/ + public Node fRelatedNode = null; + + /** + * The URI where the error occured, + * or null if there is no URI available. + */ + public String fUri = null; + + /** + * The byte offset into the input source this locator is pointing to or -1 + * if there is no byte offset available + */ + public int fByteOffset = -1; + + /** + * The UTF-16, as defined in [Unicode] and Amendment 1 of [ISO/IEC 10646], + * offset into the input source this locator is pointing to or -1 if there + * is no UTF-16 offset available. + */ + public int fUtf16Offset = -1; + + // + // Constructors + // + + public DOMLocatorImpl(){ + } + + public DOMLocatorImpl (int lineNumber, int columnNumber, String uri ){ + fLineNumber = lineNumber ; + fColumnNumber = columnNumber ; + fUri = uri; + } // DOMLocatorImpl (int lineNumber, int columnNumber, String uri ) + + public DOMLocatorImpl (int lineNumber, int columnNumber, int utf16Offset, String uri ){ + fLineNumber = lineNumber ; + fColumnNumber = columnNumber ; + fUri = uri; + fUtf16Offset = utf16Offset; + } // DOMLocatorImpl (int lineNumber, int columnNumber, int utf16Offset, String uri ) + + public DOMLocatorImpl (int lineNumber, int columnNumber, int byteoffset, Node relatedData, String uri ){ + fLineNumber = lineNumber ; + fColumnNumber = columnNumber ; + fByteOffset = byteoffset ; + fRelatedNode = relatedData ; + fUri = uri; + } // DOMLocatorImpl (int lineNumber, int columnNumber, int offset, Node errorNode, String uri ) + + public DOMLocatorImpl (int lineNumber, int columnNumber, int byteoffset, Node relatedData, String uri, int utf16Offset ){ + fLineNumber = lineNumber ; + fColumnNumber = columnNumber ; + fByteOffset = byteoffset ; + fRelatedNode = relatedData ; + fUri = uri; + fUtf16Offset = utf16Offset; + } // DOMLocatorImpl (int lineNumber, int columnNumber, int offset, Node errorNode, String uri ) + + + /** + * The line number where the error occured, or -1 if there is no line + * number available. + */ + public int getLineNumber(){ + return fLineNumber; + } + + /** + * The column number where the error occured, or -1 if there is no column + * number available. + */ + public int getColumnNumber(){ + return fColumnNumber; + } + + + /** + * The URI where the error occured, or null if there is no URI available. + */ + public String getUri(){ + return fUri; + } + + + public Node getRelatedNode(){ + return fRelatedNode; + } + + + /** + * The byte offset into the input source this locator is pointing to or -1 + * if there is no byte offset available + */ + public int getByteOffset(){ + return fByteOffset; + } + + /** + * The UTF-16, as defined in [Unicode] and Amendment 1 of [ISO/IEC 10646], + * offset into the input source this locator is pointing to or -1 if there + * is no UTF-16 offset available. + */ + public int getUtf16Offset(){ + return fUtf16Offset; + } + +}// class DOMLocatorImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMMessageFormatter.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMMessageFormatter.java new file mode 100644 index 0000000..36ce3f1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMMessageFormatter.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * Used to format DOM error messages, using the system locale. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @version $Id$ + */ +public class DOMMessageFormatter { + + public static final String DOM_DOMAIN = "http://www.w3.org/dom/DOMTR"; + public static final String XML_DOMAIN = "http://www.w3.org/TR/1998/REC-xml-19980210"; + public static final String SERIALIZER_DOMAIN = "http://apache.org/xml/serializer"; + + private static ResourceBundle domResourceBundle = null; + private static ResourceBundle xmlResourceBundle = null; + private static ResourceBundle serResourceBundle = null; + private static Locale locale = null; + + DOMMessageFormatter() { + locale = Locale.getDefault(); + } + + /** + * Formats a message with the specified arguments using the given + * locale information. + * + * @param domain domain from which error string is to come. + * @param key The message key. + * @param arguments The message replacement text arguments. The order + * of the arguments must match that of the placeholders + * in the actual message. + * + * @return the formatted message. + * + * @throws MissingResourceException Thrown if the message with the + * specified key cannot be found. + */ + public static String formatMessage(String domain, + String key, Object[] arguments) + throws MissingResourceException { + ResourceBundle resourceBundle = getResourceBundle(domain); + if(resourceBundle == null){ + init(); + resourceBundle = getResourceBundle(domain); + if(resourceBundle == null) + throw new MissingResourceException("Unknown domain" + domain, null, key); + } + // format message + String msg; + try { + msg = key + ": " + resourceBundle.getString(key); + if (arguments != null) { + try { + msg = java.text.MessageFormat.format(msg, arguments); + } + catch (Exception e) { + msg = resourceBundle.getString("FormatFailed"); + msg += " " + resourceBundle.getString(key); + } + } + } // error + catch (MissingResourceException e) { + msg = resourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(key, msg, key); + } + + // no message + if (msg == null) { + msg = key; + if (arguments.length > 0) { + StringBuffer str = new StringBuffer(msg); + str.append('?'); + for (int i = 0; i < arguments.length; i++) { + if (i > 0) { + str.append('&'); + } + str.append(String.valueOf(arguments[i])); + } + } + } + + return msg; + } + + static ResourceBundle getResourceBundle(String domain) { + if (domain == DOM_DOMAIN || domain.equals(DOM_DOMAIN)) { + return domResourceBundle; + } + else if (domain == XML_DOMAIN || domain.equals(XML_DOMAIN)) { + return xmlResourceBundle; + } + else if (domain == SERIALIZER_DOMAIN || domain.equals(SERIALIZER_DOMAIN)) { + return serResourceBundle; + } + return null; + } + + /** + * Initialize Message Formatter. + */ + public static void init() { + Locale _locale = locale; + if (_locale == null) { + _locale = Locale.getDefault(); + } + domResourceBundle = ResourceBundle.getBundle("org.apache.xerces.impl.msg.DOMMessages", _locale); + serResourceBundle = ResourceBundle.getBundle("org.apache.xerces.impl.msg.XMLSerializerMessages", _locale); + xmlResourceBundle = ResourceBundle.getBundle("org.apache.xerces.impl.msg.XMLMessages", _locale); + } + + /** + * Set Locale to be used by the formatter. + * @param dlocale + */ + public static void setLocale(Locale dlocale) { + locale = dlocale; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMNormalizer.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMNormalizer.java new file mode 100644 index 0000000..2263f5f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMNormalizer.java @@ -0,0 +1,2101 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Vector; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.RevalidationHandler; +import org.apache.xerces.impl.dtd.XMLDTDLoader; +import org.apache.xerces.impl.dtd.XMLDTDValidator; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xs.util.SimpleLocator; +import org.apache.xerces.util.AugmentationsImpl; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.Attr; +import org.w3c.dom.Comment; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Entity; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +/** + * This class adds implementation for normalizeDocument method. + * It acts as if the document was going through a save and load cycle, putting + * the document in a "normal" form. The actual result depends on the features being set + * and governing what operations actually take place. See setNormalizationFeature for details. + * Noticeably this method normalizes Text nodes, makes the document "namespace wellformed", + * according to the algorithm described below in pseudo code, by adding missing namespace + * declaration attributes and adding or changing namespace prefixes, updates the replacement + * tree of EntityReference nodes, normalizes attribute values, etc. + * Mutation events, when supported, are generated to reflect the changes occuring on the + * document. + * See Namespace normalization for details on how namespace declaration attributes and prefixes + * are normalized. + * + * NOTE: There is an initial support for DOM revalidation with XML Schema as a grammar. + * The tree might not be validated correctly if entityReferences, CDATA sections are + * present in the tree. The PSVI information is not exposed, normalized data (including element + * default content is not available). + * + * @xerces.experimental + * + * @author Elena Litani, IBM + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @version $Id$ + */ +public class DOMNormalizer implements XMLDocumentHandler { + + // + // constants + // + /** Debug normalize document*/ + protected final static boolean DEBUG_ND = false; + /** Debug namespace fix up algorithm*/ + protected final static boolean DEBUG = false; + /** Debug document handler events */ + protected final static boolean DEBUG_EVENTS = false; + + /** prefix added by namespace fixup algorithm should follow a pattern "NS" + index*/ + protected final static String PREFIX = "NS"; + + // + // Data + // + protected DOMConfigurationImpl fConfiguration = null; + protected CoreDocumentImpl fDocument = null; + protected final XMLAttributesProxy fAttrProxy = new XMLAttributesProxy(); + protected final QName fQName = new QName(); + + /** Validation handler represents validator instance. */ + protected RevalidationHandler fValidationHandler; + + /** symbol table */ + protected SymbolTable fSymbolTable; + /** error handler. may be null. */ + protected DOMErrorHandler fErrorHandler; + + /** + * Cached {@link DOMError} impl. + * The same object is re-used to report multiple errors. + */ + private final DOMErrorImpl fError = new DOMErrorImpl(); + + // Validation against namespace aware grammar + protected boolean fNamespaceValidation = false; + + // Update PSVI information in the tree + protected boolean fPSVI = false; + + /** The namespace context of this document: stores namespaces in scope */ + protected final NamespaceContext fNamespaceContext = new NamespaceSupport(); + + /** Stores all namespace bindings on the current element */ + protected final NamespaceContext fLocalNSBinder = new NamespaceSupport(); + + /** list of attributes */ + protected final ArrayList fAttributeList = new ArrayList(5); + + /** DOM Locator - for namespace fixup algorithm */ + protected final DOMLocatorImpl fLocator = new DOMLocatorImpl(); + + /** for setting the PSVI */ + protected Node fCurrentNode = null; + private final QName fAttrQName = new QName(); + + // attribute value normalization + final XMLString fNormalizedValue = new XMLString(new char[16], 0, 0); + + /** + * If the user stops the process, this exception will be thrown. + */ + public static final RuntimeException abort = new RuntimeException() { + private static final long serialVersionUID = 5361322877988412432L; + public Throwable fillInStackTrace() { + return this; + } + }; + + /** Empty string to pass to the validator. **/ + public static final XMLString EMPTY_STRING = new XMLString(); + + // Check if element content is all "ignorable whitespace" + private boolean fAllWhitespace = false; + + // Constructor + // + + public DOMNormalizer(){} + + + + /** + * Normalizes document. + * Note: reset() must be called before this method. + */ + protected void normalizeDocument(CoreDocumentImpl document, DOMConfigurationImpl config) { + + fDocument = document; + fConfiguration = config; + fAllWhitespace = false; + fNamespaceValidation = false; + + String xmlVersion = fDocument.getXmlVersion(); + String schemaType = null; + String [] schemaLocations = null; + + // intialize and reset DOMNormalizer component + // + fSymbolTable = (SymbolTable) fConfiguration.getProperty(DOMConfigurationImpl.SYMBOL_TABLE); + // reset namespace context + fNamespaceContext.reset(); + fNamespaceContext.declarePrefix(XMLSymbols.EMPTY_STRING, null); + + if ((fConfiguration.features & DOMConfigurationImpl.VALIDATE) != 0) { + String schemaLang = (String)fConfiguration.getProperty(DOMConfigurationImpl.JAXP_SCHEMA_LANGUAGE); + + if (schemaLang != null && schemaLang.equals(Constants.NS_XMLSCHEMA)) { + schemaType = XMLGrammarDescription.XML_SCHEMA; + fValidationHandler = CoreDOMImplementationImpl.singleton.getValidator(schemaType, xmlVersion); + fConfiguration.setFeature(DOMConfigurationImpl.SCHEMA, true); + fConfiguration.setFeature(DOMConfigurationImpl.SCHEMA_FULL_CHECKING, true); + // report fatal error on DOM Level 1 nodes + fNamespaceValidation = true; + + // check if we need to fill in PSVI + fPSVI = ((fConfiguration.features & DOMConfigurationImpl.PSVI) !=0)?true:false; + } + else { + schemaType = XMLGrammarDescription.XML_DTD; + if (schemaLang != null) { + schemaLocations = (String []) fConfiguration.getProperty(DOMConfigurationImpl.JAXP_SCHEMA_SOURCE); + } + fConfiguration.setDTDValidatorFactory(xmlVersion); + fValidationHandler = CoreDOMImplementationImpl.singleton.getValidator(schemaType, xmlVersion); + fPSVI = false; + } + + fConfiguration.setFeature(DOMConfigurationImpl.XERCES_VALIDATION, true); + + // reset ID table + fDocument.clearIdentifiers(); + + if (fValidationHandler != null) { + // reset the validation handler + ((XMLComponent) fValidationHandler).reset(fConfiguration); + } + } + else { + fValidationHandler = null; + } + + fErrorHandler = (DOMErrorHandler) fConfiguration.getParameter(Constants.DOM_ERROR_HANDLER); + if (fValidationHandler != null) { + fValidationHandler.setDocumentHandler(this); + fValidationHandler.startDocument( + new SimpleLocator(fDocument.fDocumentURI, fDocument.fDocumentURI, + -1, -1 ), fDocument.encoding, fNamespaceContext, null); + fValidationHandler.xmlDecl(fDocument.getXmlVersion(), + fDocument.getXmlEncoding(), fDocument.getXmlStandalone() ? "yes" : "no", null); + } + try { + if (schemaType == XMLGrammarDescription.XML_DTD) { + processDTD(xmlVersion, schemaLocations != null ? schemaLocations[0] : null); + } + + Node kid, next; + for (kid = fDocument.getFirstChild(); kid != null; kid = next) { + next = kid.getNextSibling(); + kid = normalizeNode(kid); + if (kid != null) { // don't advance + next = kid; + } + } + + // release resources + if (fValidationHandler != null) { + fValidationHandler.endDocument(null); + fValidationHandler.setDocumentHandler(null); + CoreDOMImplementationImpl.singleton.releaseValidator(schemaType, xmlVersion, fValidationHandler); + fValidationHandler = null; + } + } + catch (RuntimeException e) { + // release resources + if (fValidationHandler != null) { + fValidationHandler.setDocumentHandler(null); + CoreDOMImplementationImpl.singleton.releaseValidator(schemaType, xmlVersion, fValidationHandler); + fValidationHandler = null; + } + if (e == abort) { + return; // processing aborted by the user + } + throw e; // otherwise re-throw. + } + } + + /** + * + * This method acts as if the document was going through a save + * and load cycle, putting the document in a "normal" form. The actual result + * depends on the features being set and governing what operations actually + * take place. See setNormalizationFeature for details. Noticeably this method + * normalizes Text nodes, makes the document "namespace wellformed", + * according to the algorithm described below in pseudo code, by adding missing + * namespace declaration attributes and adding or changing namespace prefixes, updates + * the replacement tree of EntityReference nodes,normalizes attribute values, etc. + * + * @param node Modified node or null. If node is returned, we need + * to normalize again starting on the node returned. + * @return the normalized Node + */ + protected Node normalizeNode (Node node){ + + int type = node.getNodeType(); + boolean wellformed; + fLocator.fRelatedNode=node; + + switch (type) { + case Node.DOCUMENT_TYPE_NODE: { + if (DEBUG_ND) { + System.out.println("==>normalizeNode:{doctype}"); + } + // REVISIT: well-formedness encoding info + break; + } + + case Node.ELEMENT_NODE: { + if (DEBUG_ND) { + System.out.println("==>normalizeNode:{element} "+node.getNodeName()); + } + + //do the name check only when version of the document was changed & + //application has set the value of well-formed features to true + if (fDocument.errorChecking) { + if ( ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0) && + fDocument.isXMLVersionChanged()){ + if (fNamespaceValidation){ + wellformed = CoreDocumentImpl.isValidQName(node.getPrefix() , node.getLocalName(), fDocument.isXML11Version()); + } + else { + wellformed = CoreDocumentImpl.isXMLName(node.getNodeName() , fDocument.isXML11Version()); + } + if (!wellformed){ + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Element", node.getNodeName()}); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR, + "wf-invalid-character-in-node-name"); + } + } + } + // push namespace context + fNamespaceContext.pushContext(); + fLocalNSBinder.reset(); + + ElementImpl elem = (ElementImpl)node; + if (elem.needsSyncChildren()) { + elem.synchronizeChildren(); + } + AttributeMap attributes = (elem.hasAttributes()) ? (AttributeMap) elem.getAttributes() : null; + + // fix namespaces and remove default attributes + if ((fConfiguration.features & DOMConfigurationImpl.NAMESPACES) !=0) { + // fix namespaces + // normalize attribute values + // remove default attributes + namespaceFixUp(elem, attributes); + + if ((fConfiguration.features & DOMConfigurationImpl.NSDECL) == 0) { + // Namespace declarations may have been added by namespace fix-up. Need + // to fetch the AttributeMap again if it contained no attributes prior + // to namespace fix-up. + if (attributes == null) { + attributes = (elem.hasAttributes()) ? (AttributeMap) elem.getAttributes() : null; + } + if (attributes != null) { + for (int i = 0; i < attributes.getLength(); ++i) { + Attr att = (Attr)attributes.getItem(i); + if (XMLSymbols.PREFIX_XMLNS.equals(att.getPrefix()) || + XMLSymbols.PREFIX_XMLNS.equals(att.getName())) { + elem.removeAttributeNode(att); + --i; + } + } + } + } + + } else { + if ( attributes!=null ) { + for ( int i=0; inormalizeNode:{comments}"); + } + + if ((fConfiguration.features & DOMConfigurationImpl.COMMENTS) == 0) { + Node prevSibling = node.getPreviousSibling(); + Node parent = node.getParentNode(); + // remove the comment node + parent.removeChild(node); + if (prevSibling != null && prevSibling.getNodeType() == Node.TEXT_NODE) { + Node nextSibling = prevSibling.getNextSibling(); + if (nextSibling != null && nextSibling.getNodeType() == Node.TEXT_NODE) { + ((TextImpl)nextSibling).insertData(0, prevSibling.getNodeValue()); + parent.removeChild(prevSibling); + return nextSibling; + } + } + }//if comment node need not be removed + else { + if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0)){ + String commentdata = ((Comment)node).getData(); + // check comments for invalid xml chracter as per the version + // of the document + isCommentWF(fErrorHandler, fError, fLocator, commentdata, fDocument.isXML11Version()); + } + if (fValidationHandler != null) { + // Don't bother filling an XMLString with the text of the comment. + // We only send the comment event to the validator handler so that + // when the schema-type is DTD an error will be reported for a + // comment appearing in EMPTY content. + fValidationHandler.comment(EMPTY_STRING, null); + } + }//end-else if comment node is not to be removed. + break; + } + case Node.ENTITY_REFERENCE_NODE: { + if (DEBUG_ND) { + System.out.println("==>normalizeNode:{entityRef} "+node.getNodeName()); + } + + if ((fConfiguration.features & DOMConfigurationImpl.ENTITIES) == 0) { + Node prevSibling = node.getPreviousSibling(); + Node parent = node.getParentNode(); + ((EntityReferenceImpl)node).setReadOnly(false, true); + expandEntityRef (parent, node); + parent.removeChild(node); + Node next = (prevSibling != null)?prevSibling.getNextSibling():parent.getFirstChild(); + // The list of children #text -> &ent; + // and entity has a first child as a text + // we should not advance + if (prevSibling != null && next != null && prevSibling.getNodeType() == Node.TEXT_NODE && + next.getNodeType() == Node.TEXT_NODE) { + return prevSibling; // Don't advance + } + return next; + } else { + if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0) && + fDocument.isXMLVersionChanged()){ + CoreDocumentImpl.isXMLName(node.getNodeName() , fDocument.isXML11Version()); + } + // REVISIT: traverse entity reference and send appropriate calls to the validator + // (no normalization should be performed for the children). + } + break; + } + + case Node.CDATA_SECTION_NODE: { + if (DEBUG_ND) { + System.out.println("==>normalizeNode:{cdata}"); + } + + if ((fConfiguration.features & DOMConfigurationImpl.CDATA) == 0) { + // convert CDATA to TEXT nodes + Node prevSibling = node.getPreviousSibling(); + if (prevSibling != null && prevSibling.getNodeType() == Node.TEXT_NODE){ + ((Text)prevSibling).appendData(node.getNodeValue()); + node.getParentNode().removeChild(node); + return prevSibling; //don't advance + } + else { + Text text = fDocument.createTextNode(node.getNodeValue()); + Node parent = node.getParentNode(); + node = parent.replaceChild(text, node); + return text; //don't advance + + } + } + + // send characters call for CDATA + if (fValidationHandler != null) { + // set error node in the dom error wrapper + // so if error occurs we can report an error node + fConfiguration.fErrorHandlerWrapper.fCurrentNode = node; + fCurrentNode = node; + fValidationHandler.startCDATA(null); + fValidationHandler.characterData(node.getNodeValue(), null); + fValidationHandler.endCDATA(null); + } + String value = node.getNodeValue(); + + if ((fConfiguration.features & DOMConfigurationImpl.SPLITCDATA) != 0) { + int index; + Node parent = node.getParentNode(); + if (fDocument.errorChecking) { + isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), fDocument.isXML11Version()); + } + while ( (index=value.indexOf("]]>")) >= 0 ) { + node.setNodeValue(value.substring(0, index+2)); + value = value.substring(index +2); + + Node firstSplitNode = node; + Node newChild = fDocument.createCDATASection(value); + parent.insertBefore(newChild, node.getNextSibling()); + node = newChild; + // issue warning + fLocator.fRelatedNode = firstSplitNode; + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "cdata-sections-splitted", + null); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_WARNING, + "cdata-sections-splitted"); + } + + } + else if (fDocument.errorChecking) { + // check well-formedness + isCDataWF(fErrorHandler, fError, fLocator, value, fDocument.isXML11Version()); + } + break; + } + + case Node.TEXT_NODE: { + if (DEBUG_ND) { + System.out.println("==>normalizeNode(text):{"+node.getNodeValue()+"}"); + } + // If node is a text node, we need to check for one of two + // conditions: + // 1) There is an adjacent text node + // 2) There is no adjacent text node, but node is + // an empty text node. + Node next = node.getNextSibling(); + // If an adjacent text node, merge it with this node + if ( next!=null && next.getNodeType() == Node.TEXT_NODE ) { + ((Text)node).appendData(next.getNodeValue()); + node.getParentNode().removeChild( next ); + // We don't need to check well-formness here since we are not yet + // done with this node. + + return node; // Don't advance; + } else if (node.getNodeValue().length()==0) { + // If kid is empty, remove it + node.getParentNode().removeChild( node ); + } else { + // validator.characters() call and well-formness + // Don't send characters or check well-formness in the following cases: + // 1. entities is false, next child is entity reference: expand tree first + // 2. comments is false, and next child is comment + // 3. cdata is false, and next child is cdata + + short nextType = (next != null)?next.getNodeType():-1; + if (nextType == -1 || !(((fConfiguration.features & DOMConfigurationImpl.ENTITIES) == 0 && + nextType == Node.ENTITY_NODE) || + ((fConfiguration.features & DOMConfigurationImpl.COMMENTS) == 0 && + nextType == Node.COMMENT_NODE) || + ((fConfiguration.features & DOMConfigurationImpl.CDATA) == 0) && + nextType == Node.CDATA_SECTION_NODE)) { + if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0) ){ + isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), fDocument.isXML11Version()); + } + if (fValidationHandler != null) { + fConfiguration.fErrorHandlerWrapper.fCurrentNode = node; + fCurrentNode = node; + fValidationHandler.characterData(node.getNodeValue(), null); + if (!fNamespaceValidation) { + if (fAllWhitespace) { + fAllWhitespace = false; + ((TextImpl)node).setIgnorableWhitespace(true); + } + else { + ((TextImpl)node).setIgnorableWhitespace(false); + } + } + if (DEBUG_ND) { + System.out.println("=====>characterData(),"+nextType); + } + } + } + else { + if (DEBUG_ND) { + System.out.println("=====>don't send characters(),"+nextType); + + } + } + } + break; + } + case Node.PROCESSING_INSTRUCTION_NODE: { + + //do the well-formed valid PI target name , data check when application has set the value of well-formed feature to true + if (fDocument.errorChecking && (fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0 ) { + ProcessingInstruction pinode = (ProcessingInstruction)node ; + + String target = pinode.getTarget(); + //1.check PI target name + if(fDocument.isXML11Version()){ + wellformed = XML11Char.isXML11ValidName(target); + } + else{ + wellformed = XMLChar.isValidName(target); + } + + if (!wellformed) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Element", node.getNodeName()}); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR, + "wf-invalid-character-in-node-name"); + } + + //2. check PI data + //processing isntruction data may have certain characters + //which may not be valid XML character + isXMLCharWF(fErrorHandler, fError, fLocator, pinode.getData(), fDocument.isXML11Version()); + } + + if (fValidationHandler != null) { + // Don't bother filling an XMLString with the data section of the + // processing instruction. We only send the processing instruction + // event to the validator handler so that when the schema-type is + // DTD an error will be reported for a processing instruction + // appearing in EMPTY content. + fValidationHandler.processingInstruction(((ProcessingInstruction) node).getTarget(), EMPTY_STRING, null); + } + }//end case Node.PROCESSING_INSTRUCTION_NODE + + }//end of switch + return null; + }//normalizeNode + + private void processDTD(String xmlVersion, String schemaLocation) { + + String rootName = null; + String publicId = null; + String systemId = schemaLocation; + String baseSystemId = fDocument.getDocumentURI(); + String internalSubset = null; + + DocumentType docType = fDocument.getDoctype(); + if (docType != null) { + rootName = docType.getName(); + publicId = docType.getPublicId(); + if (systemId == null || systemId.length() == 0) { + systemId = docType.getSystemId(); + } + internalSubset = docType.getInternalSubset(); + } + // If the DOM doesn't have a DocumentType node we may still + // be able to fetch a DTD if the application provided a URI + else { + Element elem = fDocument.getDocumentElement(); + if (elem == null) return; + rootName = elem.getNodeName(); + if (systemId == null || systemId.length() == 0) return; + } + + XMLDTDLoader loader = null; + try { + fValidationHandler.doctypeDecl(rootName, publicId, systemId, null); + loader = CoreDOMImplementationImpl.singleton.getDTDLoader(xmlVersion); + loader.setFeature(DOMConfigurationImpl.XERCES_VALIDATION, true); + loader.setEntityResolver(fConfiguration.getEntityResolver()); + loader.setErrorHandler(fConfiguration.getErrorHandler()); + loader.loadGrammarWithContext((XMLDTDValidator) fValidationHandler, rootName, + publicId, systemId, baseSystemId, internalSubset); + } + // REVISIT: Should probably report this exception to the error handler. + catch (IOException e) { + } + finally { + if (loader != null) { + CoreDOMImplementationImpl.singleton.releaseDTDLoader(xmlVersion, loader); + } + } + } // processDTD(String, String) + + protected final void expandEntityRef (Node parent, Node reference){ + Node kid, next; + for (kid = reference.getFirstChild(); kid != null; kid = next) { + next = kid.getNextSibling(); + parent.insertBefore(kid, reference); + } + } + + // fix namespaces + // normalize attribute values + // remove default attributes + // check attribute names if the version of the document changed. + + protected final void namespaceFixUp (ElementImpl element, AttributeMap attributes){ + if (DEBUG) { + System.out.println("[ns-fixup] element:" +element.getNodeName()+ + " uri: "+element.getNamespaceURI()); + } + + // ------------------------------------ + // pick up local namespace declarations + // + // + // + // + // ------------------------------------ + + String value, uri, prefix; + if (attributes != null) { + + // Record all valid local declarations + for (int k = 0; k < attributes.getLength(); ++k) { + Attr attr = (Attr)attributes.getItem(k); + uri = attr.getNamespaceURI(); + if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) { + // namespace attribute + value = attr.getNodeValue(); + if (value == null) { + value=XMLSymbols.EMPTY_STRING; + } + + // Check for invalid namespace declaration: + if (fDocument.errorChecking && value.equals(NamespaceContext.XMLNS_URI)) { + //A null value for locale is passed to formatMessage, + //which means that the default locale will be used + fLocator.fRelatedNode = attr; + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN,"CantBindXMLNS",null ); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR, "CantBindXMLNS"); + } else { + // XML 1.0 Attribute value normalization + // value = normalizeAttributeValue(value, attr); + prefix = attr.getPrefix(); + prefix = (prefix == null || + prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix); + String localpart = fSymbolTable.addSymbol( attr.getLocalName()); + if (prefix == XMLSymbols.PREFIX_XMLNS) { //xmlns:prefix + + value = fSymbolTable.addSymbol(value); + if (value.length() != 0) { + fNamespaceContext.declarePrefix(localpart, value); + } else { + // REVISIT: issue error on invalid declarations + // xmlns:foo = "" + + } + //removeDefault (attr, attributes); + continue; + } else { // (localpart == fXmlnsSymbol && prefix == fEmptySymbol) -- xmlns + // empty prefix is always bound ("" or some string) + value = fSymbolTable.addSymbol(value); + fNamespaceContext.declarePrefix(XMLSymbols.EMPTY_STRING, value.length() != 0 ? value : null); + //removeDefault (attr, attributes); + continue; + } + } // end-else: valid declaration + } // end-if: namespace attribute + } + } + + + + // --------------------------------------------------------- + // Fix up namespaces for element: per DOM L3 + // Need to consider the following cases: + // + // case 1: + // We create another element body bound to the "http://xsl" namespace + // as well as namespace attribute rebounding xsl to another namespace. + // + // Need to make sure that the new namespace decl value is changed to + // "http://xsl" + // + // --------------------------------------------------------- + // check if prefix/namespace is correct for current element + // --------------------------------------------------------- + + uri = element.getNamespaceURI(); + prefix = element.getPrefix(); + if (uri != null) { // Element has a namespace + uri = fSymbolTable.addSymbol(uri); + prefix = (prefix == null || + prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix); + if (fNamespaceContext.getURI(prefix) == uri) { + // The xmlns:prefix=namespace or xmlns="default" was declared at parent. + // The binder always stores mapping of empty prefix to "". + } else { + // the prefix is either undeclared + // or + // conflict: the prefix is bound to another URI + addNamespaceDecl(prefix, uri, element); + fLocalNSBinder.declarePrefix(prefix, uri); + fNamespaceContext.declarePrefix(prefix, uri); + } + } else { // Element has no namespace + if (element.getLocalName() == null) { + + // Error: DOM Level 1 node! + if (fNamespaceValidation) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, "NullLocalElementName", + new Object[]{element.getNodeName()}); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, + "NullLocalElementName"); + } else { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, "NullLocalElementName", + new Object[]{element.getNodeName()}); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR, + "NullLocalElementName"); + } + + } else { // uri=null and no colon (DOM L2 node) + uri = fNamespaceContext.getURI(XMLSymbols.EMPTY_STRING); + if (uri !=null && uri.length() > 0) { + // undeclare default namespace declaration (before that element + // bound to non-zero length uir), but adding xmlns="" decl + addNamespaceDecl (XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING, element); + fLocalNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, null); + fNamespaceContext.declarePrefix(XMLSymbols.EMPTY_STRING, null); + } + } + } + + // ----------------------------------------- + // Fix up namespaces for attributes: per DOM L3 + // check if prefix/namespace is correct the attributes + // ----------------------------------------- + if (attributes != null) { + + // clone content of the attributes + attributes.cloneMap(fAttributeList); + for (int i = 0; i < fAttributeList.size(); i++) { + Attr attr = (Attr) fAttributeList.get(i); + fLocator.fRelatedNode = attr; + + if (DEBUG) { + System.out.println("==>[ns-fixup] process attribute: "+attr.getNodeName()); + } + // normalize attribute value + attr.normalize(); + value = attr.getValue(); + uri = attr.getNamespaceURI(); + + // make sure that value is never null. + if (value == null) { + value = XMLSymbols.EMPTY_STRING; + } + + //--------------------------------------- + // check if value of the attribute is namespace well-formed + //--------------------------------------- + if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0)) { + isAttrValueWF(fErrorHandler, fError, fLocator, attributes, attr, value, fDocument.isXML11Version()); + if (fDocument.isXMLVersionChanged()) { + boolean wellformed; + if (fNamespaceValidation){ + wellformed = CoreDocumentImpl.isValidQName(attr.getPrefix(), attr.getLocalName(), fDocument.isXML11Version()); + } + else { + wellformed = CoreDocumentImpl.isXMLName(attr.getNodeName(), fDocument.isXML11Version()); + } + if (!wellformed) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Attr", attr.getNodeName()}); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR, + "wf-invalid-character-in-node-name"); + } + } + } + + if (uri != null) { // attribute has namespace !=null + prefix = attr.getPrefix(); + prefix = (prefix == null || + prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix); + /*String localpart =*/ fSymbolTable.addSymbol( attr.getLocalName()); + + // --------------------------------------- + // skip namespace declarations + // --------------------------------------- + // REVISIT: can we assume that "uri" is from some symbol + // table, and compare by reference? -SG + if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) { + continue; + } + + // --------------------------------------- + // remove default attributes + // --------------------------------------- + /* + if (removeDefault(attr, attributes)) { + continue; + } + */ + // XML 1.0 Attribute value normalization + //value = normalizeAttributeValue(value, attr); + + // reset id-attributes + ((AttrImpl)attr).setIdAttribute(false); + + uri = fSymbolTable.addSymbol(uri); + + // find if for this prefix a URI was already declared + String declaredURI = fNamespaceContext.getURI(prefix); + + if (prefix == XMLSymbols.EMPTY_STRING || declaredURI != uri) { + // attribute has no prefix (default namespace decl does not apply to attributes) + // OR + // attribute prefix is not declared + // OR + // conflict: attribute has a prefix that conficlicts with a binding + // already active in scope + + // Find if any prefix for attributes namespace URI is available + // in the scope + String declaredPrefix = fNamespaceContext.getPrefix(uri); + if (declaredPrefix !=null && declaredPrefix !=XMLSymbols.EMPTY_STRING) { + + // use the prefix that was found (declared previously for this URI + prefix = declaredPrefix; + } else { + if (prefix != XMLSymbols.EMPTY_STRING && fLocalNSBinder.getURI(prefix) == null) { + // the current prefix is not null and it has no in scope declaration + + // use this prefix + } else { + + // find a prefix following the pattern "NS" +index (starting at 1) + // make sure this prefix is not declared in the current scope. + int counter = 1; + prefix = fSymbolTable.addSymbol(PREFIX +counter++); + while (fLocalNSBinder.getURI(prefix)!=null) { + prefix = fSymbolTable.addSymbol(PREFIX +counter++); + } + + } + // add declaration for the new prefix + addNamespaceDecl(prefix, uri, element); + value = fSymbolTable.addSymbol(value); + fLocalNSBinder.declarePrefix(prefix, value); + fNamespaceContext.declarePrefix(prefix, uri); + } + + // change prefix for this attribute + attr.setPrefix(prefix); + } + } else { // attribute uri == null + + // XML 1.0 Attribute value normalization + //value = normalizeAttributeValue(value, attr); + + // reset id-attributes + ((AttrImpl)attr).setIdAttribute(false); + + if (attr.getLocalName() == null) { + // It is an error if document has DOM L1 nodes. + if (fNamespaceValidation) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NullLocalAttrName", new Object[]{attr.getNodeName()}); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, + "NullLocalAttrName"); + } else { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NullLocalAttrName", new Object[]{attr.getNodeName()}); + reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR, + "NullLocalAttrName"); + } + } else { + // uri=null and no colon + // no fix up is needed: default namespace decl does not + + // --------------------------------------- + // remove default attributes + // --------------------------------------- + // removeDefault(attr, attributes); + } + } + } + } // end loop for attributes + } + + /** + * Adds a namespace attribute or replaces the value of existing namespace + * attribute with the given prefix and value for URI. + * In case prefix is empty will add/update default namespace declaration. + * + * @param prefix + * @param uri + * @exception IOException + */ + + protected final void addNamespaceDecl(String prefix, String uri, ElementImpl element){ + if (DEBUG) { + System.out.println("[ns-fixup] addNamespaceDecl ["+prefix+"]"); + } + if (prefix == XMLSymbols.EMPTY_STRING) { + if (DEBUG) { + System.out.println("=>add xmlns=\""+uri+"\" declaration"); + } + element.setAttributeNS(NamespaceContext.XMLNS_URI, XMLSymbols.PREFIX_XMLNS, uri); + } else { + if (DEBUG) { + System.out.println("=>add xmlns:"+prefix+"=\""+uri+"\" declaration"); + } + element.setAttributeNS(NamespaceContext.XMLNS_URI, "xmlns:"+prefix, uri); + } + } + + + // + // Methods for well-formness checking + // + + + /** + * Check if CDATA section is well-formed + * @param datavalue + * @param isXML11Version = true if XML 1.1 + */ + public static final void isCDataWF(DOMErrorHandler errorHandler, DOMErrorImpl error, DOMLocatorImpl locator, + String datavalue, boolean isXML11Version) + { + if (datavalue == null || (datavalue.length() == 0) ) { + return; + } + + char [] dataarray = datavalue.toCharArray(); + int datalength = dataarray.length; + + // version of the document is XML 1.1 + if (isXML11Version) { + // we need to check all chracters as per production rules of XML11 + int i = 0; + while(i < datalength){ + char c = dataarray[i++]; + if ( XML11Char.isXML11Invalid(c) ) { + // check if this is a supplemental character + if (XMLChar.isHighSurrogate(c) && i < datalength) { + char c2 = dataarray[i++]; + if (XMLChar.isLowSurrogate(c2) && + XMLChar.isSupplemental(XMLChar.supplemental(c, c2))) { + continue; + } + } + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.XML_DOMAIN, + "InvalidCharInCDSect", + new Object[] { Integer.toString(c, 16)}); + reportDOMError( + errorHandler, + error, + locator, + msg, + DOMError.SEVERITY_ERROR, + "wf-invalid-character"); + } + else if (c == ']') { + int count = i; + if (count < datalength && dataarray[count] == ']') { + while (++count < datalength && dataarray[count] == ']') { + // do nothing + } + if (count < datalength && dataarray[count] == '>') { + // CDEndInContent + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN, "CDEndInContent", null); + reportDOMError(errorHandler, error, locator,msg, DOMError.SEVERITY_ERROR, "wf-invalid-character"); + } + } + + } + } + } // version of the document is XML 1.0 + else { + // we need to check all chracters as per production rules of XML 1.0 + int i = 0; + while (i < datalength) { + char c = dataarray[i++]; + if( XMLChar.isInvalid(c) ) { + // check if this is a supplemental character + if (XMLChar.isHighSurrogate(c) && i < datalength) { + char c2 = dataarray[i++]; + if (XMLChar.isLowSurrogate(c2) && + XMLChar.isSupplemental(XMLChar.supplemental(c, c2))) { + continue; + } + } + // Note: The key InvalidCharInCDSect from XMLMessages.properties + // is being used to obtain the message and DOM error type + // "wf-invalid-character" is used. Also per DOM it is error but + // as per XML spec. it is fatal error + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.XML_DOMAIN, + "InvalidCharInCDSect", + new Object[]{Integer.toString(c, 16)}); + reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character"); + } + else if (c==']') { + int count = i; + if ( count< datalength && dataarray[count]==']' ) { + while (++count < datalength && dataarray[count]==']' ) { + // do nothing + } + if ( count < datalength && dataarray[count]=='>' ) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN, "CDEndInContent", null); + reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character"); + } + } + + } + } + } // end-else fDocument.isXMLVersion() + + } // isCDataWF + + /** + * NON-DOM: check for valid XML characters as per the XML version + * @param datavalue + * @param isXML11Version = true if XML 1.1 + */ + public static final void isXMLCharWF(DOMErrorHandler errorHandler, DOMErrorImpl error, DOMLocatorImpl locator, + String datavalue, boolean isXML11Version) + { + if ( datavalue == null || (datavalue.length() == 0) ) { + return; + } + + char [] dataarray = datavalue.toCharArray(); + int datalength = dataarray.length; + + // version of the document is XML 1.1 + if(isXML11Version){ + //we need to check all characters as per production rules of XML11 + int i = 0 ; + while (i < datalength) { + if(XML11Char.isXML11Invalid(dataarray[i++])){ + // check if this is a supplemental character + char ch = dataarray[i-1]; + if (XMLChar.isHighSurrogate(ch) && i < datalength) { + char ch2 = dataarray[i++]; + if (XMLChar.isLowSurrogate(ch2) && + XMLChar.isSupplemental(XMLChar.supplemental(ch, ch2))) { + continue; + } + } + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, "InvalidXMLCharInDOM", + new Object[]{Integer.toString(dataarray[i-1], 16)}); + reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, + "wf-invalid-character"); + } + } + } // version of the document is XML 1.0 + else{ + // we need to check all characters as per production rules of XML 1.0 + int i = 0 ; + while (i < datalength) { + if( XMLChar.isInvalid(dataarray[i++]) ) { + // check if this is a supplemental character + char ch = dataarray[i-1]; + if (XMLChar.isHighSurrogate(ch) && i < datalength) { + char ch2 = dataarray[i++]; + if (XMLChar.isLowSurrogate(ch2) && + XMLChar.isSupplemental(XMLChar.supplemental(ch, ch2))) { + continue; + } + } + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, "InvalidXMLCharInDOM", + new Object[]{Integer.toString(dataarray[i-1], 16)}); + reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, + "wf-invalid-character"); + } + } + } // end-else fDocument.isXMLVersion() + + } // isXMLCharWF + + /** + * NON-DOM: check if value of the comment is well-formed + * @param datavalue + * @param isXML11Version = true if XML 1.1 + */ + public static final void isCommentWF(DOMErrorHandler errorHandler, DOMErrorImpl error, DOMLocatorImpl locator, + String datavalue, boolean isXML11Version) + { + if ( datavalue == null || (datavalue.length() == 0) ) { + return; + } + + char [] dataarray = datavalue.toCharArray(); + int datalength = dataarray.length ; + + // version of the document is XML 1.1 + if (isXML11Version) { + // we need to check all chracters as per production rules of XML11 + int i = 0 ; + while (i < datalength){ + char c = dataarray[i++]; + if ( XML11Char.isXML11Invalid(c) ) { + // check if this is a supplemental character + if (XMLChar.isHighSurrogate(c) && i < datalength) { + char c2 = dataarray[i++]; + if (XMLChar.isLowSurrogate(c2) && + XMLChar.isSupplemental(XMLChar.supplemental(c, c2))) { + continue; + } + } + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN, + "InvalidCharInComment", + new Object [] {Integer.toString(dataarray[i-1], 16)}); + reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character"); + } + else if (c == '-' && i < datalength && dataarray[i] == '-') { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN, + "DashDashInComment", null); + // invalid: '--' in comment + reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character"); + } + } + } // version of the document is XML 1.0 + else { + // we need to check all chracters as per production rules of XML 1.0 + int i = 0; + while (i < datalength){ + char c = dataarray[i++]; + if( XMLChar.isInvalid(c) ){ + // check if this is a supplemental character + if (XMLChar.isHighSurrogate(c) && i < datalength) { + char c2 = dataarray[i++]; + if (XMLChar.isLowSurrogate(c2) && + XMLChar.isSupplemental(XMLChar.supplemental(c, c2))) { + continue; + } + } + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN, + "InvalidCharInComment", new Object [] {Integer.toString(dataarray[i-1], 16)}); + reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character"); + } + else if (c == '-' && istrongly + * recommended that a locator be supplied that can + * at least report the system identifier of the + * document. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param namespaceContext + * The namespace context in effect at the + * start of this document. + * This object represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * + * @param augs Additional information that may include infoset augmentations + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, + Augmentations augs) + throws XNIException{ + } + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) + throws XNIException{ + } + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement + * The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * otherwise. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) + throws XNIException{ + } + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException{ + } + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException{ + } + + /** + * The start of an element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + Element currentElement = (Element) fCurrentNode; + int attrCount = attributes.getLength(); + if (DEBUG_EVENTS) { + System.out.println("==>startElement: " +element+ + " attrs.length="+attrCount); + } + + for (int i = 0; i < attrCount; i++) { + attributes.getName(i, fAttrQName); + Attr attr = null; + + attr = currentElement.getAttributeNodeNS(fAttrQName.uri, fAttrQName.localpart); + if (attr == null) { + // Must be a non-namespace aware DOM Level 1 node. + attr = currentElement.getAttributeNode(fAttrQName.rawname); + } + AttributePSVI attrPSVI = + (AttributePSVI) attributes.getAugmentations(i).getItem(Constants.ATTRIBUTE_PSVI); + + if (attrPSVI != null) { + //REVISIT: instead we should be using augmentations: + // to set/retrieve Id attributes + XSTypeDefinition decl = attrPSVI.getMemberTypeDefinition(); + boolean id = false; + if (decl != null) { + id = ((XSSimpleType)decl).isIDType(); + } + else { + decl = attrPSVI.getTypeDefinition(); + if (decl != null) { + id = ((XSSimpleType)decl).isIDType(); + } + } + if (id) { + ((ElementImpl)currentElement).setIdAttributeNode(attr, true); + } + + if (fPSVI) { + ((PSVIAttrNSImpl) attr).setPSVI(attrPSVI); + } + + // Updating the TypeInfo for this attribute. + ((AttrImpl) attr).setType(decl); + + if ((fConfiguration.features & DOMConfigurationImpl.DTNORMALIZATION) != 0) { + // datatype-normalization + // NOTE: The specified value MUST be set after we set + // the node value because that turns the "specified" + // flag to "true" which may overwrite a "false" + // value from the attribute list. + final String normalizedValue = attrPSVI.getSchemaNormalizedValue(); + if (normalizedValue != null) { + boolean specified = attr.getSpecified(); + attr.setValue(normalizedValue); + if (!specified) { + ((AttrImpl) attr).setSpecified(specified); + } + } + } + } + else { // DTD + String type = null; + boolean isDeclared = Boolean.TRUE.equals(attributes.getAugmentations(i).getItem (Constants.ATTRIBUTE_DECLARED)); + // For DOM Level 3 TypeInfo, the type name must + // be null if this attribute has not been declared + // in the DTD. + if (isDeclared) { + type = attributes.getType(i); + if ("ID".equals (type)) { + ((ElementImpl) currentElement).setIdAttributeNode(attr, true); + } + } + // Updating the TypeInfo for this attribute. + ((AttrImpl) attr).setType(type); + } + } + } + + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + if (DEBUG_EVENTS) { + System.out.println("==>emptyElement: " +element); + } + + startElement(element, attributes, augs); + endElement(element, augs); + } + + /** + * This method notifies the start of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException{ + } + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

+ * Note: This method will never be called for the + * document entity; it is only called for external general entities + * referenced in document content. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException{ + } + + /** + * This method notifies the end of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augs) throws XNIException{ + } + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException{ + } + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException{ + fAllWhitespace = true; + } + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException { + if (DEBUG_EVENTS) { + System.out.println("==>endElement: " + element); + } + + if (augs != null) { + ElementPSVI elementPSVI = (ElementPSVI) augs.getItem(Constants.ELEMENT_PSVI); + if (elementPSVI != null) { + ElementImpl elementNode = (ElementImpl) fCurrentNode; + if (fPSVI) { + ((PSVIElementNSImpl) fCurrentNode).setPSVI(elementPSVI); + } + // Updating the TypeInfo for this element. + if (elementNode instanceof ElementNSImpl) { + XSTypeDefinition type = elementPSVI.getMemberTypeDefinition(); + if (type == null) { + type = elementPSVI.getTypeDefinition(); + } + ((ElementNSImpl) elementNode).setType(type); + } + // include element default content (if one is available) + String normalizedValue = elementPSVI.getSchemaNormalizedValue(); + if ((fConfiguration.features & DOMConfigurationImpl.DTNORMALIZATION) != 0) { + if (normalizedValue !=null) + elementNode.setTextContent(normalizedValue); + } + else { + // NOTE: this is a hack: it is possible that DOM had an empty element + // and validator sent default value using characters(), which we don't + // implement. Thus, here we attempt to add the default value. + String text = elementNode.getTextContent(); + if (text.length() == 0) { + // default content could be provided + if (normalizedValue !=null) + elementNode.setTextContent(normalizedValue); + } + } + return; + } + } + // DTD; elements have no type. + if (fCurrentNode instanceof ElementNSImpl) { + ((ElementNSImpl) fCurrentNode).setType(null); + } + } + + + /** + * The start of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException{ + } + + /** + * The end of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException{ + } + + /** + * The end of the document. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endDocument(Augmentations augs) throws XNIException{ + } + + + /** Sets the document source. */ + public void setDocumentSource(XMLDocumentSource source){ + } + + + /** Returns the document source. */ + public XMLDocumentSource getDocumentSource(){ + return null; + } + + +} // DOMNormalizer class diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMOutputImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMOutputImpl.java new file mode 100644 index 0000000..0da8f79 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMOutputImpl.java @@ -0,0 +1,170 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.OutputStream; +import java.io.Writer; + +import org.w3c.dom.ls.LSOutput; + +/** + * This class represents an output destination for data. + * This interface allows an application to encapsulate information about an + * output destination in a single object, which may include a URI, a byte stream + * (possibly with a specifiedencoding), a base URI, and/or a character stream. + * The exact definitions of a byte stream and a character stream are binding + * dependent. + * The application is expected to provide objects that implement this interface + * whenever such objects are needed. The application can either provide its + * own objects that implement this interface, or it can use the generic factory + * method DOMImplementationLS.createLSOutput() to create objects that + * implement this interface. + * The DOMSerializer will use the LSOutput object to determine where to + * serialize the output to. The DOMSerializer will look at the different + * outputs specified in the LSOutput in the following order to know which one + * to output to, the first one that data can be output to will be used: + * 1.LSOutput.characterStream + * 2.LSOutput.byteStream + * 3.LSOutput.systemId + * LSOutput objects belong to the application. The DOM implementation will + * never modify them (though it may make copies and modify the copies, + * if necessary). + * + * @xerces.internal + * + * @author Arun Yadav, Sun Microsytems + * @author Gopal Sharma, Sun Microsystems + **/ + +public class DOMOutputImpl implements LSOutput { + + protected Writer fCharStream = null; + protected OutputStream fByteStream = null; + protected String fSystemId = null; + protected String fEncoding = null; + + /** + * Default Constructor + */ + public DOMOutputImpl() {} + + /** + * An attribute of a language and binding dependent type that represents a + * writable stream of bytes. If the application knows the character encoding + * of the byte stream, it should set the encoding attribute. Setting the + * encoding in this way will override any encoding specified in an XML + * declaration in the data. + */ + + public Writer getCharacterStream(){ + return fCharStream; + }; + + /** + * An attribute of a language and binding dependent type that represents a + * writable stream of bytes. If the application knows the character encoding + * of the byte stream, it should set the encoding attribute. Setting the + * encoding in this way will override any encoding specified in an XML + * declaration in the data. + */ + + public void setCharacterStream(Writer characterStream){ + fCharStream = characterStream; + }; + + /** + * Depending on the language binding in use, this attribute may not be + * available. An attribute of a language and binding dependent type that + * represents a writable stream to which 16-bit units can be output. The + * application must encode the stream using UTF-16 (defined in [Unicode] and + * Amendment 1 of [ISO/IEC 10646]). + */ + + public OutputStream getByteStream(){ + return fByteStream; + }; + + /** + * Depending on the language binding in use, this attribute may not be + * available. An attribute of a language and binding dependent type that + * represents a writable stream to which 16-bit units can be output. The + * application must encode the stream using UTF-16 (defined in [Unicode] and + * Amendment 1 of [ISO/IEC 10646]). + */ + + public void setByteStream(OutputStream byteStream){ + fByteStream = byteStream; + }; + + /** + * The system identifier, a URI reference [IETF RFC 2396], for this output + * destination. If the application knows the character encoding of the + * object pointed to by the system identifier, it can set the encoding + * using the encoding attribute. If the system ID is a relative URI + * reference (see section 5 in [IETF RFC 2396]), the behavior is + * implementation dependent. + */ + + public String getSystemId(){ + return fSystemId; + }; + + /** + * The system identifier, a URI reference [IETF RFC 2396], for this output + * destination. If the application knows the character encoding of the + * object pointed to by the system identifier, it can set the encoding + * using the encoding attribute. If the system ID is a relative URI + * reference (see section 5 in [IETF RFC 2396]), the behavior is + * implementation dependent. + */ + + public void setSystemId(String systemId){ + fSystemId = systemId; + }; + + /** + * The character encoding, if known. The encoding must be a string + * acceptable for an XML encoding declaration ([XML 1.0] section 4.3.3 + * "Character Encoding in Entities"). This attribute has no effect when the + * application provides a character stream or string data. For other sources + * of input, an encoding specified by means of this attribute will override + * any encoding specified in the XML declaration or the Text declaration, or + * an encoding obtained from a higher level protocol, such as HTTP + * [IETF RFC 2616]. + */ + + public String getEncoding(){ + return fEncoding; + }; + + /** + * The character encoding, if known. The encoding must be a string + * acceptable for an XML encoding declaration ([XML 1.0] section 4.3.3 + * "Character Encoding in Entities"). This attribute has no effect when the + * application provides a character stream or string data. For other sources + * of input, an encoding specified by means of this attribute will override + * any encoding specified in the XML declaration or the Text declaration, or + * an encoding obtained from a higher level protocol, such as HTTP + * [IETF RFC 2616]. + */ + + public void setEncoding(String encoding){ + fEncoding = encoding; + }; + +}//DOMOutputImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMStringListImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMStringListImpl.java new file mode 100644 index 0000000..015aceb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMStringListImpl.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.ArrayList; +import java.util.Vector; + +import org.w3c.dom.DOMStringList; + +/** + * DOM Level 3 + * + * This class implements the DOM Level 3 Core interface DOMStringList. + * + * @xerces.internal + * + * @author Neil Delima, IBM + */ +public class DOMStringListImpl implements DOMStringList { + + // A collection of DOMString values + private final ArrayList fStrings; + + /** + * Construct an empty list of DOMStringListImpl + */ + public DOMStringListImpl() { + fStrings = new ArrayList(); + } + + /** + * Construct a DOMStringListImpl from an ArrayList + */ + public DOMStringListImpl(ArrayList params) { + fStrings = params; + } + + /** + * Construct a DOMStringListImpl from a Vector + */ + public DOMStringListImpl(Vector params) { + fStrings = new ArrayList(params); + } + + /** + * @see org.w3c.dom.DOMStringList#item(int) + */ + public String item(int index) { + final int length = getLength(); + if (index >= 0 && index < length) { + return (String) fStrings.get(index); + } + return null; + } + + /** + * @see org.w3c.dom.DOMStringList#getLength() + */ + public int getLength() { + return fStrings.size(); + } + + /** + * @see org.w3c.dom.DOMStringList#contains(String) + */ + public boolean contains(String param) { + return fStrings.contains(param); + } + + /** + * DOM Internal: + * Add a DOMString to the list. + * + * @param param A string to add to the list + */ + public void add(String param) { + fStrings.add(param); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DOMXSImplementationSourceImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DOMXSImplementationSourceImpl.java new file mode 100644 index 0000000..249210b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DOMXSImplementationSourceImpl.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.ArrayList; + +import org.apache.xerces.impl.xs.XSImplementationImpl; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMImplementationList; + +/** + * Allows to retrieve XSImplementation, DOM Level 3 Core and LS implementations + * and PSVI implementation. + *

See also the Document Object Model (DOM) Level 3 Core Specification. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public class DOMXSImplementationSourceImpl + extends DOMImplementationSourceImpl { + + /** + * A method to request a DOM implementation. + * @param features A string that specifies which features are required. + * This is a space separated list in which each feature is specified + * by its name optionally followed by a space and a version number. + * This is something like: "XML 1.0 Traversal Events 2.0" + * @return An implementation that has the desired features, or + * null if this source has none. + */ + public DOMImplementation getDOMImplementation(String features) { + DOMImplementation impl = super.getDOMImplementation(features); + if (impl != null){ + return impl; + } + // if not try the PSVIDOMImplementation + impl = PSVIDOMImplementationImpl.getDOMImplementation(); + if (testImpl(impl, features)) { + return impl; + } + // if not try the XSImplementation + impl = XSImplementationImpl.getDOMImplementation(); + if (testImpl(impl, features)) { + return impl; + } + + return null; + } + + /** + * A method to request a list of DOM implementations that support the + * specified features and versions, as specified in . + * @param features A string that specifies which features and versions + * are required. This is a space separated list in which each feature + * is specified by its name optionally followed by a space and a + * version number. This is something like: "XML 3.0 Traversal +Events + * 2.0" + * @return A list of DOM implementations that support the desired + * features. + */ + public DOMImplementationList getDOMImplementationList(String features) { + final ArrayList implementations = new ArrayList(); + + // first check whether the CoreDOMImplementation would do + DOMImplementationList list = super.getDOMImplementationList(features); + // Add core DOMImplementations + for (int i = 0; i < list.getLength(); ++i) { + implementations.add(list.item(i)); + } + + DOMImplementation impl = PSVIDOMImplementationImpl.getDOMImplementation(); + if (testImpl(impl, features)) { + implementations.add(impl); + } + + impl = XSImplementationImpl.getDOMImplementation(); + if (testImpl(impl, features)) { + implementations.add(impl); + } + return new DOMImplementationListImpl(implementations); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeepNodeListImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeepNodeListImpl.java new file mode 100644 index 0000000..f3b65d7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeepNodeListImpl.java @@ -0,0 +1,249 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.ArrayList; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * This class implements the DOM's NodeList behavior for + * Element.getElementsByTagName() + *

+ * The DOM describes NodeList as follows: + *

+ * 1) It may represent EITHER nodes scattered through a subtree (when + * returned by Element.getElementsByTagName), or just the immediate + * children (when returned by Node.getChildNodes). The latter is easy, + * but the former (which this class addresses) is more challenging. + *

+ * 2) Its behavior is "live" -- that is, it always reflects the + * current state of the document tree. To put it another way, the + * NodeLists obtained before and after a series of insertions and + * deletions are effectively identical (as far as the user is + * concerned, the former has been dynamically updated as the changes + * have been made). + *

+ * 3) Its API accesses individual nodes via an integer index, with the + * listed nodes numbered sequentially in the order that they were + * found during a preorder depth-first left-to-right search of the tree. + * (Of course in the case of getChildNodes, depth is not involved.) As + * nodes are inserted or deleted in the tree, and hence the NodeList, + * the numbering of nodes that follow them in the NodeList will + * change. + *

+ * It is rather painful to support the latter two in the + * getElementsByTagName case. The current solution is for Nodes to + * maintain a change count (eventually that may be a Digest instead), + * which the NodeList tracks and uses to invalidate itself. + *

+ * Unfortunately, this does _not_ respond efficiently in the case that + * the dynamic behavior was supposed to address: scanning a tree while + * it is being extended. That requires knowing which subtrees have + * changed, which can become an arbitrarily complex problem. + *

+ * We save some work by filling the ArrayList only as we access the + * item()s... but I suspect the same users who demanded index-based + * access will also start by doing a getLength() to control their loop, + * blowing this optimization out of the water. + *

+ * NOTE: Level 2 of the DOM will probably _not_ use NodeList for its + * extended search mechanisms, partly for the reasons just discussed. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeepNodeListImpl + implements NodeList { + + // + // Data + // + + protected NodeImpl rootNode; // Where the search started + protected String tagName; // Or "*" to mean all-tags-acceptable + protected int changes=0; + protected ArrayList nodes; + + protected String nsName; + protected boolean enableNS = false; + + // + // Constructors + // + + /** Constructor. */ + public DeepNodeListImpl(NodeImpl rootNode, String tagName) { + this.rootNode = rootNode; + this.tagName = tagName; + nodes = new ArrayList(); + } + + /** Constructor for Namespace support. */ + public DeepNodeListImpl(NodeImpl rootNode, + String nsName, String tagName) { + this(rootNode, tagName); + this.nsName = (nsName != null && nsName.length() != 0) ? nsName : null; + enableNS = true; + } + + // + // NodeList methods + // + + /** Returns the length of the node list. */ + public int getLength() { + // Preload all matching elements. (Stops when we run out of subtree!) + item(java.lang.Integer.MAX_VALUE); + return nodes.size(); + } + + /** Returns the node at the specified index. */ + public Node item(int index) { + Node thisNode; + + // Tree changed. Do it all from scratch! + if (rootNode.changes() != changes) { + nodes = new ArrayList(); + changes = rootNode.changes(); + } + + // In the cache + final int currentSize = nodes.size(); + if (index < currentSize) { + return (Node)nodes.get(index); + } + // Not yet seen + else { + + // Pick up where we left off (Which may be the beginning) + if (currentSize == 0) { + thisNode = rootNode; + } + else { + thisNode = (NodeImpl)(nodes.get(currentSize - 1)); + } + + // Add nodes up to the one we're looking for + while (thisNode != null && index >= nodes.size()) { + thisNode = nextMatchingElementAfter(thisNode); + if (thisNode != null) { + nodes.add(thisNode); + } + } + + // Either what we want, or null (not avail.) + return thisNode; + } + + } // item(int):Node + + // + // Protected methods (might be overridden by an extending DOM) + // + + /** + * Iterative tree-walker. When you have a Parent link, there's often no + * need to resort to recursion. NOTE THAT only Element nodes are matched + * since we're specifically supporting getElementsByTagName(). + */ + protected Node nextMatchingElementAfter(Node current) { + + Node next; + while (current != null) { + // Look down to first child. + if (current.hasChildNodes()) { + current = (current.getFirstChild()); + } + + // Look right to sibling (but not from root!) + else if (current != rootNode && null != (next = current.getNextSibling())) { + current = next; + } + + // Look up and right (but not past root!) + else { + next = null; + for (; current != rootNode; // Stop when we return to starting point + current = current.getParentNode()) { + + next = current.getNextSibling(); + if (next != null) + break; + } + current = next; + } + + // Have we found an Element with the right tagName? + // ("*" matches anything.) + if (current != rootNode + && current != null + && current.getNodeType() == Node.ELEMENT_NODE) { + if (!enableNS) { + if (tagName.equals("*") || + ((ElementImpl) current).getTagName().equals(tagName)) + { + return current; + } + } else { + // DOM2: Namespace logic. + if (tagName.equals("*")) { + if (nsName != null && nsName.equals("*")) { + return current; + } else { + ElementImpl el = (ElementImpl) current; + if ((nsName == null + && el.getNamespaceURI() == null) + || (nsName != null + && nsName.equals(el.getNamespaceURI()))) + { + return current; + } + } + } else { + ElementImpl el = (ElementImpl) current; + if (el.getLocalName() != null + && el.getLocalName().equals(tagName)) { + if (nsName != null && nsName.equals("*")) { + return current; + } else { + if ((nsName == null + && el.getNamespaceURI() == null) + || (nsName != null && + nsName.equals(el.getNamespaceURI()))) + { + return current; + } + } + } + } + } + } + + // Otherwise continue walking the tree + } + + // Fell out of tree-walk; no more instances found + return null; + + } // nextMatchingElementAfter(int):Node + +} // class DeepNodeListImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredAttrImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredAttrImpl.java new file mode 100644 index 0000000..f2d93f3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredAttrImpl.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +/* + * WARNING: because java doesn't support multi-inheritance some code is + * duplicated. If you're changing this file you probably want to change + * DeferredAttrNSImpl.java at the same time. + */ + +package org.apache.xerces.dom; + +/** + * Attribute represents an XML-style attribute of an + * Element. Typically, the allowable values are controlled by its + * declaration in the Document Type Definition (DTD) governing this + * kind of document. + *

+ * If the attribute has not been explicitly assigned a value, but has + * been declared in the DTD, it will exist and have that default. Only + * if neither the document nor the DTD specifies a value will the + * Attribute really be considered absent and have no value; in that + * case, querying the attribute will return null. + *

+ * Attributes may have multiple children that contain their data. (XML + * allows attributes to contain entity references, and tokenized + * attribute types such as NMTOKENS may have a child for each token.) + * For convenience, the Attribute object's getValue() method returns + * the string version of the attribute's value. + *

+ * Attributes are not children of the Elements they belong to, in the + * usual sense, and have no valid Parent reference. However, the spec + * says they _do_ belong to a specific Element, and an INUSE exception + * is to be thrown if the user attempts to explicitly share them + * between elements. + *

+ * Note that Elements do not permit attributes to appear to be shared + * (see the INUSE exception), so this object's mutability is + * officially not an issue. + *

+ * DeferredAttrImpl inherits from AttrImpl which does not support + * Namespaces. DeferredAttrNSImpl, which inherits from AttrNSImpl, does. + * @see DeferredAttrNSImpl + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @author Arnaud Le Hors, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public final class DeferredAttrImpl + extends AttrImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 6903232312469148636L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredAttrImpl(DeferredDocumentImpl ownerDocument, int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + needsSyncChildren(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) ownerDocument(); + name = ownerDocument.getNodeName(fNodeIndex); + int extra = ownerDocument.getNodeExtra(fNodeIndex); + isSpecified((extra & SPECIFIED) != 0); + isIdAttribute((extra & ID) != 0); + + int extraNode = ownerDocument.getLastChild(fNodeIndex); + type = ownerDocument.getTypeInfo(extraNode); + } // synchronizeData() + + /** + * Synchronizes the node's children with the internal structure. + * Fluffing the children at once solves a lot of work to keep + * the two structures in sync. The problem gets worse when + * editing the tree -- this makes it a lot easier. + */ + protected void synchronizeChildren() { + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) ownerDocument(); + ownerDocument.synchronizeChildren(this, fNodeIndex); + } // synchronizeChildren() + +} // class DeferredAttrImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredAttrNSImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredAttrNSImpl.java new file mode 100644 index 0000000..45db1f8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredAttrNSImpl.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +/* + * WARNING: because java doesn't support multi-inheritance some code is + * duplicated. If you're changing this file you probably want to change + * DeferredAttrImpl.java at the same time. + */ + + +package org.apache.xerces.dom; + +/** + * DeferredAttrNSImpl is to AttrNSImpl, what DeferredAttrImpl is to + * AttrImpl. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @author Arnaud Le Hors, IBM + * @version $Id$ + * @see DeferredAttrImpl + */ +public final class DeferredAttrNSImpl + extends AttrNSImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 6074924934945957154L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredAttrNSImpl(DeferredDocumentImpl ownerDocument, int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + needsSyncChildren(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) ownerDocument(); + name = ownerDocument.getNodeName(fNodeIndex); + + // extract prefix and local part from QName + int index = name.indexOf(':'); + if (index < 0) { + localName = name; + } + else { + localName = name.substring(index + 1); + } + + int extra = ownerDocument.getNodeExtra(fNodeIndex); + isSpecified((extra & SPECIFIED) != 0); + isIdAttribute((extra & ID) != 0); + + namespaceURI = ownerDocument.getNodeURI(fNodeIndex); + + int extraNode = ownerDocument.getLastChild(fNodeIndex); + type = ownerDocument.getTypeInfo(extraNode); + } // synchronizeData() + + /** + * Synchronizes the node's children with the internal structure. + * Fluffing the children at once solves a lot of work to keep + * the two structures in sync. The problem gets worse when + * editing the tree -- this makes it a lot easier. + */ + protected void synchronizeChildren() { + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) ownerDocument(); + ownerDocument.synchronizeChildren(this, fNodeIndex); + } // synchronizeChildren() + +} // class DeferredAttrImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredCDATASectionImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredCDATASectionImpl.java new file mode 100644 index 0000000..97da4ae --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredCDATASectionImpl.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +/** + * XML provides the CDATA markup to allow a region of text in which + * most of the XML delimiter recognition does not take place. This is + * intended to ease the task of quoting XML fragments and other + * programmatic information in a document's text without needing to + * escape these special characters. It's primarily a convenience feature + * for those who are hand-editing XML. + *

+ * CDATASection is an Extended DOM feature, and is not used in HTML + * contexts. + *

+ * Within the DOM, CDATASections are treated essentially as Text + * blocks. Their distinct type is retained in order to allow us to + * properly recreate the XML syntax when we write them out. + *

+ * Reminder: CDATA IS NOT A COMPLETELY GENERAL SOLUTION; it can't + * quote its own end-of-block marking. If you need to write out a + * CDATA that contains the ]]> sequence, it's your responsibility to + * split that string over two successive CDATAs at that time. + *

+ * CDATA does not participate in Element.normalize() processing. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredCDATASectionImpl + extends CDATASectionImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 1983580632355645726L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. All other data, + * can be requested from the ownerDocument via the index. + */ + DeferredCDATASectionImpl(DeferredDocumentImpl ownerDocument, int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) this.ownerDocument(); + data = ownerDocument.getNodeValueString(fNodeIndex); + + } // synchronizeData() + +} // class DeferredCDATASectionImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredCommentImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredCommentImpl.java new file mode 100644 index 0000000..a5cbf76 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredCommentImpl.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +/** + * Represents an XML (or HTML) comment. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredCommentImpl + extends CommentImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 6498796371083589338L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. All other data, + * can be requested from the ownerDocument via the index. + */ + DeferredCommentImpl(DeferredDocumentImpl ownerDocument, int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) this.ownerDocument(); + data = ownerDocument.getNodeValueString(fNodeIndex); + + } // synchronizeData() + +} // class DeferredCommentImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDOMImplementationImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDOMImplementationImpl.java new file mode 100644 index 0000000..6516fe0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDOMImplementationImpl.java @@ -0,0 +1,56 @@ +/* + * 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. + */ +package org.apache.xerces.dom; + +import org.w3c.dom.DOMImplementation; + +/** + *

This DOMImplementation class is description of a particular + * implementation of the Document Object Model. As such its data is + * static, shared by all instances of this implementation.

+ * + *

This implementation simply extends DOMImplementationImpl to differentiate + * between the Deferred DOM Implementations and Non-Deferred DOM Implementations.

+ * + * @xerces.internal + * + * @author Neil Delima, IBM + * + * @version $Id$ + */ +public class DeferredDOMImplementationImpl + extends DOMImplementationImpl { + + // + // Data + // + + // static + + /** Dom implementation singleton. */ + static final DeferredDOMImplementationImpl singleton = new DeferredDOMImplementationImpl(); + + + // + // Public methods + // + + /** NON-DOM: Obtain and return the single shared object */ + public static DOMImplementation getDOMImplementation() { + return singleton; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDocumentImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDocumentImpl.java new file mode 100644 index 0000000..781c11e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDocumentImpl.java @@ -0,0 +1,2155 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.ArrayList; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * The Document interface represents the entire HTML or XML document. + * Conceptually, it is the root of the document tree, and provides the + * primary access to the document's data. + *

+ * Since elements, text nodes, comments, processing instructions, + * etc. cannot exist outside the context of a Document, the Document + * interface also contains the factory methods needed to create these + * objects. The Node objects created have a ownerDocument attribute + * which associates them with the Document within whose context they + * were created. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredDocumentImpl + extends DocumentImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 5186323580749626857L; + + // debugging + + /** To include code for printing the ref count tables. */ + private static final boolean DEBUG_PRINT_REF_COUNTS = false; + + /** To include code for printing the internal tables. */ + private static final boolean DEBUG_PRINT_TABLES = false; + + /** To debug identifiers set to true and recompile. */ + private static final boolean DEBUG_IDS = false; + + // protected + + /** Chunk shift. */ + protected static final int CHUNK_SHIFT = 11; // 2^11 = 2k + + /** Chunk size. */ + protected static final int CHUNK_SIZE = (1 << CHUNK_SHIFT); + + /** Chunk mask. */ + protected static final int CHUNK_MASK = CHUNK_SIZE - 1; + + /** Initial chunk size. */ + protected static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k + + // + // Data + // + + // lazy-eval information + // To maximize memory consumption the actual semantic of these fields vary + // depending on the node type. + + /** Node count. */ + protected transient int fNodeCount = 0; + + /** Node types. */ + protected transient int fNodeType[][]; + + /** Node names. */ + protected transient Object fNodeName[][]; + + /** Node values. */ + protected transient Object fNodeValue[][]; + + /** Node parents. */ + protected transient int fNodeParent[][]; + + /** Node first children. */ + protected transient int fNodeLastChild[][]; + + /** Node prev siblings. */ + protected transient int fNodePrevSib[][]; + + /** Node namespace URI. */ + protected transient Object fNodeURI[][]; + + /** Extra data. */ + protected transient int fNodeExtra[][]; + + /** Identifier count. */ + protected transient int fIdCount; + + /** Identifier name indexes. */ + protected transient String fIdName[]; + + /** Identifier element indexes. */ + protected transient int fIdElement[]; + + /** DOM2: For namespace support in the deferred case. + */ + // Implementation Note: The deferred element and attribute must know how to + // interpret the int representing the qname. + protected boolean fNamespacesEnabled = false; + + // + // private data + // + private transient final StringBuffer fBufferStr = new StringBuffer(); + private transient final ArrayList fStrChunks = new ArrayList(); + + // + // Constructors + // + + /** + * NON-DOM: Actually creating a Document is outside the DOM's spec, + * since it has to operate in terms of a particular implementation. + */ + public DeferredDocumentImpl() { + this(false); + } // () + + /** + * NON-DOM: Actually creating a Document is outside the DOM's spec, + * since it has to operate in terms of a particular implementation. + */ + public DeferredDocumentImpl(boolean namespacesEnabled) { + this(namespacesEnabled, false); + } // (boolean) + + /** Experimental constructor. */ + public DeferredDocumentImpl(boolean namespaces, boolean grammarAccess) { + super(grammarAccess); + + needsSyncData(true); + needsSyncChildren(true); + + fNamespacesEnabled = namespaces; + + } // (boolean,boolean) + + // + // Public methods + // + + /** + * Retrieve information describing the abilities of this particular + * DOM implementation. Intended to support applications that may be + * using DOMs retrieved from several different sources, potentially + * with different underlying representations. + */ + public DOMImplementation getImplementation() { + // Currently implemented as a singleton, since it's hardcoded + // information anyway. + return DeferredDOMImplementationImpl.getDOMImplementation(); + } + + /** Returns the cached parser.getNamespaces() value.*/ + boolean getNamespacesEnabled() { + return fNamespacesEnabled; + } + + void setNamespacesEnabled(boolean enable) { + fNamespacesEnabled = enable; + } + + // internal factory methods + + /** Creates a document node in the table. */ + public int createDeferredDocument() { + int nodeIndex = createNode(Node.DOCUMENT_NODE); + return nodeIndex; + } + + /** Creates a doctype. */ + public int createDeferredDocumentType(String rootElementName, + String publicId, String systemId) { + + // create node + int nodeIndex = createNode(Node.DOCUMENT_TYPE_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + + // save name, public id, system id + setChunkValue(fNodeName, rootElementName, chunk, index); + setChunkValue(fNodeValue, publicId, chunk, index); + setChunkValue(fNodeURI, systemId, chunk, index); + + // return node index + return nodeIndex; + + } // createDeferredDocumentType(String,String,String):int + + public void setInternalSubset(int doctypeIndex, String subset) { + int chunk = doctypeIndex >> CHUNK_SHIFT; + int index = doctypeIndex & CHUNK_MASK; + + // create extra data node to store internal subset + int extraDataIndex = createNode(Node.DOCUMENT_TYPE_NODE); + int echunk = extraDataIndex >> CHUNK_SHIFT; + int eindex = extraDataIndex & CHUNK_MASK; + setChunkIndex(fNodeExtra, extraDataIndex, chunk, index); + setChunkValue(fNodeValue, subset, echunk, eindex); + } + + /** Creates a notation in the table. */ + public int createDeferredNotation(String notationName, + String publicId, String systemId, String baseURI) { + + // create node + int nodeIndex = createNode(Node.NOTATION_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + + + // create extra data node + int extraDataIndex = createNode(Node.NOTATION_NODE); + int echunk = extraDataIndex >> CHUNK_SHIFT; + int eindex = extraDataIndex & CHUNK_MASK; + + // save name, public id, system id, and notation name + setChunkValue(fNodeName, notationName, chunk, index); + setChunkValue(fNodeValue, publicId, chunk, index); + setChunkValue(fNodeURI, systemId, chunk, index); + + // in extra data node set baseURI value + setChunkIndex(fNodeExtra, extraDataIndex, chunk, index); + setChunkValue(fNodeName, baseURI, echunk, eindex); + + // return node index + return nodeIndex; + + } // createDeferredNotation(String,String,String):int + + /** Creates an entity in the table. */ + public int createDeferredEntity(String entityName, String publicId, + String systemId, String notationName, + String baseURI) { + // create node + int nodeIndex = createNode(Node.ENTITY_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + + // create extra data node + int extraDataIndex = createNode(Node.ENTITY_NODE); + int echunk = extraDataIndex >> CHUNK_SHIFT; + int eindex = extraDataIndex & CHUNK_MASK; + + // save name, public id, system id, and notation name + setChunkValue(fNodeName, entityName, chunk, index); + setChunkValue(fNodeValue, publicId, chunk, index); + setChunkValue(fNodeURI, systemId, chunk, index); + setChunkIndex(fNodeExtra, extraDataIndex, chunk, index); + // set other values in the extra chunk + // notation + setChunkValue(fNodeName, notationName, echunk, eindex); + // version L3 + setChunkValue(fNodeValue, null, echunk, eindex); + // encoding L3 + setChunkValue(fNodeURI, null, echunk, eindex); + + + int extraDataIndex2 = createNode(Node.ENTITY_NODE); + int echunk2 = extraDataIndex2 >> CHUNK_SHIFT; + int eindex2 = extraDataIndex2 & CHUNK_MASK; + + setChunkIndex(fNodeExtra, extraDataIndex2, echunk, eindex); + + // baseURI + setChunkValue(fNodeName, baseURI, echunk2, eindex2); + + // return node index + return nodeIndex; + + } // createDeferredEntity(String,String,String,String):int + + public String getDeferredEntityBaseURI (int entityIndex){ + if (entityIndex != -1) { + int extraDataIndex = getNodeExtra(entityIndex, false); + extraDataIndex = getNodeExtra(extraDataIndex, false); + return getNodeName (extraDataIndex, false); + } + return null; + } + + // DOM Level 3: setting encoding and version + public void setEntityInfo(int currentEntityDecl, + String version, String encoding){ + int eNodeIndex = getNodeExtra(currentEntityDecl, false); + if (eNodeIndex !=-1) { + int echunk = eNodeIndex >> CHUNK_SHIFT; + int eindex = eNodeIndex & CHUNK_MASK; + setChunkValue(fNodeValue, version, echunk, eindex); + setChunkValue(fNodeURI, encoding, echunk, eindex); + } + } + + // DOM Level 3: sets element TypeInfo + public void setTypeInfo(int elementNodeIndex, Object type) { + int elementChunk = elementNodeIndex >> CHUNK_SHIFT; + int elementIndex = elementNodeIndex & CHUNK_MASK; + setChunkValue(fNodeValue, type, elementChunk, elementIndex); + } + + /** + * DOM Internal + * + * An attribute specifying the actual encoding of this document. This is + * null otherwise. + *
This attribute represents the property [character encoding scheme] + * defined in . + */ + public void setInputEncoding(int currentEntityDecl, String value){ + // get first extra data chunk + int nodeIndex = getNodeExtra(currentEntityDecl, false); + // get second extra data chunk + int extraDataIndex = getNodeExtra(nodeIndex, false); + + int echunk = extraDataIndex >> CHUNK_SHIFT; + int eindex = extraDataIndex & CHUNK_MASK; + + setChunkValue(fNodeValue, value, echunk, eindex); + + } + + /** Creates an entity reference node in the table. */ + public int createDeferredEntityReference(String name, String baseURI) { + + // create node + int nodeIndex = createNode(Node.ENTITY_REFERENCE_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + setChunkValue(fNodeName, name, chunk, index); + setChunkValue(fNodeValue, baseURI, chunk, index); + + // return node index + return nodeIndex; + + } // createDeferredEntityReference(String):int + + + /** + * Creates an element node with a URI in the table and type information. + * @deprecated + */ + public int createDeferredElement(String elementURI, String elementName, + Object type) { + + // create node + int elementNodeIndex = createNode(Node.ELEMENT_NODE); + int elementChunk = elementNodeIndex >> CHUNK_SHIFT; + int elementIndex = elementNodeIndex & CHUNK_MASK; + setChunkValue(fNodeName, elementName, elementChunk, elementIndex); + setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex); + setChunkValue(fNodeValue, type, elementChunk, elementIndex); + + // return node index + return elementNodeIndex; + + } // createDeferredElement(String,String,Object):int + + /** + * Creates an element node in the table. + * @deprecated + */ + public int createDeferredElement(String elementName) { + return createDeferredElement(null, elementName); + } + + /** + * Creates an element node with a URI in the table. + */ + public int createDeferredElement(String elementURI, String elementName) { + + // create node + int elementNodeIndex = createNode(Node.ELEMENT_NODE); + int elementChunk = elementNodeIndex >> CHUNK_SHIFT; + int elementIndex = elementNodeIndex & CHUNK_MASK; + setChunkValue(fNodeName, elementName, elementChunk, elementIndex); + setChunkValue(fNodeURI, elementURI, elementChunk, elementIndex); + + // return node index + return elementNodeIndex; + + } // createDeferredElement(String,String):int + + + /** + * This method is used by the DOMParser to create attributes. + * @param elementNodeIndex + * @param attrName + * @param attrURI + * @param attrValue + * @param specified + * @param id + * @param type + * @return int + */ + public int setDeferredAttribute(int elementNodeIndex, + String attrName, + String attrURI, + String attrValue, + boolean specified, + boolean id, + Object type) { + + // create attribute + int attrNodeIndex = createDeferredAttribute(attrName, attrURI, attrValue, specified); + int attrChunk = attrNodeIndex >> CHUNK_SHIFT; + int attrIndex = attrNodeIndex & CHUNK_MASK; + // set attribute's parent to element + setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex); + + int elementChunk = elementNodeIndex >> CHUNK_SHIFT; + int elementIndex = elementNodeIndex & CHUNK_MASK; + + // get element's last attribute + int lastAttrNodeIndex = getChunkIndex(fNodeExtra, elementChunk, elementIndex); + if (lastAttrNodeIndex != 0) { + // add link from new attribute to last attribute + setChunkIndex(fNodePrevSib, lastAttrNodeIndex, attrChunk, attrIndex); + } + // add link from element to new last attribute + setChunkIndex(fNodeExtra, attrNodeIndex, elementChunk, elementIndex); + + int extra = getChunkIndex(fNodeExtra, attrChunk, attrIndex); + if (id) { + extra = extra | ID; + setChunkIndex(fNodeExtra, extra, attrChunk, attrIndex); + String value = getChunkValue(fNodeValue, attrChunk, attrIndex); + putIdentifier(value, elementNodeIndex); + } + // store type information + if (type != null) { + int extraDataIndex = createNode(DeferredNode.TYPE_NODE); + int echunk = extraDataIndex >> CHUNK_SHIFT; + int eindex = extraDataIndex & CHUNK_MASK; + + setChunkIndex(fNodeLastChild, extraDataIndex, attrChunk, attrIndex); + setChunkValue(fNodeValue, type, echunk, eindex); + } + + // return node index + return attrNodeIndex; + } + + /** + * Sets an attribute on an element node. + * @deprecated + */ + public int setDeferredAttribute(int elementNodeIndex, + String attrName, String attrURI, + String attrValue, boolean specified) { + // create attribute + int attrNodeIndex = createDeferredAttribute(attrName, attrURI, + attrValue, specified); + int attrChunk = attrNodeIndex >> CHUNK_SHIFT; + int attrIndex = attrNodeIndex & CHUNK_MASK; + // set attribute's parent to element + setChunkIndex(fNodeParent, elementNodeIndex, attrChunk, attrIndex); + + int elementChunk = elementNodeIndex >> CHUNK_SHIFT; + int elementIndex = elementNodeIndex & CHUNK_MASK; + + // get element's last attribute + int lastAttrNodeIndex = getChunkIndex(fNodeExtra, + elementChunk, elementIndex); + if (lastAttrNodeIndex != 0) { + // add link from new attribute to last attribute + setChunkIndex(fNodePrevSib, lastAttrNodeIndex, + attrChunk, attrIndex); + } + // add link from element to new last attribute + setChunkIndex(fNodeExtra, attrNodeIndex, + elementChunk, elementIndex); + + // return node index + return attrNodeIndex; + + } // setDeferredAttribute(int,String,String,String,boolean):int + + /** Creates an attribute in the table. */ + public int createDeferredAttribute(String attrName, String attrValue, + boolean specified) { + return createDeferredAttribute(attrName, null, attrValue, specified); + } + + /** Creates an attribute with a URI in the table. */ + public int createDeferredAttribute(String attrName, String attrURI, + String attrValue, boolean specified) { + + // create node + int nodeIndex = createNode(NodeImpl.ATTRIBUTE_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + setChunkValue(fNodeName, attrName, chunk, index); + setChunkValue(fNodeURI, attrURI, chunk, index); + setChunkValue(fNodeValue, attrValue, chunk, index); + int extra = specified ? SPECIFIED : 0; + setChunkIndex(fNodeExtra, extra, chunk, index); + + // return node index + return nodeIndex; + + } // createDeferredAttribute(String,String,String,boolean):int + + /** Creates an element definition in the table.*/ + public int createDeferredElementDefinition(String elementName) { + + // create node + int nodeIndex = createNode(NodeImpl.ELEMENT_DEFINITION_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + setChunkValue(fNodeName, elementName, chunk, index); + + // return node index + return nodeIndex; + + } // createDeferredElementDefinition(String):int + + /** Creates a text node in the table. */ + public int createDeferredTextNode(String data, + boolean ignorableWhitespace) { + + // create node + int nodeIndex = createNode(Node.TEXT_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + setChunkValue(fNodeValue, data, chunk, index); + // use extra to store ignorableWhitespace info + setChunkIndex(fNodeExtra, ignorableWhitespace ? 1 : 0, chunk, index); + + // return node index + return nodeIndex; + + } // createDeferredTextNode(String,boolean):int + + /** Creates a CDATA section node in the table. */ + public int createDeferredCDATASection(String data) { + + // create node + int nodeIndex = createNode(Node.CDATA_SECTION_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + setChunkValue(fNodeValue, data, chunk, index); + + // return node index + return nodeIndex; + + } // createDeferredCDATASection(String):int + + /** Creates a processing instruction node in the table. */ + public int createDeferredProcessingInstruction(String target, + String data) { + // create node + int nodeIndex = createNode(Node.PROCESSING_INSTRUCTION_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + setChunkValue(fNodeName, target, chunk, index); + setChunkValue(fNodeValue, data, chunk, index); + // return node index + return nodeIndex; + + } // createDeferredProcessingInstruction(String,String):int + + /** Creates a comment node in the table. */ + public int createDeferredComment(String data) { + + // create node + int nodeIndex = createNode(Node.COMMENT_NODE); + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + setChunkValue(fNodeValue, data, chunk, index); + + // return node index + return nodeIndex; + + } // createDeferredComment(String):int + + /** Creates a clone of the specified node. */ + public int cloneNode(int nodeIndex, boolean deep) { + + // clone immediate node + + int nchunk = nodeIndex >> CHUNK_SHIFT; + int nindex = nodeIndex & CHUNK_MASK; + int nodeType = fNodeType[nchunk][nindex]; + int cloneIndex = createNode((short)nodeType); + int cchunk = cloneIndex >> CHUNK_SHIFT; + int cindex = cloneIndex & CHUNK_MASK; + setChunkValue(fNodeName, fNodeName[nchunk][nindex], cchunk, cindex); + setChunkValue(fNodeValue, fNodeValue[nchunk][nindex], cchunk, cindex); + setChunkValue(fNodeURI, fNodeURI[nchunk][nindex], cchunk, cindex); + int extraIndex = fNodeExtra[nchunk][nindex]; + if (extraIndex != -1) { + if (nodeType != Node.ATTRIBUTE_NODE && nodeType != Node.TEXT_NODE) { + extraIndex = cloneNode(extraIndex, false); + } + setChunkIndex(fNodeExtra, extraIndex, cchunk, cindex); + } + + // clone and attach children + if (deep) { + int prevIndex = -1; + int childIndex = getLastChild(nodeIndex, false); + while (childIndex != -1) { + int clonedChildIndex = cloneNode(childIndex, deep); + insertBefore(cloneIndex, clonedChildIndex, prevIndex); + prevIndex = clonedChildIndex; + childIndex = getRealPrevSibling(childIndex, false); + } + + + } + + // return cloned node index + return cloneIndex; + + } // cloneNode(int,boolean):int + + /** Appends a child to the specified parent in the table. */ + public void appendChild(int parentIndex, int childIndex) { + + // append parent index + int pchunk = parentIndex >> CHUNK_SHIFT; + int pindex = parentIndex & CHUNK_MASK; + int cchunk = childIndex >> CHUNK_SHIFT; + int cindex = childIndex & CHUNK_MASK; + setChunkIndex(fNodeParent, parentIndex, cchunk, cindex); + + // set previous sibling of new child + int olast = getChunkIndex(fNodeLastChild, pchunk, pindex); + setChunkIndex(fNodePrevSib, olast, cchunk, cindex); + + // update parent's last child + setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex); + + } // appendChild(int,int) + + /** Adds an attribute node to the specified element. */ + public int setAttributeNode(int elemIndex, int attrIndex) { + + int echunk = elemIndex >> CHUNK_SHIFT; + int eindex = elemIndex & CHUNK_MASK; + int achunk = attrIndex >> CHUNK_SHIFT; + int aindex = attrIndex & CHUNK_MASK; + + // see if this attribute is already here + String attrName = getChunkValue(fNodeName, achunk, aindex); + int oldAttrIndex = getChunkIndex(fNodeExtra, echunk, eindex); + int nextIndex = -1; + int oachunk = -1; + int oaindex = -1; + while (oldAttrIndex != -1) { + oachunk = oldAttrIndex >> CHUNK_SHIFT; + oaindex = oldAttrIndex & CHUNK_MASK; + String oldAttrName = getChunkValue(fNodeName, oachunk, oaindex); + if (oldAttrName.equals(attrName)) { + break; + } + nextIndex = oldAttrIndex; + oldAttrIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex); + } + + // remove old attribute + if (oldAttrIndex != -1) { + + // patch links + int prevIndex = getChunkIndex(fNodePrevSib, oachunk, oaindex); + if (nextIndex == -1) { + setChunkIndex(fNodeExtra, prevIndex, echunk, eindex); + } + else { + int pchunk = nextIndex >> CHUNK_SHIFT; + int pindex = nextIndex & CHUNK_MASK; + setChunkIndex(fNodePrevSib, prevIndex, pchunk, pindex); + } + + // remove connections to siblings + clearChunkIndex(fNodeType, oachunk, oaindex); + clearChunkValue(fNodeName, oachunk, oaindex); + clearChunkValue(fNodeValue, oachunk, oaindex); + clearChunkIndex(fNodeParent, oachunk, oaindex); + clearChunkIndex(fNodePrevSib, oachunk, oaindex); + int attrTextIndex = + clearChunkIndex(fNodeLastChild, oachunk, oaindex); + int atchunk = attrTextIndex >> CHUNK_SHIFT; + int atindex = attrTextIndex & CHUNK_MASK; + clearChunkIndex(fNodeType, atchunk, atindex); + clearChunkValue(fNodeValue, atchunk, atindex); + clearChunkIndex(fNodeParent, atchunk, atindex); + clearChunkIndex(fNodeLastChild, atchunk, atindex); + } + + // add new attribute + int prevIndex = getChunkIndex(fNodeExtra, echunk, eindex); + setChunkIndex(fNodeExtra, attrIndex, echunk, eindex); + setChunkIndex(fNodePrevSib, prevIndex, achunk, aindex); + + // return + return oldAttrIndex; + + } // setAttributeNode(int,int):int + + + /** Adds an attribute node to the specified element. */ + public void setIdAttributeNode(int elemIndex, int attrIndex) { + + int chunk = attrIndex >> CHUNK_SHIFT; + int index = attrIndex & CHUNK_MASK; + int extra = getChunkIndex(fNodeExtra, chunk, index); + extra = extra | ID; + setChunkIndex(fNodeExtra, extra, chunk, index); + + String value = getChunkValue(fNodeValue, chunk, index); + putIdentifier(value, elemIndex); + } + + + /** Sets type of attribute */ + public void setIdAttribute(int attrIndex) { + + int chunk = attrIndex >> CHUNK_SHIFT; + int index = attrIndex & CHUNK_MASK; + int extra = getChunkIndex(fNodeExtra, chunk, index); + extra = extra | ID; + setChunkIndex(fNodeExtra, extra, chunk, index); + } + + /** Inserts a child before the specified node in the table. */ + public int insertBefore(int parentIndex, int newChildIndex, int refChildIndex) { + + if (refChildIndex == -1) { + appendChild(parentIndex, newChildIndex); + return newChildIndex; + } + + int nchunk = newChildIndex >> CHUNK_SHIFT; + int nindex = newChildIndex & CHUNK_MASK; + int rchunk = refChildIndex >> CHUNK_SHIFT; + int rindex = refChildIndex & CHUNK_MASK; + int previousIndex = getChunkIndex(fNodePrevSib, rchunk, rindex); + setChunkIndex(fNodePrevSib, newChildIndex, rchunk, rindex); + setChunkIndex(fNodePrevSib, previousIndex, nchunk, nindex); + + return newChildIndex; + + } // insertBefore(int,int,int):int + + /** Sets the last child of the parentIndex to childIndex. */ + public void setAsLastChild(int parentIndex, int childIndex) { + int pchunk = parentIndex >> CHUNK_SHIFT; + int pindex = parentIndex & CHUNK_MASK; + setChunkIndex(fNodeLastChild, childIndex, pchunk, pindex); + } // setAsLastChild(int,int) + + /** + * Returns the parent node of the given node. + * Calling this method does not free the parent index. + */ + public int getParentNode(int nodeIndex) { + return getParentNode(nodeIndex, false); + } + + /** + * Returns the parent node of the given node. + * @param free True to free parent node. + */ + public int getParentNode(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return -1; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + return free ? clearChunkIndex(fNodeParent, chunk, index) + : getChunkIndex(fNodeParent, chunk, index); + + } // getParentNode(int):int + + /** Returns the last child of the given node. */ + public int getLastChild(int nodeIndex) { + return getLastChild(nodeIndex, true); + } + + /** + * Returns the last child of the given node. + * @param free True to free child index. + */ + public int getLastChild(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return -1; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + return free ? clearChunkIndex(fNodeLastChild, chunk, index) + : getChunkIndex(fNodeLastChild, chunk, index); + + } // getLastChild(int,boolean):int + + /** + * Returns the prev sibling of the given node. + * This is post-normalization of Text Nodes. + */ + public int getPrevSibling(int nodeIndex) { + return getPrevSibling(nodeIndex, true); + } + + /** + * Returns the prev sibling of the given node. + * @param free True to free sibling index. + */ + public int getPrevSibling(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return -1; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + int type = getChunkIndex(fNodeType, chunk, index); + if (type == Node.TEXT_NODE) { + do { + nodeIndex = getChunkIndex(fNodePrevSib, chunk, index); + if (nodeIndex == -1) { + break; + } + chunk = nodeIndex >> CHUNK_SHIFT; + index = nodeIndex & CHUNK_MASK; + type = getChunkIndex(fNodeType, chunk, index); + } while (type == Node.TEXT_NODE); + } + else { + nodeIndex = getChunkIndex(fNodePrevSib, chunk, index); + } + + return nodeIndex; + + } // getPrevSibling(int,boolean):int + + /** + * Returns the real prev sibling of the given node, + * directly from the data structures. Used by TextImpl#getNodeValue() + * to normalize values. + */ + public int getRealPrevSibling(int nodeIndex) { + return getRealPrevSibling(nodeIndex, true); + } + + /** + * Returns the real prev sibling of the given node. + * @param free True to free sibling index. + */ + public int getRealPrevSibling(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return -1; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + return free ? clearChunkIndex(fNodePrevSib, chunk, index) + : getChunkIndex(fNodePrevSib, chunk, index); + + } // getReadPrevSibling(int,boolean):int + + /** + * Returns the index of the element definition in the table + * with the specified name index, or -1 if no such definition + * exists. + */ + public int lookupElementDefinition(String elementName) { + + if (fNodeCount > 1) { + + // find doctype + int docTypeIndex = -1; + int nchunk = 0; + int nindex = 0; + for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex); + index != -1; + index = getChunkIndex(fNodePrevSib, nchunk, nindex)) { + + nchunk = index >> CHUNK_SHIFT; + nindex = index & CHUNK_MASK; + if (getChunkIndex(fNodeType, nchunk, nindex) == Node.DOCUMENT_TYPE_NODE) { + docTypeIndex = index; + break; + } + } + + // find element definition + if (docTypeIndex == -1) { + return -1; + } + nchunk = docTypeIndex >> CHUNK_SHIFT; + nindex = docTypeIndex & CHUNK_MASK; + for (int index = getChunkIndex(fNodeLastChild, nchunk, nindex); + index != -1; + index = getChunkIndex(fNodePrevSib, nchunk, nindex)) { + + nchunk = index >> CHUNK_SHIFT; + nindex = index & CHUNK_MASK; + if (getChunkIndex(fNodeType, nchunk, nindex) == + NodeImpl.ELEMENT_DEFINITION_NODE + && getChunkValue(fNodeName, nchunk, nindex) == elementName) { + return index; + } + } + } + + return -1; + + } // lookupElementDefinition(String):int + + /** Instantiates the requested node object. */ + public DeferredNode getNodeObject(int nodeIndex) { + + // is there anything to do? + if (nodeIndex == -1) { + return null; + } + + // get node type + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + int type = getChunkIndex(fNodeType, chunk, index); + if (type != Node.TEXT_NODE && type != Node.CDATA_SECTION_NODE) { + clearChunkIndex(fNodeType, chunk, index); + } + + // create new node + DeferredNode node = null; + switch (type) { + + // + // Standard DOM node types + // + + case Node.ATTRIBUTE_NODE: { + if (fNamespacesEnabled) { + node = new DeferredAttrNSImpl(this, nodeIndex); + } else { + node = new DeferredAttrImpl(this, nodeIndex); + } + break; + } + + case Node.CDATA_SECTION_NODE: { + node = new DeferredCDATASectionImpl(this, nodeIndex); + break; + } + + case Node.COMMENT_NODE: { + node = new DeferredCommentImpl(this, nodeIndex); + break; + } + + // NOTE: Document fragments can never be "fast". + // + // The parser will never ask to create a document + // fragment during the parse. Document fragments + // are used by the application *after* the parse. + // + // case Node.DOCUMENT_FRAGMENT_NODE: { break; } + case Node.DOCUMENT_NODE: { + // this node is never "fast" + node = this; + break; + } + + case Node.DOCUMENT_TYPE_NODE: { + node = new DeferredDocumentTypeImpl(this, nodeIndex); + // save the doctype node + docType = (DocumentTypeImpl)node; + break; + } + + case Node.ELEMENT_NODE: { + + if (DEBUG_IDS) { + System.out.println("getNodeObject(ELEMENT_NODE): "+nodeIndex); + } + + // create node + if (fNamespacesEnabled) { + node = new DeferredElementNSImpl(this, nodeIndex); + } else { + node = new DeferredElementImpl(this, nodeIndex); + } + + // check to see if this element needs to be + // registered for its ID attributes + if (fIdElement != null) { + int idIndex = binarySearch(fIdElement, 0, + fIdCount-1, nodeIndex); + while (idIndex != -1) { + + if (DEBUG_IDS) { + System.out.println(" id index: "+idIndex); + System.out.println(" fIdName["+idIndex+ + "]: "+fIdName[idIndex]); + } + + // register ID + String name = fIdName[idIndex]; + if (name != null) { + if (DEBUG_IDS) { + System.out.println(" name: "+name); + System.out.print("getNodeObject()#"); + } + putIdentifier0(name, (Element)node); + fIdName[idIndex] = null; + } + + // continue if there are more IDs for + // this element + if (idIndex + 1 < fIdCount && + fIdElement[idIndex + 1] == nodeIndex) { + idIndex++; + } + else { + idIndex = -1; + } + } + } + break; + } + + case Node.ENTITY_NODE: { + node = new DeferredEntityImpl(this, nodeIndex); + break; + } + + case Node.ENTITY_REFERENCE_NODE: { + node = new DeferredEntityReferenceImpl(this, nodeIndex); + break; + } + + case Node.NOTATION_NODE: { + node = new DeferredNotationImpl(this, nodeIndex); + break; + } + + case Node.PROCESSING_INSTRUCTION_NODE: { + node = new DeferredProcessingInstructionImpl(this, nodeIndex); + break; + } + + case Node.TEXT_NODE: { + node = new DeferredTextImpl(this, nodeIndex); + break; + } + + // + // non-standard DOM node types + // + + case NodeImpl.ELEMENT_DEFINITION_NODE: { + node = new DeferredElementDefinitionImpl(this, nodeIndex); + break; + } + + default: { + throw new IllegalArgumentException("type: "+type); + } + + } // switch node type + + // store and return + if (node != null) { + return node; + } + + // error + throw new IllegalArgumentException(); + + } // createNodeObject(int):Node + + /** Returns the name of the given node. */ + public String getNodeName(int nodeIndex) { + return getNodeName(nodeIndex, true); + } // getNodeNameString(int):String + + /** + * Returns the name of the given node. + * @param free True to free the string index. + */ + public String getNodeName(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return null; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + return free ? clearChunkValue(fNodeName, chunk, index) + : getChunkValue(fNodeName, chunk, index); + + } // getNodeName(int,boolean):String + + /** Returns the real value of the given node. */ + public String getNodeValueString(int nodeIndex) { + return getNodeValueString(nodeIndex, true); + } // getNodeValueString(int):String + + /** + * Returns the real value of the given node. + * @param free True to free the string index. + */ + public String getNodeValueString(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return null; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + String value = free ? clearChunkValue(fNodeValue, chunk, index) + : getChunkValue(fNodeValue, chunk, index); + if (value == null) { + return null; + } + + int type = getChunkIndex(fNodeType, chunk, index); + if (type == Node.TEXT_NODE) { + int prevSib = getRealPrevSibling(nodeIndex); + if (prevSib != -1 && + getNodeType(prevSib, false) == Node.TEXT_NODE) { + // append data that is stored in fNodeValue + // REVISIT: for text nodes it works differently than for CDATA + // nodes. + fStrChunks.add(value); + do { + // go in reverse order: find last child, then + // its previous sibling, etc + chunk = prevSib >> CHUNK_SHIFT; + index = prevSib & CHUNK_MASK; + value = getChunkValue(fNodeValue, chunk, index); + fStrChunks.add(value); + prevSib = getChunkIndex(fNodePrevSib, chunk, index); + if (prevSib == -1) { + break; + } + } while (getNodeType(prevSib, false) == Node.TEXT_NODE); + + int chunkCount = fStrChunks.size(); + + // add to the buffer in the correct order. + for (int i = chunkCount - 1; i >= 0; i--) { + fBufferStr.append((String)fStrChunks.get(i)); + } + + value = fBufferStr.toString(); + fStrChunks.clear(); + fBufferStr.setLength(0); + return value; + } + } + else if (type == Node.CDATA_SECTION_NODE) { + // find if any other data stored in children + int child = getLastChild(nodeIndex, false); + if (child !=-1) { + // append data that is stored in fNodeValue + fBufferStr.append(value); + while (child !=-1) { + // go in reverse order: find last child, then + // its previous sibling, etc + chunk = child >> CHUNK_SHIFT; + index = child & CHUNK_MASK; + value = getChunkValue(fNodeValue, chunk, index); + fStrChunks.add(value); + child = getChunkIndex(fNodePrevSib, chunk, index); + } + // add to the buffer in the correct order. + for (int i=fStrChunks.size()-1; i>=0; i--) { + fBufferStr.append((String)fStrChunks.get(i)); + } + + value = fBufferStr.toString(); + fStrChunks.clear(); + fBufferStr.setLength(0); + return value; + } + } + + return value; + + } // getNodeValueString(int,boolean):String + + /** + * Returns the value of the given node. + */ + public String getNodeValue(int nodeIndex) { + return getNodeValue(nodeIndex, true); + } + + /** + * Clears the type info that is stored in the fNodeValue array + * @param nodeIndex + * @return Object - type information for the attribute/element node + */ + public Object getTypeInfo(int nodeIndex) { + if (nodeIndex == -1) { + return null; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + + + Object value = fNodeValue[chunk] != null ? fNodeValue[chunk][index] : null; + if (value != null) { + fNodeValue[chunk][index] = null; + RefCount c = (RefCount) fNodeValue[chunk][CHUNK_SIZE]; + c.fCount--; + if (c.fCount == 0) { + fNodeValue[chunk] = null; + } + } + return value; + } + + /** + * Returns the value of the given node. + * @param free True to free the value index. + */ + public String getNodeValue(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return null; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + return free ? clearChunkValue(fNodeValue, chunk, index) + : getChunkValue(fNodeValue, chunk, index); + + } // getNodeValue(int,boolean):String + + /** + * Returns the extra info of the given node. + * Used by AttrImpl to store specified value (1 == true). + */ + public int getNodeExtra(int nodeIndex) { + return getNodeExtra(nodeIndex, true); + } + + /** + * Returns the extra info of the given node. + * @param free True to free the value index. + */ + public int getNodeExtra(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return -1; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + return free ? clearChunkIndex(fNodeExtra, chunk, index) + : getChunkIndex(fNodeExtra, chunk, index); + + } // getNodeExtra(int,boolean):int + + /** Returns the type of the given node. */ + public short getNodeType(int nodeIndex) { + return getNodeType(nodeIndex, true); + } + + /** + * Returns the type of the given node. + * @param free True to free type index. + */ + public short getNodeType(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return -1; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + return free ? (short)clearChunkIndex(fNodeType, chunk, index) + : (short)getChunkIndex(fNodeType, chunk, index); + + } // getNodeType(int):int + + /** Returns the attribute value of the given name. */ + public String getAttribute(int elemIndex, String name) { + if (elemIndex == -1 || name == null) { + return null; + } + int echunk = elemIndex >> CHUNK_SHIFT; + int eindex = elemIndex & CHUNK_MASK; + int attrIndex = getChunkIndex(fNodeExtra, echunk, eindex); + while (attrIndex != -1) { + int achunk = attrIndex >> CHUNK_SHIFT; + int aindex = attrIndex & CHUNK_MASK; + if (getChunkValue(fNodeName, achunk, aindex) == name) { + return getChunkValue(fNodeValue, achunk, aindex); + } + attrIndex = getChunkIndex(fNodePrevSib, achunk, aindex); + } + return null; + } + + /** Returns the URI of the given node. */ + public String getNodeURI(int nodeIndex) { + return getNodeURI(nodeIndex, true); + } + + /** + * Returns the URI of the given node. + * @param free True to free URI index. + */ + public String getNodeURI(int nodeIndex, boolean free) { + + if (nodeIndex == -1) { + return null; + } + + int chunk = nodeIndex >> CHUNK_SHIFT; + int index = nodeIndex & CHUNK_MASK; + return free ? clearChunkValue(fNodeURI, chunk, index) + : getChunkValue(fNodeURI, chunk, index); + + } // getNodeURI(int,int):String + + // identifier maintenance + + /** Registers an identifier name with a specified element node. */ + public void putIdentifier(String name, int elementNodeIndex) { + + if (DEBUG_IDS) { + System.out.println("putIdentifier(" + name + ", " + + elementNodeIndex + ')' + " // " + + getChunkValue(fNodeName, + elementNodeIndex >> CHUNK_SHIFT, + elementNodeIndex & CHUNK_MASK)); + } + + // initialize arrays + if (fIdName == null) { + fIdName = new String[64]; + fIdElement = new int[64]; + } + + // resize arrays + if (fIdCount == fIdName.length) { + String idName[] = new String[fIdCount * 2]; + System.arraycopy(fIdName, 0, idName, 0, fIdCount); + fIdName = idName; + + int idElement[] = new int[idName.length]; + System.arraycopy(fIdElement, 0, idElement, 0, fIdCount); + fIdElement = idElement; + } + + // store identifier + fIdName[fIdCount] = name; + fIdElement[fIdCount] = elementNodeIndex; + fIdCount++; + + } // putIdentifier(String,int) + + // + // DEBUG + // + + /** Prints out the tables. */ + public void print() { + + if (DEBUG_PRINT_REF_COUNTS) { + System.out.print("num\t"); + System.out.print("type\t"); + System.out.print("name\t"); + System.out.print("val\t"); + System.out.print("par\t"); + System.out.print("lch\t"); + System.out.print("psib"); + System.out.println(); + for (int i = 0; i < fNodeType.length; i++) { + if (fNodeType[i] != null) { + // separator + System.out.print("--------"); + System.out.print("--------"); + System.out.print("--------"); + System.out.print("--------"); + System.out.print("--------"); + System.out.print("--------"); + System.out.print("--------"); + System.out.println(); + + // ref count + System.out.print(i); + System.out.print('\t'); + switch (fNodeType[i][CHUNK_SIZE]) { + case DocumentImpl.ELEMENT_DEFINITION_NODE: { System.out.print("EDef"); break; } + case Node.DOCUMENT_NODE: { System.out.print("Doc"); break; } + case Node.DOCUMENT_TYPE_NODE: { System.out.print("DType"); break; } + case Node.COMMENT_NODE: { System.out.print("Com"); break; } + case Node.PROCESSING_INSTRUCTION_NODE: { System.out.print("PI"); break; } + case Node.ELEMENT_NODE: { System.out.print("Elem"); break; } + case Node.ENTITY_NODE: { System.out.print("Ent"); break; } + case Node.ENTITY_REFERENCE_NODE: { System.out.print("ERef"); break; } + case Node.TEXT_NODE: { System.out.print("Text"); break; } + case Node.ATTRIBUTE_NODE: { System.out.print("Attr"); break; } + case DeferredNode.TYPE_NODE: { System.out.print("TypeInfo"); break; } + default: { System.out.print("?"+fNodeType[i][CHUNK_SIZE]); } + } + System.out.print('\t'); + System.out.print(fNodeName[i][CHUNK_SIZE]); + System.out.print('\t'); + System.out.print(fNodeValue[i][CHUNK_SIZE]); + System.out.print('\t'); + System.out.print(fNodeURI[i][CHUNK_SIZE]); + System.out.print('\t'); + System.out.print(fNodeParent[i][CHUNK_SIZE]); + System.out.print('\t'); + System.out.print(fNodeLastChild[i][CHUNK_SIZE]); + System.out.print('\t'); + System.out.print(fNodePrevSib[i][CHUNK_SIZE]); + System.out.print('\t'); + System.out.print(fNodeExtra[i][CHUNK_SIZE]); + System.out.println(); + } + } + } + + if (DEBUG_PRINT_TABLES) { + // This assumes that the document is small + System.out.println("# start table"); + for (int i = 0; i < fNodeCount; i++) { + int chunk = i >> CHUNK_SHIFT; + int index = i & CHUNK_MASK; + if (i % 10 == 0) { + System.out.print("num\t"); + System.out.print("type\t"); + System.out.print("name\t"); + System.out.print("val\t"); + System.out.print("uri\t"); + System.out.print("par\t"); + System.out.print("lch\t"); + System.out.print("psib\t"); + System.out.print("xtra"); + System.out.println(); + } + System.out.print(i); + System.out.print('\t'); + switch (getChunkIndex(fNodeType, chunk, index)) { + case DocumentImpl.ELEMENT_DEFINITION_NODE: { System.out.print("EDef"); break; } + case Node.DOCUMENT_NODE: { System.out.print("Doc"); break; } + case Node.DOCUMENT_TYPE_NODE: { System.out.print("DType"); break; } + case Node.COMMENT_NODE: { System.out.print("Com"); break; } + case Node.PROCESSING_INSTRUCTION_NODE: { System.out.print("PI"); break; } + case Node.ELEMENT_NODE: { System.out.print("Elem"); break; } + case Node.ENTITY_NODE: { System.out.print("Ent"); break; } + case Node.ENTITY_REFERENCE_NODE: { System.out.print("ERef"); break; } + case Node.TEXT_NODE: { System.out.print("Text"); break; } + case Node.ATTRIBUTE_NODE: { System.out.print("Attr"); break; } + case DeferredNode.TYPE_NODE: { System.out.print("TypeInfo"); break; } + default: { System.out.print("?"+getChunkIndex(fNodeType, chunk, index)); } + } + System.out.print('\t'); + System.out.print(getChunkValue(fNodeName, chunk, index)); + System.out.print('\t'); + System.out.print(getNodeValue(chunk, index)); + System.out.print('\t'); + System.out.print(getChunkValue(fNodeURI, chunk, index)); + System.out.print('\t'); + System.out.print(getChunkIndex(fNodeParent, chunk, index)); + System.out.print('\t'); + System.out.print(getChunkIndex(fNodeLastChild, chunk, index)); + System.out.print('\t'); + System.out.print(getChunkIndex(fNodePrevSib, chunk, index)); + System.out.print('\t'); + System.out.print(getChunkIndex(fNodeExtra, chunk, index)); + System.out.println(); + } + System.out.println("# end table"); + } + + } // print() + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return 0; + } + + // + // Protected methods + // + + /** Synchronizes the node's data. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff up enough nodes to fill identifiers hash + if (fIdElement != null) { + + // REVISIT: There has to be a more efficient way of + // doing this. But keep in mind that the + // tree can have been altered and re-ordered + // before all of the element nodes with ID + // attributes have been registered. For now + // this is reasonable and safe. -Ac + + IntVector path = new IntVector(); + for (int i = 0; i < fIdCount; i++) { + + // ignore if it's already been registered + int elementNodeIndex = fIdElement[i]; + String idName = fIdName[i]; + if (idName == null) { + continue; + } + + // find path from this element to the root + path.removeAllElements(); + int index = elementNodeIndex; + do { + path.addElement(index); + int pchunk = index >> CHUNK_SHIFT; + int pindex = index & CHUNK_MASK; + index = getChunkIndex(fNodeParent, pchunk, pindex); + } while (index != -1); + + // Traverse path (backwards), fluffing the elements + // along the way. When this loop finishes, "place" + // will contain the reference to the element node + // we're interested in. -Ac + Node place = this; + for (int j = path.size() - 2; j >= 0; j--) { + index = path.elementAt(j); + Node child = place.getLastChild(); + while (child != null) { + if (child instanceof DeferredNode) { + int nodeIndex = + ((DeferredNode)child).getNodeIndex(); + if (nodeIndex == index) { + place = child; + break; + } + } + child = child.getPreviousSibling(); + } + } + + // register the element + Element element = (Element)place; + putIdentifier0(idName, element); + fIdName[i] = null; + + // see if there are more IDs on this element + while (i + 1 < fIdCount && + fIdElement[i + 1] == elementNodeIndex) { + idName = fIdName[++i]; + if (idName == null) { + continue; + } + putIdentifier0(idName, element); + } + } + + } // if identifiers + + } // synchronizeData() + + /** + * Synchronizes the node's children with the internal structure. + * Fluffing the children at once solves a lot of work to keep + * the two structures in sync. The problem gets worse when + * editing the tree -- this makes it a lot easier. + */ + protected void synchronizeChildren() { + + if (needsSyncData()) { + synchronizeData(); + /* + * when we have elements with IDs this method is being recursively + * called from synchronizeData, in which case we've already gone + * through the following and we can now simply stop here. + */ + if (!needsSyncChildren()) { + return; + } + } + + // we don't want to generate any event for this so turn them off + boolean orig = mutationEvents; + mutationEvents = false; + + // no need to sync in the future + needsSyncChildren(false); + + getNodeType(0); + + // create children and link them as siblings + ChildNode first = null; + ChildNode last = null; + for (int index = getLastChild(0); + index != -1; + index = getPrevSibling(index)) { + + ChildNode node = (ChildNode)getNodeObject(index); + if (last == null) { + last = node; + } + else { + first.previousSibling = node; + } + node.ownerNode = this; + node.isOwned(true); + node.nextSibling = first; + first = node; + + // save doctype and document type + int type = node.getNodeType(); + if (type == Node.ELEMENT_NODE) { + docElement = (ElementImpl)node; + } + else if (type == Node.DOCUMENT_TYPE_NODE) { + docType = (DocumentTypeImpl)node; + } + } + + if (first != null) { + firstChild = first; + first.isFirstChild(true); + lastChild(last); + } + + // set mutation events flag back to its original value + mutationEvents = orig; + + } // synchronizeChildren() + + /** + * Synchronizes the node's children with the internal structure. + * Fluffing the children at once solves a lot of work to keep + * the two structures in sync. The problem gets worse when + * editing the tree -- this makes it a lot easier. + * This is not directly used in this class but this method is + * here so that it can be shared by all deferred subclasses of AttrImpl. + */ + protected final void synchronizeChildren(AttrImpl a, int nodeIndex) { + + // we don't want to generate any event for this so turn them off + boolean orig = getMutationEvents(); + setMutationEvents(false); + + // no need to sync in the future + a.needsSyncChildren(false); + + // create children and link them as siblings or simply store the value + // as a String if all we have is one piece of text + int last = getLastChild(nodeIndex); + int prev = getPrevSibling(last); + if (prev == -1) { + a.value = getNodeValueString(nodeIndex); + a.hasStringValue(true); + } + else { + ChildNode firstNode = null; + ChildNode lastNode = null; + for (int index = last; index != -1; + index = getPrevSibling(index)) { + + ChildNode node = (ChildNode) getNodeObject(index); + if (lastNode == null) { + lastNode = node; + } + else { + firstNode.previousSibling = node; + } + node.ownerNode = a; + node.isOwned(true); + node.nextSibling = firstNode; + firstNode = node; + } + if (lastNode != null) { + a.value = firstNode; // firstChild = firstNode + firstNode.isFirstChild(true); + a.lastChild(lastNode); + } + a.hasStringValue(false); + } + + // set mutation events flag back to its original value + setMutationEvents(orig); + + } // synchronizeChildren(AttrImpl,int):void + + + /** + * Synchronizes the node's children with the internal structure. + * Fluffing the children at once solves a lot of work to keep + * the two structures in sync. The problem gets worse when + * editing the tree -- this makes it a lot easier. + * This is not directly used in this class but this method is + * here so that it can be shared by all deferred subclasses of ParentNode. + */ + protected final void synchronizeChildren(ParentNode p, int nodeIndex) { + + // we don't want to generate any event for this so turn them off + boolean orig = getMutationEvents(); + setMutationEvents(false); + + // no need to sync in the future + p.needsSyncChildren(false); + + // create children and link them as siblings + ChildNode firstNode = null; + ChildNode lastNode = null; + for (int index = getLastChild(nodeIndex); + index != -1; + index = getPrevSibling(index)) { + + ChildNode node = (ChildNode) getNodeObject(index); + if (lastNode == null) { + lastNode = node; + } + else { + firstNode.previousSibling = node; + } + node.ownerNode = p; + node.isOwned(true); + node.nextSibling = firstNode; + firstNode = node; + } + if (lastNode != null) { + p.firstChild = firstNode; + firstNode.isFirstChild(true); + p.lastChild(lastNode); + } + + // set mutation events flag back to its original value + setMutationEvents(orig); + + } // synchronizeChildren(ParentNode,int):void + + // utility methods + + /** Ensures that the internal tables are large enough. */ + protected void ensureCapacity(int chunk) { + if (fNodeType == null) { + // create buffers + fNodeType = new int[INITIAL_CHUNK_COUNT][]; + fNodeName = new Object[INITIAL_CHUNK_COUNT][]; + fNodeValue = new Object[INITIAL_CHUNK_COUNT][]; + fNodeParent = new int[INITIAL_CHUNK_COUNT][]; + fNodeLastChild = new int[INITIAL_CHUNK_COUNT][]; + fNodePrevSib = new int[INITIAL_CHUNK_COUNT][]; + fNodeURI = new Object[INITIAL_CHUNK_COUNT][]; + fNodeExtra = new int[INITIAL_CHUNK_COUNT][]; + } + else if (fNodeType.length <= chunk) { + // resize the tables + int newsize = chunk * 2; + + int[][] newArray = new int[newsize][]; + System.arraycopy(fNodeType, 0, newArray, 0, chunk); + fNodeType = newArray; + + Object[][] newStrArray = new Object[newsize][]; + System.arraycopy(fNodeName, 0, newStrArray, 0, chunk); + fNodeName = newStrArray; + + newStrArray = new Object[newsize][]; + System.arraycopy(fNodeValue, 0, newStrArray, 0, chunk); + fNodeValue = newStrArray; + + newArray = new int[newsize][]; + System.arraycopy(fNodeParent, 0, newArray, 0, chunk); + fNodeParent = newArray; + + newArray = new int[newsize][]; + System.arraycopy(fNodeLastChild, 0, newArray, 0, chunk); + fNodeLastChild = newArray; + + newArray = new int[newsize][]; + System.arraycopy(fNodePrevSib, 0, newArray, 0, chunk); + fNodePrevSib = newArray; + + newStrArray = new Object[newsize][]; + System.arraycopy(fNodeURI, 0, newStrArray, 0, chunk); + fNodeURI = newStrArray; + + newArray = new int[newsize][]; + System.arraycopy(fNodeExtra, 0, newArray, 0, chunk); + fNodeExtra = newArray; + } + else if (fNodeType[chunk] != null) { + // Done - there's sufficient capacity + return; + } + + // create new chunks + createChunk(fNodeType, chunk); + createChunk(fNodeName, chunk); + createChunk(fNodeValue, chunk); + createChunk(fNodeParent, chunk); + createChunk(fNodeLastChild, chunk); + createChunk(fNodePrevSib, chunk); + createChunk(fNodeURI, chunk); + createChunk(fNodeExtra, chunk); + + // Done + return; + + } // ensureCapacity(int,int) + + /** Creates a node of the specified type. */ + protected int createNode(short nodeType) { + // ensure tables are large enough + int chunk = fNodeCount >> CHUNK_SHIFT; + int index = fNodeCount & CHUNK_MASK; + ensureCapacity(chunk); + + // initialize node + setChunkIndex(fNodeType, nodeType, chunk, index); + + // return node index number + return fNodeCount++; + + } // createNode(short):int + + /** + * Performs a binary search for a target value in an array of + * values. The array of values must be in ascending sorted order + * before calling this method and all array values must be + * non-negative. + * + * @param values The array of values to search. + * @param start The starting offset of the search. + * @param end The ending offset of the search. + * @param target The target value. + * + * @return This function will return the first occurrence + * of the target value, or -1 if the target value cannot + * be found. + */ + protected static int binarySearch(final int values[], + int start, int end, int target) { + + if (DEBUG_IDS) { + System.out.println("binarySearch(), target: "+target); + } + + // look for target value + while (start <= end) { + + // is this the one we're looking for? + int middle = (start + end) >>> 1; + int value = values[middle]; + if (DEBUG_IDS) { + System.out.print(" value: "+value+", target: "+target+" // "); + print(values, start, end, middle, target); + } + if (value == target) { + while (middle > 0 && values[middle - 1] == target) { + middle--; + } + if (DEBUG_IDS) { + System.out.println("FOUND AT "+middle); + } + return middle; + } + + // is this point higher or lower? + if (value > target) { + end = middle - 1; + } + else { + start = middle + 1; + } + + } // while + + // not found + if (DEBUG_IDS) { + System.out.println("NOT FOUND!"); + } + return -1; + + } // binarySearch(int[],int,int,int):int + + // + // Private methods + // + private static final int[] INIT_ARRAY = new int[CHUNK_SIZE + 1]; + static { + for (int i = 0; i < CHUNK_SIZE; i++) { + INIT_ARRAY[i] = -1; + } + } + /** Creates the specified chunk in the given array of chunks. */ + private final void createChunk(int data[][], int chunk) { + data[chunk] = new int[CHUNK_SIZE + 1]; + System.arraycopy(INIT_ARRAY, 0, data[chunk], 0, CHUNK_SIZE); + } + + static final class RefCount { + int fCount; + } + + private final void createChunk(Object data[][], int chunk) { + data[chunk] = new Object[CHUNK_SIZE + 1]; + data[chunk][CHUNK_SIZE] = new RefCount(); + } + + /** + * Sets the specified value in the given of data at the chunk and index. + * + * @return Returns the old value. + */ + private final int setChunkIndex(int data[][], int value, + int chunk, int index) { + if (value == -1) { + return clearChunkIndex(data, chunk, index); + } + int [] dataChunk = data[chunk]; + // Re-create chunk if it was deleted. + if (dataChunk == null) { + createChunk(data, chunk); + dataChunk = data[chunk]; + } + int ovalue = dataChunk[index]; + if (ovalue == -1) { + dataChunk[CHUNK_SIZE]++; + } + dataChunk[index] = value; + return ovalue; + } + private final String setChunkValue(Object data[][], Object value, + int chunk, int index) { + if (value == null) { + return clearChunkValue(data, chunk, index); + } + Object [] dataChunk = data[chunk]; + // Re-create chunk if it was deleted. + if (dataChunk == null) { + createChunk(data, chunk); + dataChunk = data[chunk]; + } + String ovalue = (String) dataChunk[index]; + if (ovalue == null) { + RefCount c = (RefCount) dataChunk[CHUNK_SIZE]; + c.fCount++; + } + dataChunk[index] = value; + return ovalue; + } + + /** + * Returns the specified value in the given data at the chunk and index. + */ + private final int getChunkIndex(int data[][], int chunk, int index) { + return data[chunk] != null ? data[chunk][index] : -1; + } + private final String getChunkValue(Object data[][], int chunk, int index) { + return data[chunk] != null ? (String) data[chunk][index] : null; + } + private final String getNodeValue(int chunk, int index) { + Object data = fNodeValue[chunk][index]; + if (data == null){ + return null; + } + else if (data instanceof String){ + return (String)data; + } + else { + // type information + return data.toString(); + } + } + + + /** + * Clears the specified value in the given data at the chunk and index. + * Note that this method will clear the given chunk if the reference + * count becomes zero. + * + * @return Returns the old value. + */ + private final int clearChunkIndex(int data[][], int chunk, int index) { + int value = data[chunk] != null ? data[chunk][index] : -1; + if (value != -1) { + data[chunk][CHUNK_SIZE]--; + data[chunk][index] = -1; + if (data[chunk][CHUNK_SIZE] == 0) { + data[chunk] = null; + } + } + return value; + } + private final String clearChunkValue(Object data[][], + int chunk, int index) { + String value = data[chunk] != null ? (String)data[chunk][index] : null; + if (value != null) { + data[chunk][index] = null; + RefCount c = (RefCount) data[chunk][CHUNK_SIZE]; + c.fCount--; + if (c.fCount == 0) { + data[chunk] = null; + } + } + return value; + } + + /** + * This version of putIdentifier is needed to avoid fluffing + * all of the paths to ID attributes when a node object is + * created that contains an ID attribute. + */ + private final void putIdentifier0(String idName, Element element) { + + if (DEBUG_IDS) { + System.out.println("putIdentifier0("+ + idName+", "+ + element+')'); + } + + // create hashtable + if (identifiers == null) { + identifiers = new java.util.Hashtable(); + } + + // save ID and its associated element + identifiers.put(idName, element); + + } // putIdentifier0(String,Element) + + /** Prints the ID array. */ + private static void print(int values[], int start, int end, + int middle, int target) { + + if (DEBUG_IDS) { + System.out.print(start); + System.out.print(" ["); + for (int i = start; i < end; i++) { + if (middle == i) { + System.out.print("!"); + } + System.out.print(values[i]); + if (values[i] == target) { + System.out.print("*"); + } + if (i < end - 1) { + System.out.print(" "); + } + } + System.out.println("] "+end); + } + + } // print(int[],int,int,int,int) + + // + // Classes + // + + /** + * A simple integer vector. + */ + static final class IntVector { + + // + // Data + // + + /** Data. */ + private int data[]; + + /** Size. */ + private int size; + + // + // Public methods + // + + /** Returns the length of this vector. */ + public int size() { + return size; + } + + /** Returns the element at the specified index. */ + public int elementAt(int index) { + return data[index]; + } + + /** Appends an element to the end of the vector. */ + public void addElement(int element) { + ensureCapacity(size + 1); + data[size++] = element; + } + + /** Clears the vector. */ + public void removeAllElements() { + size = 0; + } + + // + // Private methods + // + + /** Makes sure that there is enough storage. */ + private void ensureCapacity(int newsize) { + + if (data == null) { + data = new int[newsize + 15]; + } + else if (newsize > data.length) { + int newdata[] = new int[newsize + 15]; + System.arraycopy(data, 0, newdata, 0, data.length); + data = newdata; + } + + } // ensureCapacity(int) + + } // class IntVector + +} // class DeferredDocumentImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDocumentTypeImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDocumentTypeImpl.java new file mode 100644 index 0000000..bba39c2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredDocumentTypeImpl.java @@ -0,0 +1,185 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.Node; + +/** + * This class represents a Document Type declaraction in + * the document itself, not a Document Type Definition (DTD). + * An XML document may (or may not) have such a reference. + *

+ * DocumentType is an Extended DOM feature, used in XML documents but + * not in HTML. + *

+ * Note that Entities and Notations are no longer children of the + * DocumentType, but are parentless nodes hung only in their + * appropriate NamedNodeMaps. + *

+ * This area is UNDERSPECIFIED IN REC-DOM-Level-1-19981001 + * Most notably, absolutely no provision was made for storing + * and using Element and Attribute information. Nor was the linkage + * between Entities and Entity References nailed down solidly. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredDocumentTypeImpl + extends DocumentTypeImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -2172579663227313509L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredDocumentTypeImpl(DeferredDocumentImpl ownerDocument, int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + needsSyncChildren(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl)this.ownerDocument; + name = ownerDocument.getNodeName(fNodeIndex); + + // public and system ids + publicID = ownerDocument.getNodeValue(fNodeIndex); + systemID = ownerDocument.getNodeURI(fNodeIndex); + int extraDataIndex = ownerDocument.getNodeExtra(fNodeIndex); + internalSubset = ownerDocument.getNodeValue(extraDataIndex); + } // synchronizeData() + + /** Synchronizes the entities, notations, and elements. */ + protected void synchronizeChildren() { + + // we don't want to generate any event for this so turn them off + boolean orig = ownerDocument().getMutationEvents(); + ownerDocument().setMutationEvents(false); + + // no need to synchronize again + needsSyncChildren(false); + + // create new node maps + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl)this.ownerDocument; + + entities = new NamedNodeMapImpl(this); + notations = new NamedNodeMapImpl(this); + elements = new NamedNodeMapImpl(this); + + // fill node maps + DeferredNode last = null; + for (int index = ownerDocument.getLastChild(fNodeIndex); + index != -1; + index = ownerDocument.getPrevSibling(index)) { + + DeferredNode node = ownerDocument.getNodeObject(index); + int type = node.getNodeType(); + switch (type) { + + // internal, external, and unparsed entities + case Node.ENTITY_NODE: { + entities.setNamedItem(node); + break; + } + + // notations + case Node.NOTATION_NODE: { + notations.setNamedItem(node); + break; + } + + // element definitions + case NodeImpl.ELEMENT_DEFINITION_NODE: { + elements.setNamedItem(node); + break; + } + + // elements + case Node.ELEMENT_NODE: { + if (((DocumentImpl)getOwnerDocument()).allowGrammarAccess){ + insertBefore(node, last); + last = node; + break; + } + } + + // NOTE: Should never get here! -Ac + default: { + System.out.println("DeferredDocumentTypeImpl" + + "#synchronizeInfo: " + + "node.getNodeType() = " + + node.getNodeType() + + ", class = " + + node.getClass().getName()); + } + } + } + + // set mutation events flag back to its original value + ownerDocument().setMutationEvents(orig); + + // set entities and notations read_only per DOM spec + setReadOnly(true, false); + + } // synchronizeChildren() + +} // class DeferredDocumentTypeImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementDefinitionImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementDefinitionImpl.java new file mode 100644 index 0000000..2913a63 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementDefinitionImpl.java @@ -0,0 +1,124 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.Node; + +/** + * NON-DOM CLASS: Describe one of the Elements (and its associated + * Attributes) defined in this Document Type. + *

+ * I've included this in Level 1 purely as an anchor point for default + * attributes. In Level 2 it should enable the ChildRule support. + * + * @xerces.internal + * + * @version $Id$ + */ +public class DeferredElementDefinitionImpl + extends ElementDefinitionImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 6703238199538041591L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredElementDefinitionImpl(DeferredDocumentImpl ownerDocument, + int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + needsSyncChildren(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl)this.ownerDocument; + name = ownerDocument.getNodeName(fNodeIndex); + + } // synchronizeData() + + /** Synchronizes the default attribute values. */ + protected void synchronizeChildren() { + + // we don't want to generate any event for this so turn them off + boolean orig = ownerDocument.getMutationEvents(); + ownerDocument.setMutationEvents(false); + + // attributes are now synced + needsSyncChildren(false); + + // create attributes node map + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl)this.ownerDocument; + attributes = new NamedNodeMapImpl(ownerDocument); + + // Default attributes dangle as children of the element + // definition "node" in the internal fast table. + for (int nodeIndex = ownerDocument.getLastChild(fNodeIndex); + nodeIndex != -1; + nodeIndex = ownerDocument.getPrevSibling(nodeIndex)) { + Node attr = ownerDocument.getNodeObject(nodeIndex); + attributes.setNamedItem(attr); + } + + // set mutation events flag back to its original value + ownerDocument.setMutationEvents(orig); + + } // synchronizeChildren() + +} // class DeferredElementDefinitionImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementImpl.java new file mode 100644 index 0000000..ee09d2a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementImpl.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +/* + * WARNING: because java doesn't support multi-inheritance some code is + * duplicated. If you're changing this file you probably want to change + * DeferredElementNSImpl.java at the same time. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.NamedNodeMap; + +/** + * Elements represent most of the "markup" and structure of the + * document. They contain both the data for the element itself + * (element name and attributes), and any contained nodes, including + * document text (as children). + *

+ * Elements may have Attributes associated with them; the API for this is + * defined in Node, but the function is implemented here. In general, XML + * applications should retrive Attributes as Nodes, since they may contain + * entity references and hence be a fairly complex sub-tree. HTML users will + * be dealing with simple string values, and convenience methods are provided + * to work in terms of Strings. + *

+ * DeferredElementImpl inherits from ElementImpl which does not support + * Namespaces. DeferredElementNSImpl, which inherits from ElementNSImpl, does. + * @see DeferredElementNSImpl + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredElementImpl + extends ElementImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -7670981133940934842L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. All + * other data, can be requested from the ownerDocument via the index. + */ + DeferredElementImpl(DeferredDocumentImpl ownerDoc, int nodeIndex) { + super(ownerDoc, null); + + fNodeIndex = nodeIndex; + needsSyncChildren(true); + + } // (DocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public final int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected final void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl)this.ownerDocument; + + // we don't want to generate any event for this so turn them off + boolean orig = ownerDocument.mutationEvents; + ownerDocument.mutationEvents = false; + + name = ownerDocument.getNodeName(fNodeIndex); + + // attributes + setupDefaultAttributes(); + int index = ownerDocument.getNodeExtra(fNodeIndex); + if (index != -1) { + NamedNodeMap attrs = getAttributes(); + do { + NodeImpl attr = (NodeImpl)ownerDocument.getNodeObject(index); + attrs.setNamedItem(attr); + index = ownerDocument.getPrevSibling(index); + } while (index != -1); + } + + // set mutation events flag back to its original value + ownerDocument.mutationEvents = orig; + + } // synchronizeData() + + protected final void synchronizeChildren() { + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) ownerDocument(); + ownerDocument.synchronizeChildren(this, fNodeIndex); + } // synchronizeChildren() + +} // class DeferredElementImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementNSImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementNSImpl.java new file mode 100644 index 0000000..bfb0b8f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredElementNSImpl.java @@ -0,0 +1,158 @@ +/* + * 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. + */ + + +/* + * WARNING: because java doesn't support multi-inheritance some code is + * duplicated. If you're changing this file you probably want to change + * DeferredElementImpl.java at the same time. + * + * @version $Id$ + */ + +package org.apache.xerces.dom; + +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.NamedNodeMap; + +/** + * DeferredElementNSImpl is to ElementNSImpl, what DeferredElementImpl is to + * ElementImpl. + * + * @xerces.internal + * + * @see DeferredElementImpl + */ +public class DeferredElementNSImpl + extends ElementNSImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -5001885145370927385L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. All + * other data, can be requested from the ownerDocument via the index. + */ + DeferredElementNSImpl(DeferredDocumentImpl ownerDoc, int nodeIndex) { + super(ownerDoc, null); + + fNodeIndex = nodeIndex; + needsSyncChildren(true); + + } // (DocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public final int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected final void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) this.ownerDocument; + + // we don't want to generate any event for this so turn them off + boolean orig = ownerDocument.mutationEvents; + ownerDocument.mutationEvents = false; + + name = ownerDocument.getNodeName(fNodeIndex); + + // extract local part from QName + int index = name.indexOf(':'); + if (index < 0) { + localName = name; + } + else { + localName = name.substring(index + 1); + } + + namespaceURI = ownerDocument.getNodeURI(fNodeIndex); + type = (XSTypeDefinition)ownerDocument.getTypeInfo(fNodeIndex); + + // attributes + setupDefaultAttributes(); + int attrIndex = ownerDocument.getNodeExtra(fNodeIndex); + if (attrIndex != -1) { + NamedNodeMap attrs = getAttributes(); + boolean seenSchemaDefault = false; + do { + AttrImpl attr = (AttrImpl) ownerDocument.getNodeObject(attrIndex); + // Take special care of schema defaulted attributes. Calling the + // non-namespace aware setAttributeNode() method could overwrite + // another attribute with the same local name. + if (!attr.getSpecified() && (seenSchemaDefault || + (attr.getNamespaceURI() != null && + attr.getNamespaceURI() != NamespaceContext.XMLNS_URI && + attr.getName().indexOf(':') < 0))) { + seenSchemaDefault = true; + attrs.setNamedItemNS(attr); + } + else { + attrs.setNamedItem(attr); + } + attrIndex = ownerDocument.getPrevSibling(attrIndex); + } while (attrIndex != -1); + } + + // set mutation events flag back to its original value + ownerDocument.mutationEvents = orig; + + } // synchronizeData() + + /** + * Synchronizes the node's children with the internal structure. + * Fluffing the children at once solves a lot of work to keep + * the two structures in sync. The problem gets worse when + * editing the tree -- this makes it a lot easier. + */ + protected final void synchronizeChildren() { + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) ownerDocument(); + ownerDocument.synchronizeChildren(this, fNodeIndex); + } // synchronizeChildren() + +} // class DeferredElementImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredEntityImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredEntityImpl.java new file mode 100644 index 0000000..269d1c5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredEntityImpl.java @@ -0,0 +1,151 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + + +/** + * Entity nodes hold the reference data for an XML Entity -- either + * parsed or unparsed. The nodeName (inherited from Node) will contain + * the name (if any) of the Entity. Its data will be contained in the + * Entity's children, in exactly the structure which an + * EntityReference to this name will present within the document's + * body. + *

+ * Note that this object models the actual entity, _not_ the entity + * declaration or the entity reference. + *

+ * An XML processor may choose to completely expand entities before + * the structure model is passed to the DOM; in this case, there will + * be no EntityReferences in the DOM tree. + *

+ * Quoting the 10/01 DOM Proposal, + *

+ * "The DOM Level 1 does not support editing Entity nodes; if a user + * wants to make changes to the contents of an Entity, every related + * EntityReference node has to be replaced in the structure model by + * a clone of the Entity's contents, and then the desired changes + * must be made to each of those clones instead. All the + * descendants of an Entity node are readonly." + *
+ * I'm interpreting this as: It is the parser's responsibilty to call + * the non-DOM operation setReadOnly(true,true) after it constructs + * the Entity. Since the DOM explicitly decided not to deal with this, + * _any_ answer will involve a non-DOM operation, and this is the + * simplest solution. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredEntityImpl + extends EntityImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 4760180431078941638L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredEntityImpl(DeferredDocumentImpl ownerDocument, int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + needsSyncChildren(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** + * Synchronize the entity data. This is special because of the way + * that the "fast" version stores the information. + */ + protected void synchronizeData() { + + // no need to sychronize again + needsSyncData(false); + + // get the node data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl)this.ownerDocument; + name = ownerDocument.getNodeName(fNodeIndex); + + // get the entity data + publicId = ownerDocument.getNodeValue(fNodeIndex); + systemId = ownerDocument.getNodeURI(fNodeIndex); + int extraDataIndex = ownerDocument.getNodeExtra(fNodeIndex); + ownerDocument.getNodeType(extraDataIndex); + + notationName = ownerDocument.getNodeName(extraDataIndex); + + // encoding and version DOM L3 + version = ownerDocument.getNodeValue(extraDataIndex); + encoding = ownerDocument.getNodeURI(extraDataIndex); + + // baseURI, actualEncoding DOM L3 + int extraIndex2 = ownerDocument.getNodeExtra(extraDataIndex); + baseURI = ownerDocument.getNodeName(extraIndex2); + inputEncoding = ownerDocument.getNodeValue(extraIndex2); + + } // synchronizeData() + + /** Synchronize the children. */ + protected void synchronizeChildren() { + + // no need to synchronize again + needsSyncChildren(false); + + isReadOnly(false); + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) ownerDocument(); + ownerDocument.synchronizeChildren(this, fNodeIndex); + setReadOnly(true, true); + + } // synchronizeChildren() + +} // class DeferredEntityImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredEntityReferenceImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredEntityReferenceImpl.java new file mode 100644 index 0000000..1fab9d6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredEntityReferenceImpl.java @@ -0,0 +1,153 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +/** + * EntityReference models the XML &entityname; syntax, when used for + * entities defined by the DOM. Entities hardcoded into XML, such as + * character entities, should instead have been translated into text + * by the code which generated the DOM tree. + *

+ * An XML processor has the alternative of fully expanding Entities + * into the normal document tree. If it does so, no EntityReference nodes + * will appear. + *

+ * Similarly, non-validating XML processors are not required to read + * or process entity declarations made in the external subset or + * declared in external parameter entities. Hence, some applications + * may not make the replacement value available for Parsed Entities + * of these types. + *

+ * EntityReference behaves as a read-only node, and the children of + * the EntityReference (which reflect those of the Entity, and should + * also be read-only) give its replacement value, if any. They are + * supposed to automagically stay in synch if the DocumentType is + * updated with new values for the Entity. + *

+ * The defined behavior makes efficient storage difficult for the DOM + * implementor. We can't just look aside to the Entity's definition + * in the DocumentType since those nodes have the wrong parent (unless + * we can come up with a clever "imaginary parent" mechanism). We + * must at least appear to clone those children... which raises the + * issue of keeping the reference synchronized with its parent. + * This leads me back to the "cached image of centrally defined data" + * solution, much as I dislike it. + *

+ * For now I have decided, since REC-DOM-Level-1-19980818 doesn't + * cover this in much detail, that synchronization doesn't have to be + * considered while the user is deep in the tree. That is, if you're + * looking within one of the EntityReferennce's children and the Entity + * changes, you won't be informed; instead, you will continue to access + * the same object -- which may or may not still be part of the tree. + * This is the same behavior that obtains elsewhere in the DOM if the + * subtree you're looking at is deleted from its parent, so it's + * acceptable here. (If it really bothers folks, we could set things + * up so deleted subtrees are walked and marked invalid, but that's + * not part of the DOM's defined behavior.) + *

+ * As a result, only the EntityReference itself has to be aware of + * changes in the Entity. And it can take advantage of the same + * structure-change-monitoring code I implemented to support + * DeepNodeList. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredEntityReferenceImpl + extends EntityReferenceImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 390319091370032223L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredEntityReferenceImpl(DeferredDocumentImpl ownerDocument, + int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** + * Synchronize the entity data. This is special because of the way + * that the "fast" version stores the information. + */ + protected void synchronizeData() { + + // no need to sychronize again + needsSyncData(false); + + // get the node data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl)this.ownerDocument; + name = ownerDocument.getNodeName(fNodeIndex); + baseURI = ownerDocument.getNodeValue(fNodeIndex); + + } // synchronizeData() + + /** Synchronize the children. */ + protected void synchronizeChildren() { + + // no need to synchronize again + needsSyncChildren(false); + + // get children + isReadOnly(false); + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) ownerDocument(); + ownerDocument.synchronizeChildren(this, fNodeIndex); + setReadOnly(true, true); + + } // synchronizeChildren() + +} // class DeferredEntityReferenceImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredNode.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredNode.java new file mode 100644 index 0000000..f54376a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredNode.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.Node; + +/** + * An interface for deferred node object. + * + * @xerces.internal + * + * @version $Id$ + */ +public interface DeferredNode extends Node { + + + public static final short TYPE_NODE = 20; + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex(); + +} // interface DeferredNode diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredNotationImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredNotationImpl.java new file mode 100644 index 0000000..ce8c600 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredNotationImpl.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +/** + * Notations are how the Document Type Description (DTD) records hints + * about the format of an XML "unparsed entity" -- in other words, + * non-XML data bound to this document type, which some applications + * may wish to consult when manipulating the document. A Notation + * represents a name-value pair, with its nodeName being set to the + * declared name of the notation. + *

+ * Notations are also used to formally declare the "targets" of + * Processing Instructions. + *

+ * Note that the Notation's data is non-DOM information; the DOM only + * records what and where it is. + *

+ * See the XML 1.0 spec, sections 4.7 and 2.6, for more info. + *

+ * Level 1 of the DOM does not support editing Notation contents. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredNotationImpl + extends NotationImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 5705337172887990848L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredNotationImpl(DeferredDocumentImpl ownerDocument, int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** + * Synchronizes the data. This is special because of the way + * that the "fast" notation stores its information internally. + */ + protected void synchronizeData() { + + // no need to synchronize again + needsSyncData(false); + + // name + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl)this.ownerDocument(); + name = ownerDocument.getNodeName(fNodeIndex); + + ownerDocument.getNodeType(fNodeIndex); + // public and system ids + publicId = ownerDocument.getNodeValue(fNodeIndex); + systemId = ownerDocument.getNodeURI(fNodeIndex); + int extraDataIndex = ownerDocument.getNodeExtra(fNodeIndex); + ownerDocument.getNodeType(extraDataIndex); + baseURI = ownerDocument.getNodeName(extraDataIndex); + + + } // synchronizeData() + +} // class DeferredNotationImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredProcessingInstructionImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredProcessingInstructionImpl.java new file mode 100644 index 0000000..c1f2f90 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredProcessingInstructionImpl.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +/** + * Processing Instructions (PIs) permit documents to carry + * processor-specific information alongside their actual content. PIs + * are most common in XML, but they are supported in HTML as well. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredProcessingInstructionImpl + extends ProcessingInstructionImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -4643577954293565388L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredProcessingInstructionImpl(DeferredDocumentImpl ownerDocument, + int nodeIndex) { + super(ownerDocument, null, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the data. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // fluff data + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) this.ownerDocument(); + target = ownerDocument.getNodeName(fNodeIndex); + data = ownerDocument.getNodeValueString(fNodeIndex); + + } // synchronizeData() + +} // class DeferredProcessingInstructionImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DeferredTextImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredTextImpl.java new file mode 100644 index 0000000..e17dced --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DeferredTextImpl.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +/** + * Text nodes hold the non-markup, non-Entity content of + * an Element or Attribute. + *

+ * When a document is first made available to the DOM, there is only + * one Text object for each block of adjacent plain-text. Users (ie, + * applications) may create multiple adjacent Texts during editing -- + * see {@link org.w3c.dom.Element#normalize} for discussion. + *

+ * Note that CDATASection is a subclass of Text. This is conceptually + * valid, since they're really just two different ways of quoting + * characters when they're written out as part of an XML stream. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DeferredTextImpl + extends TextImpl + implements DeferredNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 2310613872100393425L; + + // + // Data + // + + /** Node index. */ + protected transient int fNodeIndex; + + // + // Constructors + // + + /** + * This is the deferred constructor. Only the fNodeIndex is given here. + * All other data, can be requested from the ownerDocument via the index. + */ + DeferredTextImpl(DeferredDocumentImpl ownerDocument, int nodeIndex) { + super(ownerDocument, null); + + fNodeIndex = nodeIndex; + needsSyncData(true); + + } // (DeferredDocumentImpl,int) + + // + // DeferredNode methods + // + + /** Returns the node index. */ + public int getNodeIndex() { + return fNodeIndex; + } + + // + // Protected methods + // + + /** Synchronizes the underlying data. */ + protected void synchronizeData() { + + // no need for future synchronizations + needsSyncData(false); + + // get initial text value + DeferredDocumentImpl ownerDocument = + (DeferredDocumentImpl) this.ownerDocument(); + data = ownerDocument.getNodeValueString(fNodeIndex); + + // NOTE: We used to normalize adjacent text node values here. + // This code has moved to the DeferredDocumentImpl + // getNodeValueString() method. -Ac + + // ignorable whitespace + isIgnorableWhitespace(ownerDocument.getNodeExtra(fNodeIndex) == 1); + + } // synchronizeData() + +} // class DeferredTextImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DocumentFragmentImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DocumentFragmentImpl.java new file mode 100644 index 0000000..b5cdd6b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DocumentFragmentImpl.java @@ -0,0 +1,153 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * DocumentFragment is a "lightweight" or "minimal" Document + * object. It is very common to want to be able to extract a portion + * of a document's tree or to create a new fragment of a + * document. Imagine implementing a user command like cut or + * rearranging a document by moving fragments around. It is desirable + * to have an object which can hold such fragments and it is quite + * natural to use a Node for this purpose. While it is true that a + * Document object could fulfil this role, a Document object can + * potentially be a heavyweight object, depending on the underlying + * implementation... and in DOM Level 1, nodes aren't allowed to cross + * Document boundaries anyway. What is really needed for this is a + * very lightweight object. DocumentFragment is such an object. + *

+ * Furthermore, various operations -- such as inserting nodes as + * children of another Node -- may take DocumentFragment objects as + * arguments; this results in all the child nodes of the + * DocumentFragment being moved to the child list of this node. + *

+ * The children of a DocumentFragment node are zero or more nodes + * representing the tops of any sub-trees defining the structure of + * the document. DocumentFragment do not need to be well-formed XML + * documents (although they do need to follow the rules imposed upon + * well-formed XML parsed entities, which can have multiple top + * nodes). For example, a DocumentFragment might have only one child + * and that child node could be a Text node. Such a structure model + * represents neither an HTML document nor a well-formed XML document. + *

+ * When a DocumentFragment is inserted into a Document (or indeed any + * other Node that may take children) the children of the + * DocumentFragment and not the DocumentFragment itself are inserted + * into the Node. This makes the DocumentFragment very useful when the + * user wishes to create nodes that are siblings; the DocumentFragment + * acts as the parent of these nodes so that the user can use the + * standard methods from the Node interface, such as insertBefore() + * and appendChild(). + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DocumentFragmentImpl + extends ParentNode + implements DocumentFragment { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -7596449967279236746L; + + // + // Constructors + // + + /** Factory constructor. */ + public DocumentFragmentImpl(CoreDocumentImpl ownerDoc) { + super(ownerDoc); + } + + /** Constructor for serialization. */ + public DocumentFragmentImpl() {} + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.DOCUMENT_FRAGMENT_NODE; + } + + /** Returns the node name. */ + public String getNodeName() { + return "#document-fragment"; + } + + /** + * Override default behavior to call normalize() on this Node's + * children. It is up to implementors or Node to override normalize() + * to take action. + */ + public void normalize() { + // No need to normalize if already normalized. + if (isNormalized()) { + return; + } + if (needsSyncChildren()) { + synchronizeChildren(); + } + ChildNode kid, next; + + for (kid = firstChild; kid != null; kid = next) { + next = kid.nextSibling; + + // If kid is a text node, we need to check for one of two + // conditions: + // 1) There is an adjacent text node + // 2) There is no adjacent text node, but kid is + // an empty text node. + if ( kid.getNodeType() == Node.TEXT_NODE ) + { + // If an adjacent text node, merge it with kid + if ( next!=null && next.getNodeType() == Node.TEXT_NODE ) + { + ((Text)kid).appendData(next.getNodeValue()); + removeChild( next ); + next = kid; // Don't advance; there might be another. + } + else + { + // If kid is empty, remove it + if ( kid.getNodeValue() == null || kid.getNodeValue().length() == 0 ) { + removeChild( kid ); + } + } + } + + kid.normalize(); + } + + isNormalized(true); + } + +} // class DocumentFragmentImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DocumentImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DocumentImpl.java new file mode 100644 index 0000000..c4005aa --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DocumentImpl.java @@ -0,0 +1,1486 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.Serializable; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; + +import org.apache.xerces.dom.events.EventImpl; +import org.apache.xerces.dom.events.MouseEventImpl; +import org.apache.xerces.dom.events.MutationEventImpl; +import org.apache.xerces.dom.events.UIEventImpl; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.events.DocumentEvent; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventException; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.ranges.DocumentRange; +import org.w3c.dom.ranges.Range; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; + + +/** + * The Document interface represents the entire HTML or XML document. + * Conceptually, it is the root of the document tree, and provides the + * primary access to the document's data. + *

+ * Since elements, text nodes, comments, processing instructions, + * etc. cannot exist outside the context of a Document, the Document + * interface also contains the factory methods needed to create these + * objects. The Node objects created have a ownerDocument attribute + * which associates them with the Document within whose context they + * were created. + *

+ * The DocumentImpl class also implements the DOM Level 2 DocumentTraversal + * interface. This interface is comprised of factory methods needed to + * create NodeIterators and TreeWalkers. The process of creating NodeIterator + * objects also adds these references to this document. + * After finishing with an iterator it is important to remove the object + * using the remove methods in this implementation. This allows the release of + * the references from the iterator objects to the DOM Nodes. + *

+ * Note: When any node in the document is serialized, the + * entire document is serialized along with it. + * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Joe Kesselman, IBM + * @author Andy Clark, IBM + * @author Ralf Pfeiffer, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DocumentImpl + extends CoreDocumentImpl + implements DocumentTraversal, DocumentEvent, DocumentRange { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 515687835542616694L; + + // + // Data + // + + /** Node Iterators */ + protected transient List iterators; + + /** Reference queue for cleared Node Iterator references */ + protected transient ReferenceQueue iteratorReferenceQueue; + + /** Ranges */ + protected transient List ranges; + + /** Reference queue for cleared Range references */ + protected transient ReferenceQueue rangeReferenceQueue; + + /** Table for event listeners registered to this document nodes. */ + protected Hashtable eventListeners; + + /** Bypass mutation events firing. */ + protected boolean mutationEvents = false; + + // + // Constructors + // + + /** + * NON-DOM: Actually creating a Document is outside the DOM's spec, + * since it has to operate in terms of a particular implementation. + */ + public DocumentImpl() { + super(); + } + + /** Constructor. */ + public DocumentImpl(boolean grammarAccess) { + super(grammarAccess); + } + + /** + * For DOM2 support. + * The createDocument factory method is in DOMImplementation. + */ + public DocumentImpl(DocumentType doctype) + { + super(doctype); + } + + /** For DOM2 support. */ + public DocumentImpl(DocumentType doctype, boolean grammarAccess) { + super(doctype, grammarAccess); + } + + // + // Node methods + // + + /** + * Deep-clone a document, including fixing ownerDoc for the cloned + * children. Note that this requires bypassing the WRONG_DOCUMENT_ERR + * protection. I've chosen to implement it by calling importNode + * which is DOM Level 2. + * + * @return org.w3c.dom.Node + * @param deep boolean, iff true replicate children + */ + public Node cloneNode(boolean deep) { + + DocumentImpl newdoc = new DocumentImpl(); + callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED); + cloneNode(newdoc, deep); + + // experimental + newdoc.mutationEvents = mutationEvents; + + return newdoc; + + } // cloneNode(boolean):Node + + /** + * Retrieve information describing the abilities of this particular + * DOM implementation. Intended to support applications that may be + * using DOMs retrieved from several different sources, potentially + * with different underlying representations. + */ + public DOMImplementation getImplementation() { + // Currently implemented as a singleton, since it's hardcoded + // information anyway. + return DOMImplementationImpl.getDOMImplementation(); + } + + // + // DocumentTraversal methods + // + + /** + * NON-DOM extension: + * Create and return a NodeIterator. The NodeIterator is + * added to a list of NodeIterators so that it can be + * removed to free up the DOM Nodes it references. + * + * @param root The root of the iterator. + * @param whatToShow The whatToShow mask. + * @param filter The NodeFilter installed. Null means no filter. + */ + public NodeIterator createNodeIterator(Node root, + short whatToShow, + NodeFilter filter) + { + return createNodeIterator(root, whatToShow, filter, true); + } + + /** + * Create and return a NodeIterator. The NodeIterator is + * added to a list of NodeIterators so that it can be + * removed to free up the DOM Nodes it references. + * + * @param root The root of the iterator. + * @param whatToShow The whatToShow mask. + * @param filter The NodeFilter installed. Null means no filter. + * @param entityReferenceExpansion true to expand the contents of + * EntityReference nodes + * @since WD-DOM-Level-2-19990923 + */ + public NodeIterator createNodeIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + { + + if (root == null) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + NodeIterator iterator = new NodeIteratorImpl(this, + root, + whatToShow, + filter, + entityReferenceExpansion); + if (iterators == null) { + iterators = new LinkedList(); + iteratorReferenceQueue = new ReferenceQueue(); + } + + removeStaleIteratorReferences(); + iterators.add(new WeakReference(iterator, iteratorReferenceQueue)); + + return iterator; + } + + /** + * NON-DOM extension: + * Create and return a TreeWalker. + * + * @param root The root of the iterator. + * @param whatToShow The whatToShow mask. + * @param filter The NodeFilter installed. Null means no filter. + */ + public TreeWalker createTreeWalker(Node root, + short whatToShow, + NodeFilter filter) + { + return createTreeWalker(root, whatToShow, filter, true); + } + /** + * Create and return a TreeWalker. + * + * @param root The root of the iterator. + * @param whatToShow The whatToShow mask. + * @param filter The NodeFilter installed. Null means no filter. + * @param entityReferenceExpansion true to expand the contents of + * EntityReference nodes + * @since WD-DOM-Level-2-19990923 + */ + public TreeWalker createTreeWalker(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + { + if (root == null) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + return new TreeWalkerImpl(root, whatToShow, filter, + entityReferenceExpansion); + } + + // + // Not DOM Level 2. Support DocumentTraversal methods. + // + + /** + * This is not called by the developer client. The + * developer client uses the detach() function on the + * NodeIterator itself.

+ * + * This function is called from the NodeIterator#detach(). + */ + void removeNodeIterator(NodeIterator nodeIterator) { + + if (nodeIterator == null) return; + if (iterators == null) return; + + removeStaleIteratorReferences(); + Iterator i = iterators.iterator(); + while (i.hasNext()) { + Object iterator = ((Reference) i.next()).get(); + if (iterator == nodeIterator) { + i.remove(); + return; + } + // Remove stale reference from the list. + else if (iterator == null) { + i.remove(); + } + } + } + + /** + * Remove stale iterator references from the iterator list. + */ + private void removeStaleIteratorReferences() { + removeStaleReferences(iteratorReferenceQueue, iterators); + } + + /** + * Remove stale references from the given list. + */ + private void removeStaleReferences(ReferenceQueue queue, List list) { + Reference ref = queue.poll(); + int count = 0; + while (ref != null) { + ++count; + ref = queue.poll(); + } + if (count > 0) { + final Iterator i = list.iterator(); + while (i.hasNext()) { + Object o = ((Reference) i.next()).get(); + if (o == null) { + i.remove(); + if (--count <= 0) { + return; + } + } + } + } + } + + // + // DocumentRange methods + // + /** + */ + public Range createRange() { + + if (ranges == null) { + ranges = new LinkedList(); + rangeReferenceQueue = new ReferenceQueue(); + } + + Range range = new RangeImpl(this); + + removeStaleRangeReferences(); + ranges.add(new WeakReference(range, rangeReferenceQueue)); + + return range; + + } + + /** Not a client function. Called by Range.detach(), + * so a Range can remove itself from the list of + * Ranges. + */ + void removeRange(Range range) { + + if (range == null) return; + if (ranges == null) return; + + removeStaleRangeReferences(); + Iterator i = ranges.iterator(); + while (i.hasNext()) { + Object otherRange = ((Reference) i.next()).get(); + if (otherRange == range) { + i.remove(); + return; + } + // Remove stale reference from the list. + else if (otherRange == null) { + i.remove(); + } + } + } + + /** + * A method to be called when some text was changed in a text node, + * so that live objects can be notified. + */ + void replacedText(CharacterDataImpl node) { + // notify ranges + if (ranges != null) { + notifyRangesReplacedText(node); + } + } + + private void notifyRangesReplacedText(CharacterDataImpl node) { + removeStaleRangeReferences(); + final Iterator i = ranges.iterator(); + while (i.hasNext()) { + RangeImpl range = (RangeImpl) ((Reference) i.next()).get(); + if (range != null) { + range.receiveReplacedText(node); + } + // Remove stale reference from the list. + else { + i.remove(); + } + } + } + + /** + * A method to be called when some text was deleted from a text node, + * so that live objects can be notified. + */ + void deletedText(CharacterDataImpl node, int offset, int count) { + // notify ranges + if (ranges != null) { + notifyRangesDeletedText(node, offset, count); + } + } + + private void notifyRangesDeletedText(CharacterDataImpl node, int offset, int count) { + removeStaleRangeReferences(); + final Iterator i = ranges.iterator(); + while (i.hasNext()) { + RangeImpl range = (RangeImpl) ((Reference) i.next()).get(); + if (range != null) { + range.receiveDeletedText(node, offset, count); + } + // Remove stale reference from the list. + else { + i.remove(); + } + } + } + + /** + * A method to be called when some text was inserted into a text node, + * so that live objects can be notified. + */ + void insertedText(CharacterDataImpl node, int offset, int count) { + // notify ranges + if (ranges != null) { + notifyRangesInsertedText(node, offset, count); + } + } + + private void notifyRangesInsertedText(CharacterDataImpl node, int offset, int count) { + removeStaleRangeReferences(); + final Iterator i = ranges.iterator(); + while (i.hasNext()) { + RangeImpl range = (RangeImpl) ((Reference) i.next()).get(); + if (range != null) { + range.receiveInsertedText(node, offset, count); + } + // Remove stale reference from the list. + else { + i.remove(); + } + } + } + + /** + * A method to be called when a text node has been split, + * so that live objects can be notified. + */ + void splitData(Node node, Node newNode, int offset) { + // notify ranges + if (ranges != null) { + notifyRangesSplitData(node, newNode, offset); + } + } + + private void notifyRangesSplitData(Node node, Node newNode, int offset) { + removeStaleRangeReferences(); + final Iterator i = ranges.iterator(); + while (i.hasNext()) { + RangeImpl range = (RangeImpl) ((Reference) i.next()).get(); + if (range != null) { + range.receiveSplitData(node, newNode, offset); + } + // Remove stale reference from the list. + else { + i.remove(); + } + } + } + + /** + * Remove stale range references from the range list. + */ + private void removeStaleRangeReferences() { + removeStaleReferences(rangeReferenceQueue, ranges); + } + + // + // DocumentEvent methods + // + + /** + * Introduced in DOM Level 2. Optional.

+ * Create and return Event objects. + * + * @param type The eventType parameter specifies the type of Event + * interface to be created. If the Event interface specified is supported + * by the implementation this method will return a new Event of the + * interface type requested. If the Event is to be dispatched via the + * dispatchEvent method the appropriate event init method must be called + * after creation in order to initialize the Event's values. As an + * example, a user wishing to synthesize some kind of Event would call + * createEvent with the parameter "Events". The initEvent method could then + * be called on the newly created Event to set the specific type of Event + * to be dispatched and set its context information. + * @return Newly created Event + * @exception DOMException NOT_SUPPORTED_ERR: Raised if the implementation + * does not support the type of Event interface requested + * @since WD-DOM-Level-2-19990923 + */ + public Event createEvent(String type) throws DOMException { + if (type.equalsIgnoreCase("Events") || + "Event".equals(type)) { + return new EventImpl(); + } + else if (type.equalsIgnoreCase("MutationEvents") || + "MutationEvent".equals(type)) { + return new MutationEventImpl(); + } + else if (type.equalsIgnoreCase("UIEvents") || + "UIEvent".equals(type)) { + return new UIEventImpl(); + } + else if (type.equalsIgnoreCase("MouseEvents") || + "MouseEvent".equals(type)) { + return new MouseEventImpl(); + } + else { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + } + + /** + * Sets whether the DOM implementation generates mutation events + * upon operations. + */ + void setMutationEvents(boolean set) { + mutationEvents = set; + } + + /** + * Returns true if the DOM implementation generates mutation events. + */ + boolean getMutationEvents() { + return mutationEvents; + } + + /** + * Store event listener registered on a given node + * This is another place where we could use weak references! Indeed, the + * node here won't be GC'ed as long as some listener is registered on it, + * since the eventsListeners table will have a reference to the node. + */ + protected void setEventListeners(NodeImpl n, Vector listeners) { + if (eventListeners == null) { + eventListeners = new Hashtable(); + } + if (listeners == null) { + eventListeners.remove(n); + if (eventListeners.isEmpty()) { + // stop firing events when there isn't any listener + mutationEvents = false; + } + } else { + eventListeners.put(n, listeners); + // turn mutation events on + mutationEvents = true; + } + } + + /** + * Retreive event listener registered on a given node + */ + protected Vector getEventListeners(NodeImpl n) { + if (eventListeners == null) { + return null; + } + return (Vector) eventListeners.get(n); + } + + // + // EventTarget support (public and internal) + // + + // + // Constants + // + + /* + * NON-DOM INTERNAL: Class LEntry is just a struct used to represent + * event listeners registered with this node. Copies of this object + * are hung from the nodeListeners Vector. + *

+ * I considered using two vectors -- one for capture, + * one for bubble -- but decided that since the list of listeners + * is probably short in most cases, it might not be worth spending + * the space. ***** REVISIT WHEN WE HAVE MORE EXPERIENCE. + */ + class LEntry implements Serializable { + + private static final long serialVersionUID = -8426757059492421631L; + String type; + EventListener listener; + boolean useCapture; + + /** NON-DOM INTERNAL: Constructor for Listener list Entry + * @param type Event name (NOT event group!) to listen for. + * @param listener Who gets called when event is dispatched + * @param useCaptue True iff listener is registered on + * capturing phase rather than at-target or bubbling + */ + LEntry(String type, EventListener listener, boolean useCapture) + { + this.type = type; + this.listener = listener; + this.useCapture = useCapture; + } + + } // LEntry + + /** + * Introduced in DOM Level 2.

Register an event listener with this + * Node. A listener may be independently registered as both Capturing and + * Bubbling, but may only be registered once per role; redundant + * registrations are ignored. + * @param node node to add listener to + * @param type Event name (NOT event group!) to listen for. + * @param listener Who gets called when event is dispatched + * @param useCapture True iff listener is registered on + * capturing phase rather than at-target or bubbling + */ + protected void addEventListener(NodeImpl node, String type, + EventListener listener, boolean useCapture) + { + // We can't dispatch to blank type-name, and of course we need + // a listener to dispatch to + if (type == null || type.length() == 0 || listener == null) + return; + + // Each listener may be registered only once per type per phase. + // Simplest way to code that is to zap the previous entry, if any. + removeEventListener(node, type, listener, useCapture); + + Vector nodeListeners = getEventListeners(node); + if(nodeListeners == null) { + nodeListeners = new Vector(); + setEventListeners(node, nodeListeners); + } + nodeListeners.addElement(new LEntry(type, listener, useCapture)); + + // Record active listener + LCount lc = LCount.lookup(type); + if (useCapture) { + ++lc.captures; + ++lc.total; + } + else { + ++lc.bubbles; + ++lc.total; + } + + } // addEventListener(NodeImpl,String,EventListener,boolean) :void + + /** + * Introduced in DOM Level 2.

Deregister an event listener previously + * registered with this Node. A listener must be independently removed + * from the Capturing and Bubbling roles. Redundant removals (of listeners + * not currently registered for this role) are ignored. + * @param node node to remove listener from + * @param type Event name (NOT event group!) to listen for. + * @param listener Who gets called when event is dispatched + * @param useCapture True iff listener is registered on + * capturing phase rather than at-target or bubbling + */ + protected void removeEventListener(NodeImpl node, String type, + EventListener listener, + boolean useCapture) + { + // If this couldn't be a valid listener registration, ignore request + if (type == null || type.length() == 0 || listener == null) + return; + Vector nodeListeners = getEventListeners(node); + if (nodeListeners == null) + return; + + // Note that addListener has previously ensured that + // each listener may be registered only once per type per phase. + // count-down is OK for deletions! + for (int i = nodeListeners.size() - 1; i >= 0; --i) { + LEntry le = (LEntry) nodeListeners.elementAt(i); + if (le.useCapture == useCapture && le.listener == listener && + le.type.equals(type)) { + nodeListeners.removeElementAt(i); + // Storage management: Discard empty listener lists + if (nodeListeners.size() == 0) + setEventListeners(node, null); + + // Remove active listener + LCount lc = LCount.lookup(type); + if (useCapture) { + --lc.captures; + --lc.total; + } + else { + --lc.bubbles; + --lc.total; + } + + break; // Found it; no need to loop farther. + } + } + } // removeEventListener(NodeImpl,String,EventListener,boolean) :void + + protected void copyEventListeners(NodeImpl src, NodeImpl tgt) { + Vector nodeListeners = getEventListeners(src); + if (nodeListeners == null) { + return; + } + setEventListeners(tgt, (Vector) nodeListeners.clone()); + } + + /** + * Introduced in DOM Level 2.

+ * Distribution engine for DOM Level 2 Events. + *

+ * Event propagation runs as follows: + *

    + *
  1. Event is dispatched to a particular target node, which invokes + * this code. Note that the event's stopPropagation flag is + * cleared when dispatch begins; thereafter, if it has + * been set before processing of a node commences, we instead + * immediately advance to the DEFAULT phase. + *
  2. The node's ancestors are established as destinations for events. + * For capture and bubble purposes, node ancestry is determined at + * the time dispatch starts. If an event handler alters the document + * tree, that does not change which nodes will be informed of the event. + *
  3. CAPTURING_PHASE: Ancestors are scanned, root to target, for + * Capturing listeners. If found, they are invoked (see below). + *
  4. AT_TARGET: + * Event is dispatched to NON-CAPTURING listeners on the + * target node. Note that capturing listeners on this node are _not_ + * invoked. + *
  5. BUBBLING_PHASE: Ancestors are scanned, target to root, for + * non-capturing listeners. + *
  6. Default processing: Some DOMs have default behaviors bound to + * specific nodes. If this DOM does, and if the event's preventDefault + * flag has not been set, we now return to the target node and process + * its default handler for this event, if any. + *
+ *

+ * Note that registration of handlers during processing of an event does + * not take effect during this phase of this event; they will not be called + * until the next time this node is visited by dispatchEvent. On the other + * hand, removals take effect immediately. + *

+ * If an event handler itself causes events to be dispatched, they are + * processed synchronously, before processing resumes + * on the event which triggered them. Please be aware that this may + * result in events arriving at listeners "out of order" relative + * to the actual sequence of requests. + *

+ * Note that our implementation resets the event's stop/prevent flags + * when dispatch begins. + * I believe the DOM's intent is that event objects be redispatchable, + * though it isn't stated in those terms. + * @param node node to dispatch to + * @param event the event object to be dispatched to + * registered EventListeners + * @return true if the event's preventDefault() + * method was invoked by an EventListener; otherwise false. + */ + protected boolean dispatchEvent(NodeImpl node, Event event) { + if (event == null) return false; + + // Can't use anyone else's implementation, since there's no public + // API for setting the event's processing-state fields. + EventImpl evt = (EventImpl)event; + + // VALIDATE -- must have been initialized at least once, must have + // a non-null non-blank name. + if (!evt.initialized || evt.type == null || evt.type.length() == 0) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "UNSPECIFIED_EVENT_TYPE_ERR", null); + throw new EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR, msg); + } + + // If nobody is listening for this event, discard immediately + LCount lc = LCount.lookup(evt.getType()); + if (lc.total == 0) + return evt.preventDefault; + + // INITIALIZE THE EVENT'S DISPATCH STATUS + // (Note that Event objects are reusable in our implementation; + // that doesn't seem to be explicitly guaranteed in the DOM, but + // I believe it is the intent.) + evt.target = node; + evt.stopPropagation = false; + evt.preventDefault = false; + + // Capture pre-event parentage chain, not including target; + // use pre-event-dispatch ancestors even if event handlers mutate + // document and change the target's context. + // Note that this is parents ONLY; events do not + // cross the Attr/Element "blood/brain barrier". + // DOMAttrModified. which looks like an exception, + // is issued to the Element rather than the Attr + // and causes a _second_ DOMSubtreeModified in the Element's + // tree. + ArrayList pv = new ArrayList(10); + Node p = node; + Node n = p.getParentNode(); + while (n != null) { + pv.add(n); + p = n; + n = n.getParentNode(); + } + + // CAPTURING_PHASE: + if (lc.captures > 0) { + evt.eventPhase = Event.CAPTURING_PHASE; + // Ancestors are scanned, root to target, for + // Capturing listeners. + for (int j = pv.size() - 1; j >= 0; --j) { + if (evt.stopPropagation) + break; // Someone set the flag. Phase ends. + + // Handle all capturing listeners on this node + NodeImpl nn = (NodeImpl) pv.get(j); + evt.currentTarget = nn; + Vector nodeListeners = getEventListeners(nn); + if (nodeListeners != null) { + Vector nl = (Vector) nodeListeners.clone(); + // call listeners in the order in which they got registered + int nlsize = nl.size(); + for (int i = 0; i < nlsize; i++) { + LEntry le = (LEntry) nl.elementAt(i); + if (le.useCapture && le.type.equals(evt.type) && + nodeListeners.contains(le)) { + try { + le.listener.handleEvent(evt); + } + catch (Exception e) { + // All exceptions are ignored. + } + } + } + } + } + } + + + // Both AT_TARGET and BUBBLE use non-capturing listeners. + if (lc.bubbles > 0) { + // AT_TARGET PHASE: Event is dispatched to NON-CAPTURING listeners + // on the target node. Note that capturing listeners on the target + // node are _not_ invoked, even during the capture phase. + evt.eventPhase = Event.AT_TARGET; + evt.currentTarget = node; + Vector nodeListeners = getEventListeners(node); + if (!evt.stopPropagation && nodeListeners != null) { + Vector nl = (Vector) nodeListeners.clone(); + // call listeners in the order in which they got registered + int nlsize = nl.size(); + for (int i = 0; i < nlsize; i++) { + LEntry le = (LEntry) nl.elementAt(i); + if (!le.useCapture && le.type.equals(evt.type) && + nodeListeners.contains(le)) { + try { + le.listener.handleEvent(evt); + } + catch (Exception e) { + // All exceptions are ignored. + } + } + } + } + // BUBBLING_PHASE: Ancestors are scanned, target to root, for + // non-capturing listeners. If the event's preventBubbling flag + // has been set before processing of a node commences, we + // instead immediately advance to the default phase. + // Note that not all events bubble. + if (evt.bubbles) { + evt.eventPhase = Event.BUBBLING_PHASE; + int pvsize = pv.size(); + for (int j = 0; j < pvsize; j++) { + if (evt.stopPropagation) + break; // Someone set the flag. Phase ends. + + // Handle all bubbling listeners on this node + NodeImpl nn = (NodeImpl) pv.get(j); + evt.currentTarget = nn; + nodeListeners = getEventListeners(nn); + if (nodeListeners != null) { + Vector nl = (Vector) nodeListeners.clone(); + // call listeners in the order in which they got + // registered + int nlsize = nl.size(); + for (int i = 0; i < nlsize; i++) { + LEntry le = (LEntry) nl.elementAt(i); + if (!le.useCapture && le.type.equals(evt.type) && + nodeListeners.contains(le)) { + try { + le.listener.handleEvent(evt); + } + catch (Exception e) { + // All exceptions are ignored. + } + } + } + } + } + } + } + + // DEFAULT PHASE: Some DOMs have default behaviors bound to specific + // nodes. If this DOM does, and if the event's preventDefault flag has + // not been set, we now return to the target node and process its + // default handler for this event, if any. + // No specific phase value defined, since this is DOM-internal + if (lc.defaults > 0 && (!evt.cancelable || !evt.preventDefault)) { + // evt.eventPhase = Event.DEFAULT_PHASE; + // evt.currentTarget = node; + // DO_DEFAULT_OPERATION + } + + return evt.preventDefault; + } // dispatchEvent(NodeImpl,Event) :boolean + + /** + * NON-DOM INTERNAL: DOMNodeInsertedIntoDocument and ...RemovedFrom... + * are dispatched to an entire subtree. This is the distribution code + * therefor. They DO NOT bubble, thanks be, but may be captured. + *

+ * Similar to code in dispatchingEventToSubtree however this method + * is only used on the target node and does not start a dispatching chain + * on the sibling of the target node as this is not part of the subtree + * ***** At the moment I'm being sloppy and using the normal + * capture dispatcher on every node. This could be optimized hugely + * by writing a capture engine that tracks our position in the tree to + * update the capture chain without repeated chases up to root. + * @param n target node (that was directly inserted or removed) + * @param e event to be sent to that node and its subtree + */ + protected void dispatchEventToSubtree(Node n, Event e) { + + ((NodeImpl) n).dispatchEvent(e); + if (n.getNodeType() == Node.ELEMENT_NODE) { + NamedNodeMap a = n.getAttributes(); + for (int i = a.getLength() - 1; i >= 0; --i) + dispatchingEventToSubtree(a.item(i), e); + } + dispatchingEventToSubtree(n.getFirstChild(), e); + + } // dispatchEventToSubtree(NodeImpl,Node,Event) :void + + + /** + * Dispatches event to the target node's descendents recursively + * + * @param n node to dispatch to + * @param e event to be sent to that node and its subtree + */ + protected void dispatchingEventToSubtree(Node n, Event e) { + if (n==null) + return; + + // ***** Recursive implementation. This is excessively expensive, + // and should be replaced in conjunction with optimization + // mentioned above. + ((NodeImpl) n).dispatchEvent(e); + if (n.getNodeType() == Node.ELEMENT_NODE) { + NamedNodeMap a = n.getAttributes(); + for (int i = a.getLength() - 1; i >= 0; --i) + dispatchingEventToSubtree(a.item(i), e); + } + dispatchingEventToSubtree(n.getFirstChild(), e); + dispatchingEventToSubtree(n.getNextSibling(), e); + } + + /** + * NON-DOM INTERNAL: Return object for getEnclosingAttr. Carries + * (two values, the Attr node affected (if any) and its previous + * string value. Simple struct, no methods. + */ + class EnclosingAttr implements Serializable { + private static final long serialVersionUID = 5208387723391647216L; + AttrImpl node; + String oldvalue; + } + + EnclosingAttr savedEnclosingAttr; + + /** + * NON-DOM INTERNAL: Convenience wrapper for calling + * dispatchAggregateEvents when the context was established + * by savedEnclosingAttr. + * @param node node to dispatch to + * @param ea description of Attr affected by current operation + */ + protected void dispatchAggregateEvents(NodeImpl node, EnclosingAttr ea) { + if (ea != null) + dispatchAggregateEvents(node, ea.node, ea.oldvalue, + MutationEvent.MODIFICATION); + else + dispatchAggregateEvents(node, null, null, (short) 0); + + } // dispatchAggregateEvents(NodeImpl,EnclosingAttr) :void + + /** + * NON-DOM INTERNAL: Generate the "aggregated" post-mutation events + * DOMAttrModified and DOMSubtreeModified. + * Both of these should be issued only once for each user-requested + * mutation operation, even if that involves multiple changes to + * the DOM. + * For example, if a DOM operation makes multiple changes to a single + * Attr before returning, it would be nice to generate only one + * DOMAttrModified, and multiple changes over larger scope but within + * a recognizable single subtree might want to generate only one + * DOMSubtreeModified, sent to their lowest common ancestor. + *

+ * To manage this, use the "internal" versions of insert and remove + * with MUTATION_LOCAL, then make an explicit call to this routine + * at the higher level. Some examples now exist in our code. + * + * @param node The node to dispatch to + * @param enclosingAttr The Attr node (if any) whose value has been changed + * as a result of the DOM operation. Null if none such. + * @param oldvalue The String value previously held by the + * enclosingAttr. Ignored if none such. + * @param change Type of modification to the attr. See + * MutationEvent.attrChange + */ + protected void dispatchAggregateEvents(NodeImpl node, + AttrImpl enclosingAttr, + String oldvalue, short change) { + // We have to send DOMAttrModified. + NodeImpl owner = null; + if (enclosingAttr != null) { + LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED); + owner = (NodeImpl) enclosingAttr.getOwnerElement(); + if (lc.total > 0) { + if (owner != null) { + MutationEventImpl me = new MutationEventImpl(); + me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED, + true, false, enclosingAttr, + oldvalue, + enclosingAttr.getNodeValue(), + enclosingAttr.getNodeName(), + change); + owner.dispatchEvent(me); + } + } + } + // DOMSubtreeModified gets sent to the lowest common root of a + // set of changes. + // "This event is dispatched after all other events caused by the + // mutation have been fired." + LCount lc = LCount.lookup(MutationEventImpl.DOM_SUBTREE_MODIFIED); + if (lc.total > 0) { + MutationEvent me = new MutationEventImpl(); + me.initMutationEvent(MutationEventImpl.DOM_SUBTREE_MODIFIED, + true, false, null, null, + null, null, (short) 0); + + // If we're within an Attr, DStM gets sent to the Attr + // and to its owningElement. Otherwise we dispatch it + // locally. + if (enclosingAttr != null) { + dispatchEvent(enclosingAttr, me); + if (owner != null) + dispatchEvent(owner, me); + } + else + dispatchEvent(node, me); + } + } // dispatchAggregateEvents(NodeImpl, AttrImpl,String) :void + + /** + * NON-DOM INTERNAL: Pre-mutation context check, in + * preparation for later generating DOMAttrModified events. + * Determines whether this node is within an Attr + * @param node node to get enclosing attribute for + */ + protected void saveEnclosingAttr(NodeImpl node) { + savedEnclosingAttr = null; + // MUTATION PREPROCESSING AND PRE-EVENTS: + // If we're within the scope of an Attr and DOMAttrModified + // was requested, we need to preserve its previous value for + // that event. + LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED); + if (lc.total > 0) { + NodeImpl eventAncestor = node; + while (true) { + if (eventAncestor == null) + return; + int type = eventAncestor.getNodeType(); + if (type == Node.ATTRIBUTE_NODE) { + EnclosingAttr retval = new EnclosingAttr(); + retval.node = (AttrImpl) eventAncestor; + retval.oldvalue = retval.node.getNodeValue(); + savedEnclosingAttr = retval; + return; + } + else if (type == Node.ENTITY_REFERENCE_NODE) + eventAncestor = eventAncestor.parentNode(); + else if (type == Node.TEXT_NODE) + eventAncestor = eventAncestor.parentNode(); + else + return; + // Any other parent means we're not in an Attr + } + } + } // saveEnclosingAttr(NodeImpl) :void + + /** + * A method to be called when a character data node has been modified + */ + void modifyingCharacterData(NodeImpl node, boolean replace) { + if (mutationEvents) { + if (!replace) { + saveEnclosingAttr(node); + } + } + } + + /** + * A method to be called when a character data node has been modified + */ + void modifiedCharacterData(NodeImpl node, String oldvalue, String value, boolean replace) { + if (mutationEvents) { + mutationEventsModifiedCharacterData(node, oldvalue, value, replace); + } + } + + private void mutationEventsModifiedCharacterData(NodeImpl node, String oldvalue, String value, boolean replace) { + if (!replace) { + // MUTATION POST-EVENTS: + LCount lc = + LCount.lookup(MutationEventImpl.DOM_CHARACTER_DATA_MODIFIED); + if (lc.total > 0) { + MutationEvent me = new MutationEventImpl(); + me.initMutationEvent( + MutationEventImpl.DOM_CHARACTER_DATA_MODIFIED, + true, false, null, + oldvalue, value, null, (short) 0); + dispatchEvent(node, me); + } + + // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified, + // if required. (Common to most kinds of mutation) + dispatchAggregateEvents(node, savedEnclosingAttr); + } // End mutation postprocessing + } + + /** + * A method to be called when a character data node has been replaced + */ + void replacedCharacterData(NodeImpl node, String oldvalue, String value) { + //now that we have finished replacing data, we need to perform the same actions + //that are required after a character data node has been modified + //send the value of false for replace parameter so that mutation + //events if appropriate will be initiated + modifiedCharacterData(node, oldvalue, value, false); + } + + /** + * A method to be called when a node is about to be inserted in the tree. + */ + void insertingNode(NodeImpl node, boolean replace) { + if (mutationEvents) { + if (!replace) { + saveEnclosingAttr(node); + } + } + } + + /** + * A method to be called when a node has been inserted in the tree. + */ + void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) { + if (mutationEvents) { + mutationEventsInsertedNode(node, newInternal, replace); + } + + // notify the range of insertions + if (ranges != null) { + notifyRangesInsertedNode(newInternal); + } + } + + private void mutationEventsInsertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) { + // MUTATION POST-EVENTS: + // "Local" events (non-aggregated) + // New child is told it was inserted, and where + LCount lc = LCount.lookup(MutationEventImpl.DOM_NODE_INSERTED); + if (lc.total > 0) { + MutationEventImpl me = new MutationEventImpl(); + me.initMutationEvent(MutationEventImpl.DOM_NODE_INSERTED, + true, false, node, + null, null, null, (short) 0); + dispatchEvent(newInternal, me); + } + + // If within the Document, tell the subtree it's been added + // to the Doc. + lc = LCount.lookup( + MutationEventImpl.DOM_NODE_INSERTED_INTO_DOCUMENT); + if (lc.total > 0) { + NodeImpl eventAncestor = node; + if (savedEnclosingAttr != null) + eventAncestor = (NodeImpl) + savedEnclosingAttr.node.getOwnerElement(); + if (eventAncestor != null) { // Might have been orphan Attr + NodeImpl p = eventAncestor; + while (p != null) { + eventAncestor = p; // Last non-null ancestor + // In this context, ancestry includes + // walking back from Attr to Element + if (p.getNodeType() == ATTRIBUTE_NODE) { + p = (NodeImpl) ((AttrImpl)p).getOwnerElement(); + } + else { + p = p.parentNode(); + } + } + if (eventAncestor.getNodeType() == Node.DOCUMENT_NODE){ + MutationEventImpl me = new MutationEventImpl(); + me.initMutationEvent(MutationEventImpl + .DOM_NODE_INSERTED_INTO_DOCUMENT, + false,false,null,null, + null,null,(short)0); + dispatchEventToSubtree(newInternal, me); + } + } + } + if (!replace) { + // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified + // (Common to most kinds of mutation) + dispatchAggregateEvents(node, savedEnclosingAttr); + } + } + + private void notifyRangesInsertedNode(NodeImpl newInternal) { + removeStaleRangeReferences(); + final Iterator i = ranges.iterator(); + while (i.hasNext()) { + RangeImpl range = (RangeImpl) ((Reference) i.next()).get(); + if (range != null) { + range.insertedNodeFromDOM(newInternal); + } + // Remove stale reference from the list. + else { + i.remove(); + } + } + } + + /** + * A method to be called when a node is about to be removed from the tree. + */ + void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) { + + // notify iterators + if (iterators != null) { + notifyIteratorsRemovingNode(oldChild); + } + + // notify ranges + if (ranges != null) { + notifyRangesRemovingNode(oldChild); + } + + // mutation events + if (mutationEvents) { + mutationEventsRemovingNode(node, oldChild, replace); + } + } + + private void notifyIteratorsRemovingNode(NodeImpl oldChild) { + removeStaleIteratorReferences(); + final Iterator i = iterators.iterator(); + while (i.hasNext()) { + NodeIteratorImpl iterator = (NodeIteratorImpl) ((Reference) i.next()).get(); + if (iterator != null) { + iterator.removeNode(oldChild); + } + // Remove stale reference from the list. + else { + i.remove(); + } + } + } + + private void notifyRangesRemovingNode(NodeImpl oldChild) { + removeStaleRangeReferences(); + final Iterator i = ranges.iterator(); + while (i.hasNext()) { + RangeImpl range = (RangeImpl) ((Reference) i.next()).get(); + if (range != null) { + range.removeNode(oldChild); + } + // Remove stale reference from the list. + else { + i.remove(); + } + } + } + + private void mutationEventsRemovingNode(NodeImpl node, NodeImpl oldChild, boolean replace) { + // MUTATION PREPROCESSING AND PRE-EVENTS: + // If we're within the scope of an Attr and DOMAttrModified + // was requested, we need to preserve its previous value for + // that event. + if (!replace) { + saveEnclosingAttr(node); + } + // Child is told that it is about to be removed + LCount lc = LCount.lookup(MutationEventImpl.DOM_NODE_REMOVED); + if (lc.total > 0) { + MutationEventImpl me= new MutationEventImpl(); + me.initMutationEvent(MutationEventImpl.DOM_NODE_REMOVED, + true, false, node, null, + null, null, (short) 0); + dispatchEvent(oldChild, me); + } + + // If within Document, child's subtree is informed that it's + // losing that status + lc = LCount.lookup( + MutationEventImpl.DOM_NODE_REMOVED_FROM_DOCUMENT); + if (lc.total > 0) { + NodeImpl eventAncestor = this; + if(savedEnclosingAttr != null) + eventAncestor = (NodeImpl) + savedEnclosingAttr.node.getOwnerElement(); + if (eventAncestor != null) { // Might have been orphan Attr + for (NodeImpl p = eventAncestor.parentNode(); + p != null; p = p.parentNode()) { + eventAncestor = p; // Last non-null ancestor + } + if (eventAncestor.getNodeType() == Node.DOCUMENT_NODE){ + MutationEventImpl me = new MutationEventImpl(); + me.initMutationEvent( + MutationEventImpl.DOM_NODE_REMOVED_FROM_DOCUMENT, + false, false, null, + null, null, null, (short) 0); + dispatchEventToSubtree(oldChild, me); + } + } + } + // End mutation preprocessing + } + + /** + * A method to be called when a node has been removed from the tree. + */ + void removedNode(NodeImpl node, boolean replace) { + if (mutationEvents) { + // MUTATION POST-EVENTS: + // Subroutine: Transmit DOMAttrModified and DOMSubtreeModified, + // if required. (Common to most kinds of mutation) + if (!replace) { + dispatchAggregateEvents(node, savedEnclosingAttr); + } + } // End mutation postprocessing + } + + /** + * A method to be called when a node is about to be replaced in the tree. + */ + void replacingNode(NodeImpl node) { + if (mutationEvents) { + saveEnclosingAttr(node); + } + } + + /** + * A method to be called when character data is about to be replaced in the tree. + */ + void replacingData (NodeImpl node) { + if (mutationEvents) { + saveEnclosingAttr(node); + } + } + + /** + * A method to be called when a node has been replaced in the tree. + */ + void replacedNode(NodeImpl node) { + if (mutationEvents) { + dispatchAggregateEvents(node, savedEnclosingAttr); + } + } + + /** + * A method to be called when an attribute value has been modified + */ + void modifiedAttrValue(AttrImpl attr, String oldvalue) { + if (mutationEvents) { + // MUTATION POST-EVENTS: + dispatchAggregateEvents(attr, attr, oldvalue, + MutationEvent.MODIFICATION); + } + } + + /** + * A method to be called when an attribute node has been set + */ + void setAttrNode(AttrImpl attr, AttrImpl previous) { + if (mutationEvents) { + // MUTATION POST-EVENTS: + if (previous == null) { + dispatchAggregateEvents(attr.ownerNode, attr, null, + MutationEvent.ADDITION); + } + else { + dispatchAggregateEvents(attr.ownerNode, attr, + previous.getNodeValue(), + MutationEvent.MODIFICATION); + } + } + } + + /** + * A method to be called when an attribute node has been removed + */ + void removedAttrNode(AttrImpl attr, NodeImpl oldOwner, String name) { + // We can't use the standard dispatchAggregate, since it assumes + // that the Attr is still attached to an owner. This code is + // similar but dispatches to the previous owner, "element". + if (mutationEvents) { + mutationEventsRemovedAttrNode(attr, oldOwner, name); + } + } + + private void mutationEventsRemovedAttrNode(AttrImpl attr, NodeImpl oldOwner, String name) { + // If we have to send DOMAttrModified (determined earlier), + // do so. + LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED); + if (lc.total > 0) { + MutationEventImpl me= new MutationEventImpl(); + me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED, + true, false, attr, + attr.getNodeValue(), null, name, + MutationEvent.REMOVAL); + dispatchEvent(oldOwner, me); + } + + // We can hand off to process DOMSubtreeModified, though. + // Note that only the Element needs to be informed; the + // Attr's subtree has not been changed by this operation. + dispatchAggregateEvents(oldOwner, null, null, (short) 0); + } + + /** + * A method to be called when an attribute node has been renamed + */ + void renamedAttrNode(Attr oldAt, Attr newAt) { + // REVISIT: To be implemented!!! + } + + /** + * A method to be called when an element has been renamed + */ + void renamedElement(Element oldEl, Element newEl) { + // REVISIT: To be implemented!!! + } + +} // class DocumentImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/DocumentTypeImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/DocumentTypeImpl.java new file mode 100644 index 0000000..4f33644 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/DocumentTypeImpl.java @@ -0,0 +1,484 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.Hashtable; + +import org.w3c.dom.DOMException; +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.UserDataHandler; + +/** + * This class represents a Document Type declaraction in + * the document itself, not a Document Type Definition (DTD). + * An XML document may (or may not) have such a reference. + *

+ * DocumentType is an Extended DOM feature, used in XML documents but + * not in HTML. + *

+ * Note that Entities and Notations are no longer children of the + * DocumentType, but are parentless nodes hung only in their + * appropriate NamedNodeMaps. + *

+ * This area is UNDERSPECIFIED IN REC-DOM-Level-1-19981001 + * Most notably, absolutely no provision was made for storing + * and using Element and Attribute information. Nor was the linkage + * between Entities and Entity References nailed down solidly. + * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Joe Kesselman, IBM + * @author Andy Clark, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class DocumentTypeImpl + extends ParentNode + implements DocumentType { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 7751299192316526485L; + + // + // Data + // + + /** Document type name. */ + protected String name; + + /** Entities. */ + protected NamedNodeMapImpl entities; + + /** Notations. */ + protected NamedNodeMapImpl notations; + + // NON-DOM + + /** Elements. */ + protected NamedNodeMapImpl elements; + + // DOM2: support public ID. + protected String publicID; + + // DOM2: support system ID. + protected String systemID; + + // DOM2: support internal subset. + protected String internalSubset; + + /** The following are required for compareDocumentPosition + */ + // Doctype number. Doc types which have no owner may be assigned + // a number, on demand, for ordering purposes for compareDocumentPosition + private int doctypeNumber=0; + + // + // Constructors + // + private Hashtable userData = null; + /** Factory method for creating a document type node. */ + public DocumentTypeImpl(CoreDocumentImpl ownerDocument, String name) { + super(ownerDocument); + + this.name = name; + // DOM + entities = new NamedNodeMapImpl(this); + notations = new NamedNodeMapImpl(this); + + // NON-DOM + elements = new NamedNodeMapImpl(this); + + } // (CoreDocumentImpl,String) + + /** Factory method for creating a document type node. */ + public DocumentTypeImpl(CoreDocumentImpl ownerDocument, + String qualifiedName, + String publicID, String systemID) { + this(ownerDocument, qualifiedName); + this.publicID = publicID; + this.systemID = systemID; + + } // (CoreDocumentImpl,String) + + // + // DOM2: methods. + // + + /** + * Introduced in DOM Level 2.

+ * + * Return the public identifier of this Document type. + * @since WD-DOM-Level-2-19990923 + */ + public String getPublicId() { + if (needsSyncData()) { + synchronizeData(); + } + return publicID; + } + /** + * Introduced in DOM Level 2.

+ * + * Return the system identifier of this Document type. + * @since WD-DOM-Level-2-19990923 + */ + public String getSystemId() { + if (needsSyncData()) { + synchronizeData(); + } + return systemID; + } + + /** + * NON-DOM.

+ * + * Set the internalSubset given as a string. + */ + public void setInternalSubset(String internalSubset) { + if (needsSyncData()) { + synchronizeData(); + } + this.internalSubset = internalSubset; + } + + /** + * Introduced in DOM Level 2.

+ * + * Return the internalSubset given as a string. + * @since WD-DOM-Level-2-19990923 + */ + public String getInternalSubset() { + if (needsSyncData()) { + synchronizeData(); + } + return internalSubset; + } + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.DOCUMENT_TYPE_NODE; + } + + /** + * Returns the document type name + */ + public String getNodeName() { + if (needsSyncData()) { + synchronizeData(); + } + return name; + } + + /** Clones the node. */ + public Node cloneNode(boolean deep) { + + DocumentTypeImpl newnode = (DocumentTypeImpl)super.cloneNode(deep); + // NamedNodeMaps must be cloned explicitly, to avoid sharing them. + newnode.entities = entities.cloneMap(newnode); + newnode.notations = notations.cloneMap(newnode); + newnode.elements = elements.cloneMap(newnode); + + return newnode; + + } // cloneNode(boolean):Node + + /* + * Get Node text content + * @since DOM Level 3 + */ + public String getTextContent() throws DOMException { + return null; + } + + /* + * Set Node text content + * @since DOM Level 3 + */ + public void setTextContent(String textContent) + throws DOMException { + // no-op + } + + /** + * DOM Level 3 WD- Experimental. + * Override inherited behavior from ParentNodeImpl to support deep equal. + */ + public boolean isEqualNode(Node arg) { + + if (!super.isEqualNode(arg)) { + return false; + } + + if (needsSyncData()) { + synchronizeData(); + } + DocumentTypeImpl argDocType = (DocumentTypeImpl) arg; + + //test if the following string attributes are equal: publicId, + //systemId, internalSubset. + if ((getPublicId() == null && argDocType.getPublicId() != null) + || (getPublicId() != null && argDocType.getPublicId() == null) + || (getSystemId() == null && argDocType.getSystemId() != null) + || (getSystemId() != null && argDocType.getSystemId() == null) + || (getInternalSubset() == null + && argDocType.getInternalSubset() != null) + || (getInternalSubset() != null + && argDocType.getInternalSubset() == null)) { + return false; + } + + if (getPublicId() != null) { + if (!getPublicId().equals(argDocType.getPublicId())) { + return false; + } + } + + if (getSystemId() != null) { + if (!getSystemId().equals(argDocType.getSystemId())) { + return false; + } + } + + if (getInternalSubset() != null) { + if (!getInternalSubset().equals(argDocType.getInternalSubset())) { + return false; + } + } + + //test if NamedNodeMaps entities and notations are equal + NamedNodeMapImpl argEntities = argDocType.entities; + + if ((entities == null && argEntities != null) + || (entities != null && argEntities == null)) + return false; + + if (entities != null && argEntities != null) { + if (entities.getLength() != argEntities.getLength()) + return false; + + for (int index = 0; entities.item(index) != null; index++) { + Node entNode1 = entities.item(index); + Node entNode2 = + argEntities.getNamedItem(entNode1.getNodeName()); + + if (!((NodeImpl) entNode1).isEqualNode(entNode2)) + return false; + } + } + + NamedNodeMapImpl argNotations = argDocType.notations; + + if ((notations == null && argNotations != null) + || (notations != null && argNotations == null)) + return false; + + if (notations != null && argNotations != null) { + if (notations.getLength() != argNotations.getLength()) + return false; + + for (int index = 0; notations.item(index) != null; index++) { + Node noteNode1 = notations.item(index); + Node noteNode2 = + argNotations.getNamedItem(noteNode1.getNodeName()); + + if (!((NodeImpl) noteNode1).isEqualNode(noteNode2)) + return false; + } + } + + return true; + } //end isEqualNode + + + /** + * NON-DOM + * set the ownerDocument of this node and its children + */ + protected void setOwnerDocument(CoreDocumentImpl doc) { + super.setOwnerDocument(doc); + entities.setOwnerDocument(doc); + notations.setOwnerDocument(doc); + elements.setOwnerDocument(doc); + } + + /** NON-DOM + Get the number associated with this doctype. + */ + protected int getNodeNumber() { + // If the doctype has a document owner, get the node number + // relative to the owner doc + if (getOwnerDocument()!=null) + return super.getNodeNumber(); + + // The doctype is disconnected and not associated with any document. + // Assign the doctype a number relative to the implementation. + if (doctypeNumber==0) { + + CoreDOMImplementationImpl cd = (CoreDOMImplementationImpl)CoreDOMImplementationImpl.getDOMImplementation(); + doctypeNumber = cd.assignDocTypeNumber(); + } + return doctypeNumber; + } + + // + // DocumentType methods + // + + /** + * Name of this document type. If we loaded from a DTD, this should + * be the name immediately following the DOCTYPE keyword. + */ + public String getName() { + + if (needsSyncData()) { + synchronizeData(); + } + return name; + + } // getName():String + + /** + * Access the collection of general Entities, both external and + * internal, defined in the DTD. For example, in: + *

+ *

+     *   <!doctype example SYSTEM "ex.dtd" [
+     *     <!ENTITY foo "foo">
+     *     <!ENTITY bar "bar">
+     *     <!ENTITY % baz "baz">
+     *     ]>
+     * 
+ *

+ * The Entities map includes foo and bar, but not baz. It is promised that + * only Nodes which are Entities will exist in this NamedNodeMap. + *

+ * For HTML, this will always be null. + *

+ * Note that "built in" entities such as & and < should be + * converted to their actual characters before being placed in the DOM's + * contained text, and should be converted back when the DOM is rendered + * as XML or HTML, and hence DO NOT appear here. + */ + public NamedNodeMap getEntities() { + if (needsSyncChildren()) { + synchronizeChildren(); + } + return entities; + } + + /** + * Access the collection of Notations defined in the DTD. A + * notation declares, by name, the format of an XML unparsed entity + * or is used to formally declare a Processing Instruction target. + */ + public NamedNodeMap getNotations() { + if (needsSyncChildren()) { + synchronizeChildren(); + } + return notations; + } + + // + // Public methods + // + + /** + * NON-DOM: Subclassed to flip the entities' and notations' readonly switch + * as well. + * @see NodeImpl#setReadOnly + */ + public void setReadOnly(boolean readOnly, boolean deep) { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + super.setReadOnly(readOnly, deep); + + // set read-only property + elements.setReadOnly(readOnly, true); + entities.setReadOnly(readOnly, true); + notations.setReadOnly(readOnly, true); + + } // setReadOnly(boolean,boolean) + + /** + * NON-DOM: Access the collection of ElementDefinitions. + * @see ElementDefinitionImpl + */ + public NamedNodeMap getElements() { + if (needsSyncChildren()) { + synchronizeChildren(); + } + return elements; + } + + public Object setUserData(String key, + Object data, UserDataHandler handler) { + if(userData == null) + userData = new Hashtable(); + if (data == null) { + if (userData != null) { + Object o = userData.remove(key); + if (o != null) { + UserDataRecord r = (UserDataRecord) o; + return r.fData; + } + } + return null; + } + else { + Object o = userData.put(key, new UserDataRecord(data, handler)); + if (o != null) { + UserDataRecord r = (UserDataRecord) o; + return r.fData; + } + } + return null; + } + + public Object getUserData(String key) { + if (userData == null) { + return null; + } + Object o = userData.get(key); + if (o != null) { + UserDataRecord r = (UserDataRecord) o; + return r.fData; + } + return null; + } + + protected Hashtable getUserDataRecord(){ + return userData; + } + +} // class DocumentTypeImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ElementDefinitionImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/ElementDefinitionImpl.java new file mode 100644 index 0000000..fc75136 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ElementDefinitionImpl.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * NON-DOM CLASS: Describe one of the Elements (and its associated + * Attributes) defined in this Document Type. + *

+ * I've included this in Level 1 purely as an anchor point for default + * attributes. In Level 2 it should enable the ChildRule support. + * + * @xerces.internal + * + * @version $Id$ + */ +public class ElementDefinitionImpl + extends ParentNode { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -8373890672670022714L; + + // + // Data + // + + /** Element definition name. */ + protected String name; + + /** Default attributes. */ + protected NamedNodeMapImpl attributes; + + // + // Constructors + // + + /** Factory constructor. */ + public ElementDefinitionImpl(CoreDocumentImpl ownerDocument, String name) { + super(ownerDocument); + this.name = name; + attributes = new NamedNodeMapImpl(ownerDocument); + } + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return NodeImpl.ELEMENT_DEFINITION_NODE; + } + + /** + * Returns the element definition name + */ + public String getNodeName() { + if (needsSyncData()) { + synchronizeData(); + } + return name; + } + + /** + * Replicate this object. + */ + public Node cloneNode(boolean deep) { + + ElementDefinitionImpl newnode = + (ElementDefinitionImpl) super.cloneNode(deep); + // NamedNodeMap must be explicitly replicated to avoid sharing + newnode.attributes = attributes.cloneMap(newnode); + return newnode; + + } // cloneNode(boolean):Node + + /** + * Query the attributes defined on this Element. + *

+ * In the base implementation this Map simply contains Attribute objects + * representing the defaults. In a more serious implementation, it would + * contain AttributeDefinitionImpl objects for all declared Attributes, + * indicating which are Default, DefaultFixed, Implicit and/or Required. + * + * @return org.w3c.dom.NamedNodeMap containing org.w3c.dom.Attribute + */ + public NamedNodeMap getAttributes() { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + return attributes; + + } // getAttributes():NamedNodeMap + +} // class ElementDefinitionImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ElementImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/ElementImpl.java new file mode 100644 index 0000000..59db6de --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ElementImpl.java @@ -0,0 +1,1375 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.apache.xerces.util.URI; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.ElementTraversal; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.TypeInfo; + +/** + * Elements represent most of the "markup" and structure of the + * document. They contain both the data for the element itself + * (element name and attributes), and any contained nodes, including + * document text (as children). + *

+ * Elements may have Attributes associated with them; the API for this is + * defined in Node, but the function is implemented here. In general, XML + * applications should retrive Attributes as Nodes, since they may contain + * entity references and hence be a fairly complex sub-tree. HTML users will + * be dealing with simple string values, and convenience methods are provided + * to work in terms of Strings. + *

+ * ElementImpl does not support Namespaces. ElementNSImpl, which inherits from + * it, does. + * + * @xerces.internal + * + * @see ElementNSImpl + * + * @author Arnaud Le Hors, IBM + * @author Joe Kesselman, IBM + * @author Andy Clark, IBM + * @author Ralf Pfeiffer, IBM + * @author Michael Glavassevich, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class ElementImpl + extends ParentNode + implements Element, ElementTraversal, TypeInfo { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 3717253516652722278L; + // + // Data + // + + /** Element name. */ + protected String name; + + /** Attributes. */ + protected AttributeMap attributes; + + // + // Constructors + // + + /** Factory constructor. */ + public ElementImpl(CoreDocumentImpl ownerDoc, String name) { + super(ownerDoc); + this.name = name; + needsSyncData(true); // synchronizeData will initialize attributes + } + + // for ElementNSImpl + protected ElementImpl() {} + + // Support for DOM Level 3 renameNode method. + // Note: This only deals with part of the pb. CoreDocumentImpl + // does all the work. + void rename(String name) { + if (needsSyncData()) { + synchronizeData(); + } + if (ownerDocument.errorChecking) { + int colon1 = name.indexOf(':'); + if(colon1 != -1){ + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + if (!CoreDocumentImpl.isXMLName(name, ownerDocument.isXML11Version())) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, + msg); + } + } + this.name = name; + reconcileDefaultAttributes(); + } + + // + // Node methods + // + + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.ELEMENT_NODE; + } + + /** + * Returns the element name + */ + public String getNodeName() { + if (needsSyncData()) { + synchronizeData(); + } + return name; + } + + /** + * Retrieve all the Attributes as a set. Note that this API is inherited + * from Node rather than specified on Element; in fact only Elements will + * ever have Attributes, but they want to allow folks to "blindly" operate + * on the tree as a set of Nodes. + */ + public NamedNodeMap getAttributes() { + + if (needsSyncData()) { + synchronizeData(); + } + if (attributes == null) { + attributes = new AttributeMap(this, null); + } + return attributes; + + } // getAttributes():NamedNodeMap + + /** + * Return a duplicate copy of this Element. Note that its children + * will not be copied unless the "deep" flag is true, but Attributes + * are always replicated. + * + * @see org.w3c.dom.Node#cloneNode(boolean) + */ + public Node cloneNode(boolean deep) { + + ElementImpl newnode = (ElementImpl) super.cloneNode(deep); + // Replicate NamedNodeMap rather than sharing it. + if (attributes != null) { + newnode.attributes = (AttributeMap) attributes.cloneMap(newnode); + } + return newnode; + + } // cloneNode(boolean):Node + + /** + * DOM Level 3 WD - Experimental. + * Retrieve baseURI + */ + public String getBaseURI() { + + if (needsSyncData()) { + synchronizeData(); + } + // Absolute base URI is computed according to + // XML Base (http://www.w3.org/TR/xmlbase/#granularity) + // 1. The base URI specified by an xml:base attribute on the element, + // if one exists + if (attributes != null) { + final Attr attrNode = getXMLBaseAttribute(); + if (attrNode != null) { + final String uri = attrNode.getNodeValue(); + if (uri.length() != 0) {// attribute value is always empty string + try { + URI _uri = new URI(uri, true); + // If the URI is already absolute return it; otherwise it's relative and we need to resolve it. + if (_uri.isAbsoluteURI()) { + return _uri.toString(); + } + + // Make any parentURI into a URI object to use with the URI(URI, String) constructor + String parentBaseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null; + if (parentBaseURI != null) { + try { + URI _parentBaseURI = new URI(parentBaseURI); + _uri.absolutize(_parentBaseURI); + return _uri.toString(); + } + catch (org.apache.xerces.util.URI.MalformedURIException ex) { + // This should never happen: parent should have checked the URI and returned null if invalid. + return null; + } + } + // REVISIT: what should happen in this case? + return null; + } + catch (org.apache.xerces.util.URI.MalformedURIException ex) { + return null; + } + } + } + } + + // 2.the base URI of the element's parent element within the + // document or external entity, if one exists + // 3. the base URI of the document entity or external entity + // containing the element + + // ownerNode serves as a parent or as document + return (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null; + } //getBaseURI + + /** + * NON-DOM + * Returns the xml:base attribute. + */ + protected Attr getXMLBaseAttribute() { + return (Attr) attributes.getNamedItem("xml:base"); + } // getXMLBaseAttribute():Attr + + /** + * NON-DOM + * set the ownerDocument of this node, its children, and its attributes + */ + protected void setOwnerDocument(CoreDocumentImpl doc) { + super.setOwnerDocument(doc); + if (attributes != null) { + attributes.setOwnerDocument(doc); + } + } + + // + // Element methods + // + + /** + * Look up a single Attribute by name. Returns the Attribute's + * string value, or an empty string (NOT null!) to indicate that the + * name did not map to a currently defined attribute. + *

+ * Note: Attributes may contain complex node trees. This method + * returns the "flattened" string obtained from Attribute.getValue(). + * If you need the structure information, see getAttributeNode(). + */ + public String getAttribute(String name) { + + if (needsSyncData()) { + synchronizeData(); + } + if (attributes == null) { + return ""; + } + Attr attr = (Attr)(attributes.getNamedItem(name)); + return (attr == null) ? "" : attr.getValue(); + + } // getAttribute(String):String + + + /** + * Look up a single Attribute by name. Returns the Attribute Node, + * so its complete child tree is available. This could be important in + * XML, where the string rendering may not be sufficient information. + *

+ * If no matching attribute is available, returns null. + */ + public Attr getAttributeNode(String name) { + + if (needsSyncData()) { + synchronizeData(); + } + if (attributes == null) { + return null; + } + return (Attr)attributes.getNamedItem(name); + + } // getAttributeNode(String):Attr + + + /** + * Returns a NodeList of all descendent nodes (children, + * grandchildren, and so on) which are Elements and which have the + * specified tag name. + *

+ * Note: NodeList is a "live" view of the DOM. Its contents will + * change as the DOM changes, and alterations made to the NodeList + * will be reflected in the DOM. + * + * @param tagname The type of element to gather. To obtain a list of + * all elements no matter what their names, use the wild-card tag + * name "*". + * + * @see DeepNodeListImpl + */ + public NodeList getElementsByTagName(String tagname) { + return new DeepNodeListImpl(this,tagname); + } + + /** + * Returns the name of the Element. Note that Element.nodeName() is + * defined to also return the tag name. + *

+ * This is case-preserving in XML. HTML should uppercasify it on the + * way in. + */ + public String getTagName() { + if (needsSyncData()) { + synchronizeData(); + } + return name; + } + + /** + * In "normal form" (as read from a source file), there will never be two + * Text children in succession. But DOM users may create successive Text + * nodes in the course of manipulating the document. Normalize walks the + * sub-tree and merges adjacent Texts, as if the DOM had been written out + * and read back in again. This simplifies implementation of higher-level + * functions that may want to assume that the document is in standard form. + *

+ * To normalize a Document, normalize its top-level Element child. + *

+ * As of PR-DOM-Level-1-19980818, CDATA -- despite being a subclass of + * Text -- is considered "markup" and will _not_ be merged either with + * normal Text or with other CDATASections. + */ + public void normalize() { + // No need to normalize if already normalized. + if (isNormalized()) { + return; + } + if (needsSyncChildren()) { + synchronizeChildren(); + } + ChildNode kid, next; + for (kid = firstChild; kid != null; kid = next) { + next = kid.nextSibling; + + // If kid is a text node, we need to check for one of two + // conditions: + // 1) There is an adjacent text node + // 2) There is no adjacent text node, but kid is + // an empty text node. + if ( kid.getNodeType() == Node.TEXT_NODE ) + { + // If an adjacent text node, merge it with kid + if ( next!=null && next.getNodeType() == Node.TEXT_NODE ) + { + ((Text)kid).appendData(next.getNodeValue()); + removeChild( next ); + next = kid; // Don't advance; there might be another. + } + else + { + // If kid is empty, remove it + if ( kid.getNodeValue() == null || kid.getNodeValue().length() == 0 ) { + removeChild( kid ); + } + } + } + + // Otherwise it might be an Element, which is handled recursively + else if (kid.getNodeType() == Node.ELEMENT_NODE) { + kid.normalize(); + } + } + + // We must also normalize all of the attributes + if ( attributes!=null ) + { + for( int i=0; i + * The default logic is actually implemented in NamedNodeMapImpl. + * PR-DOM-Level-1-19980818 doesn't fully address the DTD, so some + * of this behavior is likely to change in future versions. ????? + *

+ * Note that this call "succeeds" even if no attribute by this name + * existed -- unlike removeAttributeNode, which will throw a not-found + * exception in that case. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is + * readonly. + */ + public void removeAttribute(String name) { + + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + if (needsSyncData()) { + synchronizeData(); + } + + if (attributes == null) { + return; + } + + attributes.safeRemoveNamedItem(name); + + } // removeAttribute(String) + + + /** + * Remove the specified attribute/value pair. If the removed + * Attribute has a default value, it is immediately replaced. + *

+ * NOTE: Specifically removes THIS NODE -- not the node with this + * name, nor the node with these contents. If the specific Attribute + * object passed in is not stored in this Element, we throw a + * DOMException. If you really want to remove an attribute by name, + * use removeAttribute(). + * + * @return the Attribute object that was removed. + * @throws DOMException(NOT_FOUND_ERR) if oldattr is not an attribute of + * this Element. + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is + * readonly. + */ + public Attr removeAttributeNode(Attr oldAttr) + throws DOMException { + + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + if (needsSyncData()) { + synchronizeData(); + } + + if (attributes == null) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + return (Attr) attributes.removeItem(oldAttr, true); + + } // removeAttributeNode(Attr):Attr + + + /** + * Add a new name/value pair, or replace the value of the existing + * attribute having that name. + * + * Note: this method supports only the simplest kind of Attribute, + * one whose value is a string contained in a single Text node. + * If you want to assert a more complex value (which XML permits, + * though HTML doesn't), see setAttributeNode(). + * + * The attribute is created with specified=true, meaning it's an + * explicit value rather than inherited from the DTD as a default. + * Again, setAttributeNode can be used to achieve other results. + * + * @throws DOMException(INVALID_NAME_ERR) if the name is not acceptable. + * (Attribute factory will do that test for us.) + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is + * readonly. + */ + public void setAttribute(String name, String value) { + + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NO_MODIFICATION_ALLOWED_ERR", + null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + if (needsSyncData()) { + synchronizeData(); + } + + Attr newAttr = getAttributeNode(name); + if (newAttr == null) { + newAttr = getOwnerDocument().createAttribute(name); + + if (attributes == null) { + attributes = new AttributeMap(this, null); + } + + newAttr.setNodeValue(value); + attributes.setNamedItem(newAttr); + } + else { + newAttr.setNodeValue(value); + } + + } // setAttribute(String,String) + + /** + * Add a new attribute/value pair, or replace the value of the + * existing attribute with that name. + *

+ * This method allows you to add an Attribute that has already been + * constructed, and hence avoids the limitations of the simple + * setAttribute() call. It can handle attribute values that have + * arbitrarily complex tree structure -- in particular, those which + * had entity references mixed into their text. + * + * @throws DOMException(INUSE_ATTRIBUTE_ERR) if the Attribute object + * has already been assigned to another Element. + */ + public Attr setAttributeNode(Attr newAttr) + throws DOMException + { + + if (needsSyncData()) { + synchronizeData(); + } + + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + + if (newAttr.getOwnerDocument() != ownerDocument) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + } + + if (attributes == null) { + attributes = new AttributeMap(this, null); + } + // This will throw INUSE if necessary + return (Attr) attributes.setNamedItem(newAttr); + + } // setAttributeNode(Attr):Attr + + // + // DOM2: Namespace methods + // + + /** + * Introduced in DOM Level 2.

+ * + * Retrieves an attribute value by local name and namespace URI. + * + * @param namespaceURI + * The namespace URI of the attribute to + * retrieve. + * @param localName The local name of the attribute to retrieve. + * @return String The Attr value as a string, or empty string + * if that attribute + * does not have a specified or default value. + * @since WD-DOM-Level-2-19990923 + */ + public String getAttributeNS(String namespaceURI, String localName) { + + if (needsSyncData()) { + synchronizeData(); + } + + if (attributes == null) { + return ""; + } + + Attr attr = (Attr)(attributes.getNamedItemNS(namespaceURI, localName)); + return (attr == null) ? "" : attr.getValue(); + + } // getAttributeNS(String,String):String + + /** + * Introduced in DOM Level 2.

+ * + * Adds a new attribute. + * If the given namespaceURI is null or an empty string and the + * qualifiedName has a prefix that is "xml", the new attribute is bound to + * the predefined namespace "http://www.w3.org/XML/1998/namespace" + * [Namespaces]. If an attribute with the same local name and namespace + * URI is already present on the element, its prefix is changed to be the + * prefix part of the qualifiedName, and its value is changed to be the + * value parameter. This value is a simple string, it is not parsed as it + * is being set. So any markup (such as syntax to be recognized as an + * entity reference) is treated as literal text, and needs to be + * appropriately escaped by the implementation when it is written out. In + * order to assign an attribute value that contains entity references, the + * user must create an Attr node plus any Text and EntityReference nodes, + * build the appropriate subtree, and use setAttributeNodeNS or + * setAttributeNode to assign it as the value of an attribute. + * + * @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. + * @throws INVALID_CHARACTER_ERR: Raised if the specified + * name contains an invalid character. + * + * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this + * node is readonly. + * + * @throws NAMESPACE_ERR: Raised if the qualifiedName + * has a prefix that is "xml" and the namespaceURI + * is neither null nor an empty string nor + * "http://www.w3.org/XML/1998/namespace", or if + * the qualifiedName has a prefix that is "xmlns" + * but the namespaceURI is neither null nor an + * empty string, or if if the qualifiedName has a + * prefix different from "xml" and "xmlns" and the + * namespaceURI is null or an empty string. + * @since WD-DOM-Level-2-19990923 + */ + public void setAttributeNS(String namespaceURI,String qualifiedName, + String value) { + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NO_MODIFICATION_ALLOWED_ERR", + null); + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + if (needsSyncData()) { + synchronizeData(); + } + int index = qualifiedName.indexOf(':'); + String prefix, localName; + if (index < 0) { + prefix = null; + localName = qualifiedName; + } + else { + prefix = qualifiedName.substring(0, index); + localName = qualifiedName.substring(index + 1); + } + Attr newAttr = getAttributeNodeNS(namespaceURI, localName); + if (newAttr == null) { + // REVISIT: this is not efficient, we are creating twice the same + // strings for prefix and localName. + newAttr = getOwnerDocument().createAttributeNS( + namespaceURI, + qualifiedName); + if (attributes == null) { + attributes = new AttributeMap(this, null); + } + newAttr.setNodeValue(value); + attributes.setNamedItemNS(newAttr); + } + else { + if (newAttr instanceof AttrNSImpl){ + // change prefix and value + ((AttrNSImpl)newAttr).name= (prefix!=null)?(prefix+":"+localName):localName; + } + else { + // This case may happen if user calls: + // elem.setAttribute("name", "value"); + // elem.setAttributeNS(null, "name", "value"); + // This case is not defined by the DOM spec, we choose + // to create a new attribute in this case and remove an old one from the tree + // note this might cause events to be propagated or user data to be lost + newAttr = ((CoreDocumentImpl)getOwnerDocument()).createAttributeNS(namespaceURI, qualifiedName, localName); + attributes.setNamedItemNS(newAttr); + } + + newAttr.setNodeValue(value); + } + + } // setAttributeNS(String,String,String) + + + /** + * Introduced in DOM Level 2.

+ * + * Removes an attribute by local name and namespace URI. If the removed + * attribute has a default value it is immediately replaced. + * The replacing attribute has the same namespace URI and local name, + * as well as the original prefix.

+ * + * @param namespaceURI The namespace URI of the attribute to remove. + * + * @param localName The local name of the attribute to remove. + * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this + * node is readonly. + * @since WD-DOM-Level-2-19990923 + */ + public void removeAttributeNS(String namespaceURI, String localName) { + + if (ownerDocument.errorChecking && isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + if (needsSyncData()) { + synchronizeData(); + } + + if (attributes == null) { + return; + } + + attributes.safeRemoveNamedItemNS(namespaceURI, localName); + + } // removeAttributeNS(String,String) + + /** + * Retrieves an Attr node by local name and namespace URI. + * + * @param namespaceURI The namespace URI of the attribute to + * retrieve. + * @param localName The local name of the attribute to retrieve. + * @return Attr The Attr node with the specified attribute + * local name and namespace + * URI or null if there is no such attribute. + * @since WD-DOM-Level-2-19990923 + */ + public Attr getAttributeNodeNS(String namespaceURI, String localName){ + + if (needsSyncData()) { + synchronizeData(); + } + if (attributes == null) { + return null; + } + return (Attr)attributes.getNamedItemNS(namespaceURI, localName); + + } // getAttributeNodeNS(String,String):Attr + + /** + * Introduced in DOM Level 2.

+ * + * Adds a new attribute. If an attribute with that local name and + * namespace URI is already present in the element, it is replaced + * by the new one. + * + * @param newAttr The Attr node to add to the attribute list. When + * the Node has no namespaceURI, this method behaves + * like setAttributeNode. + * @return Attr If the newAttr attribute replaces an existing attribute + * with the same local name and namespace URI, the * + * previously existing Attr node is returned, otherwise + * null is returned. + * @throws WRONG_DOCUMENT_ERR: Raised if newAttr + * was created from a different document than the one that + * created the element. + * + * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if + * this node is readonly. + * + * @throws INUSE_ATTRIBUTE_ERR: Raised if newAttr is + * already an attribute of another Element object. The + * DOM user must explicitly clone Attr nodes to re-use + * them in other elements. + * @since WD-DOM-Level-2-19990923 + */ + public Attr setAttributeNodeNS(Attr newAttr) + throws DOMException + { + + if (needsSyncData()) { + synchronizeData(); + } + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + if (newAttr.getOwnerDocument() != ownerDocument) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + } + + if (attributes == null) { + attributes = new AttributeMap(this, null); + } + // This will throw INUSE if necessary + return (Attr) attributes.setNamedItemNS(newAttr); + + } // setAttributeNodeNS(Attr):Attr + + /** + * NON-DOM: sets attribute node for this element + */ + protected int setXercesAttributeNode (Attr attr){ + + if (needsSyncData()) { + synchronizeData(); + } + + if (attributes == null) { + attributes = new AttributeMap(this, null); + } + return attributes.addItem(attr); + + } + + /** + * NON-DOM: get inded of an attribute + */ + protected int getXercesAttribute(String namespaceURI, String localName){ + + if (needsSyncData()) { + synchronizeData(); + } + if (attributes == null) { + return -1; + } + return attributes.getNamedItemIndex(namespaceURI, localName); + + } + + /** + * Introduced in DOM Level 2. + */ + public boolean hasAttributes() { + if (needsSyncData()) { + synchronizeData(); + } + return (attributes != null && attributes.getLength() != 0); + } + + /** + * Introduced in DOM Level 2. + */ + public boolean hasAttribute(String name) { + return getAttributeNode(name) != null; + } + + /** + * Introduced in DOM Level 2. + */ + public boolean hasAttributeNS(String namespaceURI, String localName) { + return getAttributeNodeNS(namespaceURI, localName) != null; + } + + /** + * Introduced in DOM Level 2.

+ * + * Returns a NodeList of all the Elements with a given local name and + * namespace URI in the order in which they would be encountered in a + * preorder traversal of the Document tree, starting from this node. + * + * @param namespaceURI The namespace URI of the elements to match + * on. The special value "*" matches all + * namespaces. When it is null or an empty + * string, this method behaves like + * getElementsByTagName. + * @param localName The local name of the elements to match on. + * The special value "*" matches all local names. + * @return NodeList A new NodeList object containing all the matched + * Elements. + * @since WD-DOM-Level-2-19990923 + */ + public NodeList getElementsByTagNameNS(String namespaceURI, + String localName) { + return new DeepNodeListImpl(this, namespaceURI, localName); + } + + /** + * DOM Level 3 WD- Experimental. + * Override inherited behavior from NodeImpl and ParentNode to check on + * attributes + */ + public boolean isEqualNode(Node arg) { + if (!super.isEqualNode(arg)) { + return false; + } + boolean hasAttrs = hasAttributes(); + if (hasAttrs != ((Element) arg).hasAttributes()) { + return false; + } + if (hasAttrs) { + NamedNodeMap map1 = getAttributes(); + NamedNodeMap map2 = ((Element) arg).getAttributes(); + int len = map1.getLength(); + if (len != map2.getLength()) { + return false; + } + for (int i = 0; i < len; i++) { + Node n1 = map1.item(i); + if (n1.getLocalName() == null) { // DOM Level 1 Node + Node n2 = map2.getNamedItem(n1.getNodeName()); + if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) { + return false; + } + } + else { + Node n2 = map2.getNamedItemNS(n1.getNamespaceURI(), + n1.getLocalName()); + if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) { + return false; + } + } + } + } + return true; + } + + /** + * DOM Level 3: register the given attribute node as an ID attribute + */ + public void setIdAttributeNode(Attr at, boolean makeId) { + if (needsSyncData()) { + synchronizeData(); + } + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + + if (at.getOwnerElement() != this) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + } + ((AttrImpl) at).isIdAttribute(makeId); + if (!makeId) { + ownerDocument.removeIdentifier(at.getValue()); + } + else { + ownerDocument.putIdentifier(at.getValue(), this); + } + } + + /** + * DOM Level 3: register the given attribute node as an ID attribute + */ + public void setIdAttribute(String name, boolean makeId) { + if (needsSyncData()) { + synchronizeData(); + } + Attr at = getAttributeNode(name); + + if( at == null){ + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + + if (at.getOwnerElement() != this) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + } + + ((AttrImpl) at).isIdAttribute(makeId); + if (!makeId) { + ownerDocument.removeIdentifier(at.getValue()); + } + else { + ownerDocument.putIdentifier(at.getValue(), this); + } + } + + /** + * DOM Level 3: register the given attribute node as an ID attribute + */ + public void setIdAttributeNS(String namespaceURI, String localName, + boolean makeId) { + if (needsSyncData()) { + synchronizeData(); + } + Attr at = getAttributeNodeNS(namespaceURI, localName); + + if( at == null){ + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + + if (at.getOwnerElement() != this) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + } + ((AttrImpl) at).isIdAttribute(makeId); + if (!makeId) { + ownerDocument.removeIdentifier(at.getValue()); + } + else { + ownerDocument.putIdentifier(at.getValue(), this); + } + } + + /** + * @see org.w3c.dom.TypeInfo#getTypeName() + */ + public String getTypeName() { + return null; + } + + /** + * @see org.w3c.dom.TypeInfo#getTypeNamespace() + */ + public String getTypeNamespace() { + return null; + } + + /** + * Introduced in DOM Level 3.

+ * Checks if a type is derived from another by restriction. See: + * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom + * + * @param typeNamespaceArg + * The namspace of the ancestor type declaration + * @param typeNameArg + * The name of the ancestor type declaration + * @param derivationMethod + * The derivation method + * + * @return boolean True if the type is derived by restriciton for the + * reference type + */ + public boolean isDerivedFrom(String typeNamespaceArg, + String typeNameArg, + int derivationMethod) { + + return false; + } + + /** + * Method getSchemaTypeInfo. + * @return TypeInfo + */ + public TypeInfo getSchemaTypeInfo(){ + if(needsSyncData()) { + synchronizeData(); + } + return this; + } + + // + // Public methods + // + + /** + * NON-DOM: Subclassed to flip the attributes' readonly switch as well. + * @see NodeImpl#setReadOnly + */ + public void setReadOnly(boolean readOnly, boolean deep) { + super.setReadOnly(readOnly,deep); + if (attributes != null) { + attributes.setReadOnly(readOnly,true); + } + } + + + + // + // Protected methods + // + + /** Synchronizes the data (name and value) for fast nodes. */ + protected void synchronizeData() { + + // no need to sync in the future + needsSyncData(false); + + // we don't want to generate any event for this so turn them off + boolean orig = ownerDocument.getMutationEvents(); + ownerDocument.setMutationEvents(false); + + // attributes + setupDefaultAttributes(); + + // set mutation events flag back to its original value + ownerDocument.setMutationEvents(orig); + + } // synchronizeData() + + // support for DOM Level 3 renameNode method + // @param el The element from which to take the attributes + void moveSpecifiedAttributes(ElementImpl el) { + if (needsSyncData()) { + synchronizeData(); + } + if (el.hasAttributes()) { + if (attributes == null) { + attributes = new AttributeMap(this, null); + } + attributes.moveSpecifiedAttributes(el.attributes); + } + } + + /** Setup the default attributes. */ + protected void setupDefaultAttributes() { + NamedNodeMapImpl defaults = getDefaultAttributes(); + if (defaults != null) { + attributes = new AttributeMap(this, defaults); + } + } + + /** Reconcile default attributes. */ + protected void reconcileDefaultAttributes() { + if (attributes != null) { + NamedNodeMapImpl defaults = getDefaultAttributes(); + attributes.reconcileDefaults(defaults); + } + } + + /** Get the default attributes. */ + protected NamedNodeMapImpl getDefaultAttributes() { + + DocumentTypeImpl doctype = + (DocumentTypeImpl) ownerDocument.getDoctype(); + if (doctype == null) { + return null; + } + ElementDefinitionImpl eldef = + (ElementDefinitionImpl)doctype.getElements() + .getNamedItem(getNodeName()); + if (eldef == null) { + return null; + } + return (NamedNodeMapImpl) eldef.getAttributes(); + + } // getDefaultAttributes() + + // + // ElementTraversal methods + // + + /** + * @see + * Element Traversal Specification + */ + public final int getChildElementCount() { + int count = 0; + Element child = getFirstElementChild(); + while (child != null) { + ++count; + child = ((ElementImpl) child).getNextElementSibling(); + } + return count; + } // getChildElementCount():int + + /** + * @see + * Element Traversal Specification + */ + public final Element getFirstElementChild() { + Node n = getFirstChild(); + while (n != null) { + switch (n.getNodeType()) { + case Node.ELEMENT_NODE: + return (Element) n; + case Node.ENTITY_REFERENCE_NODE: + final Element e = getFirstElementChild(n); + if (e != null) { + return e; + } + break; + } + n = n.getNextSibling(); + } + return null; + } // getFirstElementChild():Element + + /** + * @see + * Element Traversal Specification + */ + public final Element getLastElementChild() { + Node n = getLastChild(); + while (n != null) { + switch (n.getNodeType()) { + case Node.ELEMENT_NODE: + return (Element) n; + case Node.ENTITY_REFERENCE_NODE: + final Element e = getLastElementChild(n); + if (e != null) { + return e; + } + break; + } + n = n.getPreviousSibling(); + } + return null; + } // getLastElementChild():Element + + /** + * @see + * Element Traversal Specification + */ + public final Element getNextElementSibling() { + Node n = getNextLogicalSibling(this); + while (n != null) { + switch (n.getNodeType()) { + case Node.ELEMENT_NODE: + return (Element) n; + case Node.ENTITY_REFERENCE_NODE: + final Element e = getFirstElementChild(n); + if (e != null) { + return e; + } + break; + } + n = getNextLogicalSibling(n); + } + return null; + } // getNextElementSibling():Element + + /** + * @see + * Element Traversal Specification + */ + public final Element getPreviousElementSibling() { + Node n = getPreviousLogicalSibling(this); + while (n != null) { + switch (n.getNodeType()) { + case Node.ELEMENT_NODE: + return (Element) n; + case Node.ENTITY_REFERENCE_NODE: + final Element e = getLastElementChild(n); + if (e != null) { + return e; + } + break; + } + n = getPreviousLogicalSibling(n); + } + return null; + } // getPreviousElementSibling():Element + + // Returns the first element node found from a + // non-recursive in order traversal of the given node. + private Element getFirstElementChild(Node n) { + final Node top = n; + while (n != null) { + if (n.getNodeType() == Node.ELEMENT_NODE) { + return (Element) n; + } + Node next = n.getFirstChild(); + while (next == null) { + if (top == n) { + break; + } + next = n.getNextSibling(); + if (next == null) { + n = n.getParentNode(); + if (n == null || top == n) { + return null; + } + } + } + n = next; + } + return null; + } // getFirstElementChild(Node):Element + + // Returns the first element node found from a + // non-recursive reverse order traversal of the given node. + private Element getLastElementChild(Node n) { + final Node top = n; + while (n != null) { + if (n.getNodeType() == Node.ELEMENT_NODE) { + return (Element) n; + } + Node next = n.getLastChild(); + while (next == null) { + if (top == n) { + break; + } + next = n.getPreviousSibling(); + if (next == null) { + n = n.getParentNode(); + if (n == null || top == n) { + return null; + } + } + } + n = next; + } + return null; + } // getLastElementChild(Node):Element + + // Returns the next logical sibling with respect to the given node. + private Node getNextLogicalSibling(Node n) { + Node next = n.getNextSibling(); + // If "n" has no following sibling and its parent is an entity reference node we + // need to continue the search through the following siblings of the entity + // reference as these are logically siblings of the given node. + if (next == null) { + Node parent = n.getParentNode(); + while (parent != null && parent.getNodeType() == Node.ENTITY_REFERENCE_NODE) { + next = parent.getNextSibling(); + if (next != null) { + break; + } + parent = parent.getParentNode(); + } + } + return next; + } // getNextLogicalSibling(Node):Node + + // Returns the previous logical sibling with respect to the given node. + private Node getPreviousLogicalSibling(Node n) { + Node prev = n.getPreviousSibling(); + // If "n" has no previous sibling and its parent is an entity reference node we + // need to continue the search through the previous siblings of the entity + // reference as these are logically siblings of the given node. + if (prev == null) { + Node parent = n.getParentNode(); + while (parent != null && parent.getNodeType() == Node.ENTITY_REFERENCE_NODE) { + prev = parent.getPreviousSibling(); + if (prev != null) { + break; + } + parent = parent.getParentNode(); + } + } + return prev; + } // getPreviousLogicalSibling(Node):Node + +} // class ElementImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ElementNSImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/ElementNSImpl.java new file mode 100644 index 0000000..6d00e4d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ElementNSImpl.java @@ -0,0 +1,378 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.xs.XSComplexTypeDecl; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; + + + +/** + * ElementNSImpl inherits from ElementImpl and adds namespace support. + *

+ * The qualified name is the node name, and we store localName which is also + * used in all queries. On the other hand we recompute the prefix when + * necessary. + * + * @xerces.internal + * + * @author Elena litani, IBM + * @author Neeraj Bajaj, Sun Microsystems + * @version $Id$ + */ +public class ElementNSImpl + extends ElementImpl { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -9142310625494392642L; + static final String xmlURI = "http://www.w3.org/XML/1998/namespace"; + + // + // Data + // + + /** DOM2: Namespace URI. */ + protected String namespaceURI; + + /** DOM2: localName. */ + protected String localName; + + /** DOM3: type information */ + // REVISIT: we are losing the type information in DOM during serialization + transient XSTypeDefinition type; + + protected ElementNSImpl() { + super(); + } + /** + * DOM2: Constructor for Namespace implementation. + */ + protected ElementNSImpl(CoreDocumentImpl ownerDocument, + String namespaceURI, + String qualifiedName) + throws DOMException + { + super(ownerDocument, qualifiedName); + setName(namespaceURI, qualifiedName); + } + + private void setName(String namespaceURI, String qname) { + + String prefix; + // DOM Level 3: namespace URI is never empty string. + this.namespaceURI = namespaceURI; + if (namespaceURI != null) { + //convert the empty string to 'null' + this.namespaceURI = (namespaceURI.length() == 0) ? null : namespaceURI; + } + + int colon1, colon2 ; + + //NAMESPACE_ERR: + //1. if the qualified name is 'null' it is malformed. + //2. or if the qualifiedName is null and the namespaceURI is different from null, + // We dont need to check for namespaceURI != null, if qualified name is null throw DOMException. + if(qname == null){ + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + else{ + colon1 = qname.indexOf(':'); + colon2 = qname.lastIndexOf(':'); + } + + ownerDocument.checkNamespaceWF(qname, colon1, colon2); + if (colon1 < 0) { + // there is no prefix + localName = qname; + if (ownerDocument.errorChecking) { + ownerDocument.checkQName(null, localName); + if (qname.equals("xmlns") + && (namespaceURI == null + || !namespaceURI.equals(NamespaceContext.XMLNS_URI)) + || (namespaceURI!=null && namespaceURI.equals(NamespaceContext.XMLNS_URI) + && !qname.equals("xmlns"))) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + } + }//there is a prefix + else { + prefix = qname.substring(0, colon1); + localName = qname.substring(colon2 + 1); + + //NAMESPACE_ERR: + //1. if the qualifiedName has a prefix and the namespaceURI is null, + + //2. or if the qualifiedName has a prefix that is "xml" and the namespaceURI + //is different from " http://www.w3.org/XML/1998/namespace" + + if (ownerDocument.errorChecking) { + if( namespaceURI == null || ( prefix.equals("xml") && !namespaceURI.equals(NamespaceContext.XML_URI) )){ + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", + null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + + ownerDocument.checkQName(prefix, localName); + ownerDocument.checkDOMNSErr(prefix, namespaceURI); + } + } + } + + // when local name is known + protected ElementNSImpl(CoreDocumentImpl ownerDocument, + String namespaceURI, String qualifiedName, + String localName) + throws DOMException + { + super(ownerDocument, qualifiedName); + + this.localName = localName; + this.namespaceURI = namespaceURI; + } + + // for DeferredElementImpl + protected ElementNSImpl(CoreDocumentImpl ownerDocument, + String value) { + super(ownerDocument, value); + } + + // Support for DOM Level 3 renameNode method. + // Note: This only deals with part of the pb. CoreDocumentImpl + // does all the work. + void rename(String namespaceURI, String qualifiedName) + { + if (needsSyncData()) { + synchronizeData(); + } + this.name = qualifiedName; + setName(namespaceURI, qualifiedName); + reconcileDefaultAttributes(); + } + + // + // Node methods + // + + + + // + //DOM2: Namespace methods. + // + + /** + * Introduced in DOM Level 2.

+ * + * 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 created with a DOM Level 1 method, such as createElement + * from the Document interface, this is null. + * @since WD-DOM-Level-2-19990923 + */ + public String getNamespaceURI() + { + if (needsSyncData()) { + synchronizeData(); + } + return namespaceURI; + } + + /** + * Introduced in DOM Level 2.

+ * + * The namespace prefix of this node, or null if it is unspecified.

+ * + * For nodes created with a DOM Level 1 method, such as createElement + * from the Document interface, this is null.

+ * + * @since WD-DOM-Level-2-19990923 + */ + public String getPrefix() + { + + if (needsSyncData()) { + synchronizeData(); + } + int index = name.indexOf(':'); + return index < 0 ? null : name.substring(0, index); + } + + /** + * Introduced in DOM Level 2.

+ * + * Note that setting this attribute changes the nodeName attribute, which holds the + * qualified name, as well as the tagName and name attributes of the Element + * and Attr interfaces, when applicable.

+ * + * @param prefix The namespace prefix of this node, or null(empty string) if it is unspecified. + * + * @exception INVALID_CHARACTER_ERR + * Raised if the specified + * prefix contains an invalid character. + * @exception DOMException + * @since WD-DOM-Level-2-19990923 + */ + public void setPrefix(String prefix) + throws DOMException + { + if (needsSyncData()) { + synchronizeData(); + } + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + if (prefix != null && prefix.length() != 0) { + if (!CoreDocumentImpl.isXMLName(prefix,ownerDocument.isXML11Version())) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); + } + if (namespaceURI == null || prefix.indexOf(':') >=0) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } else if (prefix.equals("xml")) { + if (!namespaceURI.equals(xmlURI)) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + throw new DOMException(DOMException.NAMESPACE_ERR, msg); + } + } + } + + } + // update node name with new qualifiedName + if (prefix !=null && prefix.length() != 0) { + name = prefix + ":" + localName; + } + else { + name = localName; + } + } + + /** + * Introduced in DOM Level 2.

+ * + * Returns the local part of the qualified name of this node. + * @since WD-DOM-Level-2-19990923 + */ + public String getLocalName() + { + if (needsSyncData()) { + synchronizeData(); + } + return localName; + } + + /** + * NON-DOM + * Returns the xml:base attribute. + */ + protected Attr getXMLBaseAttribute() { + return (Attr) attributes.getNamedItemNS("http://www.w3.org/XML/1998/namespace", "base"); + } // getXMLBaseAttribute():Attr + + /** + * @see org.w3c.dom.TypeInfo#getTypeName() + */ + public String getTypeName() { + if (type !=null){ + if (type instanceof XSSimpleTypeDecl) { + return ((XSSimpleTypeDecl) type).getTypeName(); + } else if (type instanceof XSComplexTypeDecl) { + return ((XSComplexTypeDecl) type).getTypeName(); + } + } + return null; + } + + /** + * @see org.w3c.dom.TypeInfo#getTypeNamespace() + */ + public String getTypeNamespace() { + if (type !=null){ + return type.getNamespace(); + } + return null; + } + + /** + * Introduced in DOM Level 2.

+ * Checks if a type is derived from another by restriction. See: + * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom + * + * @param typeNamespaceArg + * The namspace of the ancestor type declaration + * @param typeNameArg + * The name of the ancestor type declaration + * @param derivationMethod + * The derivation method + * + * @return boolean True if the type is derived by restriciton for the + * reference type + */ + public boolean isDerivedFrom(String typeNamespaceArg, String typeNameArg, + int derivationMethod) { + if(needsSyncData()) { + synchronizeData(); + } + if (type != null) { + if (type instanceof XSSimpleTypeDecl) { + return ((XSSimpleTypeDecl) type).isDOMDerivedFrom( + typeNamespaceArg, typeNameArg, derivationMethod); + } else if (type instanceof XSComplexTypeDecl) { + return ((XSComplexTypeDecl) type).isDOMDerivedFrom( + typeNamespaceArg, typeNameArg, derivationMethod); + } + } + return false; + } + + /** + * NON-DOM: setting type used by the DOM parser + * @see NodeImpl#setReadOnly + */ + public void setType(XSTypeDefinition type) { + this.type = type; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/EntityImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/EntityImpl.java new file mode 100644 index 0000000..7921d9a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/EntityImpl.java @@ -0,0 +1,340 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.Entity; +import org.w3c.dom.Node; + +/** + * Entity nodes hold the reference data for an XML Entity -- either + * parsed or unparsed. The nodeName (inherited from Node) will contain + * the name (if any) of the Entity. Its data will be contained in the + * Entity's children, in exactly the structure which an + * EntityReference to this name will present within the document's + * body. + *

+ * Note that this object models the actual entity, _not_ the entity + * declaration or the entity reference. + *

+ * An XML processor may choose to completely expand entities before + * the structure model is passed to the DOM; in this case, there will + * be no EntityReferences in the DOM tree. + *

+ * Quoting the 10/01 DOM Proposal, + *

+ * "The DOM Level 1 does not support editing Entity nodes; if a user + * wants to make changes to the contents of an Entity, every related + * EntityReference node has to be replaced in the structure model by + * a clone of the Entity's contents, and then the desired changes + * must be made to each of those clones instead. All the + * descendants of an Entity node are readonly." + *
+ * I'm interpreting this as: It is the parser's responsibilty to call + * the non-DOM operation setReadOnly(true,true) after it constructs + * the Entity. Since the DOM explicitly decided not to deal with this, + * _any_ answer will involve a non-DOM operation, and this is the + * simplest solution. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class EntityImpl + extends ParentNode + implements Entity { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -3575760943444303423L; + + // + // Data + // + + /** Entity name. */ + protected String name; + + /** Public identifier. */ + protected String publicId; + + /** System identifier. */ + protected String systemId; + + /** Encoding */ + protected String encoding; + + + /** Input Encoding */ + protected String inputEncoding; + + /** Version */ + protected String version; + + + /** Notation name. */ + protected String notationName; + + /** base uri*/ + protected String baseURI; + + // + // Constructors + // + + /** Factory constructor. */ + public EntityImpl(CoreDocumentImpl ownerDoc, String name) { + super(ownerDoc); + this.name = name; + isReadOnly(true); + } + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.ENTITY_NODE; + } + + /** + * Returns the entity name + */ + public String getNodeName() { + if (needsSyncData()) { + synchronizeData(); + } + return name; + } + + /** Clone node. */ + public Node cloneNode(boolean deep) { + EntityImpl newentity = (EntityImpl)super.cloneNode(deep); + newentity.setReadOnly(true, deep); + return newentity; + } + + // + // Entity methods + // + + /** + * The public identifier associated with the entity. If not specified, + * this will be null. + */ + public String getPublicId() { + + if (needsSyncData()) { + synchronizeData(); + } + return publicId; + + } // getPublicId():String + + /** + * The system identifier associated with the entity. If not specified, + * this will be null. + */ + public String getSystemId() { + + if (needsSyncData()) { + synchronizeData(); + } + return systemId; + + } // getSystemId():String + + /** + * DOM Level 3 WD - experimental + * the version number of this entity, when it is an external parsed entity. + */ + public String getXmlVersion() { + + if (needsSyncData()) { + synchronizeData(); + } + return version; + + } // getVersion():String + + + /** + * DOM Level 3 WD - experimental + * the encoding of this entity, when it is an external parsed entity. + */ + public String getXmlEncoding() { + + if (needsSyncData()) { + synchronizeData(); + } + + return encoding; + + } // getVersion():String + + + + + + /** + * Unparsed entities -- which contain non-XML data -- have a + * "notation name" which tells applications how to deal with them. + * Parsed entities, which are in XML format, don't need this and + * set it to null. + */ + public String getNotationName() { + + if (needsSyncData()) { + synchronizeData(); + } + return notationName; + + } // getNotationName():String + + // + // Public methods + // + + /** + * DOM Level 2: The public identifier associated with the entity. If not specified, + * this will be null. */ + public void setPublicId(String id) { + + if (needsSyncData()) { + synchronizeData(); + } + publicId = id; + + } // setPublicId(String) + + /** + * NON-DOM + * encoding - An attribute specifying, as part of the text declaration, + * the encoding of this entity, when it is an external parsed entity. + * This is null otherwise + * + */ + public void setXmlEncoding(String value) { + if (needsSyncData()) { + synchronizeData(); + } + encoding = value; + } // setEncoding (String) + + + /** + * An attribute specifying the encoding used for this entity at the tiome + * of parsing, when it is an external parsed entity. This is + * null if it an entity from the internal subset or if it + * is not known.. + * @since DOM Level 3 + */ + public String getInputEncoding(){ + if (needsSyncData()) { + synchronizeData(); + } + return inputEncoding; + } + + /** + * NON-DOM, used to set the input encoding. + */ + public void setInputEncoding(String inputEncoding){ + if (needsSyncData()) { + synchronizeData(); + } + this.inputEncoding = inputEncoding; + } + + /** + * NON-DOM + * version - An attribute specifying, as part of the text declaration, + * the version number of this entity, when it is an external parsed entity. + * This is null otherwise + */ + public void setXmlVersion(String value) { + if (needsSyncData()) { + synchronizeData(); + } + version = value; + } // setVersion (String) + + + /** + * DOM Level 2: The system identifier associated with the entity. If not + * specified, this will be null. + */ + public void setSystemId(String id) { + if (needsSyncData()) { + synchronizeData(); + } + systemId = id; + + } // setSystemId(String) + + /** + * DOM Level 2: Unparsed entities -- which contain non-XML data -- have a + * "notation name" which tells applications how to deal with them. + * Parsed entities, which are in XML format, don't need this and + * set it to null. + */ + public void setNotationName(String name) { + if (needsSyncData()) { + synchronizeData(); + } + notationName = name; + + } // setNotationName(String) + + + + /** + * Returns the absolute base URI of this node or null if the implementation + * wasn't able to obtain an absolute URI. Note: If the URI is malformed, a + * null is returned. + * + * @return The absolute base URI of this node or null. + * @since DOM Level 3 + */ + public String getBaseURI() { + + if (needsSyncData()) { + synchronizeData(); + } + return (baseURI!=null)?baseURI:((CoreDocumentImpl)getOwnerDocument()).getBaseURI(); + } + + /** NON-DOM: set base uri*/ + public void setBaseURI(String uri){ + if (needsSyncData()) { + synchronizeData(); + } + baseURI = uri; + } + + + +} // class EntityImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/EntityReferenceImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/EntityReferenceImpl.java new file mode 100644 index 0000000..8b424d9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/EntityReferenceImpl.java @@ -0,0 +1,400 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.apache.xerces.util.URI; +import org.w3c.dom.DocumentType; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * EntityReference models the XML &entityname; syntax, when used for + * entities defined by the DOM. Entities hardcoded into XML, such as + * character entities, should instead have been translated into text + * by the code which generated the DOM tree. + *

+ * An XML processor has the alternative of fully expanding Entities + * into the normal document tree. If it does so, no EntityReference nodes + * will appear. + *

+ * Similarly, non-validating XML processors are not required to read + * or process entity declarations made in the external subset or + * declared in external parameter entities. Hence, some applications + * may not make the replacement value available for Parsed Entities + * of these types. + *

+ * EntityReference behaves as a read-only node, and the children of + * the EntityReference (which reflect those of the Entity, and should + * also be read-only) give its replacement value, if any. They are + * supposed to automagically stay in synch if the DocumentType is + * updated with new values for the Entity. + *

+ * The defined behavior makes efficient storage difficult for the DOM + * implementor. We can't just look aside to the Entity's definition + * in the DocumentType since those nodes have the wrong parent (unless + * we can come up with a clever "imaginary parent" mechanism). We + * must at least appear to clone those children... which raises the + * issue of keeping the reference synchronized with its parent. + * This leads me back to the "cached image of centrally defined data" + * solution, much as I dislike it. + *

+ * For now I have decided, since REC-DOM-Level-1-19980818 doesn't + * cover this in much detail, that synchronization doesn't have to be + * considered while the user is deep in the tree. That is, if you're + * looking within one of the EntityReferennce's children and the Entity + * changes, you won't be informed; instead, you will continue to access + * the same object -- which may or may not still be part of the tree. + * This is the same behavior that obtains elsewhere in the DOM if the + * subtree you're looking at is deleted from its parent, so it's + * acceptable here. (If it really bothers folks, we could set things + * up so deleted subtrees are walked and marked invalid, but that's + * not part of the DOM's defined behavior.) + *

+ * As a result, only the EntityReference itself has to be aware of + * changes in the Entity. And it can take advantage of the same + * structure-change-monitoring code I implemented to support + * DeepNodeList. + * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Joe Kesselman, IBM + * @author Andy Clark, IBM + * @author Ralf Pfeiffer, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class EntityReferenceImpl +extends ParentNode +implements EntityReference { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -7381452955687102062L; + + // + // Data + // + + /** Name of Entity referenced */ + protected String name; + /** Base URI*/ + protected String baseURI; + + + /** Entity changes. */ + //protected int entityChanges = -1; + + /** Enable synchronize. */ + //protected boolean fEnableSynchronize = false; + + // + // Constructors + // + + /** Factory constructor. */ + public EntityReferenceImpl(CoreDocumentImpl ownerDoc, String name) { + super(ownerDoc); + this.name = name; + isReadOnly(true); + needsSyncChildren(true); + } + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.ENTITY_REFERENCE_NODE; + } + + /** + * Returns the name of the entity referenced + */ + public String getNodeName() { + if (needsSyncData()) { + synchronizeData(); + } + return name; + } + + /** Clone node. */ + public Node cloneNode(boolean deep) { + EntityReferenceImpl er = (EntityReferenceImpl)super.cloneNode(deep); + er.setReadOnly(true, deep); + return er; + } + + /** + * Returns the absolute base URI of this node or null if the implementation + * wasn't able to obtain an absolute URI. Note: If the URI is malformed, a + * null is returned. + * + * @return The absolute base URI of this node or null. + * @since DOM Level 3 + */ + public String getBaseURI() { + if (needsSyncData()) { + synchronizeData(); + } + if (baseURI == null) { + DocumentType doctype; + NamedNodeMap entities; + EntityImpl entDef; + if (null != (doctype = getOwnerDocument().getDoctype()) && + null != (entities = doctype.getEntities())) { + + entDef = (EntityImpl)entities.getNamedItem(getNodeName()); + if (entDef !=null) { + return entDef.getBaseURI(); + } + } + } else if (baseURI != null && baseURI.length() != 0 ) {// attribute value is always empty string + try { + return new URI(baseURI).toString(); + } + catch (org.apache.xerces.util.URI.MalformedURIException e){ + // REVISIT: what should happen in this case? + return null; + } + } + return baseURI; + } + + + /** NON-DOM: set base uri*/ + public void setBaseURI(String uri){ + if (needsSyncData()) { + synchronizeData(); + } + baseURI = uri; + } + + /** + * NON-DOM: compute string representation of the entity reference. + * This method is used to retrieve a string value for an attribute node that has child nodes. + * @return String representing a value of this entity ref. or + * null if any node other than EntityReference, Text is encountered + * during computation + */ + protected String getEntityRefValue (){ + if (needsSyncChildren()){ + synchronizeChildren(); + } + + String value = ""; + if (firstChild != null){ + if (firstChild.getNodeType() == Node.ENTITY_REFERENCE_NODE){ + value = ((EntityReferenceImpl)firstChild).getEntityRefValue(); + } + else if (firstChild.getNodeType() == Node.TEXT_NODE){ + value = firstChild.getNodeValue(); + } + else { + // invalid to have other types of nodes in attr value + return null; + } + + if (firstChild.nextSibling == null){ + return value; + } + else { + StringBuffer buff = new StringBuffer(value); + ChildNode next = firstChild.nextSibling; + while (next != null){ + + if (next.getNodeType() == Node.ENTITY_REFERENCE_NODE){ + value = ((EntityReferenceImpl)next).getEntityRefValue(); + } + else if (next.getNodeType() == Node.TEXT_NODE){ + value = next.getNodeValue(); + } + else { + // invalid to have other types of nodes in attr value + return null; + } + buff.append(value); + next = next.nextSibling; + + } + return buff.toString(); + } + } + return ""; + } + + /** + * EntityReference's children are a reflection of those defined in the + * named Entity. This method creates them if they haven't been created yet. + * This doesn't support editing the Entity though, since this only called + * once for all. + */ + protected void synchronizeChildren() { + // no need to synchronize again + needsSyncChildren(false); + + DocumentType doctype; + NamedNodeMap entities; + EntityImpl entDef; + if (null != (doctype = getOwnerDocument().getDoctype()) && + null != (entities = doctype.getEntities())) { + + entDef = (EntityImpl)entities.getNamedItem(getNodeName()); + + // No Entity by this name, stop here. + if (entDef == null) + return; + + // If entity's definition exists, clone its kids + isReadOnly(false); + for (Node defkid = entDef.getFirstChild(); + defkid != null; + defkid = defkid.getNextSibling()) { + Node newkid = defkid.cloneNode(true); + insertBefore(newkid, null); + } + setReadOnly(true, true); + } + } + + + /** + * NON-DOM: sets the node and its children value. + *

+ * Note: make sure that entity reference and its kids could be set readonly. + */ + public void setReadOnly(boolean readOnly, boolean deep) { + + if (needsSyncData()) { + synchronizeData(); + } + if (deep) { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + // Recursively set kids + for (ChildNode mykid = firstChild; + mykid != null; + mykid = mykid.nextSibling) { + + mykid.setReadOnly(readOnly,true); + + } + } + isReadOnly(readOnly); + } // setReadOnly(boolean,boolean) + + + /** + * Enable the synchronize method which may do cloning. This method is enabled + * when the parser is done with an EntityReference. + /*** + // revisit: enable editing of Entity + public void enableSynchronize(boolean enableSynchronize) { + fEnableSynchronize= enableSynchronize; + } + /***/ + + /** + * EntityReference's children are a reflection of those defined in the + * named Entity. This method updates them if the Entity is changed. + *

+ * It is unclear what the least-cost resynch mechanism is. + * If we expect the kids to be shallow, and/or expect changes + * to the Entity contents to be rare, wiping them all out + * and recloning is simplest. + *

+ * If we expect them to be deep, + * it might be better to first decide which kids (if any) + * persist, and keep the ones (if any) that are unchanged + * rather than doing all the work of cloning them again. + * But that latter gets into having to convolve the two child lists, + * insert new information in the right order (and possibly reorder + * the existing kids), and a few other complexities that I really + * don't want to deal with in this implementation. + *

+ * Note that if we decide that we need to update the EntityReference's + * contents, we have to turn off the readOnly flag temporarily to do so. + * When we get around to adding multitasking support, this whole method + * should probably be an atomic operation. + * + * @see DocumentTypeImpl + * @see EntityImpl + */ + // The Xerces parser invokes callbacks for startEnityReference + // the parsed value of the entity EACH TIME, so it is actually + // easier to create the nodes through the callbacks rather than + // clone the Entity. + /*** + // revisit: enable editing of Entity + private void synchronize() { + if (!fEnableSynchronize) { + return; + } + DocumentType doctype; + NamedNodeMap entities; + EntityImpl entDef; + if (null != (doctype = getOwnerDocument().getDoctype()) && + null != (entities = doctype.getEntities())) { + + entDef = (EntityImpl)entities.getNamedItem(getNodeName()); + + // No Entity by this name. If we had a change count, reset it. + if(null==entDef) + entityChanges=-1; + + // If no kids availalble, wipe any pre-existing children. + // (See discussion above.) + // Note that we have to use the superclass to avoid recursion + // through Synchronize. + readOnly=false; + if(null==entDef || !entDef.hasChildNodes()) + for(Node kid=super.getFirstChild(); + kid!=null; + kid=super.getFirstChild()) + removeChild(kid); + + // If entity's definition changed, clone its kids + // (See discussion above.) + if(null!=entDef && entDef.changes!=entityChanges) { + for(Node defkid=entDef.getFirstChild(); + defkid!=null; + defkid=defkid.getNextSibling()) { + + NodeImpl newkid=(NodeImpl) defkid.cloneNode(true); + newkid.setReadOnly(true,true); + insertBefore(newkid,null); + } + entityChanges=entDef.changes; + } + readOnly=true; + } + } + /***/ + + +} // class EntityReferenceImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/LCount.java b/resources/xerces2-j-src/org/apache/xerces/dom/LCount.java new file mode 100644 index 0000000..313a29b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/LCount.java @@ -0,0 +1,55 @@ +/* + * 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. + */ +package org.apache.xerces.dom; + + +/** Internal class LCount is used to track the number of + listeners registered for a given event name, as an entry + in a global hashtable. This should allow us to avoid generating, + or discard, events for which no listeners are registered. + + ***** There should undoubtedly be methods here to manipulate + this table. At the moment that code's residing in NodeImpl. + Move it when we have a chance to do so. Sorry; we were + rushed. + + ???? CONCERN: Hashtables are known to be "overserialized" in + current versions of Java. That may impact performance. + + ???? CONCERN: The hashtable should probably be a per-document object. + Finer granularity would be even better, but would cost more cycles to + resolve and might not save enough event traffic to be worth the investment. +*/ +/** + * @xerces.internal + * + * @version $Id$ + */ + +class LCount +{ + static java.util.Hashtable lCounts=new java.util.Hashtable(); + public int captures=0,bubbles=0,defaults, total=0; + + static LCount lookup(String evtName) + { + LCount lc=(LCount)lCounts.get(evtName); + if(lc==null) + lCounts.put(evtName,(lc=new LCount())); + return lc; + } +} // class LCount diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/NamedNodeMapImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/NamedNodeMapImpl.java new file mode 100644 index 0000000..23a9f22 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/NamedNodeMapImpl.java @@ -0,0 +1,628 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * NamedNodeMaps represent collections of Nodes that can be accessed + * by name. Entity and Notation nodes are stored in NamedNodeMaps + * attached to the DocumentType. Attributes are placed in a NamedNodeMap + * attached to the elem they're related too. However, because attributes + * require more work, such as firing mutation events, they are stored in + * a subclass of NamedNodeMapImpl. + *

+ * Only one Node may be stored per name; attempting to + * store another will replace the previous value. + *

+ * NOTE: The "primary" storage key is taken from the NodeName attribute of the + * node. The "secondary" storage key is the namespaceURI and localName, when + * accessed by DOM level 2 nodes. All nodes, even DOM Level 2 nodes are stored + * in a single ArrayList sorted by the primary "nodename" key. + *

+ * NOTE: item()'s integer index does _not_ imply that the named nodes + * must be stored in an array; that's only an access method. Note too + * that these indices are "live"; if someone changes the map's + * contents, the indices associated with nodes may change. + *

+ * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class NamedNodeMapImpl + implements NamedNodeMap, Serializable { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -7039242451046758020L; + + // + // Data + // + + protected short flags; + + protected final static short READONLY = 0x1<<0; + protected final static short CHANGED = 0x1<<1; + protected final static short HASDEFAULTS = 0x1<<2; + + /** Nodes. */ + protected List nodes; + + protected NodeImpl ownerNode; // the node this map belongs to + + // + // Constructors + // + + /** Constructs a named node map. */ + protected NamedNodeMapImpl(NodeImpl ownerNode) { + this.ownerNode = ownerNode; + } + + // + // NamedNodeMap methods + // + + /** + * Report how many nodes are currently stored in this NamedNodeMap. + * Caveat: This is a count rather than an index, so the + * highest-numbered node at any time can be accessed via + * item(getLength()-1). + */ + public int getLength() { + return (nodes != null) ? nodes.size() : 0; + } + + /** + * Retrieve an item from the map by 0-based index. + * + * @param index Which item to retrieve. Note that indices are just an + * enumeration of the current contents; they aren't guaranteed to be + * stable, nor do they imply any promises about the order of the + * NamedNodeMap's contents. In other words, DO NOT assume either that + * index(i) will always refer to the same entry, or that there is any + * stable ordering of entries... and be prepared for double-reporting + * or skips as insertion and deletion occur. + * + * @return the node which currenly has the specified index, or null if index + * is greater than or equal to getLength(). + */ + public Node item(int index) { + return (nodes != null && index < nodes.size()) ? + (Node)(nodes.get(index)) : null; + } + + /** + * Retrieve a node by name. + * + * @param name Name of a node to look up. + * @return the Node (of unspecified sub-class) stored with that name, or + * null if no value has been assigned to that name. + */ + public Node getNamedItem(String name) { + + int i = findNamePoint(name,0); + return (i < 0) ? null : (Node)(nodes.get(i)); + + } // getNamedItem(String):Node + + /** + * Introduced in DOM Level 2.

+ * Retrieves a node specified by local name and namespace URI. + * + * @param namespaceURI The namespace URI of the node to retrieve. + * When it is null or an empty string, this + * method behaves like getNamedItem. + * @param localName The local name of the node to retrieve. + * @return Node A Node (of any type) with the specified name, or null if the specified + * name did not identify any node in the map. + */ + public Node getNamedItemNS(String namespaceURI, String localName) { + + int i = findNamePoint(namespaceURI, localName); + return (i < 0) ? null : (Node)(nodes.get(i)); + + } // getNamedItemNS(String,String):Node + + /** + * Adds a node using its nodeName attribute. + * As the nodeName attribute is used to derive the name which the node must be + * stored under, multiple nodes of certain types (those that have a "special" string + * value) cannot be stored as the names would clash. This is seen as preferable to + * allowing nodes to be aliased. + * @see org.w3c.dom.NamedNodeMap#setNamedItem + * @return If the new Node replaces an existing node the replaced Node is returned, + * otherwise null is returned. + * @param arg + * A node to store in a named node map. The node will later be + * accessible using the value of the namespaceURI and localName + * attribute of the node. If a node with those namespace URI and + * local name is already present in the map, it is replaced by the new + * one. + * @exception org.w3c.dom.DOMException The exception description. + */ + public Node setNamedItem(Node arg) + throws DOMException { + + CoreDocumentImpl ownerDocument = ownerNode.ownerDocument(); + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + if (arg.getOwnerDocument() != ownerDocument) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + } + + int i = findNamePoint(arg.getNodeName(),0); + NodeImpl previous = null; + if (i >= 0) { + previous = (NodeImpl) nodes.get(i); + nodes.set(i, arg); + } else { + i = -1 - i; // Insert point (may be end of list) + if (null == nodes) { + nodes = new ArrayList(5); + } + nodes.add(i, arg); + } + return previous; + + } // setNamedItem(Node):Node + + /** + * Adds a node using its namespaceURI and localName. + * @see org.w3c.dom.NamedNodeMap#setNamedItem + * @return If the new Node replaces an existing node the replaced Node is returned, + * otherwise null is returned. + * @param arg A node to store in a named node map. The node will later be + * accessible using the value of the namespaceURI and localName + * attribute of the node. If a node with those namespace URI and + * local name is already present in the map, it is replaced by the new + * one. + */ + public Node setNamedItemNS(Node arg) + throws DOMException { + + CoreDocumentImpl ownerDocument = ownerNode.ownerDocument(); + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg); + } + + if(arg.getOwnerDocument() != ownerDocument) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); + } + } + + int i = findNamePoint(arg.getNamespaceURI(), arg.getLocalName()); + NodeImpl previous = null; + if (i >= 0) { + previous = (NodeImpl) nodes.get(i); + nodes.set(i, arg); + } else { + // If we can't find by namespaceURI, localName, then we find by + // nodeName so we know where to insert. + i = findNamePoint(arg.getNodeName(),0); + if (i >= 0) { + previous = (NodeImpl) nodes.get(i); + nodes.add(i, arg); + } else { + i = -1 - i; // Insert point (may be end of list) + if (null == nodes) { + nodes = new ArrayList(5); + } + nodes.add(i, arg); + } + } + return previous; + + } // setNamedItemNS(Node):Node + + /** + * Removes a node specified by name. + * @param name The name of a node to remove. + * @return The node removed from the map if a node with such a name exists. + */ + /***/ + public Node removeNamedItem(String name) + throws DOMException { + + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw + new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + int i = findNamePoint(name,0); + if (i < 0) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + + NodeImpl n = (NodeImpl)nodes.get(i); + nodes.remove(i); + + return n; + + } // removeNamedItem(String):Node + + /** + * Introduced in DOM Level 2.

+ * Removes a node specified by local name and namespace URI. + * @param namespaceURI + * The namespace URI of the node to remove. + * When it is null or an empty string, this + * method behaves like removeNamedItem. + * @param name The local name of the node to remove. + * @return Node The node removed from the map if a node with such + * a local name and namespace URI exists. + * @throws NOT_FOUND_ERR: Raised if there is no node named + * name in the map. + + */ + public Node removeNamedItemNS(String namespaceURI, String name) + throws DOMException { + + if (isReadOnly()) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null); + throw + new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + msg); + } + int i = findNamePoint(namespaceURI, name); + if (i < 0) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + + NodeImpl n = (NodeImpl)nodes.get(i); + nodes.remove(i); + + return n; + + } // removeNamedItem(String):Node + + // + // Public methods + // + + /** + * Cloning a NamedNodeMap is a DEEP OPERATION; it always clones + * all the nodes contained in the map. + */ + + public NamedNodeMapImpl cloneMap(NodeImpl ownerNode) { + NamedNodeMapImpl newmap = new NamedNodeMapImpl(ownerNode); + newmap.cloneContent(this); + return newmap; + } + + protected void cloneContent(NamedNodeMapImpl srcmap) { + List srcnodes = srcmap.nodes; + if (srcnodes != null) { + int size = srcnodes.size(); + if (size != 0) { + if (nodes == null) { + nodes = new ArrayList(size); + } + else { + nodes.clear(); + } + for (int i = 0; i < size; ++i) { + NodeImpl n = (NodeImpl) srcmap.nodes.get(i); + NodeImpl clone = (NodeImpl) n.cloneNode(true); + clone.isSpecified(n.isSpecified()); + nodes.add(clone); + } + } + } + } // cloneMap():NamedNodeMapImpl + + // + // Package methods + // + + /** + * Internal subroutine to allow read-only Nodes to make their contained + * NamedNodeMaps readonly too. I expect that in fact the shallow + * version of this operation will never be + * + * @param readOnly boolean true to make read-only, false to permit editing. + * @param deep boolean true to pass this request along to the contained + * nodes, false to only toggle the NamedNodeMap itself. I expect that + * the shallow version of this operation will never be used, but I want + * to design it in now, while I'm thinking about it. + */ + void setReadOnly(boolean readOnly, boolean deep) { + isReadOnly(readOnly); + if (deep && nodes != null) { + for (int i = nodes.size() - 1; i >= 0; i--) { + ((NodeImpl) nodes.get(i)).setReadOnly(readOnly,deep); + } + } + } // setReadOnly(boolean,boolean) + + /** + * Internal subroutine returns this NodeNameMap's (shallow) readOnly value. + * + */ + boolean getReadOnly() { + return isReadOnly(); + } // getReadOnly() + + + // + // Protected methods + // + + /** + * NON-DOM + * set the ownerDocument of this node, and the attributes it contains + */ + protected void setOwnerDocument(CoreDocumentImpl doc) { + if (nodes != null) { + final int size = nodes.size(); + for (int i = 0; i < size; ++i) { + ((NodeImpl)item(i)).setOwnerDocument(doc); + } + } + } + + final boolean isReadOnly() { + return (flags & READONLY) != 0; + } + + final void isReadOnly(boolean value) { + flags = (short) (value ? flags | READONLY : flags & ~READONLY); + } + + final boolean changed() { + return (flags & CHANGED) != 0; + } + + final void changed(boolean value) { + flags = (short) (value ? flags | CHANGED : flags & ~CHANGED); + } + + final boolean hasDefaults() { + return (flags & HASDEFAULTS) != 0; + } + + final void hasDefaults(boolean value) { + flags = (short) (value ? flags | HASDEFAULTS : flags & ~HASDEFAULTS); + } + + // + // Private methods + // + + /** + * Subroutine: Locate the named item, or the point at which said item + * should be added. + * + * @param name Name of a node to look up. + * + * @return If positive or zero, the index of the found item. + * If negative, index of the appropriate point at which to insert + * the item, encoded as -1-index and hence reconvertable by subtracting + * it from -1. (Encoding because I don't want to recompare the strings + * but don't want to burn bytes on a datatype to hold a flagged value.) + */ + protected int findNamePoint(String name, int start) { + + // Binary search + int i = 0; + if (nodes != null) { + int first = start; + int last = nodes.size() - 1; + + while (first <= last) { + i = (first + last) / 2; + int test = name.compareTo(((Node)(nodes.get(i))).getNodeName()); + if (test == 0) { + return i; // Name found + } + else if (test < 0) { + last = i - 1; + } + else { + first = i + 1; + } + } + + if (first > i) { + i = first; + } + } + + return -1 - i; // not-found has to be encoded. + + } // findNamePoint(String):int + + + /** This findNamePoint is for DOM Level 2 Namespaces. + */ + protected int findNamePoint(String namespaceURI, String name) { + + if (nodes == null) return -1; + if (name == null) return -1; + + // This is a linear search through the same nodes ArrayList. + // The ArrayList is sorted on the DOM Level 1 nodename. + // The DOM Level 2 NS keys are namespaceURI and Localname, + // so we must linear search thru it. + // In addition, to get this to work with nodes without any namespace + // (namespaceURI and localNames are both null) we then use the nodeName + // as a secondary key. + final int size = nodes.size(); + for (int i = 0; i < size; ++i) { + NodeImpl a = (NodeImpl)nodes.get(i); + String aNamespaceURI = a.getNamespaceURI(); + String aLocalName = a.getLocalName(); + if (namespaceURI == null) { + if (aNamespaceURI == null + && + (name.equals(aLocalName) + || + (aLocalName == null && name.equals(a.getNodeName())))) + return i; + } else { + if (namespaceURI.equals(aNamespaceURI) + && + name.equals(aLocalName)) + return i; + } + } + return -1; + } + + // compare 2 nodes in the map. If a precedes b, return true, otherwise + // return false + protected boolean precedes(Node a, Node b) { + + if (nodes != null) { + final int size = nodes.size(); + for (int i = 0; i < size; ++i) { + Node n = (Node)nodes.get(i); + if (n==a) return true; + if (n==b) return false; + } + } + return false; + } + + + /** + * NON-DOM: Remove attribute at specified index + */ + protected void removeItem(int index) { + if (nodes != null && index < nodes.size()){ + nodes.remove(index); + } + } + + + protected Object getItem (int index){ + if (nodes != null) { + return nodes.get(index); + } + return null; + } + + protected int addItem (Node arg) { + int i = findNamePoint(arg.getNamespaceURI(), arg.getLocalName()); + if (i >= 0) { + nodes.set(i, arg); + } + else { + // If we can't find by namespaceURI, localName, then we find by + // nodeName so we know where to insert. + i = findNamePoint(arg.getNodeName(),0); + if (i >= 0) { + nodes.add(i, arg); + } + else { + i = -1 - i; // Insert point (may be end of list) + if (null == nodes) { + nodes = new ArrayList(5); + } + nodes.add(i, arg); + } + } + return i; + } + + /** + * NON-DOM: copy content of this map into the specified ArrayList + * + * @param list ArrayList to copy information into. + * @return A copy of this node named map + */ + protected ArrayList cloneMap(ArrayList list) { + if (list == null) { + list = new ArrayList(5); + } + list.clear(); + if (nodes != null) { + final int size = nodes.size(); + for (int i = 0; i < size; ++i) { + list.add(nodes.get(i)); + } + } + return list; + } + + protected int getNamedItemIndex(String namespaceURI, String localName) { + return findNamePoint(namespaceURI, localName); + } + + /** + * NON-DOM remove all elements from this map + */ + public void removeAll (){ + if (nodes != null) { + nodes.clear(); + } + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + if (nodes != null) { + // cast to Vector is required + nodes = new ArrayList((Vector)nodes); + } + } + + private void writeObject(ObjectOutputStream out) throws IOException { + List oldNodes = this.nodes; + try { + if (oldNodes != null) { + this.nodes = new Vector(oldNodes); + } + out.defaultWriteObject(); + } + // If the write fails for some reason ensure + // that we restore the original object. + finally { + this.nodes = oldNodes; + } + } + +} // class NamedNodeMapImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/NodeImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/NodeImpl.java new file mode 100644 index 0000000..f18afe1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/NodeImpl.java @@ -0,0 +1,2028 @@ + /* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Hashtable; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; + +/** + * NodeImpl provides the basic structure of a DOM tree. It is never used + * directly, but instead is subclassed to add type and data + * information, and additional methods, appropriate to each node of + * the tree. Only its subclasses should be instantiated -- and those, + * with the exception of Document itself, only through a specific + * Document's factory methods. + *

+ * The Node interface provides shared behaviors such as siblings and + * children, both for consistancy and so that the most common tree + * operations may be performed without constantly having to downcast + * to specific node types. When there is no obvious mapping for one of + * these queries, it will respond with null. + * Note that the default behavior is that children are forbidden. To + * permit them, the subclass ParentNode overrides several methods. + *

+ * NodeImpl also implements NodeList, so it can return itself in + * response to the getChildNodes() query. This eliminiates the need + * for a separate ChildNodeList object. Note that this is an + * IMPLEMENTATION DETAIL; applications should _never_ assume that + * this identity exists. + *

+ * All nodes in a single document must originate + * in that document. (Note that this is much tighter than "must be + * same implementation") Nodes are all aware of their ownerDocument, + * and attempts to mismatch will throw WRONG_DOCUMENT_ERR. + *

+ * However, to save memory not all nodes always have a direct reference + * to their ownerDocument. When a node is owned by another node it relies + * on its owner to store its ownerDocument. Parent nodes always store it + * though, so there is never more than one level of indirection. + * And when a node doesn't have an owner, ownerNode refers to its + * ownerDocument. + *

+ * This class doesn't directly support mutation events, however, it still + * implements the EventTarget interface and forward all related calls to the + * document so that the document class do so. + * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Joe Kesselman, IBM + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public abstract class NodeImpl + implements Node, NodeList, EventTarget, Cloneable, Serializable{ + + // + // Constants + // + + + // TreePosition Constants. + // Taken from DOM L3 Node interface. + /** + * The node precedes the reference node. + */ + public static final short TREE_POSITION_PRECEDING = 0x01; + /** + * The node follows the reference node. + */ + public static final short TREE_POSITION_FOLLOWING = 0x02; + /** + * The node is an ancestor of the reference node. + */ + public static final short TREE_POSITION_ANCESTOR = 0x04; + /** + * The node is a descendant of the reference node. + */ + public static final short TREE_POSITION_DESCENDANT = 0x08; + /** + * The two nodes have an equivalent position. This is the case of two + * attributes that have the same ownerElement, and two + * nodes that are the same. + */ + public static final short TREE_POSITION_EQUIVALENT = 0x10; + /** + * The two nodes are the same. Two nodes that are the same have an + * equivalent position, though the reverse may not be true. + */ + public static final short TREE_POSITION_SAME_NODE = 0x20; + /** + * The two nodes are disconnected, they do not have any common ancestor. + * This is the case of two nodes that are not in the same document. + */ + public static final short TREE_POSITION_DISCONNECTED = 0x00; + + + // DocumentPosition + public static final short DOCUMENT_POSITION_DISCONNECTED = 0x01; + public static final short DOCUMENT_POSITION_PRECEDING = 0x02; + public static final short DOCUMENT_POSITION_FOLLOWING = 0x04; + public static final short DOCUMENT_POSITION_CONTAINS = 0x08; + public static final short DOCUMENT_POSITION_IS_CONTAINED = 0x10; + public static final short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; + + /** Serialization version. */ + static final long serialVersionUID = -6316591992167219696L; + + // public + + /** Element definition node type. */ + public static final short ELEMENT_DEFINITION_NODE = 21; + + // + // Data + // + + // links + + protected NodeImpl ownerNode; // typically the parent but not always! + + // data + + protected short flags; + + protected final static short READONLY = 0x1<<0; + protected final static short SYNCDATA = 0x1<<1; + protected final static short SYNCCHILDREN = 0x1<<2; + protected final static short OWNED = 0x1<<3; + protected final static short FIRSTCHILD = 0x1<<4; + protected final static short SPECIFIED = 0x1<<5; + protected final static short IGNORABLEWS = 0x1<<6; + protected final static short HASSTRING = 0x1<<7; + protected final static short NORMALIZED = 0x1<<8; + protected final static short ID = 0x1<<9; + + // + // Constructors + // + + /** + * No public constructor; only subclasses of Node should be + * instantiated, and those normally via a Document's factory methods + *

+ * Every Node knows what Document it belongs to. + */ + protected NodeImpl(CoreDocumentImpl ownerDocument) { + // as long as we do not have any owner, ownerNode is our ownerDocument + ownerNode = ownerDocument; + } // (CoreDocumentImpl) + + /** Constructor for serialization. */ + public NodeImpl() {} + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public abstract short getNodeType(); + + /** + * the name of this node. + */ + public abstract String getNodeName(); + + /** + * Returns the node value. + * @throws DOMException(DOMSTRING_SIZE_ERR) + */ + public String getNodeValue() + throws DOMException { + return null; // overridden in some subclasses + } + + /** + * Sets the node value. + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) + */ + public void setNodeValue(String x) + throws DOMException { + // Default behavior is to do nothing, overridden in some subclasses + } + + /** + * Adds a child node to the end of the list of children for this node. + * Convenience shorthand for insertBefore(newChild,null). + * @see #insertBefore(Node, Node) + *

+ * By default we do not accept any children, ParentNode overrides this. + * @see ParentNode + * + * @return newChild, in its new state (relocated, or emptied in the case of + * DocumentNode.) + * + * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a + * type that shouldn't be a child of this node. + * + * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a + * different owner document than we do. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node appendChild(Node newChild) throws DOMException { + return insertBefore(newChild, null); + } + + /** + * Returns a duplicate of a given node. You can consider this a + * generic "copy constructor" for nodes. The newly returned object should + * be completely independent of the source object's subtree, so changes + * in one after the clone has been made will not affect the other. + *

+ * Note: since we never have any children deep is meaningless here, + * ParentNode overrides this behavior. + * @see ParentNode + * + *

+ * Example: Cloning a Text node will copy both the node and the text it + * contains. + *

+ * Example: Cloning something that has children -- Element or Attr, for + * example -- will _not_ clone those children unless a "deep clone" + * has been requested. A shallow clone of an Attr node will yield an + * empty Attr of the same name. + *

+ * NOTE: Clones will always be read/write, even if the node being cloned + * is read-only, to permit applications using only the DOM API to obtain + * editable copies of locked portions of the tree. + */ + public Node cloneNode(boolean deep) { + + if (needsSyncData()) { + synchronizeData(); + } + + NodeImpl newnode; + try { + newnode = (NodeImpl)clone(); + } + catch (CloneNotSupportedException e) { + // if we get here we have an error in our program we may as well + // be vocal about it, so that people can take appropriate action. + throw new RuntimeException("**Internal Error**" + e); + } + + // Need to break the association w/ original kids + newnode.ownerNode = ownerDocument(); + newnode.isOwned(false); + + // By default we make all clones readwrite, + // this is overriden in readonly subclasses + newnode.isReadOnly(false); + + ownerDocument().callUserDataHandlers(this, newnode, + UserDataHandler.NODE_CLONED); + + return newnode; + + } // cloneNode(boolean):Node + + /** + * Find the Document that this Node belongs to (the document in + * whose context the Node was created). The Node may or may not + * currently be part of that Document's actual contents. + */ + public Document getOwnerDocument() { + // if we have an owner simply forward the request + // otherwise ownerNode is our ownerDocument + if (isOwned()) { + return ownerNode.ownerDocument(); + } else { + return (Document) ownerNode; + } + } + + /** + * same as above but returns internal type and this one is not overridden + * by CoreDocumentImpl to return null + */ + CoreDocumentImpl ownerDocument() { + // if we have an owner simply forward the request + // otherwise ownerNode is our ownerDocument + if (isOwned()) { + return ownerNode.ownerDocument(); + } else { + return (CoreDocumentImpl) ownerNode; + } + } + + /** + * NON-DOM + * set the ownerDocument of this node + */ + protected void setOwnerDocument(CoreDocumentImpl doc) { + if (needsSyncData()) { + synchronizeData(); + } + // if we have an owner we rely on it to have it right + // otherwise ownerNode is our ownerDocument + if (!isOwned()) { + ownerNode = doc; + } + } + + /** + * Returns the node number + */ + protected int getNodeNumber() { + int nodeNumber; + CoreDocumentImpl cd = (CoreDocumentImpl)(this.getOwnerDocument()); + nodeNumber = cd.getNodeNumber(this); + return nodeNumber; + } + + /** + * Obtain the DOM-tree parent of this node, or null if it is not + * currently active in the DOM tree (perhaps because it has just been + * created or removed). Note that Document, DocumentFragment, and + * Attribute will never have parents. + */ + public Node getParentNode() { + return null; // overriden by ChildNode + } + + /* + * same as above but returns internal type + */ + NodeImpl parentNode() { + return null; + } + + /** The next child of this node's parent, or null if none */ + public Node getNextSibling() { + return null; // default behavior, overriden in ChildNode + } + + /** The previous child of this node's parent, or null if none */ + public Node getPreviousSibling() { + return null; // default behavior, overriden in ChildNode + } + + ChildNode previousSibling() { + return null; // default behavior, overriden in ChildNode + } + + /** + * Return the collection of attributes associated with this node, + * or null if none. At this writing, Element is the only type of node + * which will ever have attributes. + * + * @see ElementImpl + */ + public NamedNodeMap getAttributes() { + return null; // overridden in ElementImpl + } + + /** + * Returns whether this node (if it is an element) has any attributes. + * @return true if this node has any attributes, + * false otherwise. + * @since DOM Level 2 + * @see ElementImpl + */ + public boolean hasAttributes() { + return false; // overridden in ElementImpl + } + + /** + * Test whether this node has any children. Convenience shorthand + * for (Node.getFirstChild()!=null) + *

+ * By default we do not have any children, ParentNode overrides this. + * @see ParentNode + */ + public boolean hasChildNodes() { + return false; + } + + /** + * Obtain a NodeList enumerating all children of this node. If there + * are none, an (initially) empty NodeList is returned. + *

+ * NodeLists are "live"; as children are added/removed the NodeList + * will immediately reflect those changes. Also, the NodeList refers + * to the actual nodes, so changes to those nodes made via the DOM tree + * will be reflected in the NodeList and vice versa. + *

+ * In this implementation, Nodes implement the NodeList interface and + * provide their own getChildNodes() support. Other DOMs may solve this + * differently. + */ + public NodeList getChildNodes() { + return this; + } + + /** The first child of this Node, or null if none. + *

+ * By default we do not have any children, ParentNode overrides this. + * @see ParentNode + */ + public Node getFirstChild() { + return null; + } + + /** The first child of this Node, or null if none. + *

+ * By default we do not have any children, ParentNode overrides this. + * @see ParentNode + */ + public Node getLastChild() { + return null; + } + + /** + * Move one or more node(s) to our list of children. Note that this + * implicitly removes them from their previous parent. + *

+ * By default we do not accept any children, ParentNode overrides this. + * @see ParentNode + * + * @param newChild The Node to be moved to our subtree. As a + * convenience feature, inserting a DocumentNode will instead insert + * all its children. + * + * @param refChild Current child which newChild should be placed + * immediately before. If refChild is null, the insertion occurs + * after all existing Nodes, like appendChild(). + * + * @return newChild, in its new state (relocated, or emptied in the case of + * DocumentNode.) + * + * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a + * type that shouldn't be a child of this node, or if newChild is an + * ancestor of this node. + * + * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a + * different owner document than we do. + * + * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node insertBefore(Node newChild, Node refChild) + throws DOMException { + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, + "HIERARCHY_REQUEST_ERR", null)); + } + + /** + * Remove a child from this Node. The removed child's subtree + * remains intact so it may be re-inserted elsewhere. + *

+ * By default we do not have any children, ParentNode overrides this. + * @see ParentNode + * + * @return oldChild, in its new state (removed). + * + * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node removeChild(Node oldChild) + throws DOMException { + throw new DOMException(DOMException.NOT_FOUND_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, + "NOT_FOUND_ERR", null)); + } + + /** + * Make newChild occupy the location that oldChild used to + * have. Note that newChild will first be removed from its previous + * parent, if any. Equivalent to inserting newChild before oldChild, + * then removing oldChild. + *

+ * By default we do not have any children, ParentNode overrides this. + * @see ParentNode + * + * @return oldChild, in its new state (removed). + * + * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a + * type that shouldn't be a child of this node, or if newChild is + * one of our ancestors. + * + * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a + * different owner document than we do. + * + * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node replaceChild(Node newChild, Node oldChild) + throws DOMException { + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, + "HIERARCHY_REQUEST_ERR", null)); + } + + // + // NodeList methods + // + + /** + * NodeList method: Count the immediate children of this node + *

+ * By default we do not have any children, ParentNode overrides this. + * @see ParentNode + * + * @return int + */ + public int getLength() { + return 0; + } + + /** + * NodeList method: Return the Nth immediate child of this node, or + * null if the index is out of bounds. + *

+ * By default we do not have any children, ParentNode overrides this. + * @see ParentNode + * + * @return org.w3c.dom.Node + * @param index int + */ + public Node item(int index) { + return null; + } + + // + // DOM2: methods, getters, setters + // + + /** + * Puts all Text nodes in the full depth of the sub-tree + * underneath this Node, including attribute nodes, into a + * "normal" form where only markup (e.g., tags, comments, processing + * instructions, CDATA sections, and entity references) separates + * Text nodes, i.e., there are no adjacent Text + * nodes. This can be used to ensure that the DOM view of a document is + * the same as if it were saved and re-loaded, and is useful when + * operations (such as XPointer lookups) that depend on a particular + * document tree structure are to be used.In cases where the document + * contains CDATASections, the normalize operation alone may + * not be sufficient, since XPointers do not differentiate between + * Text nodes and CDATASection nodes. + *

+ * Note that this implementation simply calls normalize() on this Node's + * children. It is up to implementors or Node to override normalize() + * to take action. + */ + public void normalize() { + /* by default we do not have any children, + ParentNode overrides this behavior */ + } + + /** + * Introduced in DOM Level 2.

+ * Tests whether the DOM implementation implements a specific feature and + * that feature is supported by this node. + * @param feature The package name of the feature to test. This is the same + * name as what can be passed to the method hasFeature on + * DOMImplementation. + * @param version This is the version number of the package name 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 boolean Returns true if this node defines a subtree within which + * the specified feature is supported, false otherwise. + * @since WD-DOM-Level-2-19990923 + */ + public boolean isSupported(String feature, String version) + { + return ownerDocument().getImplementation().hasFeature(feature, + version); + } + + /** + * Introduced in DOM Level 2.

+ * + * The namespace URI of this node, or null if it is unspecified. When this + * node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE, this is + * always null and setting it has no effect.

+ * + * 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 created with a DOM Level 1 method, such as createElement + * from the Document interface, this is null. + * @since WD-DOM-Level-2-19990923 + * @see AttrNSImpl + * @see ElementNSImpl + */ + public String getNamespaceURI() + { + return null; + } + + /** + * Introduced in DOM Level 2.

+ * + * The namespace prefix of this node, or null if it is unspecified. When + * this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE this + * is always null and setting it has no effect.

+ * + * For nodes created with a DOM Level 1 method, such as createElement + * from the Document interface, this is null.

+ * + * @since WD-DOM-Level-2-19990923 + * @see AttrNSImpl + * @see ElementNSImpl + */ + public String getPrefix() + { + return null; + } + + /** + * Introduced in DOM Level 2.

+ * + * The namespace prefix of this node, or null if it is unspecified. When + * this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE + * this is always null and setting it has no effect.

+ * + * For nodes created with a DOM Level 1 method, such as createElement from + * the Document interface, this is null.

+ * + * Note that setting this attribute changes the nodeName attribute, which + * holds the qualified name, as well as the tagName and name attributes of + * the Element and Attr interfaces, when applicable.

+ * + * @throws INVALID_CHARACTER_ERR Raised if the specified + * prefix contains an invalid character. + * + * @since WD-DOM-Level-2-19990923 + * @see AttrNSImpl + * @see ElementNSImpl + */ + public void setPrefix(String prefix) + throws DOMException + { + throw new DOMException(DOMException.NAMESPACE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, + "NAMESPACE_ERR", null)); + } + + /** + * Introduced in DOM Level 2.

+ * + * Returns the local part of the qualified name of this node. + * For nodes created with a DOM Level 1 method, such as createElement + * from the Document interface, and for nodes of any type other than + * ELEMENT_NODE and ATTRIBUTE_NODE this is the same as the nodeName + * attribute. + * @since WD-DOM-Level-2-19990923 + * @see AttrNSImpl + * @see ElementNSImpl + */ + public String getLocalName() + { + return null; + } + + // + // EventTarget support + // + + public void addEventListener(String type, EventListener listener, + boolean useCapture) { + // simply forward to Document + ownerDocument().addEventListener(this, type, listener, useCapture); + } + + public void removeEventListener(String type, EventListener listener, + boolean useCapture) { + // simply forward to Document + ownerDocument().removeEventListener(this, type, listener, useCapture); + } + + public boolean dispatchEvent(Event event) { + // simply forward to Document + return ownerDocument().dispatchEvent(this, event); + } + + // + // Public DOM Level 3 methods + // + + /** + * The absolute base URI of this node or null if undefined. + * This value is computed according to . However, when the + * Document supports the feature "HTML" , the base URI is + * computed using first the value of the href attribute of the HTML BASE + * element if any, and the value of the documentURI + * attribute from the Document interface otherwise. + *
When the node is an Element, a Document + * or a a ProcessingInstruction, this attribute represents + * the properties [base URI] defined in . When the node is a + * Notation, an Entity, or an + * EntityReference, this attribute represents the + * properties [declaration base URI] in the . How will this be affected + * by resolution of relative namespace URIs issue?It's not.Should this + * only be on Document, Element, ProcessingInstruction, Entity, and + * Notation nodes, according to the infoset? If not, what is it equal to + * on other nodes? Null? An empty string? I think it should be the + * parent's.No.Should this be read-only and computed or and actual + * read-write attribute?Read-only and computed (F2F 19 Jun 2000 and + * teleconference 30 May 2001).If the base HTML element is not yet + * attached to a document, does the insert change the Document.baseURI? + * Yes. (F2F 26 Sep 2001) + * @since DOM Level 3 + */ + public String getBaseURI() { + return null; + } + + /** + * Compares a node with this node with regard to their position in the + * tree and according to the document order. This order can be extended + * by module that define additional types of nodes. + * @param other The node to compare against this node. + * @return Returns how the given node is positioned relatively to this + * node. + * @since DOM Level 3 + * @deprecated + */ + public short compareTreePosition(Node other) { + // Questions of clarification for this method - to be answered by the + // DOM WG. Current assumptions listed - LM + // + // 1. How do ENTITY nodes compare? + // Current assumption: TREE_POSITION_DISCONNECTED, as ENTITY nodes + // aren't really 'in the tree' + // + // 2. How do NOTATION nodes compare? + // Current assumption: TREE_POSITION_DISCONNECTED, as NOTATION nodes + // aren't really 'in the tree' + // + // 3. Are TREE_POSITION_ANCESTOR and TREE_POSITION_DESCENDANT + // only relevant for nodes that are "part of the document tree"? + // + // + // + // Is the element node "outer" considered an ancestor of "myattr"? + // Current assumption: No. + // + // 4. How do children of ATTRIBUTE nodes compare (with eachother, or + // with children of other attribute nodes with the same element) + // Current assumption: Children of ATTRIBUTE nodes are treated as if + // they they are the attribute node itself, unless the 2 nodes + // are both children of the same attribute. + // + // 5. How does an ENTITY_REFERENCE node compare with it's children? + // Given the DOM, it should precede its children as an ancestor. + // Given "document order", does it represent the same position? + // Current assumption: An ENTITY_REFERENCE node is an ancestor of its + // children. + // + // 6. How do children of a DocumentFragment compare? + // Current assumption: If both nodes are part of the same document + // fragment, there are compared as if they were part of a document. + + + // If the nodes are the same... + if (this==other) + return (TREE_POSITION_SAME_NODE | TREE_POSITION_EQUIVALENT); + + // If either node is of type ENTITY or NOTATION, compare as disconnected + short thisType = this.getNodeType(); + short otherType = other.getNodeType(); + + // If either node is of type ENTITY or NOTATION, compare as disconnected + if (thisType == Node.ENTITY_NODE || + thisType == Node.NOTATION_NODE || + otherType == Node.ENTITY_NODE || + otherType == Node.NOTATION_NODE ) { + return TREE_POSITION_DISCONNECTED; + } + + // Find the ancestor of each node, and the distance each node is from + // its ancestor. + // During this traversal, look for ancestor/descendent relationships + // between the 2 nodes in question. + // We do this now, so that we get this info correct for attribute nodes + // and their children. + + Node node; + Node thisAncestor = this; + Node otherAncestor = other; + int thisDepth=0; + int otherDepth=0; + for (node=this; node != null; node = node.getParentNode()) { + thisDepth +=1; + if (node == other) + // The other node is an ancestor of this one. + return (TREE_POSITION_ANCESTOR | TREE_POSITION_PRECEDING); + thisAncestor = node; + } + + for (node=other; node!=null; node=node.getParentNode()) { + otherDepth +=1; + if (node == this) + // The other node is a descendent of the reference node. + return (TREE_POSITION_DESCENDANT | TREE_POSITION_FOLLOWING); + otherAncestor = node; + } + + + Node thisNode = this; + Node otherNode = other; + + int thisAncestorType = thisAncestor.getNodeType(); + int otherAncestorType = otherAncestor.getNodeType(); + + // if the ancestor is an attribute, get owning element. + // we are now interested in the owner to determine position. + + if (thisAncestorType == Node.ATTRIBUTE_NODE) { + thisNode = ((AttrImpl)thisAncestor).getOwnerElement(); + } + if (otherAncestorType == Node.ATTRIBUTE_NODE) { + otherNode = ((AttrImpl)otherAncestor).getOwnerElement(); + } + + // Before proceeding, we should check if both ancestor nodes turned + // out to be attributes for the same element + if (thisAncestorType == Node.ATTRIBUTE_NODE && + otherAncestorType == Node.ATTRIBUTE_NODE && + thisNode==otherNode) + return TREE_POSITION_EQUIVALENT; + + // Now, find the ancestor of the owning element, if the original + // ancestor was an attribute + + // Note: the following 2 loops are quite close to the ones above. + // May want to common them up. LM. + if (thisAncestorType == Node.ATTRIBUTE_NODE) { + thisDepth=0; + for (node=thisNode; node != null; node=node.getParentNode()) { + thisDepth +=1; + if (node == otherNode) + // The other node is an ancestor of the owning element + { + return TREE_POSITION_PRECEDING; + } + thisAncestor = node; + } + } + + // Now, find the ancestor of the owning element, if the original + // ancestor was an attribute + if (otherAncestorType == Node.ATTRIBUTE_NODE) { + otherDepth=0; + for (node=otherNode; node != null; node=node.getParentNode()) { + otherDepth +=1; + if (node == thisNode) + // The other node is a descendent of the reference + // node's element + return TREE_POSITION_FOLLOWING; + otherAncestor = node; + } + } + + // thisAncestor and otherAncestor must be the same at this point, + // otherwise, we are not in the same tree or document fragment + if (thisAncestor != otherAncestor) + return TREE_POSITION_DISCONNECTED; + + + // Go up the parent chain of the deeper node, until we find a node + // with the same depth as the shallower node + + if (thisDepth > otherDepth) { + for (int i=0; i thisDocNum) + return DOCUMENT_POSITION_DISCONNECTED | + DOCUMENT_POSITION_FOLLOWING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; + else + return DOCUMENT_POSITION_DISCONNECTED | + DOCUMENT_POSITION_PRECEDING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; + + } + + // Find the ancestor of each node, and the distance each node is from + // its ancestor. + // During this traversal, look for ancestor/descendent relationships + // between the 2 nodes in question. + // We do this now, so that we get this info correct for attribute nodes + // and their children. + + Node node; + Node thisAncestor = this; + Node otherAncestor = other; + + int thisDepth=0; + int otherDepth=0; + for (node=this; node != null; node = node.getParentNode()) { + thisDepth +=1; + if (node == other) + // The other node is an ancestor of this one. + return (DOCUMENT_POSITION_CONTAINS | + DOCUMENT_POSITION_PRECEDING); + thisAncestor = node; + } + + for (node=other; node!=null; node=node.getParentNode()) { + otherDepth +=1; + if (node == this) + // The other node is a descendent of the reference node. + return (DOCUMENT_POSITION_IS_CONTAINED | + DOCUMENT_POSITION_FOLLOWING); + otherAncestor = node; + } + + + + int thisAncestorType = thisAncestor.getNodeType(); + int otherAncestorType = otherAncestor.getNodeType(); + Node thisNode = this; + Node otherNode = other; + + // Special casing for ENTITY, NOTATION, DOCTYPE and ATTRIBUTES + // LM: should rewrite this. + switch (thisAncestorType) { + case Node.NOTATION_NODE: + case Node.ENTITY_NODE: { + DocumentType container = thisOwnerDoc.getDoctype(); + if (container == otherAncestor) return + (DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_PRECEDING); + switch (otherAncestorType) { + case Node.NOTATION_NODE: + case Node.ENTITY_NODE: { + if (thisAncestorType != otherAncestorType) + // the nodes are of different types + return ((thisAncestorType>otherAncestorType) ? + DOCUMENT_POSITION_PRECEDING:DOCUMENT_POSITION_FOLLOWING); + else { + // the nodes are of the same type. Find order. + if (thisAncestorType == Node.NOTATION_NODE) + + if (((NamedNodeMapImpl)container.getNotations()).precedes(otherAncestor,thisAncestor)) + return (DOCUMENT_POSITION_PRECEDING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); + else + return (DOCUMENT_POSITION_FOLLOWING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); + else + if (((NamedNodeMapImpl)container.getEntities()).precedes(otherAncestor,thisAncestor)) + return (DOCUMENT_POSITION_PRECEDING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); + else + return (DOCUMENT_POSITION_FOLLOWING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); + } + } + } + thisNode = thisAncestor = thisOwnerDoc; + break; + } + case Node.DOCUMENT_TYPE_NODE: { + if (otherNode == thisOwnerDoc) + return (DOCUMENT_POSITION_PRECEDING | + DOCUMENT_POSITION_CONTAINS); + else if (thisOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc) + return (DOCUMENT_POSITION_FOLLOWING); + break; + } + case Node.ATTRIBUTE_NODE: { + thisNode = ((AttrImpl)thisAncestor).getOwnerElement(); + if (otherAncestorType==Node.ATTRIBUTE_NODE) { + otherNode = ((AttrImpl)otherAncestor).getOwnerElement(); + if (otherNode == thisNode) { + if (((NamedNodeMapImpl)thisNode.getAttributes()).precedes(other,this)) + return (DOCUMENT_POSITION_PRECEDING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); + else + return (DOCUMENT_POSITION_FOLLOWING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); + } + } + + // Now, find the ancestor of the element + thisDepth=0; + for (node=thisNode; node != null; node=node.getParentNode()) { + thisDepth +=1; + if (node == otherNode) + { + // The other node is an ancestor of the owning element + return (DOCUMENT_POSITION_CONTAINS | + DOCUMENT_POSITION_PRECEDING); + } + thisAncestor = node; + } + } + } + switch (otherAncestorType) { + case Node.NOTATION_NODE: + case Node.ENTITY_NODE: { + DocumentType container = thisOwnerDoc.getDoctype(); + if (container == this) return (DOCUMENT_POSITION_IS_CONTAINED | + DOCUMENT_POSITION_FOLLOWING); + otherNode = otherAncestor = thisOwnerDoc; + break; + } + case Node.DOCUMENT_TYPE_NODE: { + if (thisNode == otherOwnerDoc) + return (DOCUMENT_POSITION_FOLLOWING | + DOCUMENT_POSITION_IS_CONTAINED); + else if (otherOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc) + return (DOCUMENT_POSITION_PRECEDING); + break; + } + case Node.ATTRIBUTE_NODE: { + otherDepth=0; + otherNode = ((AttrImpl)otherAncestor).getOwnerElement(); + for (node=otherNode; node != null; node=node.getParentNode()) { + otherDepth +=1; + if (node == thisNode) + // The other node is a descendent of the reference + // node's element + return DOCUMENT_POSITION_FOLLOWING | + DOCUMENT_POSITION_IS_CONTAINED; + otherAncestor = node; + } + + } + } + + // thisAncestor and otherAncestor must be the same at this point, + // otherwise, the original nodes are disconnected + if (thisAncestor != otherAncestor) { + int thisAncestorNum, otherAncestorNum; + thisAncestorNum = ((NodeImpl)thisAncestor).getNodeNumber(); + otherAncestorNum = ((NodeImpl)otherAncestor).getNodeNumber(); + + if (thisAncestorNum > otherAncestorNum) + return DOCUMENT_POSITION_DISCONNECTED | + DOCUMENT_POSITION_FOLLOWING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; + else + return DOCUMENT_POSITION_DISCONNECTED | + DOCUMENT_POSITION_PRECEDING | + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; + } + + + // Go up the parent chain of the deeper node, until we find a node + // with the same depth as the shallower node + + if (thisDepth > otherDepth) { + for (int i=0; iText node containing the string + * this attribute is set to. On getting, no serialization is performed, + * the returned string does not contain any markup. No whitespace + * normalization is performed, the returned string does not contain the + * element content whitespaces . Similarly, on setting, no parsing is + * performed either, the input string is taken as pure textual content. + *
The string returned is made of the text content of this node + * depending on its type, as defined below: + * + * + * + * + * + + /** + * This attribute returns the text content of this node and its + * descendants. When it is defined to be null, setting it has no effect. + * When set, any possible children this node may have are removed and + * replaced by a single Text node containing the string + * this attribute is set to. On getting, no serialization is performed, + * the returned string does not contain any markup. No whitespace + * normalization is performed, the returned string does not contain the + * element content whitespaces . Similarly, on setting, no parsing is + * performed either, the input string is taken as pure textual content. + *
The string returned is made of the text content of this node + * depending on its type, as defined below: + *
Node typeContent
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Node typeContent
+ * ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE, + * DOCUMENT_FRAGMENT_NODEconcatenation of the textContent + * attribute value of every child node, excluding COMMENT_NODE and + * PROCESSING_INSTRUCTION_NODE nodes
ATTRIBUTE_NODE, TEXT_NODE, + * CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE + * nodeValue
DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE + * null
+ * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. + * @exception DOMException + * DOMSTRING_SIZE_ERR: Raised when it would return more characters than + * fit in a DOMString variable on the implementation + * platform. + * @since DOM Level 3 + */ + public String getTextContent() throws DOMException { + return getNodeValue(); // overriden in some subclasses + } + + // internal method taking a StringBuffer in parameter + void getTextContent(StringBuffer buf) throws DOMException { + String content = getNodeValue(); + if (content != null) { + buf.append(content); + } + } + + /** + * This attribute returns the text content of this node and its + * descendants. When it is defined to be null, setting it has no effect. + * When set, any possible children this node may have are removed and + * replaced by a single Text node containing the string + * this attribute is set to. On getting, no serialization is performed, + * the returned string does not contain any markup. No whitespace + * normalization is performed, the returned string does not contain the + * element content whitespaces . Similarly, on setting, no parsing is + * performed either, the input string is taken as pure textual content. + *
The string returned is made of the text content of this node + * depending on its type, as defined below: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Node typeContent
+ * ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE, + * DOCUMENT_FRAGMENT_NODEconcatenation of the textContent + * attribute value of every child node, excluding COMMENT_NODE and + * PROCESSING_INSTRUCTION_NODE nodes
ATTRIBUTE_NODE, TEXT_NODE, + * CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE + * nodeValue
DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE + * null
+ * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. + * @exception DOMException + * DOMSTRING_SIZE_ERR: Raised when it would return more characters than + * fit in a DOMString variable on the implementation + * platform. + * @since DOM Level 3 + */ + public void setTextContent(String textContent) + throws DOMException { + setNodeValue(textContent); + } + + /** + * Returns whether this node is the same node as the given one. + *
This method provides a way to determine whether two + * Node references returned by the implementation reference + * the same object. When two Node references are references + * to the same object, even if through a proxy, the references may be + * used completely interchangably, such that all attributes have the + * same values and calling the same DOM method on either reference + * always has exactly the same effect. + * @param other The node to test against. + * @return Returns true if the nodes are the same, + * false otherwise. + * @since DOM Level 3 + */ + public boolean isSameNode(Node other) { + // we do not use any wrapper so the answer is obvious + return this == other; + } + + + + + /** + * DOM Level 3: Experimental + * This method checks if the specified namespaceURI is the + * default namespace or not. + * @param namespaceURI The namespace URI to look for. + * @return true if the specified namespaceURI + * is the default namespace, false otherwise. + * @since DOM Level 3 + */ + public boolean isDefaultNamespace(String namespaceURI){ + // REVISIT: remove casts when DOM L3 becomes REC. + short type = this.getNodeType(); + switch (type) { + case Node.ELEMENT_NODE: { + String namespace = this.getNamespaceURI(); + String prefix = this.getPrefix(); + + // REVISIT: is it possible that prefix is empty string? + if (prefix == null || prefix.length() == 0) { + if (namespaceURI == null) { + return (namespace == namespaceURI); + } + return namespaceURI.equals(namespace); + } + if (this.hasAttributes()) { + ElementImpl elem = (ElementImpl)this; + NodeImpl attr = (NodeImpl)elem.getAttributeNodeNS("http://www.w3.org/2000/xmlns/", "xmlns"); + if (attr != null) { + String value = attr.getNodeValue(); + if (namespaceURI == null) { + return (namespace == value); + } + return namespaceURI.equals(value); + } + } + + NodeImpl ancestor = (NodeImpl)getElementAncestor(this); + if (ancestor != null) { + return ancestor.isDefaultNamespace(namespaceURI); + } + return false; + } + case Node.DOCUMENT_NODE:{ + Element docElement = ((Document)this).getDocumentElement(); + if (docElement != null) { + return docElement.isDefaultNamespace(namespaceURI); + } + return false; + } + + case Node.ENTITY_NODE : + case Node.NOTATION_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + case Node.DOCUMENT_TYPE_NODE: + // type is unknown + return false; + case Node.ATTRIBUTE_NODE:{ + if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) { + return ownerNode.isDefaultNamespace(namespaceURI); + + } + return false; + } + default:{ + NodeImpl ancestor = (NodeImpl)getElementAncestor(this); + if (ancestor != null) { + return ancestor.isDefaultNamespace(namespaceURI); + } + return false; + } + + } + + + } + + + /** + * + * DOM Level 3 - Experimental: + * Look up the prefix associated to the given namespace URI, starting from this node. + * + * @param namespaceURI + * @return the prefix for the namespace + */ + public String lookupPrefix(String namespaceURI){ + + // REVISIT: When Namespaces 1.1 comes out this may not be true + // Prefix can't be bound to null namespace + if (namespaceURI == null) { + return null; + } + + short type = this.getNodeType(); + + switch (type) { + case Node.ELEMENT_NODE: { + this.getNamespaceURI(); // to flip out children + return lookupNamespacePrefix(namespaceURI, (ElementImpl)this); + } + case Node.DOCUMENT_NODE:{ + Element docElement = ((Document)this).getDocumentElement(); + if (docElement != null) { + return docElement.lookupPrefix(namespaceURI); + } + return null; + } + + case Node.ENTITY_NODE : + case Node.NOTATION_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + case Node.DOCUMENT_TYPE_NODE: + // type is unknown + return null; + case Node.ATTRIBUTE_NODE:{ + if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) { + return ownerNode.lookupPrefix(namespaceURI); + + } + return null; + } + default:{ + NodeImpl ancestor = (NodeImpl)getElementAncestor(this); + if (ancestor != null) { + return ancestor.lookupPrefix(namespaceURI); + } + return null; + } + + } + } + /** + * DOM Level 3 - Experimental: + * Look up the namespace URI associated to the given prefix, starting from this node. + * Use lookupNamespaceURI(null) to lookup the default namespace + * + * @param specifiedPrefix + * @return the URI for the namespace + * @since DOM Level 3 + */ + public String lookupNamespaceURI(String specifiedPrefix) { + short type = this.getNodeType(); + switch (type) { + case Node.ELEMENT_NODE : { + + String namespace = this.getNamespaceURI(); + String prefix = this.getPrefix(); + if (namespace !=null) { + // REVISIT: is it possible that prefix is empty string? + if (specifiedPrefix== null && prefix==specifiedPrefix) { + // looking for default namespace + return namespace; + } else if (prefix != null && prefix.equals(specifiedPrefix)) { + // non default namespace + return namespace; + } + } + if (this.hasAttributes()) { + NamedNodeMap map = this.getAttributes(); + int length = map.getLength(); + for (int i=0;i 0 ? value : null; + } else if (attrPrefix !=null && + attrPrefix.equals("xmlns") && + attr.getLocalName().equals(specifiedPrefix)) { + // non default namespace + return value.length() > 0 ? value : null; + } + } + } + } + NodeImpl ancestor = (NodeImpl)getElementAncestor(this); + if (ancestor != null) { + return ancestor.lookupNamespaceURI(specifiedPrefix); + } + + return null; + + + } + case Node.DOCUMENT_NODE : { + Element docElement = ((Document)this).getDocumentElement(); + if (docElement != null) { + return docElement.lookupNamespaceURI(specifiedPrefix); + } + return null; + } + case Node.ENTITY_NODE : + case Node.NOTATION_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + case Node.DOCUMENT_TYPE_NODE: + // type is unknown + return null; + case Node.ATTRIBUTE_NODE:{ + if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) { + return ownerNode.lookupNamespaceURI(specifiedPrefix); + + } + return null; + } + default:{ + NodeImpl ancestor = (NodeImpl)getElementAncestor(this); + if (ancestor != null) { + return ancestor.lookupNamespaceURI(specifiedPrefix); + } + return null; + } + + } + } + + Node getElementAncestor(Node currentNode) { + Node parent = currentNode.getParentNode(); + while (parent != null) { + short type = parent.getNodeType(); + if (type == Node.ELEMENT_NODE) { + return parent; + } + parent = parent.getParentNode(); + } + return null; + } + + String lookupNamespacePrefix(String namespaceURI, ElementImpl el){ + String namespace = this.getNamespaceURI(); + // REVISIT: if no prefix is available is it null or empty string, or + // could be both? + String prefix = this.getPrefix(); + + if (namespace!=null && namespace.equals(namespaceURI)) { + if (prefix != null) { + String foundNamespace = el.lookupNamespaceURI(prefix); + if (foundNamespace !=null && foundNamespace.equals(namespaceURI)) { + return prefix; + } + + } + } + if (this.hasAttributes()) { + NamedNodeMap map = this.getAttributes(); + int length = map.getLength(); + for (int i=0;iThis method tests for equality of nodes, not sameness (i.e., + * whether the two nodes are references to the same object) which can be + * tested with Node.isSameNode. All nodes that are the same + * will also be equal, though the reverse may not be true. + *
Two nodes are equal if and only if the following conditions are + * satisfied: The two nodes are of the same type.The following string + * attributes are equal: nodeName, localName, + * namespaceURI, prefix, nodeValue + * , baseURI. This is: they are both null, or + * they have the same length and are character for character identical. + * The attributes NamedNodeMaps are equal. + * This is: they are both null, or they have the same + * length and for each node that exists in one map there is a node that + * exists in the other map and is equal, although not necessarily at the + * same index.The childNodes NodeLists are + * equal. This is: they are both null, or they have the + * same length and contain equal nodes at the same index. This is true + * for Attr nodes as for any other type of node. Note that + * normalization can affect equality; to avoid this, nodes should be + * normalized before being compared. + *
For two DocumentType nodes to be equal, the following + * conditions must also be satisfied: The following string attributes + * are equal: publicId, systemId, + * internalSubset.The entities + * NamedNodeMaps are equal.The notations + * NamedNodeMaps are equal. + *
On the other hand, the following do not affect equality: the + * ownerDocument attribute, the specified + * attribute for Attr nodes, the + * isWhitespaceInElementContent attribute for + * Text nodes, as well as any user data or event listeners + * registered on the nodes. + * @param arg The node to compare equality with. + * @return If the nodes, and possibly subtrees are equal, + * true otherwise false. + * @since DOM Level 3 + */ + public boolean isEqualNode(Node arg) { + if (arg == this) { + return true; + } + if (arg.getNodeType() != getNodeType()) { + return false; + } + // in theory nodeName can't be null but better be careful + // who knows what other implementations may be doing?... + if (getNodeName() == null) { + if (arg.getNodeName() != null) { + return false; + } + } + else if (!getNodeName().equals(arg.getNodeName())) { + return false; + } + + if (getLocalName() == null) { + if (arg.getLocalName() != null) { + return false; + } + } + else if (!getLocalName().equals(arg.getLocalName())) { + return false; + } + + if (getNamespaceURI() == null) { + if (arg.getNamespaceURI() != null) { + return false; + } + } + else if (!getNamespaceURI().equals(arg.getNamespaceURI())) { + return false; + } + + if (getPrefix() == null) { + if (arg.getPrefix() != null) { + return false; + } + } + else if (!getPrefix().equals(arg.getPrefix())) { + return false; + } + + if (getNodeValue() == null) { + if (arg.getNodeValue() != null) { + return false; + } + } + else if (!getNodeValue().equals(arg.getNodeValue())) { + return false; + } + + + return true; + } + + /** + * @since DOM Level 3 + */ + public Object getFeature(String feature, String version) { + // we don't have any alternate node, either this node does the job + // or we don't have anything that does + return isSupported(feature, version) ? this : null; + } + + /** + * Associate an object to a key on this node. The object can later be + * retrieved from this node by calling getUserData with the + * same key. + * @param key The key to associate the object to. + * @param data The object to associate to the given key, or + * null to remove any existing association to that key. + * @param handler The handler to associate to that key, or + * null. + * @return Returns the DOMObject previously associated to + * the given key on this node, or null if there was none. + * @since DOM Level 3 + */ + public Object setUserData(String key, + Object data, + UserDataHandler handler) { + return ownerDocument().setUserData(this, key, data, handler); + } + + /** + * Retrieves the object associated to a key on a this node. The object + * must first have been set to this node by calling + * setUserData with the same key. + * @param key The key the object is associated to. + * @return Returns the DOMObject associated to the given key + * on this node, or null if there was none. + * @since DOM Level 3 + */ + public Object getUserData(String key) { + return ownerDocument().getUserData(this, key); + } + + protected Hashtable getUserDataRecord(){ + return ownerDocument().getUserDataRecord(this); + } + + // + // Public methods + // + + /** + * NON-DOM: PR-DOM-Level-1-19980818 mentions readonly nodes in conjunction + * with Entities, but provides no API to support this. + *

+ * Most DOM users should not touch this method. Its anticpated use + * is during construction of EntityRefernces, where it will be used to + * lock the contents replicated from Entity so they can't be casually + * altered. It _could_ be published as a DOM extension, if desired. + *

+ * Note: since we never have any children deep is meaningless here, + * ParentNode overrides this behavior. + * @see ParentNode + * + * @param readOnly True or false as desired. + * @param deep If true, children are also toggled. Note that this will + * not change the state of an EntityReference or its children, + * which are always read-only. + */ + public void setReadOnly(boolean readOnly, boolean deep) { + + if (needsSyncData()) { + synchronizeData(); + } + isReadOnly(readOnly); + + } // setReadOnly(boolean,boolean) + + /** + * NON-DOM: Returns true if this node is read-only. This is a + * shallow check. + */ + public boolean getReadOnly() { + + if (needsSyncData()) { + synchronizeData(); + } + return isReadOnly(); + + } // getReadOnly():boolean + + /** + * NON-DOM: As an alternative to subclassing the DOM, this implementation + * has been extended with the ability to attach an object to each node. + * (If you need multiple objects, you can attach a collection such as a + * vector or hashtable, then attach your application information to that.) + *

Important Note: You are responsible for removing references + * to your data on nodes that are no longer used. Failure to do so will + * prevent the nodes, your data is attached to, to be garbage collected + * until the whole document is. + * + * @param data the object to store or null to remove any existing reference + */ + public void setUserData(Object data) { + ownerDocument().setUserData(this, data); + } + + /** + * NON-DOM: + * Returns the user data associated to this node. + */ + public Object getUserData() { + return ownerDocument().getUserData(this); + } + + // + // Protected methods + // + + /** + * Denotes that this node has changed. + */ + protected void changed() { + // we do not actually store this information on every node, we only + // have a global indicator on the Document. Doing otherwise cost us too + // much for little gain. + ownerDocument().changed(); + } + + /** + * Returns the number of changes to this node. + */ + protected int changes() { + // we do not actually store this information on every node, we only + // have a global indicator on the Document. Doing otherwise cost us too + // much for little gain. + return ownerDocument().changes(); + } + + /** + * Override this method in subclass to hook in efficient + * internal data structure. + */ + protected void synchronizeData() { + // By default just change the flag to avoid calling this method again + needsSyncData(false); + } + + /** + * For non-child nodes, the node which "points" to this node. + * For example, the owning element for an attribute + */ + protected Node getContainer() { + return null; + } + + + /* + * Flags setters and getters + */ + + final boolean isReadOnly() { + return (flags & READONLY) != 0; + } + + final void isReadOnly(boolean value) { + flags = (short) (value ? flags | READONLY : flags & ~READONLY); + } + + final boolean needsSyncData() { + return (flags & SYNCDATA) != 0; + } + + final void needsSyncData(boolean value) { + flags = (short) (value ? flags | SYNCDATA : flags & ~SYNCDATA); + } + + final boolean needsSyncChildren() { + return (flags & SYNCCHILDREN) != 0; + } + + public final void needsSyncChildren(boolean value) { + flags = (short) (value ? flags | SYNCCHILDREN : flags & ~SYNCCHILDREN); + } + + final boolean isOwned() { + return (flags & OWNED) != 0; + } + + final void isOwned(boolean value) { + flags = (short) (value ? flags | OWNED : flags & ~OWNED); + } + + final boolean isFirstChild() { + return (flags & FIRSTCHILD) != 0; + } + + final void isFirstChild(boolean value) { + flags = (short) (value ? flags | FIRSTCHILD : flags & ~FIRSTCHILD); + } + + final boolean isSpecified() { + return (flags & SPECIFIED) != 0; + } + + final void isSpecified(boolean value) { + flags = (short) (value ? flags | SPECIFIED : flags & ~SPECIFIED); + } + + // inconsistent name to avoid clash with public method on TextImpl + final boolean internalIsIgnorableWhitespace() { + return (flags & IGNORABLEWS) != 0; + } + + final void isIgnorableWhitespace(boolean value) { + flags = (short) (value ? flags | IGNORABLEWS : flags & ~IGNORABLEWS); + } + + final boolean hasStringValue() { + return (flags & HASSTRING) != 0; + } + + final void hasStringValue(boolean value) { + flags = (short) (value ? flags | HASSTRING : flags & ~HASSTRING); + } + + final boolean isNormalized() { + return (flags & NORMALIZED) != 0; + } + + final void isNormalized(boolean value) { + // See if flag should propagate to parent. + if (!value && isNormalized() && ownerNode != null) { + ownerNode.isNormalized(false); + } + flags = (short) (value ? flags | NORMALIZED : flags & ~NORMALIZED); + } + + final boolean isIdAttribute() { + return (flags & ID) != 0; + } + + final void isIdAttribute(boolean value) { + flags = (short) (value ? flags | ID : flags & ~ID); + } + + // + // Object methods + // + + /** NON-DOM method for debugging convenience. */ + public String toString() { + return "["+getNodeName()+": "+getNodeValue()+"]"; + } + + // + // Serialization methods + // + + /** Serialize object. */ + private void writeObject(ObjectOutputStream out) throws IOException { + + // synchronize data + if (needsSyncData()) { + synchronizeData(); + } + // write object + out.defaultWriteObject(); + + } // writeObject(ObjectOutputStream) + +} // class NodeImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/NodeIteratorImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/NodeIteratorImpl.java new file mode 100644 index 0000000..52a8b94 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/NodeIteratorImpl.java @@ -0,0 +1,372 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + + +/** DefaultNodeIterator implements a NodeIterator, which iterates a + * DOM tree in the expected depth first way. + * + *

The whatToShow and filter functionality is implemented as expected. + * + *

This class also has method removeNode to enable iterator "fix-up" + * on DOM remove. It is expected that the DOM implementation call removeNode + * right before the actual DOM transformation. If not called by the DOM, + * the client could call it before doing the removal. + * + * @xerces.internal + * + * @version $Id$ + */ +public class NodeIteratorImpl implements NodeIterator { + + // + // Data + // + + /** The DocumentImpl which created this iterator, so it can be detached. */ + private DocumentImpl fDocument; + /** The root. */ + private Node fRoot; + /** The whatToShow mask. */ + private int fWhatToShow = NodeFilter.SHOW_ALL; + /** The NodeFilter reference. */ + private NodeFilter fNodeFilter; + /** If detach is called, the fDetach flag is true, otherwise flase. */ + private boolean fDetach = false; + + // + // Iterator state - current node and direction. + // + // Note: The current node and direction are sufficient to implement + // the desired behaviour of the current pointer being _between_ + // two nodes. The fCurrentNode is actually the last node returned, + // and the + // direction is whether the pointer is in front or behind this node. + // (usually akin to whether the node was returned via nextNode()) + // (eg fForward = true) or previousNode() (eg fForward = false). + // Note also, if removing a Node, the fCurrentNode + // can be placed on a Node which would not pass filters. + + /** The last Node returned. */ + private Node fCurrentNode; + + /** The direction of the iterator on the fCurrentNode. + *

+     *  nextNode()  ==      fForward = true;
+     *  previousNode() ==   fForward = false;
+     *  
+ */ + private boolean fForward = true; + + /** When TRUE, the children of entites references are returned in the iterator. */ + private boolean fEntityReferenceExpansion; + + // + // Constructor + // + + /** Public constructor */ + public NodeIteratorImpl( DocumentImpl document, + Node root, + int whatToShow, + NodeFilter nodeFilter, + boolean entityReferenceExpansion) { + fDocument = document; + fRoot = root; + fCurrentNode = null; + fWhatToShow = whatToShow; + fNodeFilter = nodeFilter; + fEntityReferenceExpansion = entityReferenceExpansion; + } + + public Node getRoot() { + return fRoot; + } + + // Implementation Note: Note that the iterator looks at whatToShow + // and filter values at each call, and therefore one _could_ add + // setters for these values and alter them while iterating! + + /** Return the whatToShow value */ + public int getWhatToShow() { + return fWhatToShow; + } + + /** Return the filter */ + public NodeFilter getFilter() { + return fNodeFilter; + } + + /** Return whether children entity references are included in the iterator. */ + public boolean getExpandEntityReferences() { + return fEntityReferenceExpansion; + } + + /** Return the next Node in the Iterator. The node is the next node in + * depth-first order which also passes the filter, and whatToShow. + * If there is no next node which passes these criteria, then return null. + */ + public Node nextNode() { + + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + + // if root is null there is no next node. + if (fRoot == null) return null; + + Node nextNode = fCurrentNode; + boolean accepted = false; // the next node has not been accepted. + + accepted_loop: + while (!accepted) { + + // if last direction is not forward, repeat node. + if (!fForward && nextNode!=null) { + //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName()); + nextNode = fCurrentNode; + } else { + // else get the next node via depth-first + if (!fEntityReferenceExpansion + && nextNode != null + && nextNode.getNodeType() == Node.ENTITY_REFERENCE_NODE) { + nextNode = nextNode(nextNode, false); + } else { + nextNode = nextNode(nextNode, true); + } + } + + fForward = true; //REVIST: should direction be set forward before null check? + + // nothing in the list. return null. + if (nextNode == null) return null; + + // does node pass the filters and whatToShow? + accepted = acceptNode(nextNode); + if (accepted) { + // if so, then the node is the current node. + fCurrentNode = nextNode; + return fCurrentNode; + } else + continue accepted_loop; + + } // while (!accepted) { + + // no nodes, or no accepted nodes. + return null; + + } + + /** Return the previous Node in the Iterator. The node is the next node in + * _backwards_ depth-first order which also passes the filter, and whatToShow. + */ + public Node previousNode() { + + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + + // if the root is null, or the current node is null, return null. + if (fRoot == null || fCurrentNode == null) return null; + + Node previousNode = fCurrentNode; + boolean accepted = false; + + accepted_loop: + while (!accepted) { + + if (fForward && previousNode != null) { + //repeat last node. + previousNode = fCurrentNode; + } else { + // get previous node in backwards depth first order. + previousNode = previousNode(previousNode); + } + + // we are going backwards + fForward = false; + + // if the new previous node is null, we're at head or past the root, + // so return null. + if (previousNode == null) return null; + + // check if node passes filters and whatToShow. + accepted = acceptNode(previousNode); + if (accepted) { + // if accepted, update the current node, and return it. + fCurrentNode = previousNode; + return fCurrentNode; + } else + continue accepted_loop; + } + // there are no nodes? + return null; + } + + /** The node is accepted if it passes the whatToShow and the filter. */ + boolean acceptNode(Node node) { + + if (fNodeFilter == null) { + return ( fWhatToShow & (1 << node.getNodeType()-1)) != 0 ; + } else { + return ((fWhatToShow & (1 << node.getNodeType()-1)) != 0 ) + && fNodeFilter.acceptNode(node) == NodeFilter.FILTER_ACCEPT; + } + } + + /** Return node, if matches or any parent if matches. */ + Node matchNodeOrParent(Node node) { + // Additions and removals in the underlying data structure may occur + // before any iterations, and in this case the reference_node is null. + if (fCurrentNode == null) return null; + + // check if the removed node is an _ancestor_ of the + // reference node + for (Node n = fCurrentNode; n != fRoot; n = n.getParentNode()) { + if (node == n) return n; + } + return null; + } + + /** The method nextNode(Node, boolean) returns the next node + * from the actual DOM tree. + * + * The boolean visitChildren determines whether to visit the children. + * The result is the nextNode. + */ + Node nextNode(Node node, boolean visitChildren) { + + if (node == null) return fRoot; + + Node result; + // only check children if we visit children. + if (visitChildren) { + //if hasChildren, return 1st child. + if (node.hasChildNodes()) { + result = node.getFirstChild(); + return result; + } + } + + if (node == fRoot) { //if Root has no kids + return null; + } + + // if hasSibling, return sibling + result = node.getNextSibling(); + if (result != null) return result; + + + // return parent's 1st sibling. + Node parent = node.getParentNode(); + while (parent != null && parent != fRoot) { + result = parent.getNextSibling(); + if (result != null) { + return result; + } else { + parent = parent.getParentNode(); + } + + } // while (parent != null && parent != fRoot) { + + // end of list, return null + return null; + } + + /** The method previousNode(Node) returns the previous node + * from the actual DOM tree. + */ + Node previousNode(Node node) { + + Node result; + + // if we're at the root, return null. + if (node == fRoot) return null; + + // get sibling + result = node.getPreviousSibling(); + if (result == null) { + //if 1st sibling, return parent + result = node.getParentNode(); + return result; + } + + // if sibling has children, keep getting last child of child. + if (result.hasChildNodes() + && !(!fEntityReferenceExpansion + && result != null + && result.getNodeType() == Node.ENTITY_REFERENCE_NODE)) + + { + while (result.hasChildNodes()) { + result = result.getLastChild(); + } + } + + return result; + } + + /** Fix-up the iterator on a remove. Called by DOM or otherwise, + * before an actual DOM remove. + */ + public void removeNode(Node node) { + + // Implementation note: Fix-up means setting the current node properly + // after a remove. + + if (node == null) return; + + Node deleted = matchNodeOrParent(node); + + if (deleted == null) return; + + if (fForward) { + fCurrentNode = previousNode(deleted); + } else + // if (!fForward) + { + Node next = nextNode(deleted, false); + if (next!=null) { + // normal case: there _are_ nodes following this in the iterator. + fCurrentNode = next; + } else { + // the last node in the iterator is to be removed, + // so we set the current node to be the previous one. + fCurrentNode = previousNode(deleted); + fForward = true; + } + + } + + } + + public void detach() { + fDetach = true; + fDocument.removeNodeIterator(this); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/NodeListCache.java b/resources/xerces2-j-src/org/apache/xerces/dom/NodeListCache.java new file mode 100644 index 0000000..133b8d5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/NodeListCache.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.Serializable; + +/** + * This class is used, via a pool managed on CoreDocumentImpl, in ParentNode to + * improve performance of the NodeList accessors, getLength() and item(i). + * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * + * @version $Id$ + */ +class NodeListCache implements Serializable { + + /** Serialization version. */ + private static final long serialVersionUID = -7927529254918631002L; + + /** Cached node list length. */ + int fLength = -1; + + /** Last requested node index. */ + int fChildIndex = -1; + + /** Last requested node. */ + ChildNode fChild; + + /** Owner of this cache */ + ParentNode fOwner; + + /** Pointer to the next object on the list, + only meaningful when actully stored in the free list. */ + NodeListCache next; + + NodeListCache(ParentNode owner) { + fOwner = owner; + } +} + diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/NotationImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/NotationImpl.java new file mode 100644 index 0000000..2e32325 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/NotationImpl.java @@ -0,0 +1,210 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.apache.xerces.util.URI; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.Notation; + +/** + * Notations are how the Document Type Description (DTD) records hints + * about the format of an XML "unparsed entity" -- in other words, + * non-XML data bound to this document type, which some applications + * may wish to consult when manipulating the document. A Notation + * represents a name-value pair, with its nodeName being set to the + * declared name of the notation. + *

+ * Notations are also used to formally declare the "targets" of + * Processing Instructions. + *

+ * Note that the Notation's data is non-DOM information; the DOM only + * records what and where it is. + *

+ * See the XML 1.0 spec, sections 4.7 and 2.6, for more info. + *

+ * Level 1 of the DOM does not support editing Notation contents. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class NotationImpl + extends NodeImpl + implements Notation { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -764632195890658402L; + + // + // Data + // + + /** Notation name. */ + protected String name; + + /** Public identifier. */ + protected String publicId; + + /** System identifier. */ + protected String systemId; + + /** Base URI*/ + protected String baseURI; + + // + // Constructors + // + + /** Factory constructor. */ + public NotationImpl(CoreDocumentImpl ownerDoc, String name) { + super(ownerDoc); + this.name = name; + } + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.NOTATION_NODE; + } + + /** + * Returns the notation name + */ + public String getNodeName() { + if (needsSyncData()) { + synchronizeData(); + } + return name; + } + + // + // Notation methods + // + + /** + * The Public Identifier for this Notation. If no public identifier + * was specified, this will be null. + */ + public String getPublicId() { + + if (needsSyncData()) { + synchronizeData(); + } + return publicId; + + } // getPublicId():String + + /** + * The System Identifier for this Notation. If no system identifier + * was specified, this will be null. + */ + public String getSystemId() { + + if (needsSyncData()) { + synchronizeData(); + } + return systemId; + + } // getSystemId():String + + // + // Public methods + // + + /** + * NON-DOM: The Public Identifier for this Notation. If no public + * identifier was specified, this will be null. + */ + public void setPublicId(String id) { + + if (isReadOnly()) { + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null)); + } + if (needsSyncData()) { + synchronizeData(); + } + publicId = id; + + } // setPublicId(String) + + /** + * NON-DOM: The System Identifier for this Notation. If no system + * identifier was specified, this will be null. + */ + public void setSystemId(String id) { + + if(isReadOnly()) { + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null)); + } + if (needsSyncData()) { + synchronizeData(); + } + systemId = id; + + } // setSystemId(String) + + + /** + * Returns the absolute base URI of this node or null if the implementation + * wasn't able to obtain an absolute URI. Note: If the URI is malformed, a + * null is returned. + * + * @return The absolute base URI of this node or null. + * @since DOM Level 3 + */ + public String getBaseURI() { + if (needsSyncData()) { + synchronizeData(); + } + if (baseURI != null && baseURI.length() != 0 ) {// attribute value is always empty string + try { + return new URI(baseURI).toString(); + } + catch (org.apache.xerces.util.URI.MalformedURIException e){ + // REVISIT: what should happen in this case? + return null; + } + } + return baseURI; + } + + /** NON-DOM: set base uri*/ + public void setBaseURI(String uri){ + if (needsSyncData()) { + synchronizeData(); + } + baseURI = uri; + } + +} // class NotationImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ObjectFactory.java b/resources/xerces2-j-src/org/apache/xerces/dom/ObjectFactory.java new file mode 100644 index 0000000..11eebe2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ObjectFactory.java @@ -0,0 +1,545 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; + +/** + * This class is duplicated for each JAXP subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of the JAXP + * API. + *

+ * This code is designed to implement the JAXP 1.1 spec pluggability + * feature and is designed to run on JDK version 1.1 and + * later, and to compile on JDK 1.2 and onward. + * The code also runs both as part of an unbundled jar file and + * when bundled as part of the JDK. + *

+ * + * @xerces.internal + * + * @version $Id$ + */ +final class ObjectFactory { + + // + // Constants + // + + // name of default properties file to look for in JDK's jre/lib directory + private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties"; + + /** Set to true for debugging */ + private static final boolean DEBUG = isDebugEnabled(); + + /** + * Default columns per line. + */ + private static final int DEFAULT_LINE_LENGTH = 80; + + /** cache the contents of the xerces.properties file. + * Until an attempt has been made to read this file, this will + * be null; if the file does not exist or we encounter some other error + * during the read, this will be empty. + */ + private static Properties fXercesProperties = null; + + /*** + * Cache the time stamp of the xerces.properties file so + * that we know if it's been modified and can invalidate + * the cache when necessary. + */ + private static long fLastModified = -1; + + // + // static methods + // + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *

    + *
  1. query the system property using System.getProperty + *
  2. read META-INF/services/factoryId file + *
  3. use fallback classname + *
+ * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, String fallbackClassName) + throws ConfigurationError { + return createObject(factoryId, null, fallbackClassName); + } // createObject(String,String):Object + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *
    + *
  1. query the system property using System.getProperty + *
  2. read $java.home/lib/propertiesFilename file + *
  3. read META-INF/services/factoryId file + *
  4. use fallback classname + *
+ * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param propertiesFilename The filename in the $java.home/lib directory + * of the properties file. If none specified, + * ${java.home}/lib/xerces.properties will be used. + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, + String propertiesFilename, + String fallbackClassName) + throws ConfigurationError + { + if (DEBUG) debugPrintln("debug is on"); + + ClassLoader cl = findClassLoader(); + + // Use the system property first + try { + String systemProp = SecuritySupport.getSystemProperty(factoryId); + if (systemProp != null && systemProp.length() > 0) { + if (DEBUG) debugPrintln("found system property, value=" + systemProp); + return newInstance(systemProp, cl, true); + } + } catch (SecurityException se) { + // Ignore and continue w/ next location + } + + // Try to read from propertiesFilename, or $java.home/lib/xerces.properties + String factoryClassName = null; + // no properties file name specified; use $JAVA_HOME/lib/xerces.properties: + if (propertiesFilename == null) { + File propertiesFile = null; + boolean propertiesFileExists = false; + try { + String javah = SecuritySupport.getSystemProperty("java.home"); + propertiesFilename = javah + File.separator + + "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME; + propertiesFile = new File(propertiesFilename); + propertiesFileExists = SecuritySupport.getFileExists(propertiesFile); + } catch (SecurityException e) { + // try again... + fLastModified = -1; + fXercesProperties = null; + } + + synchronized (ObjectFactory.class) { + boolean loadProperties = false; + FileInputStream fis = null; + try { + // file existed last time + if(fLastModified >= 0) { + if(propertiesFileExists && + (fLastModified < (fLastModified = SecuritySupport.getLastModified(propertiesFile)))) { + loadProperties = true; + } else { + // file has stopped existing... + if(!propertiesFileExists) { + fLastModified = -1; + fXercesProperties = null; + } // else, file wasn't modified! + } + } else { + // file has started to exist: + if(propertiesFileExists) { + loadProperties = true; + fLastModified = SecuritySupport.getLastModified(propertiesFile); + } // else, nothing's changed + } + if(loadProperties) { + // must never have attempted to read xerces.properties before (or it's outdeated) + fXercesProperties = new Properties(); + fis = SecuritySupport.getFileInputStream(propertiesFile); + fXercesProperties.load(fis); + } + } catch (Exception x) { + fXercesProperties = null; + fLastModified = -1; + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if(fXercesProperties != null) { + factoryClassName = fXercesProperties.getProperty(factoryId); + } + } else { + FileInputStream fis = null; + try { + fis = SecuritySupport.getFileInputStream(new File(propertiesFilename)); + Properties props = new Properties(); + props.load(fis); + factoryClassName = props.getProperty(factoryId); + } catch (Exception x) { + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if (factoryClassName != null) { + if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName); + return newInstance(factoryClassName, cl, true); + } + + // Try Jar Service Provider Mechanism + Object provider = findJarServiceProvider(factoryId); + if (provider != null) { + return provider; + } + + if (fallbackClassName == null) { + throw new ConfigurationError( + "Provider for " + factoryId + " cannot be found", null); + } + + if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); + return newInstance(fallbackClassName, cl, true); + } // createObject(String,String,String):Object + + // + // Private static methods + // + + /** Returns true if debug has been enabled. */ + private static boolean isDebugEnabled() { + try { + String val = SecuritySupport.getSystemProperty("xerces.debug"); + // Allow simply setting the prop to turn on debug + return (val != null && (!"false".equals(val))); + } + catch (SecurityException se) {} + return false; + } // isDebugEnabled() + + /** Prints a message to standard error if debugging is enabled. */ + private static void debugPrintln(String msg) { + if (DEBUG) { + System.err.println("XERCES: " + msg); + } + } // debugPrintln(String) + + /** + * Figure out which ClassLoader to use. For JDK 1.2 and later use + * the context ClassLoader. + */ + static ClassLoader findClassLoader() + throws ConfigurationError + { + // Figure out which ClassLoader to use for loading the provider + // class. If there is a Context ClassLoader then use it. + ClassLoader context = SecuritySupport.getContextClassLoader(); + ClassLoader system = SecuritySupport.getSystemClassLoader(); + + ClassLoader chain = system; + while (true) { + if (context == chain) { + // Assert: we are on JDK 1.1 or we have no Context ClassLoader + // or any Context ClassLoader in chain of system classloader + // (including extension ClassLoader) so extend to widest + // ClassLoader (always look in system ClassLoader if Xerces + // is in boot/extension/system classpath and in current + // ClassLoader otherwise); normal classloaders delegate + // back to system ClassLoader first so this widening doesn't + // change the fact that context ClassLoader will be consulted + ClassLoader current = ObjectFactory.class.getClassLoader(); + + chain = system; + while (true) { + if (current == chain) { + // Assert: Current ClassLoader in chain of + // boot/extension/system ClassLoaders + return system; + } + if (chain == null) { + break; + } + chain = SecuritySupport.getParentClassLoader(chain); + } + + // Assert: Current ClassLoader not in chain of + // boot/extension/system ClassLoaders + return current; + } + + if (chain == null) { + // boot ClassLoader reached + break; + } + + // Check for any extension ClassLoaders in chain up to + // boot ClassLoader + chain = SecuritySupport.getParentClassLoader(chain); + }; + + // Assert: Context ClassLoader not in chain of + // boot/extension/system ClassLoaders + return context; + } // findClassLoader():ClassLoader + + /** + * Create an instance of a class using the specified ClassLoader + */ + static Object newInstance(String className, ClassLoader cl, + boolean doFallback) + throws ConfigurationError + { + // assert(className != null); + try{ + Class providerClass = findProviderClass(className, cl, doFallback); + Object instance = providerClass.newInstance(); + if (DEBUG) debugPrintln("created new instance of " + providerClass + + " using ClassLoader: " + cl); + return instance; + } catch (ClassNotFoundException x) { + throw new ConfigurationError( + "Provider " + className + " not found", x); + } catch (Exception x) { + throw new ConfigurationError( + "Provider " + className + " could not be instantiated: " + x, + x); + } + } + + /** + * Find a Class using the specified ClassLoader + */ + static Class findProviderClass(String className, ClassLoader cl, + boolean doFallback) + throws ClassNotFoundException, ConfigurationError + { + //throw security exception if the calling thread is not allowed to access the package + //restrict the access to package as specified in java.security policy + SecurityManager security = System.getSecurityManager(); + if (security != null) { + final int lastDot = className.lastIndexOf('.'); + String packageName = className; + if (lastDot != -1) packageName = className.substring(0, lastDot); + security.checkPackageAccess(packageName); + } + Class providerClass; + if (cl == null) { + // XXX Use the bootstrap ClassLoader. There is no way to + // load a class using the bootstrap ClassLoader that works + // in both JDK 1.1 and Java 2. However, this should still + // work b/c the following should be true: + // + // (cl == null) iff current ClassLoader == null + // + // Thus Class.forName(String) will use the current + // ClassLoader which will be the bootstrap ClassLoader. + providerClass = Class.forName(className); + } else { + try { + providerClass = cl.loadClass(className); + } catch (ClassNotFoundException x) { + if (doFallback) { + // Fall back to current classloader + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (current == null) { + providerClass = Class.forName(className); + } else if (cl != current) { + cl = current; + providerClass = cl.loadClass(className); + } else { + throw x; + } + } else { + throw x; + } + } + } + + return providerClass; + } + + /* + * Try to find provider using Jar Service Provider Mechanism + * + * @return instance of provider class if found or null + */ + private static Object findJarServiceProvider(String factoryId) + throws ConfigurationError + { + String serviceId = "META-INF/services/" + factoryId; + InputStream is = null; + + // First try the Context ClassLoader + ClassLoader cl = findClassLoader(); + + is = SecuritySupport.getResourceAsStream(cl, serviceId); + + // If no provider found then try the current ClassLoader + if (is == null) { + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (cl != current) { + cl = current; + is = SecuritySupport.getResourceAsStream(cl, serviceId); + } + } + + if (is == null) { + // No provider found + return null; + } + + if (DEBUG) debugPrintln("found jar resource=" + serviceId + + " using ClassLoader: " + cl); + + // Read the service provider name in UTF-8 as specified in + // the jar spec. Unfortunately this fails in Microsoft + // VJ++, which does not implement the UTF-8 + // encoding. Theoretically, we should simply let it fail in + // that case, since the JVM is obviously broken if it + // doesn't support such a basic standard. But since there + // are still some users attempting to use VJ++ for + // development, we have dropped in a fallback which makes a + // second attempt using the platform's default encoding. In + // VJ++ this is apparently ASCII, which is a subset of + // UTF-8... and since the strings we'll be reading here are + // also primarily limited to the 7-bit ASCII range (at + // least, in English versions), this should work well + // enough to keep us on the air until we're ready to + // officially decommit from VJ++. [Edited comment from + // jkesselm] + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); + } catch (java.io.UnsupportedEncodingException e) { + rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); + } + + String factoryClassName = null; + try { + // XXX Does not handle all possible input as specified by the + // Jar Service Provider specification + factoryClassName = rd.readLine(); + } catch (IOException x) { + // No provider found + return null; + } + finally { + try { + // try to close the reader. + rd.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + + if (factoryClassName != null && + ! "".equals(factoryClassName)) { + if (DEBUG) debugPrintln("found in resource, value=" + + factoryClassName); + + // Note: here we do not want to fall back to the current + // ClassLoader because we want to avoid the case where the + // resource file was found using one ClassLoader and the + // provider class was instantiated using a different one. + return newInstance(factoryClassName, cl, false); + } + + // No provider found + return null; + } + + // + // Classes + // + + /** + * A configuration error. + */ + static final class ConfigurationError + extends Error { + + /** Serialization version. */ + static final long serialVersionUID = 1914065341994951202L; + + // + // Data + // + + /** Exception. */ + private Exception exception; + + // + // Constructors + // + + /** + * Construct a new instance with the specified detail string and + * exception. + */ + ConfigurationError(String msg, Exception x) { + super(msg); + this.exception = x; + } // (String,Exception) + + // + // methods + // + + /** Returns the exception associated to this error. */ + Exception getException() { + return exception; + } // getException():Exception + + } // class ConfigurationError + +} // class ObjectFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/PSVIAttrNSImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/PSVIAttrNSImpl.java new file mode 100644 index 0000000..eb05b5d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/PSVIAttrNSImpl.java @@ -0,0 +1,285 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.xs.AttributePSVImpl; +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ItemPSVI; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSAttributeDeclaration; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; +import org.apache.xerces.xs.XSValue; + +/** + * Attribute namespace implementation; stores PSVI attribute items. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class PSVIAttrNSImpl extends AttrNSImpl implements AttributePSVI { + + /** Serialization version. */ + static final long serialVersionUID = -3241738699421018889L; + + /** + * Construct an attribute node. + */ + public PSVIAttrNSImpl(CoreDocumentImpl ownerDocument, String namespaceURI, + String qualifiedName, String localName) { + super(ownerDocument, namespaceURI, qualifiedName, localName); + } + + /** + * Construct an attribute node. + */ + public PSVIAttrNSImpl(CoreDocumentImpl ownerDocument, String namespaceURI, + String qualifiedName) { + super(ownerDocument, namespaceURI, qualifiedName); + } + + /** attribute declaration */ + protected XSAttributeDeclaration fDeclaration = null; + + /** type of attribute, simpleType */ + protected XSTypeDefinition fTypeDecl = null; + + /** If this attribute was explicitly given a + * value in the original document, this is true; otherwise, it is false */ + protected boolean fSpecified = true; + + /** Schema value */ + protected ValidatedInfo fValue = new ValidatedInfo(); + + /** validation attempted: none, partial, full */ + protected short fValidationAttempted = AttributePSVI.VALIDATION_NONE; + + /** validity: valid, invalid, unknown */ + protected short fValidity = AttributePSVI.VALIDITY_NOTKNOWN; + + /** error codes */ + protected StringList fErrorCodes = null; + + /** error messages */ + protected StringList fErrorMessages = null; + + /** validation context: could be QName or XPath expression*/ + protected String fValidationContext = null; + + // + // AttributePSVI methods + // + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#constant() + */ + public ItemPSVI constant() { + return new AttributePSVImpl(true, this); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#isConstant() + */ + public boolean isConstant() { + return false; + } + + /** + * [schema default] + * + * @return The canonical lexical representation of the declaration's {value constraint} value. + * @see XML Schema Part 1: Structures [schema normalized value] + * @return the normalized value of this item after validation + */ + public String getSchemaNormalizedValue() { + return fValue.getNormalizedValue(); + } + + /** + * [schema specified] + * @see XML Schema Part 1: Structures [schema specified] + * @return false value was specified in schema, true value comes from the infoset + */ + public boolean getIsSchemaSpecified() { + return fSpecified; + } + + + /** + * Determines the extent to which the document has been validated + * + * @return return the [validation attempted] property. The possible values are + * NO_VALIDATION, PARTIAL_VALIDATION and FULL_VALIDATION + */ + public short getValidationAttempted() { + return fValidationAttempted; + } + + /** + * Determine the validity of the node with respect + * to the validation being attempted + * + * @return return the [validity] property. Possible values are: + * UNKNOWN_VALIDITY, INVALID_VALIDITY, VALID_VALIDITY + */ + public short getValidity() { + return fValidity; + } + + /** + * A list of error codes generated from validation attempts. + * Need to find all the possible subclause reports that need reporting + * + * @return list of error codes + */ + public StringList getErrorCodes() { + if (fErrorCodes != null) { + return fErrorCodes; + } + return StringListImpl.EMPTY_LIST; + } + + /** + * A list of error messages generated from the validation attempt or + * an empty StringList if no errors occurred during the + * validation attempt. The indices of error messages in this list are + * aligned with those in the [schema error code] list. + */ + public StringList getErrorMessages() { + if (fErrorMessages != null) { + return fErrorMessages; + } + return StringListImpl.EMPTY_LIST; + } + + // This is the only information we can provide in a pipeline. + public String getValidationContext() { + return fValidationContext; + } + + /** + * An item isomorphic to the type definition used to validate this element. + * + * @return a type declaration + */ + public XSTypeDefinition getTypeDefinition() { + return fTypeDecl; + } + + /** + * If and only if that type definition is a simple type definition + * with {variety} union, or a complex type definition whose {content type} + * is a simple thype definition with {variety} union, then an item isomorphic + * to that member of the union's {member type definitions} which actually + * validated the element item's normalized value. + * + * @return a simple type declaration + */ + public XSSimpleTypeDefinition getMemberTypeDefinition() { + return fValue.getMemberTypeDefinition(); + } + + /** + * An item isomorphic to the attribute declaration used to validate + * this attribute. + * + * @return an attribute declaration + */ + public XSAttributeDeclaration getAttributeDeclaration() { + return fDeclaration; + } + + /** + * Copy PSVI properties from another psvi item. + * + * @param attr the source of attribute PSVI items + */ + public void setPSVI(AttributePSVI attr) { + this.fDeclaration = attr.getAttributeDeclaration(); + this.fValidationContext = attr.getValidationContext(); + this.fValidity = attr.getValidity(); + this.fValidationAttempted = attr.getValidationAttempted(); + this.fErrorCodes = attr.getErrorCodes(); + this.fErrorMessages = attr.getErrorMessages(); + this.fValue.copyFrom(attr.getSchemaValue()); + this.fTypeDecl = attr.getTypeDefinition(); + this.fSpecified = attr.getIsSchemaSpecified(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getActualNormalizedValue() + */ + public Object getActualNormalizedValue() { + return fValue.getActualValue(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getActualNormalizedValueType() + */ + public short getActualNormalizedValueType() { + return fValue.getActualValueType(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getItemValueTypes() + */ + public ShortList getItemValueTypes() { + return fValue.getListValueTypes(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getSchemaValue() + */ + public XSValue getSchemaValue() { + return fValue; + } + + // REVISIT: Forbid serialization of PSVI DOM until + // we support object serialization of grammars -- mrglavas + + private void writeObject(ObjectOutputStream out) + throws IOException { + throw new NotSerializableException(getClass().getName()); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + throw new NotSerializableException(getClass().getName()); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/PSVIDOMImplementationImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/PSVIDOMImplementationImpl.java new file mode 100644 index 0000000..3f6e391 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/PSVIDOMImplementationImpl.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DocumentType; + +/** + * The DOMImplementation class is description of a particular + * implementation of the Document Object Model. As such its data is + * static, shared by all instances of this implementation. + *

+ * The DOM API requires that it be a real object rather than static + * methods. However, there's nothing that says it can't be a singleton, + * so that's how I've implemented it. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class PSVIDOMImplementationImpl extends DOMImplementationImpl { + + // + // Data + // + + // static + + /** Dom implementation singleton. */ + static final PSVIDOMImplementationImpl singleton = new PSVIDOMImplementationImpl(); + + // + // Public methods + // + + /** NON-DOM: Obtain and return the single shared object */ + public static DOMImplementation getDOMImplementation() { + return singleton; + } + + // + // DOMImplementation methods + // + + /** + * Test if the DOM implementation supports a specific "feature" -- + * currently meaning language and level thereof. + * + * @param feature The package name of the feature to test. + * In Level 1, supported values are "HTML" and "XML" (case-insensitive). + * At this writing, org.apache.xerces.dom supports only XML. + * + * @param version The version number of the feature being tested. + * This is interpreted as "Version of the DOM API supported for the + * specified Feature", and in Level 1 should be "1.0" + * + * @return true iff this implementation is compatable with the specified + * feature and version. + */ + public boolean hasFeature(String feature, String version) { + return super.hasFeature(feature, version) || + feature.equalsIgnoreCase("psvi"); + } // hasFeature(String,String):boolean + + // + // Protected methods + // + + protected CoreDocumentImpl createDocument(DocumentType doctype) { + return new PSVIDocumentImpl(doctype); + } + +} // class PSVIDOMImplementationImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/PSVIDocumentImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/PSVIDocumentImpl.java new file mode 100644 index 0000000..c448604 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/PSVIDocumentImpl.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.UserDataHandler; + +/** + * Our own document implementation, which knows how to create an element + * with PSVI information. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class PSVIDocumentImpl extends DocumentImpl { + + /** Serialization version. */ + static final long serialVersionUID = -8822220250676434522L; + + /** + * Create a document. + */ + public PSVIDocumentImpl() { + super(); + } + + /** + * For DOM2 support. + * The createDocument factory method is in DOMImplementation. + */ + public PSVIDocumentImpl(DocumentType doctype) { + super(doctype); + } + + /** + * Deep-clone a document, including fixing ownerDoc for the cloned + * children. Note that this requires bypassing the WRONG_DOCUMENT_ERR + * protection. I've chosen to implement it by calling importNode + * which is DOM Level 2. + * + * @return org.w3c.dom.Node + * @param deep boolean, iff true replicate children + */ + public Node cloneNode(boolean deep) { + + PSVIDocumentImpl newdoc = new PSVIDocumentImpl(); + callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED); + cloneNode(newdoc, deep); + + // experimental + newdoc.mutationEvents = mutationEvents; + + return newdoc; + + } // cloneNode(boolean):Node + + /** + * Retrieve information describing the abilities of this particular + * DOM implementation. Intended to support applications that may be + * using DOMs retrieved from several different sources, potentially + * with different underlying representations. + */ + public DOMImplementation getImplementation() { + // Currently implemented as a singleton, since it's hardcoded + // information anyway. + return PSVIDOMImplementationImpl.getDOMImplementation(); + } + + /** + * Create an element with PSVI information + */ + public Element createElementNS(String namespaceURI, String qualifiedName) + throws DOMException { + return new PSVIElementNSImpl(this, namespaceURI, qualifiedName); + } + + /** + * Create an element with PSVI information + */ + public Element createElementNS(String namespaceURI, String qualifiedName, + String localpart) throws DOMException { + return new PSVIElementNSImpl(this, namespaceURI, qualifiedName, localpart); + } + + /** + * Create an attribute with PSVI information + */ + public Attr createAttributeNS(String namespaceURI, String qualifiedName) + throws DOMException { + return new PSVIAttrNSImpl(this, namespaceURI, qualifiedName); + } + + /** + * Create an attribute with PSVI information + */ + public Attr createAttributeNS(String namespaceURI, String qualifiedName, + String localName) throws DOMException { + return new PSVIAttrNSImpl(this, namespaceURI, qualifiedName, localName); + } + + /** + * + * The configuration used when Document.normalizeDocument is + * invoked. + * @since DOM Level 3 + */ + public DOMConfiguration getDomConfig(){ + super.getDomConfig(); + return fConfiguration; + } + + // REVISIT: Forbid serialization of PSVI DOM until + // we support object serialization of grammars -- mrglavas + + private void writeObject(ObjectOutputStream out) + throws IOException { + throw new NotSerializableException(getClass().getName()); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + throw new NotSerializableException(getClass().getName()); + } + +} // class PSVIDocumentImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/PSVIElementNSImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/PSVIElementNSImpl.java new file mode 100644 index 0000000..3a6aec2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/PSVIElementNSImpl.java @@ -0,0 +1,336 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.xs.ElementPSVImpl; +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.ItemPSVI; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSComplexTypeDefinition; +import org.apache.xerces.xs.XSElementDeclaration; +import org.apache.xerces.xs.XSModel; +import org.apache.xerces.xs.XSNotationDeclaration; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; +import org.apache.xerces.xs.XSValue; + +/** + * Element namespace implementation; stores PSVI element items. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class PSVIElementNSImpl extends ElementNSImpl implements ElementPSVI { + + /** Serialization version. */ + static final long serialVersionUID = 6815489624636016068L; + + /** + * Construct an element node. + */ + public PSVIElementNSImpl(CoreDocumentImpl ownerDocument, String namespaceURI, + String qualifiedName, String localName) { + super(ownerDocument, namespaceURI, qualifiedName, localName); + } + + /** + * Construct an element node. + */ + public PSVIElementNSImpl(CoreDocumentImpl ownerDocument, String namespaceURI, + String qualifiedName) { + super(ownerDocument, namespaceURI, qualifiedName); + } + + /** element declaration */ + protected XSElementDeclaration fDeclaration = null; + + /** type of element, could be xsi:type */ + protected XSTypeDefinition fTypeDecl = null; + + /** true if clause 3.2 of Element Locally Valid (Element) (3.3.4) + * is satisfied, otherwise false + */ + protected boolean fNil = false; + + /** false if the element value was provided by the schema; true otherwise. + */ + protected boolean fSpecified = true; + + /** Schema value */ + protected ValidatedInfo fValue = new ValidatedInfo(); + + /** http://www.w3.org/TR/xmlschema-1/#e-notation*/ + protected XSNotationDeclaration fNotation = null; + + /** validation attempted: none, partial, full */ + protected short fValidationAttempted = ElementPSVI.VALIDATION_NONE; + + /** validity: valid, invalid, unknown */ + protected short fValidity = ElementPSVI.VALIDITY_NOTKNOWN; + + /** error codes */ + protected StringList fErrorCodes = null; + + /** error messages */ + protected StringList fErrorMessages = null; + + /** validation context: could be QName or XPath expression*/ + protected String fValidationContext = null; + + /** the schema information property */ + protected XSModel fSchemaInformation = null; + + // + // ElementPSVI methods + // + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#constant() + */ + public ItemPSVI constant() { + return new ElementPSVImpl(true, this); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#isConstant() + */ + public boolean isConstant() { + return false; + } + + /** + * [schema default] + * + * @return The canonical lexical representation of the declaration's {value constraint} value. + * @see XML Schema Part 1: Structures [schema normalized value] + * @return the normalized value of this item after validation + */ + public String getSchemaNormalizedValue() { + return fValue.getNormalizedValue(); + } + + /** + * [schema specified] + * @see XML Schema Part 1: Structures [schema specified] + * @return false value was specified in schema, true value comes from the infoset + */ + public boolean getIsSchemaSpecified() { + return fSpecified; + } + + /** + * Determines the extent to which the document has been validated + * + * @return return the [validation attempted] property. The possible values are + * NO_VALIDATION, PARTIAL_VALIDATION and FULL_VALIDATION + */ + public short getValidationAttempted() { + return fValidationAttempted; + } + + /** + * Determine the validity of the node with respect + * to the validation being attempted + * + * @return return the [validity] property. Possible values are: + * UNKNOWN_VALIDITY, INVALID_VALIDITY, VALID_VALIDITY + */ + public short getValidity() { + return fValidity; + } + + /** + * A list of error codes generated from validation attempts. + * Need to find all the possible subclause reports that need reporting + * + * @return Array of error codes + */ + public StringList getErrorCodes() { + if (fErrorCodes != null) { + return fErrorCodes; + } + return StringListImpl.EMPTY_LIST; + } + + /** + * A list of error messages generated from the validation attempt or + * an empty StringList if no errors occurred during the + * validation attempt. The indices of error messages in this list are + * aligned with those in the [schema error code] list. + */ + public StringList getErrorMessages() { + if (fErrorMessages != null) { + return fErrorMessages; + } + return StringListImpl.EMPTY_LIST; + } + + // This is the only information we can provide in a pipeline. + public String getValidationContext() { + return fValidationContext; + } + + /** + * [nil] + * @see XML Schema Part 1: Structures [notation] + * @return The notation declaration. + */ + public XSNotationDeclaration getNotation() { + return fNotation; + } + + /** + * An item isomorphic to the type definition used to validate this element. + * + * @return a type declaration + */ + public XSTypeDefinition getTypeDefinition() { + return fTypeDecl; + } + + /** + * If and only if that type definition is a simple type definition + * with {variety} union, or a complex type definition whose {content type} + * is a simple thype definition with {variety} union, then an item isomorphic + * to that member of the union's {member type definitions} which actually + * validated the element item's normalized value. + * + * @return a simple type declaration + */ + public XSSimpleTypeDefinition getMemberTypeDefinition() { + return fValue.getMemberTypeDefinition(); + } + + /** + * An item isomorphic to the element declaration used to validate + * this element. + * + * @return an element declaration + */ + public XSElementDeclaration getElementDeclaration() { + return fDeclaration; + } + + /** + * [schema information] + * @see XML Schema Part 1: Structures [schema information] + * @return The schema information property if it's the validation root, + * null otherwise. + */ + public XSModel getSchemaInformation() { + return fSchemaInformation; + } + + /** + * Copy PSVI properties from another psvi item. + * + * @param elem the source of element PSVI items + */ + public void setPSVI(ElementPSVI elem) { + this.fDeclaration = elem.getElementDeclaration(); + this.fNotation = elem.getNotation(); + this.fValidationContext = elem.getValidationContext(); + this.fTypeDecl = elem.getTypeDefinition(); + this.fSchemaInformation = elem.getSchemaInformation(); + this.fValidity = elem.getValidity(); + this.fValidationAttempted = elem.getValidationAttempted(); + this.fErrorCodes = elem.getErrorCodes(); + this.fErrorMessages = elem.getErrorMessages(); + if (fTypeDecl instanceof XSSimpleTypeDefinition || + fTypeDecl instanceof XSComplexTypeDefinition && + ((XSComplexTypeDefinition)fTypeDecl).getContentType() == XSComplexTypeDefinition.CONTENTTYPE_SIMPLE) { + this.fValue.copyFrom(elem.getSchemaValue()); + } + else { + this.fValue.reset(); + } + this.fSpecified = elem.getIsSchemaSpecified(); + this.fNil = elem.getNil(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getActualNormalizedValue() + */ + public Object getActualNormalizedValue() { + return fValue.getActualValue(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getActualNormalizedValueType() + */ + public short getActualNormalizedValueType() { + return fValue.getActualValueType(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getItemValueTypes() + */ + public ShortList getItemValueTypes() { + return fValue.getListValueTypes(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getSchemaValue() + */ + public XSValue getSchemaValue() { + return fValue; + } + + // REVISIT: Forbid serialization of PSVI DOM until + // we support object serialization of grammars -- mrglavas + + private void writeObject(ObjectOutputStream out) + throws IOException { + throw new NotSerializableException(getClass().getName()); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + throw new NotSerializableException(getClass().getName()); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ParentNode.java b/resources/xerces2-j-src/org/apache/xerces/dom/ParentNode.java new file mode 100644 index 0000000..1e3de89 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ParentNode.java @@ -0,0 +1,1031 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.UserDataHandler; + +/** + * ParentNode inherits from ChildNode and adds the capability of having child + * nodes. Not every node in the DOM can have children, so only nodes that can + * should inherit from this class and pay the price for it. + *

+ * ParentNode, just like NodeImpl, also implements NodeList, so it can + * return itself in response to the getChildNodes() query. This eliminiates + * the need for a separate ChildNodeList object. Note that this is an + * IMPLEMENTATION DETAIL; applications should _never_ assume that + * this identity exists. On the other hand, subclasses may need to override + * this, in case of conflicting names. This is the case for the classes + * HTMLSelectElementImpl and HTMLFormElementImpl of the HTML DOM. + *

+ * While we have a direct reference to the first child, the last child is + * stored as the previous sibling of the first child. First child nodes are + * marked as being so, and getNextSibling hides this fact. + *

Note: Not all parent nodes actually need to also be a child. At some + * point we used to have ParentNode inheriting from NodeImpl and another class + * called ChildAndParentNode that inherited from ChildNode. But due to the lack + * of multiple inheritance a lot of code had to be duplicated which led to a + * maintenance nightmare. At the same time only a few nodes (Document, + * DocumentFragment, Entity, and Attribute) cannot be a child so the gain in + * memory wasn't really worth it. The only type for which this would be the + * case is Attribute, but we deal with there in another special way, so this is + * not applicable. + *

+ * This class doesn't directly support mutation events, however, it notifies + * the document when mutations are performed so that the document class do so. + * + *

WARNING: Some of the code here is partially duplicated in + * AttrImpl, be careful to keep these two classes in sync! + * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Joe Kesselman, IBM + * @author Andy Clark, IBM + * @version $Id$ + */ +public abstract class ParentNode + extends ChildNode { + + /** Serialization version. */ + static final long serialVersionUID = 2815829867152120872L; + + /** Owner document. */ + protected CoreDocumentImpl ownerDocument; + + /** First child. */ + protected ChildNode firstChild = null; + + // transients + + /** NodeList cache */ + protected transient NodeListCache fNodeListCache = null; + + // + // Constructors + // + + /** + * No public constructor; only subclasses of ParentNode should be + * instantiated, and those normally via a Document's factory methods + */ + protected ParentNode(CoreDocumentImpl ownerDocument) { + super(ownerDocument); + this.ownerDocument = ownerDocument; + } + + /** Constructor for serialization. */ + public ParentNode() {} + + // + // NodeList methods + // + + /** + * Returns a duplicate of a given node. You can consider this a + * generic "copy constructor" for nodes. The newly returned object should + * be completely independent of the source object's subtree, so changes + * in one after the clone has been made will not affect the other. + *

+ * Example: Cloning a Text node will copy both the node and the text it + * contains. + *

+ * Example: Cloning something that has children -- Element or Attr, for + * example -- will _not_ clone those children unless a "deep clone" + * has been requested. A shallow clone of an Attr node will yield an + * empty Attr of the same name. + *

+ * NOTE: Clones will always be read/write, even if the node being cloned + * is read-only, to permit applications using only the DOM API to obtain + * editable copies of locked portions of the tree. + */ + public Node cloneNode(boolean deep) { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + ParentNode newnode = (ParentNode) super.cloneNode(deep); + + // set owner document + newnode.ownerDocument = ownerDocument; + + // Need to break the association w/ original kids + newnode.firstChild = null; + + // invalidate cache for children NodeList + newnode.fNodeListCache = null; + + // Then, if deep, clone the kids too. + if (deep) { + for (ChildNode child = firstChild; + child != null; + child = child.nextSibling) { + newnode.appendChild(child.cloneNode(true)); + } + } + + return newnode; + + } // cloneNode(boolean):Node + + /** + * Find the Document that this Node belongs to (the document in + * whose context the Node was created). The Node may or may not + * currently be part of that Document's actual contents. + */ + public Document getOwnerDocument() { + return ownerDocument; + } + + /** + * same as above but returns internal type and this one is not overridden + * by CoreDocumentImpl to return null + */ + CoreDocumentImpl ownerDocument() { + return ownerDocument; + } + + /** + * NON-DOM + * set the ownerDocument of this node and its children + */ + protected void setOwnerDocument(CoreDocumentImpl doc) { + if (needsSyncChildren()) { + synchronizeChildren(); + } + super.setOwnerDocument(doc); + ownerDocument = doc; + for (ChildNode child = firstChild; + child != null; child = child.nextSibling) { + child.setOwnerDocument(doc); + } + } + + /** + * Test whether this node has any children. Convenience shorthand + * for (Node.getFirstChild()!=null) + */ + public boolean hasChildNodes() { + if (needsSyncChildren()) { + synchronizeChildren(); + } + return firstChild != null; + } + + /** + * Obtain a NodeList enumerating all children of this node. If there + * are none, an (initially) empty NodeList is returned. + *

+ * NodeLists are "live"; as children are added/removed the NodeList + * will immediately reflect those changes. Also, the NodeList refers + * to the actual nodes, so changes to those nodes made via the DOM tree + * will be reflected in the NodeList and vice versa. + *

+ * In this implementation, Nodes implement the NodeList interface and + * provide their own getChildNodes() support. Other DOMs may solve this + * differently. + */ + public NodeList getChildNodes() { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + return this; + + } // getChildNodes():NodeList + + /** The first child of this Node, or null if none. */ + public Node getFirstChild() { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + return firstChild; + + } // getFirstChild():Node + + /** The last child of this Node, or null if none. */ + public Node getLastChild() { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + return lastChild(); + + } // getLastChild():Node + + final ChildNode lastChild() { + // last child is stored as the previous sibling of first child + return firstChild != null ? firstChild.previousSibling : null; + } + + final void lastChild(ChildNode node) { + // store lastChild as previous sibling of first child + if (firstChild != null) { + firstChild.previousSibling = node; + } + } + + /** + * Move one or more node(s) to our list of children. Note that this + * implicitly removes them from their previous parent. + * + * @param newChild The Node to be moved to our subtree. As a + * convenience feature, inserting a DocumentNode will instead insert + * all its children. + * + * @param refChild Current child which newChild should be placed + * immediately before. If refChild is null, the insertion occurs + * after all existing Nodes, like appendChild(). + * + * @return newChild, in its new state (relocated, or emptied in the case of + * DocumentNode.) + * + * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a + * type that shouldn't be a child of this node, or if newChild is an + * ancestor of this node. + * + * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a + * different owner document than we do. + * + * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node insertBefore(Node newChild, Node refChild) + throws DOMException { + // Tail-call; optimizer should be able to do good things with. + return internalInsertBefore(newChild, refChild, false); + } // insertBefore(Node,Node):Node + + /** NON-DOM INTERNAL: Within DOM actions,we sometimes need to be able + * to control which mutation events are spawned. This version of the + * insertBefore operation allows us to do so. It is not intended + * for use by application programs. + */ + Node internalInsertBefore(Node newChild, Node refChild, boolean replace) + throws DOMException { + + boolean errorChecking = ownerDocument.errorChecking; + + if (newChild.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { + // SLOW BUT SAFE: We could insert the whole subtree without + // juggling so many next/previous pointers. (Wipe out the + // parent's child-list, patch the parent pointers, set the + // ends of the list.) But we know some subclasses have special- + // case behavior they add to insertBefore(), so we don't risk it. + // This approch also takes fewer bytecodes. + + // NOTE: If one of the children is not a legal child of this + // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children + // have been transferred. (Alternative behaviors would be to + // reparent up to the first failure point or reparent all those + // which are acceptable to the target node, neither of which is + // as robust. PR-DOM-0818 isn't entirely clear on which it + // recommends????? + + // No need to check kids for right-document; if they weren't, + // they wouldn't be kids of that DocFrag. + if (errorChecking) { + for (Node kid = newChild.getFirstChild(); // Prescan + kid != null; kid = kid.getNextSibling()) { + + if (!ownerDocument.isKidOK(this, kid)) { + throw new DOMException( + DOMException.HIERARCHY_REQUEST_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + } + } + } + + while (newChild.hasChildNodes()) { + insertBefore(newChild.getFirstChild(), refChild); + } + return newChild; + } + + if (newChild == refChild) { + // stupid case that must be handled as a no-op triggering events... + refChild = refChild.getNextSibling(); + removeChild(newChild); + insertBefore(newChild, refChild); + return newChild; + } + + if (needsSyncChildren()) { + synchronizeChildren(); + } + + if (errorChecking) { + if (isReadOnly()) { + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null)); + } + if (newChild.getOwnerDocument() != ownerDocument && newChild != ownerDocument) { + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + if (!ownerDocument.isKidOK(this, newChild)) { + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + } + // refChild must be a child of this node (or null) + if (refChild != null && refChild.getParentNode() != this) { + throw new DOMException(DOMException.NOT_FOUND_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null)); + } + + // Prevent cycles in the tree + // newChild cannot be ancestor of this Node, + // and actually cannot be this + boolean treeSafe = true; + for (NodeImpl a = this; treeSafe && a != null; a = a.parentNode()) + { + treeSafe = newChild != a; + } + if(!treeSafe) { + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + } + } + + // notify document + ownerDocument.insertingNode(this, replace); + + // Convert to internal type, to avoid repeated casting + ChildNode newInternal = (ChildNode)newChild; + + Node oldparent = newInternal.parentNode(); + if (oldparent != null) { + oldparent.removeChild(newInternal); + } + + // Convert to internal type, to avoid repeated casting + ChildNode refInternal = (ChildNode)refChild; + + // Attach up + newInternal.ownerNode = this; + newInternal.isOwned(true); + + // Attach before and after + // Note: firstChild.previousSibling == lastChild!! + if (firstChild == null) { + // this our first and only child + firstChild = newInternal; + newInternal.isFirstChild(true); + newInternal.previousSibling = newInternal; + } + else { + if (refInternal == null) { + // this is an append + ChildNode lastChild = firstChild.previousSibling; + lastChild.nextSibling = newInternal; + newInternal.previousSibling = lastChild; + firstChild.previousSibling = newInternal; + } + else { + // this is an insert + if (refChild == firstChild) { + // at the head of the list + firstChild.isFirstChild(false); + newInternal.nextSibling = firstChild; + newInternal.previousSibling = firstChild.previousSibling; + firstChild.previousSibling = newInternal; + firstChild = newInternal; + newInternal.isFirstChild(true); + } + else { + // somewhere in the middle + ChildNode prev = refInternal.previousSibling; + newInternal.nextSibling = refInternal; + prev.nextSibling = newInternal; + refInternal.previousSibling = newInternal; + newInternal.previousSibling = prev; + } + } + } + + changed(); + + // update cached length if we have any + if (fNodeListCache != null) { + if (fNodeListCache.fLength != -1) { + fNodeListCache.fLength++; + } + if (fNodeListCache.fChildIndex != -1) { + // if we happen to insert just before the cached node, update + // the cache to the new node to match the cached index + if (fNodeListCache.fChild == refInternal) { + fNodeListCache.fChild = newInternal; + } else { + // otherwise just invalidate the cache + fNodeListCache.fChildIndex = -1; + } + } + } + + // notify document + ownerDocument.insertedNode(this, newInternal, replace); + + checkNormalizationAfterInsert(newInternal); + + return newChild; + + } // internalInsertBefore(Node,Node,boolean):Node + + /** + * Remove a child from this Node. The removed child's subtree + * remains intact so it may be re-inserted elsewhere. + * + * @return oldChild, in its new state (removed). + * + * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node removeChild(Node oldChild) + throws DOMException { + // Tail-call, should be optimizable + return internalRemoveChild(oldChild, false); + } // removeChild(Node) :Node + + /** NON-DOM INTERNAL: Within DOM actions,we sometimes need to be able + * to control which mutation events are spawned. This version of the + * removeChild operation allows us to do so. It is not intended + * for use by application programs. + */ + Node internalRemoveChild(Node oldChild, boolean replace) + throws DOMException { + + CoreDocumentImpl ownerDocument = ownerDocument(); + if (ownerDocument.errorChecking) { + if (isReadOnly()) { + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null)); + } + if (oldChild != null && oldChild.getParentNode() != this) { + throw new DOMException(DOMException.NOT_FOUND_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null)); + } + } + + ChildNode oldInternal = (ChildNode) oldChild; + + // notify document + ownerDocument.removingNode(this, oldInternal, replace); + + // Save previous sibling for normalization checking. + final ChildNode oldPreviousSibling = oldInternal.previousSibling(); + + // update cached length if we have any + if (fNodeListCache != null) { + if (fNodeListCache.fLength != -1) { + fNodeListCache.fLength--; + } + if (fNodeListCache.fChildIndex != -1) { + // if the removed node is the cached node + // move the cache to its (soon former) previous sibling + if (fNodeListCache.fChild == oldInternal) { + fNodeListCache.fChildIndex--; + fNodeListCache.fChild = oldPreviousSibling; + } else { + // otherwise just invalidate the cache + fNodeListCache.fChildIndex = -1; + } + } + } + + // Patch linked list around oldChild + // Note: lastChild == firstChild.previousSibling + if (oldInternal == firstChild) { + // removing first child + oldInternal.isFirstChild(false); + firstChild = oldInternal.nextSibling; + if (firstChild != null) { + firstChild.isFirstChild(true); + firstChild.previousSibling = oldInternal.previousSibling; + } + } else { + ChildNode prev = oldInternal.previousSibling; + ChildNode next = oldInternal.nextSibling; + prev.nextSibling = next; + if (next == null) { + // removing last child + firstChild.previousSibling = prev; + } else { + // removing some other child in the middle + next.previousSibling = prev; + } + } + + // Remove oldInternal's references to tree + oldInternal.ownerNode = ownerDocument; + oldInternal.isOwned(false); + oldInternal.nextSibling = null; + oldInternal.previousSibling = null; + + changed(); + + // notify document + ownerDocument.removedNode(this, replace); + + checkNormalizationAfterRemove(oldPreviousSibling); + + return oldInternal; + + } // internalRemoveChild(Node,boolean):Node + + /** + * Make newChild occupy the location that oldChild used to + * have. Note that newChild will first be removed from its previous + * parent, if any. Equivalent to inserting newChild before oldChild, + * then removing oldChild. + * + * @return oldChild, in its new state (removed). + * + * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a + * type that shouldn't be a child of this node, or if newChild is + * one of our ancestors. + * + * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a + * different owner document than we do. + * + * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of + * this node. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is + * read-only. + */ + public Node replaceChild(Node newChild, Node oldChild) + throws DOMException { + // If Mutation Events are being generated, this operation might + // throw aggregate events twice when modifying an Attr -- once + // on insertion and once on removal. DOM Level 2 does not specify + // this as either desirable or undesirable, but hints that + // aggregations should be issued only once per user request. + + // notify document + ownerDocument.replacingNode(this); + + internalInsertBefore(newChild, oldChild, true); + if (newChild != oldChild) { + internalRemoveChild(oldChild, true); + } + + // notify document + ownerDocument.replacedNode(this); + + return oldChild; + } + + /* + * Get Node text content + * @since DOM Level 3 + */ + public String getTextContent() throws DOMException { + Node child = getFirstChild(); + if (child != null) { + Node next = child.getNextSibling(); + if (next == null) { + return hasTextContent(child) ? ((NodeImpl) child).getTextContent() : ""; + } + StringBuffer buf = new StringBuffer(); + getTextContent(buf); + return buf.toString(); + } + return ""; + } + + // internal method taking a StringBuffer in parameter + void getTextContent(StringBuffer buf) throws DOMException { + Node child = getFirstChild(); + while (child != null) { + if (hasTextContent(child)) { + ((NodeImpl) child).getTextContent(buf); + } + child = child.getNextSibling(); + } + } + + // internal method returning whether to take the given node's text content + final boolean hasTextContent(Node child) { + return child.getNodeType() != Node.COMMENT_NODE && + child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE && + (child.getNodeType() != Node.TEXT_NODE || + ((TextImpl) child).isIgnorableWhitespace() == false); + } + + /* + * Set Node text content + * @since DOM Level 3 + */ + public void setTextContent(String textContent) + throws DOMException { + // get rid of any existing children + Node child; + while ((child = getFirstChild()) != null) { + removeChild(child); + } + // create a Text node to hold the given content + if (textContent != null && textContent.length() != 0){ + appendChild(ownerDocument().createTextNode(textContent)); + } + } + + // + // NodeList methods + // + + /** + * Count the immediate children of this node. Use to implement + * NodeList.getLength(). + * @return int + */ + private int nodeListGetLength() { + + if (fNodeListCache == null) { + if (needsSyncChildren()) { + synchronizeChildren(); + } + // get rid of trivial cases + if (firstChild == null) { + return 0; + } + if (firstChild == lastChild()) { + return 1; + } + // otherwise request a cache object + fNodeListCache = ownerDocument.getNodeListCache(this); + } + if (fNodeListCache.fLength == -1) { // is the cached length invalid ? + int l; + ChildNode n; + // start from the cached node if we have one + if (fNodeListCache.fChildIndex != -1 && + fNodeListCache.fChild != null) { + l = fNodeListCache.fChildIndex; + n = fNodeListCache.fChild; + } else { + n = firstChild; + l = 0; + } + while (n != null) { + l++; + n = n.nextSibling; + } + fNodeListCache.fLength = l; + } + + return fNodeListCache.fLength; + + } // nodeListGetLength():int + + /** + * NodeList method: Count the immediate children of this node + * @return int + */ + public int getLength() { + return nodeListGetLength(); + } + + /** + * Return the Nth immediate child of this node, or null if the index is + * out of bounds. Use to implement NodeList.item(). + * @param index int + */ + private Node nodeListItem(int index) { + + if (fNodeListCache == null) { + if (needsSyncChildren()) { + synchronizeChildren(); + } + // get rid of trivial case + if (firstChild == lastChild()) { + return index == 0 ? firstChild : null; + } + // otherwise request a cache object + fNodeListCache = ownerDocument.getNodeListCache(this); + } + int i = fNodeListCache.fChildIndex; + ChildNode n = fNodeListCache.fChild; + boolean firstAccess = true; + // short way + if (i != -1 && n != null) { + firstAccess = false; + if (i < index) { + while (i < index && n != null) { + i++; + n = n.nextSibling; + } + } + else if (i > index) { + while (i > index && n != null) { + i--; + n = n.previousSibling(); + } + } + } + else { + // long way + if (index < 0) { + return null; + } + n = firstChild; + for (i = 0; i < index && n != null; i++) { + n = n.nextSibling; + } + } + + // release cache if reaching last child or first child + if (!firstAccess && (n == firstChild || n == lastChild())) { + fNodeListCache.fChildIndex = -1; + fNodeListCache.fChild = null; + ownerDocument.freeNodeListCache(fNodeListCache); + // we can keep using the cache until it is actually reused + // fNodeListCache will be nulled by the pool (document) if that + // happens. + // fNodeListCache = null; + } + else { + // otherwise update it + fNodeListCache.fChildIndex = i; + fNodeListCache.fChild = n; + } + return n; + + } // nodeListItem(int):Node + + /** + * NodeList method: Return the Nth immediate child of this node, or + * null if the index is out of bounds. + * @return org.w3c.dom.Node + * @param index int + */ + public Node item(int index) { + return nodeListItem(index); + } // item(int):Node + + /** + * Create a NodeList to access children that is use by subclass elements + * that have methods named getLength() or item(int). ChildAndParentNode + * optimizes getChildNodes() by implementing NodeList itself. However if + * a subclass Element implements methods with the same name as the NodeList + * methods, they will override the actually methods in this class. + *

+ * To use this method, the subclass should implement getChildNodes() and + * have it call this method. The resulting NodeList instance maybe + * shared and cached in a transient field, but the cached value must be + * cleared if the node is cloned. + */ + protected final NodeList getChildNodesUnoptimized() { + if (needsSyncChildren()) { + synchronizeChildren(); + } + return new NodeList() { + /** + * @see NodeList.getLength() + */ + public int getLength() { + return nodeListGetLength(); + } // getLength():int + + /** + * @see NodeList.item(int) + */ + public Node item(int index) { + return nodeListItem(index); + } // item(int):Node + }; + } // getChildNodesUnoptimized():NodeList + + // + // DOM2: methods, getters, setters + // + + /** + * Override default behavior to call normalize() on this Node's + * children. It is up to implementors or Node to override normalize() + * to take action. + */ + public void normalize() { + // No need to normalize if already normalized. + if (isNormalized()) { + return; + } + if (needsSyncChildren()) { + synchronizeChildren(); + } + ChildNode kid; + for (kid = firstChild; kid != null; kid = kid.nextSibling) { + kid.normalize(); + } + isNormalized(true); + } + + /** + * DOM Level 3 WD- Experimental. + * Override inherited behavior from NodeImpl to support deep equal. + */ + public boolean isEqualNode(Node arg) { + if (!super.isEqualNode(arg)) { + return false; + } + // there are many ways to do this test, and there isn't any way + // better than another. Performance may vary greatly depending on + // the implementations involved. This one should work fine for us. + Node child1 = getFirstChild(); + Node child2 = arg.getFirstChild(); + while (child1 != null && child2 != null) { + if (!child1.isEqualNode(child2)) { + return false; + } + child1 = child1.getNextSibling(); + child2 = child2.getNextSibling(); + } + if (child1 != child2) { + return false; + } + return true; + } + + // + // Public methods + // + + /** + * Override default behavior so that if deep is true, children are also + * toggled. + * @see Node + *

+ * Note: this will not change the state of an EntityReference or its + * children, which are always read-only. + */ + public void setReadOnly(boolean readOnly, boolean deep) { + + super.setReadOnly(readOnly, deep); + + if (deep) { + + if (needsSyncChildren()) { + synchronizeChildren(); + } + + // Recursively set kids + for (ChildNode mykid = firstChild; + mykid != null; + mykid = mykid.nextSibling) { + if (mykid.getNodeType() != Node.ENTITY_REFERENCE_NODE) { + mykid.setReadOnly(readOnly,true); + } + } + } + } // setReadOnly(boolean,boolean) + + // + // Protected methods + // + + /** + * Override this method in subclass to hook in efficient + * internal data structure. + */ + protected void synchronizeChildren() { + // By default just change the flag to avoid calling this method again + needsSyncChildren(false); + } + + /** + * Checks the normalized state of this node after inserting a child. + * If the inserted child causes this node to be unnormalized, then this + * node is flagged accordingly. + * The conditions for changing the normalized state are: + *

    + *
  • The inserted child is a text node and one of its adjacent siblings + * is also a text node. + *
  • The inserted child is is itself unnormalized. + *
+ * + * @param insertedChild the child node that was inserted into this node + * + * @throws NullPointerException if the inserted child is null + */ + void checkNormalizationAfterInsert(ChildNode insertedChild) { + // See if insertion caused this node to be unnormalized. + if (insertedChild.getNodeType() == Node.TEXT_NODE) { + ChildNode prev = insertedChild.previousSibling(); + ChildNode next = insertedChild.nextSibling; + // If an adjacent sibling of the new child is a text node, + // flag this node as unnormalized. + if ((prev != null && prev.getNodeType() == Node.TEXT_NODE) || + (next != null && next.getNodeType() == Node.TEXT_NODE)) { + isNormalized(false); + } + } + else { + // If the new child is not normalized, + // then this node is inherently not normalized. + if (!insertedChild.isNormalized()) { + isNormalized(false); + } + } + } // checkNormalizationAfterInsert(ChildNode) + + /** + * Checks the normalized of this node after removing a child. + * If the removed child causes this node to be unnormalized, then this + * node is flagged accordingly. + * The conditions for changing the normalized state are: + *
    + *
  • The removed child had two adjacent siblings that were text nodes. + *
+ * + * @param previousSibling the previous sibling of the removed child, or + * null + */ + void checkNormalizationAfterRemove(ChildNode previousSibling) { + // See if removal caused this node to be unnormalized. + // If the adjacent siblings of the removed child were both text nodes, + // flag this node as unnormalized. + if (previousSibling != null && + previousSibling.getNodeType() == Node.TEXT_NODE) { + + ChildNode next = previousSibling.nextSibling; + if (next != null && next.getNodeType() == Node.TEXT_NODE) { + isNormalized(false); + } + } + } // checkNormalizationAfterRemove(Node) + + // + // Serialization methods + // + + /** Serialize object. */ + private void writeObject(ObjectOutputStream out) throws IOException { + + // synchronize children + if (needsSyncChildren()) { + synchronizeChildren(); + } + // write object + out.defaultWriteObject(); + + } // writeObject(ObjectOutputStream) + + /** Deserialize object. */ + private void readObject(ObjectInputStream ois) + throws ClassNotFoundException, IOException { + + // perform default deseralization + ois.defaultReadObject(); + + // hardset synchildren - so we don't try to sync - it does not make any + // sense to try to synchildren when we just deserialize object. + needsSyncChildren(false); + + } // readObject(ObjectInputStream) + + /* + * a class to store some user data along with its handler + */ + class UserDataRecord implements Serializable { + /** Serialization version. */ + private static final long serialVersionUID = 3258126977134310455L; + + Object fData; + UserDataHandler fHandler; + UserDataRecord(Object data, UserDataHandler handler) { + fData = data; + fHandler = handler; + } + } +} // class ParentNode diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/ProcessingInstructionImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/ProcessingInstructionImpl.java new file mode 100644 index 0000000..bbe5ecb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/ProcessingInstructionImpl.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; + +/** + * Processing Instructions (PIs) permit documents to carry + * processor-specific information alongside their actual content. PIs + * are most common in XML, but they are supported in HTML as well. + * + * This class inherits from CharacterDataImpl to reuse its setNodeValue method. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class ProcessingInstructionImpl + extends CharacterDataImpl + implements ProcessingInstruction { + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = 7554435174099981510L; + + // + // Data + // + + protected String target; + + // + // Constructors + // + + /** Factory constructor. */ + public ProcessingInstructionImpl(CoreDocumentImpl ownerDoc, + String target, String data) { + super(ownerDoc, data); + this.target = target; + } + + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.PROCESSING_INSTRUCTION_NODE; + } + + /** + * Returns the target + */ + public String getNodeName() { + if (needsSyncData()) { + synchronizeData(); + } + return target; + } + + // + // ProcessingInstruction methods + // + + /** + * A PI's "target" states what processor channel the PI's data + * should be directed to. It is defined differently in HTML and XML. + *

+ * In XML, a PI's "target" is the first (whitespace-delimited) token + * following the " + * In HTML, target is always null. + *

+ * Note that getNodeName is aliased to getTarget. + */ + public String getTarget() { + if (needsSyncData()) { + synchronizeData(); + } + return target; + + } // getTarget():String + + /** + * Returns the absolute base URI of this node or null if the implementation + * wasn't able to obtain an absolute URI. Note: If the URI is malformed, a + * null is returned. + * + * @return The absolute base URI of this node or null. + * @since DOM Level 3 + */ + public String getBaseURI() { + + if (needsSyncData()) { + synchronizeData(); + } + return ownerNode.getBaseURI(); + } + + +} // class ProcessingInstructionImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/RangeExceptionImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/RangeExceptionImpl.java new file mode 100644 index 0000000..f9a2316 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/RangeExceptionImpl.java @@ -0,0 +1,35 @@ +/* + * 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. + */ +package org.apache.xerces.dom; + +import org.w3c.dom.ranges.RangeException; + +/** + * @xerces.internal + * + * @version $Id$ + */ + +public class RangeExceptionImpl extends RangeException { + + /** Serialization version. */ + static final long serialVersionUID = -9058052627467240856L; + + public RangeExceptionImpl(short code, String message) { + super(code,message); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/RangeImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/RangeImpl.java new file mode 100644 index 0000000..a05bfdd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/RangeImpl.java @@ -0,0 +1,2099 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.util.ArrayList; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import org.w3c.dom.ranges.Range; +import org.w3c.dom.ranges.RangeException; + +/** + * The RangeImpl class implements the org.w3c.dom.range.Range interface. + *

Please see the API documentation for the interface classes + * and use the interfaces in your client programs. + * + * @xerces.internal + * + * @version $Id$ + */ +public class RangeImpl implements Range { + + // + // Constants + // + + + // + // Data + // + + private DocumentImpl fDocument; + private Node fStartContainer; + private Node fEndContainer; + private int fStartOffset; + private int fEndOffset; + private boolean fDetach = false; + private Node fInsertNode = null; + private Node fDeleteNode = null; + private Node fSplitNode = null; + // Was the Node inserted from the Range or the Document + private boolean fInsertedFromRange = false; + + /** The constructor. Clients must use DocumentRange.createRange(), + * because it registers the Range with the document, so it can + * be fixed-up. + */ + public RangeImpl(DocumentImpl document) { + fDocument = document; + fStartContainer = document; + fEndContainer = document; + fStartOffset = 0; + fEndOffset = 0; + fDetach = false; + } + + public Node getStartContainer() { + if ( fDetach ) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + return fStartContainer; + } + + public int getStartOffset() { + if ( fDetach ) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + return fStartOffset; + } + + public Node getEndContainer() { + if ( fDetach ) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + return fEndContainer; + } + + public int getEndOffset() { + if ( fDetach ) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + return fEndOffset; + } + + public boolean getCollapsed() { + if ( fDetach ) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + return (fStartContainer == fEndContainer + && fStartOffset == fEndOffset); + } + + public Node getCommonAncestorContainer() { + if ( fDetach ) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + ArrayList startV = new ArrayList(); + Node node; + for (node=fStartContainer; node != null; + node=node.getParentNode()) + { + startV.add(node); + } + ArrayList endV = new ArrayList(); + for (node=fEndContainer; node != null; + node=node.getParentNode()) + { + endV.add(node); + } + int s = startV.size()-1; + int e = endV.size()-1; + Object result = null; + while (s>=0 && e>=0) { + if (startV.get(s) == endV.get(e)) { + result = startV.get(s); + } else { + break; + } + --s; + --e; + } + return (Node)result; + } + + + public void setStart(Node refNode, int offset) + throws RangeException, DOMException + { + if (fDocument.errorChecking) { + if ( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( !isLegalContainer(refNode)) { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + if ( fDocument != refNode.getOwnerDocument() && fDocument != refNode) { + throw new DOMException( + DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + + checkIndex(refNode, offset); + + fStartContainer = refNode; + fStartOffset = offset; + + // If one boundary-point of a Range is set to have a root container + // other + // than the current one for the Range, the Range should be collapsed to + // the new position. + // The start position of a Range should never be after the end position. + if (getCommonAncestorContainer() == null + || (fStartContainer == fEndContainer && fEndOffset < fStartOffset)) { + collapse(true); + } + } + + public void setEnd(Node refNode, int offset) + throws RangeException, DOMException + { + if (fDocument.errorChecking) { + if (fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( !isLegalContainer(refNode)) { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + if ( fDocument != refNode.getOwnerDocument() && fDocument != refNode) { + throw new DOMException( + DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + + checkIndex(refNode, offset); + + fEndContainer = refNode; + fEndOffset = offset; + + // If one boundary-point of a Range is set to have a root container + // other + // than the current one for the Range, the Range should be collapsed to + // the new position. + // The start position of a Range should never be after the end position. + if (getCommonAncestorContainer() == null + || (fStartContainer == fEndContainer && fEndOffset < fStartOffset)) { + collapse(false); + } + } + + public void setStartBefore(Node refNode) + throws RangeException + { + if (fDocument.errorChecking) { + if (fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( !hasLegalRootContainer(refNode) || + !isLegalContainedNode(refNode) ) + { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + if ( fDocument != refNode.getOwnerDocument() && fDocument != refNode) { + throw new DOMException( + DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + + fStartContainer = refNode.getParentNode(); + int i = 0; + for (Node n = refNode; n!=null; n = n.getPreviousSibling()) { + i++; + } + fStartOffset = i-1; + + // If one boundary-point of a Range is set to have a root container + // other + // than the current one for the Range, the Range should be collapsed to + // the new position. + // The start position of a Range should never be after the end position. + if (getCommonAncestorContainer() == null + || (fStartContainer == fEndContainer && fEndOffset < fStartOffset)) { + collapse(true); + } + } + + public void setStartAfter(Node refNode) + throws RangeException + { + if (fDocument.errorChecking) { + if (fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( !hasLegalRootContainer(refNode) || + !isLegalContainedNode(refNode)) { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + if ( fDocument != refNode.getOwnerDocument() && fDocument != refNode) { + throw new DOMException( + DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + fStartContainer = refNode.getParentNode(); + int i = 0; + for (Node n = refNode; n!=null; n = n.getPreviousSibling()) { + i++; + } + fStartOffset = i; + + // If one boundary-point of a Range is set to have a root container + // other + // than the current one for the Range, the Range should be collapsed to + // the new position. + // The start position of a Range should never be after the end position. + if (getCommonAncestorContainer() == null + || (fStartContainer == fEndContainer && fEndOffset < fStartOffset)) { + collapse(true); + } + } + + public void setEndBefore(Node refNode) + throws RangeException + { + if (fDocument.errorChecking) { + if (fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( !hasLegalRootContainer(refNode) || + !isLegalContainedNode(refNode)) { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + if ( fDocument != refNode.getOwnerDocument() && fDocument != refNode) { + throw new DOMException( + DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + fEndContainer = refNode.getParentNode(); + int i = 0; + for (Node n = refNode; n!=null; n = n.getPreviousSibling()) { + i++; + } + fEndOffset = i-1; + + // If one boundary-point of a Range is set to have a root container + // other + // than the current one for the Range, the Range should be collapsed to + // the new position. + // The start position of a Range should never be after the end position. + if (getCommonAncestorContainer() == null + || (fStartContainer == fEndContainer && fEndOffset < fStartOffset)) { + collapse(false); + } + } + + public void setEndAfter(Node refNode) + throws RangeException + { + if (fDocument.errorChecking) { + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( !hasLegalRootContainer(refNode) || + !isLegalContainedNode(refNode)) { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + if ( fDocument != refNode.getOwnerDocument() && fDocument != refNode) { + throw new DOMException( + DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + fEndContainer = refNode.getParentNode(); + int i = 0; + for (Node n = refNode; n!=null; n = n.getPreviousSibling()) { + i++; + } + fEndOffset = i; + + // If one boundary-point of a Range is set to have a root container + // other + // than the current one for the Range, the Range should be collapsed to + // the new position. + // The start position of a Range should never be after the end position. + if (getCommonAncestorContainer() == null + || (fStartContainer == fEndContainer && fEndOffset < fStartOffset)) { + collapse(false); + } + } + + public void collapse(boolean toStart) { + + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + + if (toStart) { + fEndContainer = fStartContainer; + fEndOffset = fStartOffset; + } else { + fStartContainer = fEndContainer; + fStartOffset = fEndOffset; + } + } + + public void selectNode(Node refNode) + throws RangeException + { + if (fDocument.errorChecking) { + if (fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( !isLegalContainer( refNode.getParentNode() ) || + !isLegalContainedNode( refNode ) ) { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + if ( fDocument != refNode.getOwnerDocument() && fDocument != refNode) { + throw new DOMException( + DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + Node parent = refNode.getParentNode(); + if (parent != null ) // REVIST: what to do if it IS null? + { + fStartContainer = parent; + fEndContainer = parent; + int i = 0; + for (Node n = refNode; n!=null; n = n.getPreviousSibling()) { + i++; + } + fStartOffset = i-1; + fEndOffset = fStartOffset+1; + } + } + + public void selectNodeContents(Node refNode) + throws RangeException + { + if (fDocument.errorChecking) { + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( !isLegalContainer(refNode)) { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + if ( fDocument != refNode.getOwnerDocument() && fDocument != refNode) { + throw new DOMException( + DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + fStartContainer = refNode; + fEndContainer = refNode; + Node first = refNode.getFirstChild(); + fStartOffset = 0; + if (first == null) { + fEndOffset = 0; + } else { + int i = 0; + for (Node n = first; n!=null; n = n.getNextSibling()) { + i++; + } + fEndOffset = i; + } + + } + + public short compareBoundaryPoints(short how, Range sourceRange) + throws DOMException + { + if (fDocument.errorChecking) { + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + // WRONG_DOCUMENT_ERR: Raised if the two Ranges are not in the same Document or DocumentFragment. + if ((fDocument != sourceRange.getStartContainer().getOwnerDocument() + && fDocument != sourceRange.getStartContainer() + && sourceRange.getStartContainer() != null) + || (fDocument != sourceRange.getEndContainer().getOwnerDocument() + && fDocument != sourceRange.getEndContainer() + && sourceRange.getStartContainer() != null)) { + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage( DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + } + + Node endPointA; + Node endPointB; + int offsetA; + int offsetB; + + if (how == START_TO_START) { + endPointA = sourceRange.getStartContainer(); + endPointB = fStartContainer; + offsetA = sourceRange.getStartOffset(); + offsetB = fStartOffset; + } else + if (how == START_TO_END) { + endPointA = sourceRange.getStartContainer(); + endPointB = fEndContainer; + offsetA = sourceRange.getStartOffset(); + offsetB = fEndOffset; + } else + if (how == END_TO_START) { + endPointA = sourceRange.getEndContainer(); + endPointB = fStartContainer; + offsetA = sourceRange.getEndOffset(); + offsetB = fStartOffset; + } else { + endPointA = sourceRange.getEndContainer(); + endPointB = fEndContainer; + offsetA = sourceRange.getEndOffset(); + offsetB = fEndOffset; + } + + // The DOM Spec outlines four cases that need to be tested + // to compare two range boundary points: + // case 1: same container + // case 2: Child C of container A is ancestor of B + // case 3: Child C of container B is ancestor of A + // case 4: preorder traversal of context tree. + + // case 1: same container + if (endPointA == endPointB) { + if (offsetA < offsetB) return 1; + if (offsetA == offsetB) return 0; + return -1; + } + // case 2: Child C of container A is ancestor of B + // This can be quickly tested by walking the parent chain of B + for ( Node c = endPointB, p = c.getParentNode(); + p != null; + c = p, p = p.getParentNode()) + { + if (p == endPointA) { + int index = indexOf(c, endPointA); + if (offsetA <= index) return 1; + return -1; + } + } + + // case 3: Child C of container B is ancestor of A + // This can be quickly tested by walking the parent chain of A + for ( Node c = endPointA, p = c.getParentNode(); + p != null; + c = p, p = p.getParentNode()) + { + if (p == endPointB) { + int index = indexOf(c, endPointB); + if (index < offsetB) return 1; + return -1; + } + } + + // case 4: preorder traversal of context tree. + // Instead of literally walking the context tree in pre-order, + // we use relative node depth walking which is usually faster + + int depthDiff = 0; + for ( Node n = endPointA; n != null; n = n.getParentNode() ) + depthDiff++; + for ( Node n = endPointB; n != null; n = n.getParentNode() ) + depthDiff--; + while (depthDiff > 0) { + endPointA = endPointA.getParentNode(); + depthDiff--; + } + while (depthDiff < 0) { + endPointB = endPointB.getParentNode(); + depthDiff++; + } + for (Node pA = endPointA.getParentNode(), + pB = endPointB.getParentNode(); + pA != pB; + pA = pA.getParentNode(), pB = pB.getParentNode() ) + { + endPointA = pA; + endPointB = pB; + } + for ( Node n = endPointA.getNextSibling(); + n != null; + n = n.getNextSibling() ) + { + if (n == endPointB) { + return 1; + } + } + return -1; + } + + public void deleteContents() + throws DOMException + { + traverseContents(DELETE_CONTENTS); + } + + public DocumentFragment extractContents() + throws DOMException + { + return traverseContents(EXTRACT_CONTENTS); + } + + public DocumentFragment cloneContents() + throws DOMException + { + return traverseContents(CLONE_CONTENTS); + } + + public void insertNode(Node newNode) + throws DOMException, RangeException + { + if ( newNode == null ) return; //throw exception? + + int type = newNode.getNodeType(); + + if (fDocument.errorChecking) { + if (fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if ( fDocument != newNode.getOwnerDocument() ) { + throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + } + + if (type == Node.ATTRIBUTE_NODE + || type == Node.ENTITY_NODE + || type == Node.NOTATION_NODE + || type == Node.DOCUMENT_NODE) + { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + } + Node cloneCurrent; + Node current; + int currentChildren = 0; + fInsertedFromRange = true; + + //boolean MULTIPLE_MODE = false; + if (fStartContainer.getNodeType() == Node.TEXT_NODE) { + + Node parent = fStartContainer.getParentNode(); + currentChildren = parent.getChildNodes().getLength(); //holds number of kids before insertion + // split text node: results is 3 nodes.. + cloneCurrent = fStartContainer.cloneNode(false); + ((TextImpl)cloneCurrent).setNodeValueInternal( + (cloneCurrent.getNodeValue()).substring(fStartOffset)); + ((TextImpl)fStartContainer).setNodeValueInternal( + (fStartContainer.getNodeValue()).substring(0,fStartOffset)); + Node next = fStartContainer.getNextSibling(); + if (next != null) { + if (parent != null) { + parent.insertBefore(newNode, next); + parent.insertBefore(cloneCurrent, next); + } + } else { + if (parent != null) { + parent.appendChild(newNode); + parent.appendChild(cloneCurrent); + } + } + //update ranges after the insertion + if ( fEndContainer == fStartContainer) { + fEndContainer = cloneCurrent; //endContainer is the new Node created + fEndOffset -= fStartOffset; + } + else if ( fEndContainer == parent ) { //endContainer was not a text Node. + //endOffset + = number_of_children_added + fEndOffset += (parent.getChildNodes().getLength() - currentChildren); + } + + // signal other Ranges to update their start/end containers/offsets + signalSplitData(fStartContainer, cloneCurrent, fStartOffset); + + + } else { // ! TEXT_NODE + if ( fEndContainer == fStartContainer ) //need to remember number of kids + currentChildren= fEndContainer.getChildNodes().getLength(); + + current = fStartContainer.getFirstChild(); + int i = 0; + for(i = 0; i < fStartOffset && current != null; i++) { + current=current.getNextSibling(); + } + if (current != null) { + fStartContainer.insertBefore(newNode, current); + } else { + fStartContainer.appendChild(newNode); + } + //update fEndOffset. ex:

. Range(start;end): body,0; body,1 + // insert

:

. Range(start;end): body,0; body,2 + if ( fEndContainer == fStartContainer && fEndOffset != 0 ) { //update fEndOffset if not 0 + fEndOffset += (fEndContainer.getChildNodes().getLength() - currentChildren); + } + } + fInsertedFromRange = false; + } + + public void surroundContents(Node newParent) + throws DOMException, RangeException + { + if (newParent==null) return; + int type = newParent.getNodeType(); + + if (fDocument.errorChecking) { + if (fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + if (type == Node.ATTRIBUTE_NODE + || type == Node.ENTITY_NODE + || type == Node.NOTATION_NODE + || type == Node.DOCUMENT_TYPE_NODE + || type == Node.DOCUMENT_NODE + || type == Node.DOCUMENT_FRAGMENT_NODE) + { + throw new RangeExceptionImpl( + RangeException.INVALID_NODE_TYPE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_NODE_TYPE_ERR", null)); + } + } + + Node realStart = fStartContainer; + Node realEnd = fEndContainer; + if (fStartContainer.getNodeType() == Node.TEXT_NODE) { + realStart = fStartContainer.getParentNode(); + } + if (fEndContainer.getNodeType() == Node.TEXT_NODE) { + realEnd = fEndContainer.getParentNode(); + } + + if (realStart != realEnd) { + throw new RangeExceptionImpl( + RangeException.BAD_BOUNDARYPOINTS_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "BAD_BOUNDARYPOINTS_ERR", null)); + } + + DocumentFragment frag = extractContents(); + insertNode(newParent); + newParent.appendChild(frag); + selectNode(newParent); + } + + public Range cloneRange(){ + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + + Range range = fDocument.createRange(); + range.setStart(fStartContainer, fStartOffset); + range.setEnd(fEndContainer, fEndOffset); + return range; + } + + public String toString(){ + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + + Node node = fStartContainer; + Node stopNode = fEndContainer; + StringBuffer sb = new StringBuffer(); + if (fStartContainer.getNodeType() == Node.TEXT_NODE + || fStartContainer.getNodeType() == Node.CDATA_SECTION_NODE + ) { + if (fStartContainer == fEndContainer) { + sb.append(fStartContainer.getNodeValue().substring(fStartOffset, fEndOffset)); + return sb.toString(); + } + sb.append(fStartContainer.getNodeValue().substring(fStartOffset)); + node=nextNode (node,true); //fEndContainer!=fStartContainer + + } + else { //fStartContainer is not a TextNode + node=node.getFirstChild(); + if (fStartOffset>0) { //find a first node within a range, specified by fStartOffset + int counter=0; + while (counter0 && stopNode!=null ){ + --i; + stopNode = stopNode.getNextSibling(); + } + if ( stopNode == null ) + stopNode = nextNode( fEndContainer, false ); + } + while (node != stopNode) { //look into all kids of the Range + if (node == null) break; + if (node.getNodeType() == Node.TEXT_NODE + || node.getNodeType() == Node.CDATA_SECTION_NODE) { + sb.append(node.getNodeValue()); + } + + node = nextNode(node, true); + } + + if (fEndContainer.getNodeType() == Node.TEXT_NODE + || fEndContainer.getNodeType() == Node.CDATA_SECTION_NODE) { + sb.append(fEndContainer.getNodeValue().substring(0,fEndOffset)); + } + return sb.toString(); + } + + public void detach() { + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + fDetach = true; + fDocument.removeRange(this); + } + + // + // Mutation functions + // + + /** Signal other Ranges to update their start/end + * containers/offsets. The data has already been split + * into the two Nodes. + */ + void signalSplitData(Node node, Node newNode, int offset) { + fSplitNode = node; + // notify document + fDocument.splitData(node, newNode, offset); + fSplitNode = null; + } + + /** Fix up this Range if another Range has split a Text Node + * into 2 Nodes. + */ + void receiveSplitData(Node node, Node newNode, int offset) { + if (node == null || newNode == null) return; + if (fSplitNode == node) return; + + if (node == fStartContainer + && fStartContainer.getNodeType() == Node.TEXT_NODE) { + if (fStartOffset > offset) { + fStartOffset = fStartOffset - offset; + fStartContainer = newNode; + } + } + if (node == fEndContainer + && fEndContainer.getNodeType() == Node.TEXT_NODE) { + if (fEndOffset > offset) { + fEndOffset = fEndOffset-offset; + fEndContainer = newNode; + } + } + + } + + /** This function inserts text into a Node and invokes + * a method to fix-up all other Ranges. + */ + void deleteData(CharacterData node, int offset, int count) { + fDeleteNode = node; + node.deleteData( offset, count); + fDeleteNode = null; + } + + + /** This function is called from DOM. + * The text has already beeen inserted. + * Fix-up any offsets. + */ + void receiveDeletedText(CharacterDataImpl node, int offset, int count) { + if (node == null) return; + if (fDeleteNode == node) return; + if (node == fStartContainer) { + if (fStartOffset > offset + count) { + fStartOffset = offset + (fStartOffset - (offset + count)); + } + else if (fStartOffset > offset) { + fStartOffset = offset; + } + } + if (node == fEndContainer) { + if (fEndOffset > offset + count) { + fEndOffset = offset + (fEndOffset - (offset + count)); + } + else if (fEndOffset > offset) { + fEndOffset = offset; + } + } + + } + + /** This function inserts text into a Node and invokes + * a method to fix-up all other Ranges. + */ + void insertData(CharacterData node, int index, String insert) { + fInsertNode = node; + node.insertData( index, insert); + fInsertNode = null; + } + + + /** + * This function is called from DOM. + * The text has already beeen inserted. + * Fix-up any offsets. + */ + void receiveInsertedText(CharacterDataImpl node, int index, int len) { + if (node == null) return; + if (fInsertNode == node) return; + if (node == fStartContainer) { + if (index < fStartOffset) { + fStartOffset = fStartOffset + len; + } + } + if (node == fEndContainer) { + if (index < fEndOffset) { + fEndOffset = fEndOffset + len; + } + } + } + + /** + * This function is called from DOM. + * The text has already beeen replaced. + * Fix-up any offsets. + */ + void receiveReplacedText(CharacterDataImpl node) { + if (node == null) return; + if (node == fStartContainer) { + fStartOffset = 0; + } + if (node == fEndContainer) { + fEndOffset = 0; + } + } + + /** This function is called from the DOM. + * This node has already been inserted into the DOM. + * Fix-up any offsets. + */ + public void insertedNodeFromDOM(Node node) { + if (node == null) return; + if (fInsertNode == node) return; + if (fInsertedFromRange) return; // Offsets are adjusted in Range.insertNode + + Node parent = node.getParentNode(); + + if (parent == fStartContainer) { + int index = indexOf(node, fStartContainer); + if (index < fStartOffset) { + fStartOffset++; + } + } + + if (parent == fEndContainer) { + int index = indexOf(node, fEndContainer); + if (index < fEndOffset) { + fEndOffset++; + } + } + + } + + /** This function is called within Range + * instead of Node.removeChild, + * so that the range can remember that it is actively + * removing this child. + */ + + private Node fRemoveChild = null; + Node removeChild(Node parent, Node child) { + fRemoveChild = child; + Node n = parent.removeChild(child); + fRemoveChild = null; + return n; + } + + /** This function must be called by the DOM _BEFORE_ + * a node is deleted, because at that time it is + * connected in the DOM tree, which we depend on. + */ + void removeNode(Node node) { + if (node == null) return; + if (fRemoveChild == node) return; + + Node parent = node.getParentNode(); + + if (parent == fStartContainer) { + int index = indexOf(node, fStartContainer); + if (index < fStartOffset) { + fStartOffset--; + } + } + + if (parent == fEndContainer) { + int index = indexOf(node, fEndContainer); + if (index < fEndOffset) { + fEndOffset--; + } + } + //startContainer or endContainer or both is/are the ancestor(s) of the Node to be deleted + if (parent != fStartContainer + || parent != fEndContainer) { + if (isAncestorOf(node, fStartContainer)) { + fStartContainer = parent; + fStartOffset = indexOf( node, parent); + } + if (isAncestorOf(node, fEndContainer)) { + fEndContainer = parent; + fEndOffset = indexOf( node, parent); + } + } + + } + + // + // Utility functions. + // + + // parameters for traverseContents(int) + //REVIST: use boolean, since there are only 2 now... + static final int EXTRACT_CONTENTS = 1; + static final int CLONE_CONTENTS = 2; + static final int DELETE_CONTENTS = 3; + + /** + * This is the master routine invoked to visit the nodes + * selected by this range. For each such node, different + * actions are taken depending on the value of the + * how argument. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *

    + *
  1. EXTRACT_CONTENTS - will produce + * a document fragment containing the range's content. + * Partially selected nodes are copied, but fully + * selected nodes are moved. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but sill + * produced cloned content in a document fragment + * + *
  3. DELETE_CONTENTS - will delete from + * the context tree of the range, all fully selected + * nodes. + *
+ * + * @return Returns a document fragment containing any + * copied or extracted nodes. If the how + * parameter was DELETE_CONTENTS, the + * return value is null. + */ + private DocumentFragment traverseContents( int how ) + throws DOMException + { + if (fStartContainer == null || fEndContainer == null) { + return null; // REVIST: Throw exception? + } + + //Check for a detached range. + if( fDetach) { + throw new DOMException( + DOMException.INVALID_STATE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null)); + } + + /* + Traversal is accomplished by first determining the + relationship between the endpoints of the range. + For each of four significant relationships, we will + delegate the traversal call to a method that + can make appropriate assumptions. + */ + + // case 1: same container + if ( fStartContainer == fEndContainer ) + return traverseSameContainer( how ); + + + // case 2: Child C of start container is ancestor of end container + // This can be quickly tested by walking the parent chain of + // end container + int endContainerDepth = 0; + for ( Node c = fEndContainer, p = c.getParentNode(); + p != null; + c = p, p = p.getParentNode()) + { + if (p == fStartContainer) + return traverseCommonStartContainer( c, how ); + ++endContainerDepth; + } + + // case 3: Child C of container B is ancestor of A + // This can be quickly tested by walking the parent chain of A + int startContainerDepth = 0; + for ( Node c = fStartContainer, p = c.getParentNode(); + p != null; + c = p, p = p.getParentNode()) + { + if (p == fEndContainer) + return traverseCommonEndContainer( c, how ); + ++startContainerDepth; + } + + // case 4: There is a common ancestor container. Find the + // ancestor siblings that are children of that container. + int depthDiff = startContainerDepth - endContainerDepth; + + Node startNode = fStartContainer; + while (depthDiff > 0) { + startNode = startNode.getParentNode(); + depthDiff--; + } + + Node endNode = fEndContainer; + while (depthDiff < 0) { + endNode = endNode.getParentNode(); + depthDiff++; + } + + // ascend the ancestor hierarchy until we have a common parent. + for( Node sp = startNode.getParentNode(), ep = endNode.getParentNode(); + sp!=ep; + sp = sp.getParentNode(), ep = ep.getParentNode() ) + { + startNode = sp; + endNode = ep; + } + return traverseCommonAncestors( startNode, endNode, how ); + } + + /** + * Visits the nodes selected by this range when we know + * a-priori that the start and end containers are the same. + * This method is invoked by the generic traverse + * method. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *
    + *
  1. EXTRACT_CONTENTS - will produce + * a document fragment containing the range's content. + * Partially selected nodes are copied, but fully + * selected nodes are moved. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but sill + * produced cloned content in a document fragment + * + *
  3. DELETE_CONTENTS - will delete from + * the context tree of the range, all fully selected + * nodes. + *
+ * + * @return Returns a document fragment containing any + * copied or extracted nodes. If the how + * parameter was DELETE_CONTENTS, the + * return value is null. + */ + private DocumentFragment traverseSameContainer( int how ) + { + DocumentFragment frag = null; + if (how != DELETE_CONTENTS) { + frag = fDocument.createDocumentFragment(); + } + + // If selection is empty, just return the fragment + if (fStartOffset == fEndOffset) { + return frag; + } + + // Text, CDATASection, Comment and ProcessingInstruction nodes need special case handling + final short nodeType = fStartContainer.getNodeType(); + if (nodeType == Node.TEXT_NODE || + nodeType == Node.CDATA_SECTION_NODE || + nodeType == Node.COMMENT_NODE || + nodeType == Node.PROCESSING_INSTRUCTION_NODE) { + // get the substring + String s = fStartContainer.getNodeValue(); + String sub = s.substring(fStartOffset, fEndOffset); + + // set the original text node to its new value + if (how != CLONE_CONTENTS) { + ((CharacterDataImpl)fStartContainer).deleteData(fStartOffset, + fEndOffset-fStartOffset); + // Nothing is partially selected, so collapse to start point + collapse(true); + } + if (how == DELETE_CONTENTS) { + return null; + } + if (nodeType == Node.TEXT_NODE) { + frag.appendChild(fDocument.createTextNode(sub)); + } + else if (nodeType == Node.CDATA_SECTION_NODE) { + frag.appendChild(fDocument.createCDATASection(sub)); + } + else if (nodeType == Node.COMMENT_NODE) { + frag.appendChild(fDocument.createComment(sub)); + } + else { // nodeType == Node.PROCESSING_INSTRUCTION_NODE + frag.appendChild(fDocument.createProcessingInstruction(fStartContainer.getNodeName(), sub)); + } + return frag; + } + + // Copy nodes between the start/end offsets. + Node n = getSelectedNode( fStartContainer, fStartOffset ); + int cnt = fEndOffset - fStartOffset; + while( cnt > 0 ) { + Node sibling = n.getNextSibling(); + Node xferNode = traverseFullySelected( n, how ); + if ( frag!=null ) + frag.appendChild( xferNode ); + --cnt; + n = sibling; + } + + // Nothing is partially selected, so collapse to start point + if (how != CLONE_CONTENTS) { + collapse(true); + } + return frag; + } + + /** + * Visits the nodes selected by this range when we know + * a-priori that the start and end containers are not the + * same, but the start container is an ancestor of the + * end container. This method is invoked by the generic + * traverse method. + * + * @param endAncestor + * The ancestor of the end container that is a direct child + * of the start container. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *
    + *
  1. EXTRACT_CONTENTS - will produce + * a document fragment containing the range's content. + * Partially selected nodes are copied, but fully + * selected nodes are moved. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but sill + * produced cloned content in a document fragment + * + *
  3. DELETE_CONTENTS - will delete from + * the context tree of the range, all fully selected + * nodes. + *
+ * + * @return Returns a document fragment containing any + * copied or extracted nodes. If the how + * parameter was DELETE_CONTENTS, the + * return value is null. + */ + private DocumentFragment + traverseCommonStartContainer( Node endAncestor, int how ) + { + DocumentFragment frag = null; + if ( how!=DELETE_CONTENTS) + frag = fDocument.createDocumentFragment(); + Node n = traverseRightBoundary( endAncestor, how ); + if ( frag!=null ) + frag.appendChild( n ); + + int endIdx = indexOf( endAncestor, fStartContainer ); + int cnt = endIdx - fStartOffset; + if ( cnt <=0 ) + { + // Collapse to just before the endAncestor, which + // is partially selected. + if ( how != CLONE_CONTENTS ) + { + setEndBefore( endAncestor ); + collapse( false ); + } + return frag; + } + + n = endAncestor.getPreviousSibling(); + while( cnt > 0 ) + { + Node sibling = n.getPreviousSibling(); + Node xferNode = traverseFullySelected( n, how ); + if ( frag!=null ) + frag.insertBefore( xferNode, frag.getFirstChild() ); + --cnt; + n = sibling; + } + // Collapse to just before the endAncestor, which + // is partially selected. + if ( how != CLONE_CONTENTS ) + { + setEndBefore( endAncestor ); + collapse( false ); + } + return frag; + } + + /** + * Visits the nodes selected by this range when we know + * a-priori that the start and end containers are not the + * same, but the end container is an ancestor of the + * start container. This method is invoked by the generic + * traverse method. + * + * @param startAncestor + * The ancestor of the start container that is a direct + * child of the end container. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *
    + *
  1. EXTRACT_CONTENTS - will produce + * a document fragment containing the range's content. + * Partially selected nodes are copied, but fully + * selected nodes are moved. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but sill + * produced cloned content in a document fragment + * + *
  3. DELETE_CONTENTS - will delete from + * the context tree of the range, all fully selected + * nodes. + *
+ * + * @return Returns a document fragment containing any + * copied or extracted nodes. If the how + * parameter was DELETE_CONTENTS, the + * return value is null. + */ + private DocumentFragment + traverseCommonEndContainer( Node startAncestor, int how ) + { + DocumentFragment frag = null; + if ( how!=DELETE_CONTENTS) + frag = fDocument.createDocumentFragment(); + Node n = traverseLeftBoundary( startAncestor, how ); + if ( frag!=null ) + frag.appendChild( n ); + int startIdx = indexOf( startAncestor, fEndContainer ); + ++startIdx; // Because we already traversed it.... + + int cnt = fEndOffset - startIdx; + n = startAncestor.getNextSibling(); + while( cnt > 0 ) + { + Node sibling = n.getNextSibling(); + Node xferNode = traverseFullySelected( n, how ); + if ( frag!=null ) + frag.appendChild( xferNode ); + --cnt; + n = sibling; + } + + if ( how != CLONE_CONTENTS ) + { + setStartAfter( startAncestor ); + collapse( true ); + } + + return frag; + } + + /** + * Visits the nodes selected by this range when we know + * a-priori that the start and end containers are not + * the same, and we also know that neither the start + * nor end container is an ancestor of the other. + * This method is invoked by + * the generic traverse method. + * + * @param startAncestor + * Given a common ancestor of the start and end containers, + * this parameter is the ancestor (or self) of the start + * container that is a direct child of the common ancestor. + * + * @param endAncestor + * Given a common ancestor of the start and end containers, + * this parameter is the ancestor (or self) of the end + * container that is a direct child of the common ancestor. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *
    + *
  1. EXTRACT_CONTENTS - will produce + * a document fragment containing the range's content. + * Partially selected nodes are copied, but fully + * selected nodes are moved. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but sill + * produced cloned content in a document fragment + * + *
  3. DELETE_CONTENTS - will delete from + * the context tree of the range, all fully selected + * nodes. + *
+ * + * @return Returns a document fragment containing any + * copied or extracted nodes. If the how + * parameter was DELETE_CONTENTS, the + * return value is null. + */ + private DocumentFragment + traverseCommonAncestors( Node startAncestor, Node endAncestor, int how ) + { + DocumentFragment frag = null; + if ( how!=DELETE_CONTENTS) + frag = fDocument.createDocumentFragment(); + + Node n = traverseLeftBoundary( startAncestor, how ); + if ( frag!=null ) + frag.appendChild( n ); + + Node commonParent = startAncestor.getParentNode(); + int startOffset = indexOf( startAncestor, commonParent ); + int endOffset = indexOf( endAncestor, commonParent ); + ++startOffset; + + int cnt = endOffset - startOffset; + Node sibling = startAncestor.getNextSibling(); + + while( cnt > 0 ) + { + Node nextSibling = sibling.getNextSibling(); + n = traverseFullySelected( sibling, how ); + if ( frag!=null ) + frag.appendChild( n ); + sibling = nextSibling; + --cnt; + } + + n = traverseRightBoundary( endAncestor, how ); + if ( frag!=null ) + frag.appendChild( n ); + + if ( how != CLONE_CONTENTS ) + { + setStartAfter( startAncestor ); + collapse( true ); + } + return frag; + } + + /** + * Traverses the "right boundary" of this range and + * operates on each "boundary node" according to the + * how parameter. It is a-priori assumed + * by this method that the right boundary does + * not contain the range's start container. + *

+ * A "right boundary" is best visualized by thinking + * of a sample tree:

+     *                 A
+     *                /|\
+     *               / | \
+     *              /  |  \
+     *             B   C   D
+     *            /|\     /|\
+     *           E F G   H I J
+     * 
+ * Imagine first a range that begins between the + * "E" and "F" nodes and ends between the + * "I" and "J" nodes. The start container is + * "B" and the end container is "D". Given this setup, + * the following applies: + *

+ * Partially Selected Nodes: B, D
+ * Fully Selected Nodes: F, G, C, H, I + *

+ * The "right boundary" is the highest subtree node + * that contains the ending container. The root of + * this subtree is always partially selected. + *

+ * In this example, the nodes that are traversed + * as "right boundary" nodes are: H, I, and D. + * + * @param root The node that is the root of the "right boundary" subtree. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *

    + *
  1. EXTRACT_CONTENTS - will produce + * a node containing the boundaries content. + * Partially selected nodes are copied, but fully + * selected nodes are moved. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but will + * produced cloned content. + * + *
  3. DELETE_CONTENTS - will delete from + * the context tree of the range, all fully selected + * nodes within the boundary. + *
+ * + * @return Returns a node that is the result of visiting nodes. + * If the traversal operation is + * DELETE_CONTENTS the return value is null. + */ + private Node traverseRightBoundary( Node root, int how ) + { + Node next = getSelectedNode( fEndContainer, fEndOffset-1 ); + boolean isFullySelected = ( next!=fEndContainer ); + + if ( next==root ) + return traverseNode( next, isFullySelected, false, how ); + + Node parent = next.getParentNode(); + Node clonedParent = traverseNode( parent, false, false, how ); + + while( parent!=null ) + { + while( next!=null ) + { + Node prevSibling = next.getPreviousSibling(); + Node clonedChild = + traverseNode( next, isFullySelected, false, how ); + if ( how!=DELETE_CONTENTS ) + { + clonedParent.insertBefore( + clonedChild, + clonedParent.getFirstChild() + ); + } + isFullySelected = true; + next = prevSibling; + } + if ( parent==root ) + return clonedParent; + + next = parent.getPreviousSibling(); + parent = parent.getParentNode(); + Node clonedGrandParent = traverseNode( parent, false, false, how ); + if ( how!=DELETE_CONTENTS ) + clonedGrandParent.appendChild( clonedParent ); + clonedParent = clonedGrandParent; + + } + + // should never occur + return null; + } + + /** + * Traverses the "left boundary" of this range and + * operates on each "boundary node" according to the + * how parameter. It is a-priori assumed + * by this method that the left boundary does + * not contain the range's end container. + *

+ * A "left boundary" is best visualized by thinking + * of a sample tree:

+     * 
+     *                 A
+     *                /|\
+     *               / | \
+     *              /  |  \
+     *             B   C   D
+     *            /|\     /|\
+     *           E F G   H I J
+     * 
+ * Imagine first a range that begins between the + * "E" and "F" nodes and ends between the + * "I" and "J" nodes. The start container is + * "B" and the end container is "D". Given this setup, + * the following applies: + *

+ * Partially Selected Nodes: B, D
+ * Fully Selected Nodes: F, G, C, H, I + *

+ * The "left boundary" is the highest subtree node + * that contains the starting container. The root of + * this subtree is always partially selected. + *

+ * In this example, the nodes that are traversed + * as "left boundary" nodes are: F, G, and B. + * + * @param root The node that is the root of the "left boundary" subtree. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *

    + *
  1. EXTRACT_CONTENTS - will produce + * a node containing the boundaries content. + * Partially selected nodes are copied, but fully + * selected nodes are moved. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but will + * produced cloned content. + * + *
  3. DELETE_CONTENTS - will delete from + * the context tree of the range, all fully selected + * nodes within the boundary. + *
+ * + * @return Returns a node that is the result of visiting nodes. + * If the traversal operation is + * DELETE_CONTENTS the return value is null. + */ + private Node traverseLeftBoundary( Node root, int how ) + { + Node next = getSelectedNode( getStartContainer(), getStartOffset() ); + boolean isFullySelected = ( next!=getStartContainer() ); + + if ( next==root ) + return traverseNode( next, isFullySelected, true, how ); + + Node parent = next.getParentNode(); + Node clonedParent = traverseNode( parent, false, true, how ); + + while( parent!=null ) + { + while( next!=null ) + { + Node nextSibling = next.getNextSibling(); + Node clonedChild = + traverseNode( next, isFullySelected, true, how ); + if ( how!=DELETE_CONTENTS ) + clonedParent.appendChild(clonedChild); + isFullySelected = true; + next = nextSibling; + } + if ( parent==root ) + return clonedParent; + + next = parent.getNextSibling(); + parent = parent.getParentNode(); + Node clonedGrandParent = traverseNode( parent, false, true, how ); + if ( how!=DELETE_CONTENTS ) + clonedGrandParent.appendChild( clonedParent ); + clonedParent = clonedGrandParent; + + } + + // should never occur + return null; + + } + + /** + * Utility method for traversing a single node. + * Does not properly handle a text node containing both the + * start and end offsets. Such nodes should + * have been previously detected and been routed to traverseCharacterDataNode. + * + * @param n The node to be traversed. + * + * @param isFullySelected + * Set to true if the node is fully selected. Should be + * false otherwise. + * Note that although the DOM 2 specification says that a + * text node that is boththe start and end container is not + * selected, we treat it here as if it were partially + * selected. + * + * @param isLeft Is true if we are traversing the node as part of navigating + * the "left boundary" of the range. If this value is false, + * it implies we are navigating the "right boundary" of the + * range. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *
    + *
  1. EXTRACT_CONTENTS - will simply + * return the original node. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but will + * return a cloned node. + * + *
  3. DELETE_CONTENTS - will delete the + * node from it's parent, but will return null. + *
+ * + * @return Returns a node that is the result of visiting the node. + * If the traversal operation is + * DELETE_CONTENTS the return value is null. + */ + private Node traverseNode( Node n, boolean isFullySelected, boolean isLeft, int how ) + { + if ( isFullySelected ) { + return traverseFullySelected( n, how ); + } + final short nodeType = n.getNodeType(); + if (nodeType == Node.TEXT_NODE || + nodeType == Node.CDATA_SECTION_NODE || + nodeType == Node.COMMENT_NODE || + nodeType == Node.PROCESSING_INSTRUCTION_NODE) { + return traverseCharacterDataNode( n, isLeft, how ); + } + return traversePartiallySelected( n, how ); + } + + /** + * Utility method for traversing a single node when + * we know a-priori that the node if fully + * selected. + * + * @param n The node to be traversed. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *
    + *
  1. EXTRACT_CONTENTS - will simply + * return the original node. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but will + * return a cloned node. + * + *
  3. DELETE_CONTENTS - will delete the + * node from it's parent, but will return null. + *
+ * + * @return Returns a node that is the result of visiting the node. + * If the traversal operation is + * DELETE_CONTENTS the return value is null. + */ + private Node traverseFullySelected( Node n, int how ) + { + switch( how ) + { + case CLONE_CONTENTS: + return n.cloneNode( true ); + case EXTRACT_CONTENTS: + if ( n.getNodeType()==Node.DOCUMENT_TYPE_NODE ) + { + // TBD: This should be a HIERARCHY_REQUEST_ERR + throw new DOMException( + DOMException.HIERARCHY_REQUEST_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + } + return n; + case DELETE_CONTENTS: + n.getParentNode().removeChild(n); + return null; + } + return null; + } + + /** + * Utility method for traversing a single node when + * we know a-priori that the node if partially + * selected and is not a text node. + * + * @param n The node to be traversed. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *
    + *
  1. EXTRACT_CONTENTS - will simply + * return the original node. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but will + * return a cloned node. + * + *
  3. DELETE_CONTENTS - will delete the + * node from it's parent, but will return null. + *
+ * + * @return Returns a node that is the result of visiting the node. + * If the traversal operation is + * DELETE_CONTENTS the return value is null. + */ + private Node traversePartiallySelected( Node n, int how ) + { + switch( how ) + { + case DELETE_CONTENTS: + return null; + case CLONE_CONTENTS: + case EXTRACT_CONTENTS: + return n.cloneNode( false ); + } + return null; + } + + /** + * Utility method for traversing a node containing character data + * (either a Text, CDATASection, Comment or ProcessingInstruction node) + * that we know a-priori to be on a left or right boundary of the range. + * This method does not properly handle text nodes that contain + * both the start and end points of the range. + * + * @param n The node to be traversed. + * + * @param isLeft Is true if we are traversing the node as part of navigating + * the "left boundary" of the range. If this value is false, + * it implies we are navigating the "right boundary" of the + * range. + * + * @param how Specifies what type of traversal is being + * requested (extract, clone, or delete). + * Legal values for this argument are: + * + *
    + *
  1. EXTRACT_CONTENTS - will simply + * return the original node. + * + *
  2. CLONE_CONTENTS - will leave the + * context tree of the range undisturbed, but will + * return a cloned node. + * + *
  3. DELETE_CONTENTS - will delete the + * node from it's parent, but will return null. + *
+ * + * @return Returns a node that is the result of visiting the node. + * If the traversal operation is + * DELETE_CONTENTS the return value is null. + */ + private Node traverseCharacterDataNode( Node n, boolean isLeft, int how ) + { + String txtValue = n.getNodeValue(); + String newNodeValue; + String oldNodeValue; + + if ( isLeft ) + { + int offset = getStartOffset(); + newNodeValue = txtValue.substring( offset ); + oldNodeValue = txtValue.substring( 0, offset ); + } + else + { + int offset = getEndOffset(); + newNodeValue = txtValue.substring( 0, offset ); + oldNodeValue = txtValue.substring( offset ); + } + + if ( how != CLONE_CONTENTS ) + n.setNodeValue( oldNodeValue ); + if ( how==DELETE_CONTENTS ) + return null; + Node newNode = n.cloneNode( false ); + newNode.setNodeValue( newNodeValue ); + return newNode; + } + + void checkIndex(Node refNode, int offset) throws DOMException + { + if (offset < 0) { + throw new DOMException( + DOMException.INDEX_SIZE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null)); + } + + int type = refNode.getNodeType(); + + // If the node contains text, ensure that the + // offset of the range is <= to the length of the text + if (type == Node.TEXT_NODE + || type == Node.CDATA_SECTION_NODE + || type == Node.COMMENT_NODE + || type == Node.PROCESSING_INSTRUCTION_NODE) { + if (offset > refNode.getNodeValue().length()) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null)); + } + } + else { + // Since the node is not text, ensure that the offset + // is valid with respect to the number of child nodes + if (offset > refNode.getChildNodes().getLength()) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null)); + } + } + } + + /** + * Given a node, calculate what the Range's root container + * for that node would be. + */ + private Node getRootContainer( Node node ) + { + if ( node==null ) + return null; + + while( node.getParentNode()!=null ) + node = node.getParentNode(); + return node; + } + + /** + * Returns true IFF the given node can serve as a container + * for a range's boundary points. + */ + private boolean isLegalContainer( Node node ) + { + if ( node==null ) + return false; + + while( node!=null ) + { + switch( node.getNodeType() ) + { + case Node.ENTITY_NODE: + case Node.NOTATION_NODE: + case Node.DOCUMENT_TYPE_NODE: + return false; + } + node = node.getParentNode(); + } + + return true; + } + + + /** + * Finds the root container for the given node and determines + * if that root container is legal with respect to the + * DOM 2 specification. At present, that means the root + * container must be either an attribute, a document, + * or a document fragment. + */ + private boolean hasLegalRootContainer( Node node ) + { + if ( node==null ) + return false; + + Node rootContainer = getRootContainer( node ); + switch( rootContainer.getNodeType() ) + { + case Node.ATTRIBUTE_NODE: + case Node.DOCUMENT_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + return true; + } + return false; + } + + /** + * Returns true IFF the given node can be contained by + * a range. + */ + private boolean isLegalContainedNode( Node node ) + { + if ( node==null ) + return false; + switch( node.getNodeType() ) + { + case Node.DOCUMENT_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + case Node.ATTRIBUTE_NODE: + case Node.ENTITY_NODE: + case Node.NOTATION_NODE: + return false; + } + return true; + } + + Node nextNode(Node node, boolean visitChildren) { + + if (node == null) return null; + + Node result; + if (visitChildren) { + result = node.getFirstChild(); + if (result != null) { + return result; + } + } + + // if hasSibling, return sibling + result = node.getNextSibling(); + if (result != null) { + return result; + } + + + // return parent's 1st sibling. + Node parent = node.getParentNode(); + while (parent != null + && parent != fDocument + ) { + result = parent.getNextSibling(); + if (result != null) { + return result; + } else { + parent = parent.getParentNode(); + } + + } // while (parent != null && parent != fRoot) { + + // end of list, return null + return null; + } + + /** is a an ancestor of b ? */ + boolean isAncestorOf(Node a, Node b) { + for (Node node=b; node != null; node=node.getParentNode()) { + if (node == a) return true; + } + return false; + } + + /** what is the index of the child in the parent */ + int indexOf(Node child, Node parent) { + if (child.getParentNode() != parent) return -1; + int i = 0; + for(Node node = parent.getFirstChild(); node!= child; node=node.getNextSibling()) { + i++; + } + return i; + } + + /** + * Utility method to retrieve a child node by index. This method + * assumes the caller is trying to find out which node is + * selected by the given index. Note that if the index is + * greater than the number of children, this implies that the + * first node selected is the parent node itself. + * + * @param container A container node + * + * @param offset An offset within the container for which a selected node should + * be computed. If the offset is less than zero, or if the offset + * is greater than the number of children, the container is returned. + * + * @return Returns either a child node of the container or the + * container itself. + */ + private Node getSelectedNode( Node container, int offset ) + { + if ( container.getNodeType() == Node.TEXT_NODE ) + return container; + + // This case is an important convenience for + // traverseRightBoundary() + if ( offset<0 ) + return container; + + Node child = container.getFirstChild(); + while( child!=null && offset > 0 ) + { + --offset; + child = child.getNextSibling(); + } + if ( child!=null ) + return child; + return container; + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/SecuritySupport.java b/resources/xerces2-j-src/org/apache/xerces/dom/SecuritySupport.java new file mode 100644 index 0000000..43a49ad --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/SecuritySupport.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * This class is duplicated for each subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of any API. + * + * @xerces.internal + * + * @version $Id$ + */ +final class SecuritySupport { + + static ClassLoader getContextClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (SecurityException ex) { } + return cl; + } + }); + } + + static ClassLoader getSystemClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (SecurityException ex) {} + return cl; + } + }); + } + + static ClassLoader getParentClassLoader(final ClassLoader cl) { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader parent = null; + try { + parent = cl.getParent(); + } catch (SecurityException ex) {} + + // eliminate loops in case of the boot + // ClassLoader returning itself as a parent + return (parent == cl) ? null : parent; + } + }); + } + + static String getSystemProperty(final String propName) { + return (String) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(propName); + } + }); + } + + static FileInputStream getFileInputStream(final File file) + throws FileNotFoundException + { + try { + return (FileInputStream) + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws FileNotFoundException { + return new FileInputStream(file); + } + }); + } catch (PrivilegedActionException e) { + throw (FileNotFoundException)e.getException(); + } + } + + static InputStream getResourceAsStream(final ClassLoader cl, + final String name) + { + return (InputStream) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + InputStream ris; + if (cl == null) { + ris = ClassLoader.getSystemResourceAsStream(name); + } else { + ris = cl.getResourceAsStream(name); + } + return ris; + } + }); + } + + static boolean getFileExists(final File f) { + return ((Boolean) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return f.exists() ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + } + + static long getLastModified(final File f) { + return ((Long) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return new Long(f.lastModified()); + } + })).longValue(); + } + + private SecuritySupport () {} +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/TextImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/TextImpl.java new file mode 100644 index 0000000..ae2c686 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/TextImpl.java @@ -0,0 +1,658 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * Text nodes hold the non-markup, non-Entity content of + * an Element or Attribute. + *

+ * When a document is first made available to the DOM, there is only + * one Text object for each block of adjacent plain-text. Users (ie, + * applications) may create multiple adjacent Texts during editing -- + * see {@link org.w3c.dom.Element#normalize} for discussion. + *

+ * Note that CDATASection is a subclass of Text. This is conceptually + * valid, since they're really just two different ways of quoting + * characters when they're written out as part of an XML stream. + * + * @xerces.internal + * + * @version $Id$ + * @since PR-DOM-Level-1-19980818. + */ +public class TextImpl + extends CharacterDataImpl + implements CharacterData, Text { + + // + // Private Data members + // + + + // + // Constants + // + + /** Serialization version. */ + static final long serialVersionUID = -5294980852957403469L; + + // + // Constructors + // + + /** Default constructor */ + public TextImpl(){} + + /** Factory constructor. */ + public TextImpl(CoreDocumentImpl ownerDoc, String data) { + super(ownerDoc, data); + } + + /** + * NON-DOM: resets node and sets specified values for the current node + * + * @param ownerDoc + * @param data + */ + public void setValues(CoreDocumentImpl ownerDoc, String data){ + + flags=0; + nextSibling = null; + previousSibling=null; + setOwnerDocument(ownerDoc); + super.data = data; + } + // + // Node methods + // + + /** + * A short integer indicating what type of node this is. The named + * constants for this value are defined in the org.w3c.dom.Node interface. + */ + public short getNodeType() { + return Node.TEXT_NODE; + } + + /** Returns the node name. */ + public String getNodeName() { + return "#text"; + } + + /** + * NON-DOM: Set whether this Text is ignorable whitespace. + */ + public void setIgnorableWhitespace(boolean ignore) { + + if (needsSyncData()) { + synchronizeData(); + } + isIgnorableWhitespace(ignore); + + } // setIgnorableWhitespace(boolean) + + + /** + * DOM L3 Core CR - Experimental + * + * 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() { + // REVISIT: is this implemenation correct? + if (needsSyncData()) { + synchronizeData(); + } + return internalIsIgnorableWhitespace(); + } + + + /** + * DOM Level 3 WD - Experimental. + * Returns all text of Text nodes logically-adjacent text + * nodes to this node, concatenated in document order. + * @since DOM Level 3 + */ + public String getWholeText(){ + + if (needsSyncData()) { + synchronizeData(); + } + + StringBuffer buffer = new StringBuffer(); + if (data != null && data.length() != 0) { + buffer.append(data); + } + + // concatenate text of logically adjacent text nodes to the left of this node in the tree + getWholeTextBackward(this.getPreviousSibling(), buffer, this.getParentNode()); + String temp = buffer.toString(); + + // clear buffer + buffer.setLength(0); + + // concatenate text of logically adjacent text nodes to the right of this node in the tree + getWholeTextForward(this.getNextSibling(), buffer, this.getParentNode()); + + return temp + buffer.toString(); + + } + + /** + * internal method taking a StringBuffer in parameter and inserts the + * text content at the start of the buffer + * + * @param buf + */ + protected void insertTextContent(StringBuffer buf) throws DOMException { + String content = getNodeValue(); + if (content != null) { + buf.insert(0, content); + } + } + + /** + * Concatenates the text of all logically-adjacent text nodes to the + * right of this node + * @param node + * @param buffer + * @param parent + * @return true - if execution was stopped because the type of node + * other than EntityRef, Text, CDATA is encountered, otherwise + * return false + */ + private boolean getWholeTextForward(Node node, StringBuffer buffer, Node parent){ + // boolean to indicate whether node is a child of an entity reference + boolean inEntRef = false; + + if (parent!=null) { + inEntRef = parent.getNodeType()==Node.ENTITY_REFERENCE_NODE; + } + + while (node != null) { + short type = node.getNodeType(); + if (type == Node.ENTITY_REFERENCE_NODE) { + if (getWholeTextForward(node.getFirstChild(), buffer, node)){ + return true; + } + } + else if (type == Node.TEXT_NODE || + type == Node.CDATA_SECTION_NODE) { + ((NodeImpl)node).getTextContent(buffer); + } + else { + return true; + } + + node = node.getNextSibling(); + } + + // if the parent node is an entity reference node, must + // check nodes to the right of the parent entity reference node for logically adjacent + // text nodes + if (inEntRef) { + getWholeTextForward(parent.getNextSibling(), buffer, parent.getParentNode()); + return true; + } + + return false; + } + + /** + * Concatenates the text of all logically-adjacent text nodes to the left of + * the node + * @param node + * @param buffer + * @param parent + * @return true - if execution was stopped because the type of node + * other than EntityRef, Text, CDATA is encountered, otherwise + * return false + */ + private boolean getWholeTextBackward(Node node, StringBuffer buffer, Node parent){ + + // boolean to indicate whether node is a child of an entity reference + boolean inEntRef = false; + if (parent!=null) { + inEntRef = parent.getNodeType()==Node.ENTITY_REFERENCE_NODE; + } + + while (node != null) { + short type = node.getNodeType(); + if (type == Node.ENTITY_REFERENCE_NODE) { + if (getWholeTextBackward(node.getLastChild(), buffer, node)){ + return true; + } + } + else if (type == Node.TEXT_NODE || + type == Node.CDATA_SECTION_NODE) { + ((TextImpl)node).insertTextContent(buffer); + } + else { + return true; + } + + node = node.getPreviousSibling(); + } + + // if the parent node is an entity reference node, must + // check nodes to the left of the parent entity reference node for logically adjacent + // text nodes + if (inEntRef) { + getWholeTextBackward(parent.getPreviousSibling(), buffer, parent.getParentNode()); + return true; + } + + return false; + } + + /** + * 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. + * + * @param content + * The content of the replacing Text node. + * @return text - The Text node created with the specified content. + * @since DOM Level 3 + */ + public Text replaceWholeText(String content) throws DOMException { + + if (needsSyncData()) { + synchronizeData(); + } + + //if the content is null + Node parent = this.getParentNode(); + if (content == null || content.length() == 0) { + // remove current node + if (parent != null) { // check if node in the tree + parent.removeChild(this); + } + return null; + } + + // make sure we can make the replacement + if (ownerDocument().errorChecking) { + if (!canModifyPrev(this)) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NO_MODIFICATION_ALLOWED_ERR", null)); + } + + // make sure we can make the replacement + if (!canModifyNext(this)) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NO_MODIFICATION_ALLOWED_ERR", null)); + } + } + + //replace the text node + Text currentNode = null; + if (isReadOnly()) { + Text newNode = this.ownerDocument().createTextNode(content); + if (parent != null) { // check if node in the tree + parent.insertBefore(newNode, this); + parent.removeChild(this); + currentNode = newNode; + } else { + return newNode; + } + } else { + this.setData(content); + currentNode = this; + } + + //check logically-adjacent text nodes + Node prev = currentNode.getPreviousSibling(); + while (prev != null) { + //If the logically-adjacent next node can be removed + //remove it. A logically adjacent node can be removed if + //it is a Text or CDATASection node or an EntityReference with + //Text and CDATA only children. + if ((prev.getNodeType() == Node.TEXT_NODE) + || (prev.getNodeType() == Node.CDATA_SECTION_NODE) + || (prev.getNodeType() == Node.ENTITY_REFERENCE_NODE && hasTextOnlyChildren(prev))) { + parent.removeChild(prev); + prev = currentNode; + } else { + break; + } + prev = prev.getPreviousSibling(); + } + + //check logically-adjacent text nodes + Node next = currentNode.getNextSibling(); + while (next != null) { + //If the logically-adjacent next node can be removed + //remove it. A logically adjacent node can be removed if + //it is a Text or CDATASection node or an EntityReference with + //Text and CDATA only children. + if ((next.getNodeType() == Node.TEXT_NODE) + || (next.getNodeType() == Node.CDATA_SECTION_NODE) + || (next.getNodeType() == Node.ENTITY_REFERENCE_NODE && hasTextOnlyChildren(next))) { + parent.removeChild(next); + next = currentNode; + } else { + break; + } + next = next.getNextSibling(); + } + + return currentNode; + } + + /** + * 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. Traverse previous + * siblings of the node to be replaced. If a previous sibling is an + * EntityReference node, get it's last child. If the last child was a Text + * or CDATASection node and its previous siblings are neither a replaceable + * EntityReference or Text or CDATASection nodes, return false. IF the last + * child was neither Text nor CDATASection nor a replaceable EntityReference + * Node, then return true. If the last child was a Text or CDATASection node + * any its previous sibling was not or was an EntityReference that did not + * contain only Text or CDATASection nodes, return false. Check this + * recursively for EntityReference nodes. + * + * @param node + * @return true - can replace text false - can't replace exception must be + * raised + */ + private boolean canModifyPrev(Node node) { + boolean textLastChild = false; + + Node prev = node.getPreviousSibling(); + + while (prev != null) { + + short type = prev.getNodeType(); + + if (type == Node.ENTITY_REFERENCE_NODE) { + //If the previous sibling was entityreference + //check if its content is replaceable + Node lastChild = prev.getLastChild(); + + //if the entity reference has no children + //return false + if (lastChild == null) { + return false; + } + + //The replacement text of the entity reference should + //be either only text,cadatsections or replaceable entity + //reference nodes or the last child should be neither of these + while (lastChild != null) { + short lType = lastChild.getNodeType(); + + if (lType == Node.TEXT_NODE + || lType == Node.CDATA_SECTION_NODE) { + textLastChild = true; + } else if (lType == Node.ENTITY_REFERENCE_NODE) { + if (!canModifyPrev(lastChild)) { + return false; + } else { + //If the EntityReference child contains + //only text, or non-text or ends with a + //non-text node. + textLastChild = true; + } + } else { + //If the last child was replaceable and others are not + //Text or CDataSection or replaceable EntityRef nodes + //return false. + if (textLastChild) { + return false; + } else { + return true; + } + } + lastChild = lastChild.getPreviousSibling(); + } + } else if (type == Node.TEXT_NODE + || type == Node.CDATA_SECTION_NODE) { + //If the previous sibling was text or cdatasection move to next + } else { + //If the previous sibling was anything but text or + //cdatasection or an entity reference, stop search and + //return true + return true; + } + + prev = prev.getPreviousSibling(); + } + + return true; + } + + /** + * 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. Traverse previous + * siblings of the node to be replaced. If a previous sibling is an + * EntityReference node, get it's last child. If the first child was a Text + * or CDATASection node and its next siblings are neither a replaceable + * EntityReference or Text or CDATASection nodes, return false. IF the first + * child was neither Text nor CDATASection nor a replaceable EntityReference + * Node, then return true. If the first child was a Text or CDATASection + * node any its next sibling was not or was an EntityReference that did not + * contain only Text or CDATASection nodes, return false. Check this + * recursively for EntityReference nodes. + * + * @param node + * @return true - can replace text false - can't replace exception must be + * raised + */ + private boolean canModifyNext(Node node) { + boolean textFirstChild = false; + + Node next = node.getNextSibling(); + while (next != null) { + + short type = next.getNodeType(); + + if (type == Node.ENTITY_REFERENCE_NODE) { + //If the previous sibling was entityreference + //check if its content is replaceable + Node firstChild = next.getFirstChild(); + + //if the entity reference has no children + //return false + if (firstChild == null) { + return false; + } + + //The replacement text of the entity reference should + //be either only text,cadatsections or replaceable entity + //reference nodes or the last child should be neither of these + while (firstChild != null) { + short lType = firstChild.getNodeType(); + + if (lType == Node.TEXT_NODE + || lType == Node.CDATA_SECTION_NODE) { + textFirstChild = true; + } else if (lType == Node.ENTITY_REFERENCE_NODE) { + if (!canModifyNext(firstChild)) { + return false; + } else { + //If the EntityReference child contains + //only text, or non-text or ends with a + //non-text node. + textFirstChild = true; + } + } else { + //If the first child was replaceable text and next + //children are not, then return false + if (textFirstChild) { + return false; + } else { + return true; + } + } + firstChild = firstChild.getNextSibling(); + } + } else if (type == Node.TEXT_NODE + || type == Node.CDATA_SECTION_NODE) { + //If the previous sibling was text or cdatasection move to next + } else { + //If the next sibling was anything but text or + //cdatasection or an entity reference, stop search and + //return true + return true; + } + + next = next.getNextSibling(); + } + + return true; + } + + /** + * Check if an EntityReference node has Text Only child nodes + * + * @param node + * @return true - Contains text only children + */ + private boolean hasTextOnlyChildren(Node node) { + + Node child = node; + + if (child == null) { + return false; + } + + child = child.getFirstChild(); + while (child != null) { + int type = child.getNodeType(); + + if (type == Node.ENTITY_REFERENCE_NODE) { + return hasTextOnlyChildren(child); + } + else if (type != Node.TEXT_NODE + && type != Node.CDATA_SECTION_NODE + && type != Node.ENTITY_REFERENCE_NODE) { + return false; + } + child = child.getNextSibling(); + } + return true; + } + + + /** + * NON-DOM: Returns whether this Text is ignorable whitespace. + */ + public boolean isIgnorableWhitespace() { + + if (needsSyncData()) { + synchronizeData(); + } + return internalIsIgnorableWhitespace(); + + } // isIgnorableWhitespace():boolean + + + // + // Text methods + // + + /** + * Break a text node into two sibling nodes. (Note that if the current node + * has no parent, they won't wind up as "siblings" -- they'll both be + * orphans.) + * + * @param offset + * The offset at which to split. If offset is at the end of the + * available data, the second node will be empty. + * + * @return A reference to the new node (containing data after the offset + * point). The original node will contain data up to that point. + * + * @throws DOMException(INDEX_SIZE_ERR) + * if offset is <0 or >length. + * + * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) + * if node is read-only. + */ + public Text splitText(int offset) + throws DOMException { + + if (isReadOnly()) { + throw new DOMException( + DOMException.NO_MODIFICATION_ALLOWED_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null)); + } + + if (needsSyncData()) { + synchronizeData(); + } + if (offset < 0 || offset > data.length() ) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null)); + } + + // split text into two separate nodes + Text newText = + getOwnerDocument().createTextNode(data.substring(offset)); + setNodeValue(data.substring(0, offset)); + + // insert new text node + Node parentNode = getParentNode(); + if (parentNode != null) { + parentNode.insertBefore(newText, nextSibling); + } + + return newText; + + } // splitText(int):Text + + + /** + * NON-DOM (used by DOMParser): Reset data for the node. + */ + public void replaceData (String value){ + data = value; + } + + + /** + * NON-DOM (used by DOMParser: Sets data to empty string. + * Returns the value the data was set to. + */ + public String removeData (){ + String olddata=data; + data = ""; + return olddata; + } + +} // class TextImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/TreeWalkerImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/TreeWalkerImpl.java new file mode 100644 index 0000000..16e02ab --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/TreeWalkerImpl.java @@ -0,0 +1,529 @@ +/* + * 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. + */ + +package org.apache.xerces.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.TreeWalker; + +/** + * This class implements the TreeWalker interface. + * + * @xerces.internal + * + * @version $Id$ + */ +public class TreeWalkerImpl implements TreeWalker { + + // + // Data + // + + /** When TRUE, the children of entites references are returned in the iterator. */ + private boolean fEntityReferenceExpansion = false; + /** The whatToShow mask. */ + int fWhatToShow = NodeFilter.SHOW_ALL; + /** The NodeFilter reference. */ + NodeFilter fNodeFilter; + /** The current Node. */ + Node fCurrentNode; + /** The root Node. */ + Node fRoot; + /** Use Node.isSameNode() to check if one node is the same as another. */ + private boolean fUseIsSameNode; + + // + // Implementation Note: No state is kept except the data above + // (fWhatToShow, fNodeFilter, fCurrentNode, fRoot) such that + // setters could be created for these data values and the + // implementation will still work. + + + // + // Constructor + // + + /** Public constructor */ + public TreeWalkerImpl(Node root, + int whatToShow, + NodeFilter nodeFilter, + boolean entityReferenceExpansion) { + fCurrentNode = root; + fRoot = root; + fUseIsSameNode = useIsSameNode(root); + fWhatToShow = whatToShow; + fNodeFilter = nodeFilter; + fEntityReferenceExpansion = entityReferenceExpansion; + } + + public Node getRoot() { + return fRoot; + } + + /** Return the whatToShow value */ + public int getWhatToShow() { + return fWhatToShow; + } + + public void setWhatShow(int whatToShow){ + fWhatToShow = whatToShow; + } + /** Return the NodeFilter */ + public NodeFilter getFilter() { + return fNodeFilter; + } + + /** Return whether children entity references are included in the iterator. */ + public boolean getExpandEntityReferences() { + return fEntityReferenceExpansion; + } + + /** Return the current Node. */ + public Node getCurrentNode() { + return fCurrentNode; + } + /** Return the current Node. */ + public void setCurrentNode(Node node) { + if (node == null) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + + fCurrentNode = node; + } + + /** Return the parent Node from the current node, + * after applying filter, whatToshow. + * If result is not null, set the current Node. + */ + public Node parentNode() { + + if (fCurrentNode == null) return null; + + Node node = getParentNode(fCurrentNode); + if (node !=null) { + fCurrentNode = node; + } + return node; + + } + + /** Return the first child Node from the current node, + * after applying filter, whatToshow. + * If result is not null, set the current Node. + */ + public Node firstChild() { + + if (fCurrentNode == null) return null; + + Node node = getFirstChild(fCurrentNode); + if (node !=null) { + fCurrentNode = node; + } + return node; + } + /** Return the last child Node from the current node, + * after applying filter, whatToshow. + * If result is not null, set the current Node. + */ + public Node lastChild() { + + if (fCurrentNode == null) return null; + + Node node = getLastChild(fCurrentNode); + if (node !=null) { + fCurrentNode = node; + } + return node; + } + + /** Return the previous sibling Node from the current node, + * after applying filter, whatToshow. + * If result is not null, set the current Node. + */ + public Node previousSibling() { + + if (fCurrentNode == null) return null; + + Node node = getPreviousSibling(fCurrentNode); + if (node !=null) { + fCurrentNode = node; + } + return node; + } + + /** Return the next sibling Node from the current node, + * after applying filter, whatToshow. + * If result is not null, set the current Node. + */ + public Node nextSibling(){ + if (fCurrentNode == null) return null; + + Node node = getNextSibling(fCurrentNode); + if (node !=null) { + fCurrentNode = node; + } + return node; + } + + /** Return the previous Node from the current node, + * after applying filter, whatToshow. + * If result is not null, set the current Node. + */ + public Node previousNode() { + Node result; + + if (fCurrentNode == null) return null; + + // get sibling + result = getPreviousSibling(fCurrentNode); + if (result == null) { + result = getParentNode(fCurrentNode); + if (result != null) { + fCurrentNode = result; + return fCurrentNode; + } + return null; + } + + // get the lastChild of result. + Node lastChild = getLastChild(result); + + Node prev = lastChild ; + while (lastChild != null) { + prev = lastChild ; + lastChild = getLastChild(prev) ; + } + + lastChild = prev ; + + // if there is a lastChild which passes filters return it. + if (lastChild != null) { + fCurrentNode = lastChild; + return fCurrentNode; + } + + // otherwise return the previous sibling. + if (result != null) { + fCurrentNode = result; + return fCurrentNode; + } + + // otherwise return null. + return null; + } + + /** Return the next Node from the current node, + * after applying filter, whatToshow. + * If result is not null, set the current Node. + */ + public Node nextNode() { + + if (fCurrentNode == null) return null; + + Node result = getFirstChild(fCurrentNode); + + if (result != null) { + fCurrentNode = result; + return result; + } + + result = getNextSibling(fCurrentNode); + + if (result != null) { + fCurrentNode = result; + return result; + } + + // return parent's 1st sibling. + Node parent = getParentNode(fCurrentNode); + while (parent != null) { + result = getNextSibling(parent); + if (result != null) { + fCurrentNode = result; + return result; + } else { + parent = getParentNode(parent); + } + } + + // end , return null + return null; + } + + /** Internal function. + * Return the parent Node, from the input node + * after applying filter, whatToshow. + * The current node is not consulted or set. + */ + Node getParentNode(Node node) { + + if (node == null || isSameNode(node, fRoot)) return null; + + Node newNode = node.getParentNode(); + if (newNode == null) return null; + + int accept = acceptNode(newNode); + + if (accept == NodeFilter.FILTER_ACCEPT) + return newNode; + else + //if (accept == NodeFilter.SKIP_NODE) // and REJECT too. + { + return getParentNode(newNode); + } + + + } + + /** Internal function. + * Return the nextSibling Node, from the input node + * after applying filter, whatToshow. + * The current node is not consulted or set. + */ + Node getNextSibling(Node node) { + return getNextSibling(node, fRoot); + } + + /** Internal function. + * Return the nextSibling Node, from the input node + * after applying filter, whatToshow. + * NEVER TRAVERSES ABOVE THE SPECIFIED ROOT NODE. + * The current node is not consulted or set. + */ + Node getNextSibling(Node node, Node root) { + + if (node == null || isSameNode(node, root)) return null; + + Node newNode = node.getNextSibling(); + if (newNode == null) { + + newNode = node.getParentNode(); + + if (newNode == null || isSameNode(newNode, root)) return null; + + int parentAccept = acceptNode(newNode); + + if (parentAccept==NodeFilter.FILTER_SKIP) { + return getNextSibling(newNode, root); + } + + return null; + } + + int accept = acceptNode(newNode); + + if (accept == NodeFilter.FILTER_ACCEPT) + return newNode; + else + if (accept == NodeFilter.FILTER_SKIP) { + Node fChild = getFirstChild(newNode); + if (fChild == null) { + return getNextSibling(newNode, root); + } + return fChild; + } + else + //if (accept == NodeFilter.REJECT_NODE) + { + return getNextSibling(newNode, root); + } + + } // getNextSibling(Node node) { + + /** Internal function. + * Return the previous sibling Node, from the input node + * after applying filter, whatToshow. + * The current node is not consulted or set. + */ + Node getPreviousSibling(Node node) { + return getPreviousSibling(node, fRoot); + } + + /** Internal function. + * Return the previousSibling Node, from the input node + * after applying filter, whatToshow. + * NEVER TRAVERSES ABOVE THE SPECIFIED ROOT NODE. + * The current node is not consulted or set. + */ + Node getPreviousSibling(Node node, Node root) { + + if (node == null || isSameNode(node, root)) return null; + + Node newNode = node.getPreviousSibling(); + if (newNode == null) { + + newNode = node.getParentNode(); + if (newNode == null || isSameNode(newNode, root)) return null; + + int parentAccept = acceptNode(newNode); + + if (parentAccept==NodeFilter.FILTER_SKIP) { + return getPreviousSibling(newNode, root); + } + + return null; + } + + int accept = acceptNode(newNode); + + if (accept == NodeFilter.FILTER_ACCEPT) + return newNode; + else + if (accept == NodeFilter.FILTER_SKIP) { + Node fChild = getLastChild(newNode); + if (fChild == null) { + return getPreviousSibling(newNode, root); + } + return fChild; + } + else + //if (accept == NodeFilter.REJECT_NODE) + { + return getPreviousSibling(newNode, root); + } + + } // getPreviousSibling(Node node) { + + /** Internal function. + * Return the first child Node, from the input node + * after applying filter, whatToshow. + * The current node is not consulted or set. + */ + Node getFirstChild(Node node) { + if (node == null) return null; + + if ( !fEntityReferenceExpansion + && node.getNodeType() == Node.ENTITY_REFERENCE_NODE) + return null; + Node newNode = node.getFirstChild(); + if (newNode == null) return null; + int accept = acceptNode(newNode); + + if (accept == NodeFilter.FILTER_ACCEPT) + return newNode; + else + if (accept == NodeFilter.FILTER_SKIP + && newNode.hasChildNodes()) + { + Node fChild = getFirstChild(newNode); + + if (fChild == null) { + return getNextSibling(newNode, node); + } + return fChild; + } + else + //if (accept == NodeFilter.REJECT_NODE) + { + return getNextSibling(newNode, node); + } + + + } + + /** Internal function. + * Return the last child Node, from the input node + * after applying filter, whatToshow. + * The current node is not consulted or set. + */ + Node getLastChild(Node node) { + + if (node == null) return null; + + if ( !fEntityReferenceExpansion + && node.getNodeType() == Node.ENTITY_REFERENCE_NODE) + return null; + + Node newNode = node.getLastChild(); + if (newNode == null) return null; + + int accept = acceptNode(newNode); + + if (accept == NodeFilter.FILTER_ACCEPT) + return newNode; + else + if (accept == NodeFilter.FILTER_SKIP + && newNode.hasChildNodes()) + { + Node lChild = getLastChild(newNode); + if (lChild == null) { + return getPreviousSibling(newNode, node); + } + return lChild; + } + else + //if (accept == NodeFilter.REJECT_NODE) + { + return getPreviousSibling(newNode, node); + } + + + } + + /** Internal function. + * The node whatToShow and the filter are combined into one result. */ + short acceptNode(Node node) { + /*** + 7.1.2.4. Filters and whatToShow flags + + Iterator and TreeWalker apply whatToShow flags before applying Filters. If a node is rejected by the + active whatToShow flags, a Filter will not be called to evaluate that node. When a node is rejected by + the active whatToShow flags, children of that node will still be considered, and Filters may be called to + evaluate them. + ***/ + + if (fNodeFilter == null) { + if ( ( fWhatToShow & (1 << node.getNodeType()-1)) != 0) { + return NodeFilter.FILTER_ACCEPT; + } else { + return NodeFilter.FILTER_SKIP; + } + } else { + if ((fWhatToShow & (1 << node.getNodeType()-1)) != 0 ) { + return fNodeFilter.acceptNode(node); + } else { + // What to show has failed. See above excerpt from spec. + // Equivalent to FILTER_SKIP. + return NodeFilter.FILTER_SKIP; + } + } + } + + /** + * Use isSameNode() for testing node identity if the DOM implementation + * supports DOM Level 3 core and it isn't the Xerces implementation. + */ + private boolean useIsSameNode(Node node) { + if (node instanceof NodeImpl) { + return false; + } + Document doc = node.getNodeType() == Node.DOCUMENT_NODE + ? (Document) node : node.getOwnerDocument(); + return (doc != null && doc.getImplementation().hasFeature("Core", "3.0")); + } + + /** + * Returns true if m is the same node n. + */ + private boolean isSameNode(Node m, Node n) { + return (fUseIsSameNode) ? m.isSameNode(n) : m == n; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/events/EventImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/events/EventImpl.java new file mode 100644 index 0000000..c3d722f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/events/EventImpl.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.xerces.dom.events; + +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventTarget; + +/** + * EventImpl is an implementation of the basic "generic" DOM Level 2 Event + * object. It may be subclassed by more specialized event sets. + * Note that in our implementation, events are re-dispatchable (dispatch + * clears the stopPropagation and preventDefault flags before it starts); + * I believe that is the DOM's intent but I don't see an explicit statement + * to this effect. + * + * @xerces.internal + * + * @version $Id$ + */ +public class EventImpl implements Event { + + public String type = null; + public EventTarget target; + public EventTarget currentTarget; + public short eventPhase; + public boolean initialized = false, bubbles = true, cancelable = false; + public boolean stopPropagation = false, preventDefault = false; + + protected long timeStamp = System.currentTimeMillis(); + + /** + * The DOM doesn't deal with constructors, so instead we have an + * initializer call to set most of the read-only fields. The + * others are set, and reset, by the event subsystem during dispatch. + *

+ * Note that init() -- and the subclass-specific initWhatever() calls -- + * may be reinvoked. At least one initialization is required; repeated + * initializations overwrite the event with new values of their + * parameters. + */ + public void initEvent(String eventTypeArg, boolean canBubbleArg, + boolean cancelableArg) { + type = eventTypeArg; + bubbles = canBubbleArg; + cancelable = cancelableArg; + initialized = true; + } + + /** + * @return true iff this Event is of a class and type which supports + * bubbling. In the generic case, this is True. + */ + public boolean getBubbles() { + return bubbles; + } + + /** + * @return true iff this Event is of a class and type which (a) has a + * Default Behavior in this DOM, and (b)allows cancellation (blocking) + * of that behavior. In the generic case, this is False. + */ + public boolean getCancelable() { + return cancelable; + } + + /** + * @return the Node (EventTarget) whose EventListeners are currently + * being processed. During capture and bubble phases, this may not be + * the target node. + */ + public EventTarget getCurrentTarget() { + return currentTarget; + } + + /** + * @return the current processing phase for this event -- + * CAPTURING_PHASE, AT_TARGET, BUBBLING_PHASE. (There may be + * an internal DEFAULT_PHASE as well, but the users won't see it.) + */ + public short getEventPhase() { + return eventPhase; + } + + /** + * @return the EventTarget (Node) to which the event was originally + * dispatched. + */ + public EventTarget getTarget() { + return target; + } + + /** + * @return event name as a string + */ + public String getType() { + return type; + } + + public long getTimeStamp() { + return timeStamp; + } + + /** + * Causes exit from in-progress event dispatch before the next + * currentTarget is selected. Replaces the preventBubble() and + * preventCapture() methods which were present in early drafts; + * they may be reintroduced in future levels of the DOM. + */ + public void stopPropagation() { + stopPropagation = true; + } + + /** + * Prevents any default processing built into the target node from + * occurring. + */ + public void preventDefault() { + preventDefault = true; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/events/MouseEventImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/events/MouseEventImpl.java new file mode 100644 index 0000000..4989568 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/events/MouseEventImpl.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package org.apache.xerces.dom.events; + +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MouseEvent; +import org.w3c.dom.views.AbstractView; + +/** + * An implementation of the DOM Level 2 MouseEvent interface. + * + * @xerces.internal + * + * @version $Id$ + */ +public class MouseEventImpl + extends UIEventImpl + implements MouseEvent { + + private int fScreenX; + private int fScreenY; + private int fClientX; + private int fClientY; + private boolean fCtrlKey; + private boolean fAltKey; + private boolean fShiftKey; + private boolean fMetaKey; + private short fButton; + private EventTarget fRelatedTarget; + + public int getScreenX() { + return fScreenX; + } + + public int getScreenY() { + return fScreenY; + } + + public int getClientX() { + return fClientX; + } + + public int getClientY() { + return fClientY; + } + + public boolean getCtrlKey() { + return fCtrlKey; + } + + public boolean getAltKey() { + return fAltKey; + } + + public boolean getShiftKey() { + return fShiftKey; + } + + public boolean getMetaKey() { + return fMetaKey; + } + + public short getButton() { + return fButton; + } + + public EventTarget getRelatedTarget() { + return fRelatedTarget; + } + + public void initMouseEvent(String typeArg, boolean canBubbleArg, boolean cancelableArg, AbstractView viewArg, + int detailArg, int screenXArg, int screenYArg, int clientXArg, int clientYArg, + boolean ctrlKeyArg, boolean altKeyArg, boolean shiftKeyArg, boolean metaKeyArg, + short buttonArg, EventTarget relatedTargetArg) { + fScreenX = screenXArg; + fScreenY = screenYArg; + fClientX = clientXArg; + fClientY = clientYArg; + fCtrlKey = ctrlKeyArg; + fAltKey = altKeyArg; + fShiftKey = shiftKeyArg; + fMetaKey = metaKeyArg; + fButton = buttonArg; + fRelatedTarget = relatedTargetArg; + super.initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/events/MutationEventImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/events/MutationEventImpl.java new file mode 100644 index 0000000..b977459 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/events/MutationEventImpl.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package org.apache.xerces.dom.events; + +import org.w3c.dom.Node; +import org.w3c.dom.events.MutationEvent; + +/** + * An implementation of the DOM Level 2 MutationEvent interface. + * + * @xerces.internal + * + * @version $Id$ + */ +public class MutationEventImpl + extends EventImpl + implements MutationEvent { + + Node relatedNode = null; + String prevValue = null; + String newValue = null; + String attrName = null; + + // REVISIT: The DOM Level 2 PR has a bug: the init method should let this + // attribute be specified. Since it doesn't we have to give write access. + public short attrChange; + + // NON-DOM CONSTANTS: Storage efficiency, avoid risk of typos. + public static final String DOM_SUBTREE_MODIFIED = "DOMSubtreeModified"; + public static final String DOM_NODE_INSERTED = "DOMNodeInserted"; + public static final String DOM_NODE_REMOVED = "DOMNodeRemoved"; + public static final String DOM_NODE_REMOVED_FROM_DOCUMENT = "DOMNodeRemovedFromDocument"; + public static final String DOM_NODE_INSERTED_INTO_DOCUMENT = "DOMNodeInsertedIntoDocument"; + public static final String DOM_ATTR_MODIFIED = "DOMAttrModified"; + public static final String DOM_CHARACTER_DATA_MODIFIED = "DOMCharacterDataModified"; + + /** + * @return the name of the Attr which + * changed, for DOMAttrModified events. + * Undefined for others. + */ + public String getAttrName() { + return attrName; + } + + /** + * attrChange indicates the type of change which triggered + * the DOMAttrModified event. The values can be MODIFICATION + * , ADDITION, or REMOVAL. + */ + public short getAttrChange() { + return attrChange; + } + + /** + * @return the new string value of the Attr for DOMAttrModified events, or + * of the CharacterData node for DOMCharDataModifed events. + * Undefined for others. + */ + public String getNewValue() { + return newValue; + } + + /** + * @return the previous string value of the Attr for DOMAttrModified events, or + * of the CharacterData node for DOMCharDataModifed events. + * Undefined for others. + */ + public String getPrevValue() { + return prevValue; + } + + /** + * @return a Node related to this event, other than the target that the + * node was dispatched to. For DOMNodeRemoved, it is the node which + * was removed. + * No other uses are currently defined. + */ + public Node getRelatedNode() { + return relatedNode; + } + + /** + * Initialize a mutation event, or overwrite the event's current + * settings with new values of the parameters. + */ + public void initMutationEvent(String typeArg, boolean canBubbleArg, + boolean cancelableArg, Node relatedNodeArg, String prevValueArg, + String newValueArg, String attrNameArg, short attrChangeArg) { + relatedNode = relatedNodeArg; + prevValue = prevValueArg; + newValue = newValueArg; + attrName = attrNameArg; + attrChange = attrChangeArg; + super.initEvent(typeArg, canBubbleArg, cancelableArg); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/events/UIEventImpl.java b/resources/xerces2-j-src/org/apache/xerces/dom/events/UIEventImpl.java new file mode 100644 index 0000000..b9b0023 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/events/UIEventImpl.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +package org.apache.xerces.dom.events; + +import org.w3c.dom.events.UIEvent; +import org.w3c.dom.views.AbstractView; + +/** + * An implementation of the DOM Level 2 UIEvent interface. + * + * @xerces.internal + * + * @version $Id$ + */ +public class UIEventImpl + extends EventImpl + implements UIEvent { + + private AbstractView fView; + private int fDetail; + + public AbstractView getView() { + return fView; + } + + public int getDetail() { + return fDetail; + } + + public void initUIEvent(String typeArg, boolean canBubbleArg, boolean cancelableArg, + AbstractView viewArg, int detailArg) { + fView = viewArg; + fDetail = detailArg; + super.initEvent(typeArg, canBubbleArg, cancelableArg); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/org.apache.xerces.dom.DOMImplementationSourceImpl b/resources/xerces2-j-src/org/apache/xerces/dom/org.apache.xerces.dom.DOMImplementationSourceImpl new file mode 100644 index 0000000..d92a986 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/org.apache.xerces.dom.DOMImplementationSourceImpl @@ -0,0 +1 @@ +org.apache.xerces.dom.DOMImplementationSourceImpl \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/dom/org.w3c.dom.DOMImplementationSourceList b/resources/xerces2-j-src/org/apache/xerces/dom/org.w3c.dom.DOMImplementationSourceList new file mode 100644 index 0000000..7a52dd1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom/org.w3c.dom.DOMImplementationSourceList @@ -0,0 +1 @@ +org.apache.xerces.dom.DOMXSImplementationSourceImpl \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASAttributeDeclaration.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASAttributeDeclaration.java new file mode 100644 index 0000000..0cf018e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASAttributeDeclaration.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * An attribute declaration in the context of a ASObject.The + * constant 'REQUIRED' is missing from this interface. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASAttributeDeclaration extends ASObject { + // VALUE_TYPES + /** + * Describes that the attribute does not have any value constraint. + */ + public static final short VALUE_NONE = 0; + /** + * Indicates that the there is a default value constraint. + */ + public static final short VALUE_DEFAULT = 1; + /** + * Indicates that there is a fixed value constraint for this attribute. + */ + public static final short VALUE_FIXED = 2; + + /** + * Datatype of the attribute. + */ + public ASDataType getDataType(); + /** + * Datatype of the attribute. + */ + public void setDataType(ASDataType dataType); + + /** + * Default or fixed value. + */ + public String getDataValue(); + /** + * Default or fixed value. + */ + public void setDataValue(String dataValue); + + /** + * Valid attribute values, separated by commas, in a string. + */ + public String getEnumAttr(); + /** + * Valid attribute values, separated by commas, in a string. + */ + public void setEnumAttr(String enumAttr); + + /** + * Owner elements ASObject of attribute, meaning that an + * attribute declaration can be shared by multiple elements. + */ + public ASObjectList getOwnerElements(); + /** + * Owner elements ASObject of attribute, meaning that an + * attribute declaration can be shared by multiple elements. + */ + public void setOwnerElements(ASObjectList ownerElements); + + /** + * Constraint type if any for this attribute. + */ + public short getDefaultType(); + /** + * Constraint type if any for this attribute. + */ + public void setDefaultType(short defaultType); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASContentModel.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASContentModel.java new file mode 100644 index 0000000..10d4f58 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASContentModel.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * The content model of a declared element. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASContentModel extends ASObject { + /** + * Signifies unbounded upper limit. The MAX_VALUE value is + * 0xFFFFFFFF FFFFFFFF. This needs to be better defined in + * the generated bindings. + */ + public static final int AS_UNBOUNDED = Integer.MAX_VALUE; + // ASContentModelType + /** + * This constant value signifies a sequence operator. For example, in a + * DTD, this would be the ',' operator. + */ + public static final short AS_SEQUENCE = 0; + /** + * This constant value signifies a choice operator. For example, in a DTD, + * this would be the '|' operator. + */ + public static final short AS_CHOICE = 1; + /** + * All of the above. + */ + public static final short AS_ALL = 2; + /** + * None of the above, i.e., neither a choice nor sequence operator. + */ + public static final short AS_NONE = 3; + + /** + * One of AS_CHOICE, AS_SEQUENCE, + * AS_ALL or AS_NONE. The operator is applied + * to all the components(ASObjects) in the subModels. For + * example, if the list operator is AS_CHOICE and the + * components in subModels are a, b and c then the abstract schema for + * the element being declared is (a|b|c). + */ + public short getListOperator(); + /** + * One of AS_CHOICE, AS_SEQUENCE, + * AS_ALL or AS_NONE. The operator is applied + * to all the components(ASObjects) in the subModels. For + * example, if the list operator is AS_CHOICE and the + * components in subModels are a, b and c then the abstract schema for + * the element being declared is (a|b|c). + */ + public void setListOperator(short listOperator); + + /** + * min occurrence for this content particle. Its value may be 0 or a + * positive integer. + */ + public int getMinOccurs(); + /** + * min occurrence for this content particle. Its value may be 0 or a + * positive integer. + */ + public void setMinOccurs(int minOccurs); + + /** + * maximum occurrence for this content particle. Its value may be + * 0, a positive integer, or AS_UNBOUNDED to + * indicate that no upper limit has been set. + */ + public int getMaxOccurs(); + /** + * maximum occurrence for this content particle. Its value may be + * 0, a positive integer, or AS_UNBOUNDED to + * indicate that no upper limit has been set. + */ + public void setMaxOccurs(int maxOccurs); + + /** + * Pointers to ASObjects such as + * ASElementDeclarations and further + * ASContentModels. + */ + public ASObjectList getSubModels(); + /** + * Pointers to ASObjects such as + * ASElementDeclarations and further + * ASContentModels. + */ + public void setSubModels(ASObjectList subModels); + + /** + * Removes the ASObject in the submodel. Nodes that already + * exist in the list are moved as needed. + * @param oldNode The node to be removed. + */ + public void removesubModel(ASObject oldNode); + + /** + * Inserts a new node in the submodel. Nodes that already exist in the + * list are moved as needed. + * @param newNode The new node to be inserted. + * @exception DOMASException + * DUPLICATE_NAME_ERR: Raised if a element declaration + * already exists with the same name within an AS_CHOICE + * operator. + */ + public void insertsubModel(ASObject newNode) + throws DOMASException; + + /** + * Appends a new node to the end of the list representing the + * subModels. + * @param newNode The new node to be appended. + * @return the length of the subModels. + * @exception DOMASException + * DUPLICATE_NAME_ERR: Raised if a element declaration + * already exists with the same name within an AS_CHOICE + * operator. + *
TYPE_ERR: Raised if type is neither an + * ASContentModel nor an ASElementDeclaration + * . + */ + public int appendsubModel(ASObject newNode) + throws DOMASException; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASDataType.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASDataType.java new file mode 100644 index 0000000..d49adb2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASDataType.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * The datatypes supported by DOM AS implementations. Further datatypes may be + * added in the Schema/PSVI spec. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASDataType { + /** + * One of the enumerated codes representing the data type. + */ + public short getDataType(); + + // DATA_TYPES + /** + * A code representing the string data type as defined in . + */ + public static final short STRING_DATATYPE = 1; + /** + * The NOTATION data type as defined in . + */ + public static final short NOTATION_DATATYPE = 10; + /** + * The ID data type as defined in . + */ + public static final short ID_DATATYPE = 11; + /** + * The IDREF data type as defined in . + */ + public static final short IDREF_DATATYPE = 12; + /** + * The IDREFS data type as defined in . + */ + public static final short IDREFS_DATATYPE = 13; + /** + * The ENTITY data type as defined in . + */ + public static final short ENTITY_DATATYPE = 14; + /** + * The ENTITIES data type as defined in . + */ + public static final short ENTITIES_DATATYPE = 15; + /** + * The NMTOKEN data type as defined in . + */ + public static final short NMTOKEN_DATATYPE = 16; + /** + * The NMTOKENS data type as defined in . + */ + public static final short NMTOKENS_DATATYPE = 17; + /** + * A code representing the boolean data type as defined in . + */ + public static final short BOOLEAN_DATATYPE = 100; + /** + * A code representing the float data type as defined in . + */ + public static final short FLOAT_DATATYPE = 101; + /** + * A code representing the double data type as defined in . + */ + public static final short DOUBLE_DATATYPE = 102; + /** + * The decimal data type as defined in . + */ + public static final short DECIMAL_DATATYPE = 103; + /** + * The hexbinary data type as defined in . + */ + public static final short HEXBINARY_DATATYPE = 104; + /** + * The base64binary data type as defined in . + */ + public static final short BASE64BINARY_DATATYPE = 105; + /** + * Then uri reference data type as defined in . + */ + public static final short ANYURI_DATATYPE = 106; + /** + * Then XML qualified name data type as defined in . + */ + public static final short QNAME_DATATYPE = 107; + /** + * The duration data type as defined in . + */ + public static final short DURATION_DATATYPE = 108; + /** + * The datetime data type as defined in . + */ + public static final short DATETIME_DATATYPE = 109; + /** + * The date data type as defined in . + */ + public static final short DATE_DATATYPE = 110; + /** + * The time data type as defined in . + */ + public static final short TIME_DATATYPE = 111; + /** + * The yearmonth data type as defined in . + */ + public static final short GYEARMONTH_DATATYPE = 112; + /** + * The year data type as defined in . + */ + public static final short GYEAR_DATATYPE = 113; + /** + * The monthday data type as defined in . + */ + public static final short GMONTHDAY_DATATYPE = 114; + /** + * The day data type as defined in . + */ + public static final short GDAY_DATATYPE = 115; + /** + * The month data type as defined in . + */ + public static final short GMONTH_DATATYPE = 116; + /** + * The integer data type as defined in . + */ + public static final short INTEGER = 117; + /** + * A code representing the Name data type as defined in . + */ + public static final short NAME_DATATYPE = 200; + /** + * A code representing the NCName data type as defined in . + */ + public static final short NCNAME_DATATYPE = 201; + /** + * A code representing the Normalized string data type as defined in . + */ + public static final short NORMALIZEDSTRING_DATATYPE = 202; + /** + * The token data type as defined in . + */ + public static final short TOKEN_DATATYPE = 203; + /** + * The Language data type as defined in . + */ + public static final short LANGUAGE_DATATYPE = 204; + /** + * The Non-positive integer data type as defined in . + */ + public static final short NONPOSITIVEINTEGER_DATATYPE = 205; + /** + * Then negative integer data type as defined in . + */ + public static final short NEGATIVEINTEGER_DATATYPE = 206; + /** + * Then long data type as defined in . + */ + public static final short LONG_DATATYPE = 207; + /** + * The integer data type as defined in . + */ + public static final short INT_DATATYPE = 208; + /** + * The short data type as defined in . + */ + public static final short SHORT_DATATYPE = 209; + /** + * The byte data type as defined in . + */ + public static final short BYTE_DATATYPE = 210; + /** + * The non-negative integer data type as defined in . + */ + public static final short NONNEGATIVEINTEGER_DATATYPE = 211; + /** + * The unsigned long data type as defined in . + */ + public static final short UNSIGNEDLONG_DATATYPE = 212; + /** + * The unsigned integer data type as defined in . + */ + public static final short UNSIGNEDINT_DATATYPE = 213; + /** + * The unsigned short data type as defined in . + */ + public static final short UNSIGNEDSHORT_DATATYPE = 214; + /** + * The unsigned byte data type as defined in . + */ + public static final short UNSIGNEDBYTE_DATATYPE = 215; + /** + * The positive integer data type as defined in . + */ + public static final short POSITIVEINTEGER_DATATYPE = 216; + /** + * The other simple data type as defined in . + */ + public static final short OTHER_SIMPLE_DATATYPE = 1000; + /** + * The user-defined complex data type as defined in . + */ + public static final short COMPLEX_DATATYPE = 1001; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASElementDeclaration.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASElementDeclaration.java new file mode 100644 index 0000000..f2915dd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASElementDeclaration.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * The element name along with the content specification in the context of an + * ASObject. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASElementDeclaration extends ASObject { + // CONTENT_MODEL_TYPES + /** + * Represents an EMPTY content type for an Element declaration. + */ + public static final short EMPTY_CONTENTTYPE = 1; + /** + * Represents an ANY content type for an Element declaration. + */ + public static final short ANY_CONTENTTYPE = 2; + /** + * Represents a MIXED content type for an Element declaration. Note that + * isPCDataOnly would also need to checked, in addition to + * this, if an element's content model was simply text, as an example. + */ + public static final short MIXED_CONTENTTYPE = 3; + /** + * Represents an ELEMENTS only content type for an Element declaration. + */ + public static final short ELEMENTS_CONTENTTYPE = 4; + + /** + * A boolean defining whether the element order and number of the child + * elements for mixed content type has to be respected or not. For + * example XML Schema defined mixed content types the order is important + * and needs to be respected whether for DTD based AS the order and + * number of child elements are not important. + */ + public boolean getStrictMixedContent(); + /** + * A boolean defining whether the element order and number of the child + * elements for mixed content type has to be respected or not. For + * example XML Schema defined mixed content types the order is important + * and needs to be respected whether for DTD based AS the order and + * number of child elements are not important. + */ + public void setStrictMixedContent(boolean strictMixedContent); + + /** + * Datatype of the element. + */ + public ASDataType getElementType(); + /** + * Datatype of the element. + */ + public void setElementType(ASDataType elementType); + + /** + * Boolean defining whether the element type contains child elements and + * PCDATA or PCDATA only for mixed element types. true if + * the element is of type PCDATA only. Relevant only for mixed content + * type elements. + */ + public boolean getIsPCDataOnly(); + /** + * Boolean defining whether the element type contains child elements and + * PCDATA or PCDATA only for mixed element types. true if + * the element is of type PCDATA only. Relevant only for mixed content + * type elements. + */ + public void setIsPCDataOnly(boolean isPCDataOnly); + + /** + * The content type of the element. One of EMPTY_CONTENTTYPE, + * ANY_CONTENTTYPE, MIXED_CONTENTTYPE, + * ELEMENTS_CONTENTTYPE. + */ + public short getContentType(); + /** + * The content type of the element. One of EMPTY_CONTENTTYPE, + * ANY_CONTENTTYPE, MIXED_CONTENTTYPE, + * ELEMENTS_CONTENTTYPE. + */ + public void setContentType(short contentType); + + /** + * the URI reference representing the system identifier for the notation + * declaration, if present, null otherwise. + */ + public String getSystemId(); + /** + * the URI reference representing the system identifier for the notation + * declaration, if present, null otherwise. + */ + public void setSystemId(String systemId); + + /** + * The content model of element. + */ + public ASContentModel getAsCM(); + /** + * The content model of element. + */ + public void setAsCM(ASContentModel asCM); + + /** + * TheASNamedObjectMap containing + * ASAttributeDeclarations for all the attributes that can + * appear on this type of element. + */ + public ASNamedObjectMap getASAttributeDecls(); + /** + * TheASNamedObjectMap containing + * ASAttributeDeclarations for all the attributes that can + * appear on this type of element. + */ + public void setASAttributeDecls(ASNamedObjectMap ASAttributeDecls); + + /** + * Adds an ASAttributeDeclaration for the element being + * declared. + * @param attributeDecl The new attribute to add. If the attribute + * declaration already exists for the element, the call does not have + * any effect. + */ + public void addASAttributeDecl(ASAttributeDeclaration attributeDecl); + + /** + * Removes an ASAttributeDeclaration from the element being + * declared. + * @param attributeDecl The attribute declaraition to be removed. If the + * attribute declaration does not exist for the element, the call does + * not have any effect. + * @return null if the attribute does not exist. Otherwise + * returns the attribute being removed. + */ + public ASAttributeDeclaration removeASAttributeDecl(ASAttributeDeclaration attributeDecl); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASEntityDeclaration.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASEntityDeclaration.java new file mode 100644 index 0000000..963b351 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASEntityDeclaration.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * Models a general entity declaration in an abstract schema. The abstract + * schema does not handle any parameter entity. It is assumed that the + * parameter entities are expanded by the implementation as the abstract + * schema is built. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASEntityDeclaration extends ASObject { + // EntityType + /** + * constant defining an internal entity. + */ + public static final short INTERNAL_ENTITY = 1; + /** + * constant defining an external entity. + */ + public static final short EXTERNAL_ENTITY = 2; + + /** + * The type of the entity as defined above. + */ + public short getEntityType(); + /** + * The type of the entity as defined above. + */ + public void setEntityType(short entityType); + + /** + * The replacement text for the internal entity. The entity references + * within the replacement text are kept intact. For an entity of type + * EXTERNAL_ENTITY, this is null. + */ + public String getEntityValue(); + /** + * The replacement text for the internal entity. The entity references + * within the replacement text are kept intact. For an entity of type + * EXTERNAL_ENTITY, this is null. + */ + public void setEntityValue(String entityValue); + + /** + * the URI reference representing the system identifier for the notation + * declaration, if present, null otherwise. + */ + public String getSystemId(); + /** + * the URI reference representing the system identifier for the notation + * declaration, if present, null otherwise. + */ + public void setSystemId(String systemId); + + /** + * The string representing the public identifier for this notation + * declaration, if present; null otherwise. + */ + public String getPublicId(); + /** + * The string representing the public identifier for this notation + * declaration, if present; null otherwise. + */ + public void setPublicId(String publicId); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASModel.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASModel.java new file mode 100644 index 0000000..e4da759 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASModel.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +import org.w3c.dom.DOMException; + +/** + * @deprecated + * To begin with, an abstract schema is a generic structure that could + * contain both internal and external subsets. An ASModel is an + * abstract object that could map to a DTD , an XML Schema , a database + * schema, etc. An ASModel could represent either an internal + * or an external subset; hence an abstract schema could be composed of an + * ASModel representing the internal subset and an + * ASModel representing the external subset. Note that the + * ASModel representing the external subset could consult the + * ASModel representing the internal subset. Furthermore, the + * ASModel representing the internal subset could be set to + * null by the setInternalAS method as a mechanism for + * "removal". In addition, only one ASModel representing the + * external subset can be specified as "active" and it is possible that none + * are "active". Finally, the ASModel contains the factory + * methods needed to create a various types of ASObjects like + * ASElementDeclaration, ASAttributeDeclaration, + * etc. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASModel extends ASObject { + /** + * true if this ASModel defines the document + * structure in terms of namespaces and local names ; false + * if the document structure is defined only in terms of + * QNames. + */ + public boolean getIsNamespaceAware(); + + /** + * 0 if used internally, 1 if used externally, 2 if not all. An exception + * will be raised if it is incompatibly shared or in use as an internal + * subset. + */ + public short getUsageLocation(); + + /** + * The URI reference. + */ + public String getAsLocation(); + /** + * The URI reference. + */ + public void setAsLocation(String asLocation); + + /** + * The hint to locating an ASModel. + */ + public String getAsHint(); + /** + * The hint to locating an ASModel. + */ + public void setAsHint(String asHint); + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global" + * element declarations. If one attempts to add, set, or remove a node + * type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getElementDeclarations(); + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global" + * attribute declarations. If one attempts to add, set, or remove a node + * type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getAttributeDeclarations(); + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global" + * notation declarations. If one attempts to add, set, or remove a node + * type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getNotationDeclarations(); + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global" + * entity declarations. If one attempts to add, set, or remove a node + * type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getEntityDeclarations(); + + /** + * Instead of returning an all-in-one ASObject with + * ASModel methods, have discernible top-level/"global + * content model declarations. If one attempts to add, set, or remove a + * node type other than the intended one, a hierarchy exception (or + * equivalent is thrown). + */ + public ASNamedObjectMap getContentModelDeclarations(); + + /** + * This method will allow the nesting or "importation" of ASModels. + * @param abstractSchema ASModel to be set. Subsequent calls will nest + * the ASModels within the specified ownerASModel. + */ + public void addASModel(ASModel abstractSchema); + + /** + * To retrieve a list of nested ASModels without reference to names. + * @return A list of ASModels. + */ + public ASObjectList getASModels(); + + /** + * Removes only the specified ASModel from the list of + * ASModels. + * @param as AS to be removed. + */ + public void removeAS(ASModel as); + + /** + * Determines if an ASModel itself is valid, i.e., confirming + * that it's well-formed and valid per its own formal grammar. + * @return true if the ASModel is valid, + * false otherwise. + */ + public boolean validate(); + + /** + * Creates an element declaration for the element type specified. + * @param namespaceURI The namespace URI of the element type + * being declared. + * @param name The name of the element. The format of the name could be + * an NCName as defined by XML Namespaces or a Name as defined by XML + * 1.0; it's ASModel-dependent. + * @return A new ASElementDeclaration object with + * name attribute set to tagname and + * namespaceURI set to systemId. Other + * attributes of the element declaration are set through + * ASElementDeclaration interface methods. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the specified name contains an + * illegal character. + */ + public ASElementDeclaration createASElementDeclaration(String namespaceURI, + String name) + throws DOMException; + + /** + * Creates an attribute declaration. + * @param namespaceURI The namespace URI of the attribute being declared. + * @param name The name of the attribute. The format of the name could be + * an NCName as defined by XML Namespaces or a Name as defined by XML + * 1.0; it's ASModel-dependent. + * @return A new ASAttributeDeclaration object with + * appropriate attributes set by input parameters. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the input name + * parameter contains an illegal character. + */ + public ASAttributeDeclaration createASAttributeDeclaration(String namespaceURI, + String name) + throws DOMException; + + /** + * Creates a new notation declaration. + * @param namespaceURI The namespace URI of the notation being declared. + * @param name The name of the notation. The format of the name could be + * an NCName as defined by XML Namespaces or a Name as defined by XML + * 1.0; it's ASModel-dependent. + * @param systemId The system identifier for the notation declaration. + * @param publicId The public identifier for the notation declaration. + * @return A new ASNotationDeclaration object with + * notationName attribute set to name and + * publicId and systemId set to the + * corresponding fields. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the specified name contains an + * illegal character. + */ + public ASNotationDeclaration createASNotationDeclaration(String namespaceURI, + String name, + String systemId, + String publicId) + throws DOMException; + + /** + * Creates an ASEntityDeclaration. + * @param name The name of the entity being declared. + * @return A new ASEntityDeclaration object with + * entityName attribute set to name. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the specified name contains an + * illegal character. + */ + public ASEntityDeclaration createASEntityDeclaration(String name) + throws DOMException; + + /** + * Creates an object which describes part of an + * ASElementDeclaration's content model. + * @param minOccurs The minimum occurrence for the subModels of this + * ASContentModel. + * @param maxOccurs The maximum occurrence for the subModels of this + * ASContentModel. + * @param operator operator of type AS_CHOICE, + * AS_SEQUENCE, AS_ALL or + * AS_NONE. + * @return A new ASContentModel object. + * @exception DOMASException + * A DOMASException, e.g., minOccurs > maxOccurs. + */ + public ASContentModel createASContentModel(int minOccurs, + int maxOccurs, + short operator) + throws DOMASException; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASNamedObjectMap.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASNamedObjectMap.java new file mode 100644 index 0000000..2bf706e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASNamedObjectMap.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +import org.w3c.dom.DOMException; + +/** + * @deprecated + * Objects implementing the ASNamedObjectMap interface are used + * to represent collections of abstract schema nodes that can be accessed by + * name. Note that ASNamedObjectMap does not inherit from + * ASObjectList; ASNamedObjectMaps are not + * maintained in any particular order. Objects contained in an object + * implementing ASNamedObjectMap may also be accessed by an + * ordinal index, but this is simply to allow convenient enumeration of the + * contents of a ASNamedObjectMap, and does not imply that the + * DOM specifies an order to these ASObjects. + *

ASNamedObjectMap object in the DOM are live. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASNamedObjectMap { + /** + * The number of ASObjects in the ASObjectList. + * The range of valid child node indices is 0 to length-1 + * inclusive. + */ + public int getLength(); + + /** + * Retrieves an ASObject specified by name. + * @param name The nodeName of an ASObject to + * retrieve. + * @return An ASObject with specified node name and + * null if the map does not contain an element with the + * given name. + */ + public ASObject getNamedItem(String name); + + /** + * Retrieves an ASObject specified by local name and + * namespace URI. + * @param namespaceURI The namespace URI of the ASObject to + * retrieve. + * @param localName The local name of the ASObject to + * retrieve. + * @return A ASObject (of any type) with the specified local + * name and namespace URI, or null if they do not + * identify any ASObject in this map. + */ + public ASObject getNamedItemNS(String namespaceURI, + String localName); + + /** + * Returns the indexth item in the map. The index starts at + * 0. If index is greater than or equal to the + * number of nodes in the list, this returns null. + * @param index The position in the map from which the item is to be + * retrieved. + * @return The ASObject at the indexth position + * in the ASNamedObjectMap, or null if that + * is not a valid index. + */ + public ASObject item(int index); + + /** + * Removes an ASObject specified by a nodeName. + * @param name The nodeName of the ASObject to + * be removed. + * @return The ASObject removed from this map if an + * ASObject with such a name exists. + * @exception DOMException + * NOT_FOUND_ERR: Raised if there is no node named name in + * this map. + *
NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly. + */ + public ASObject removeNamedItem(String name) + throws DOMException; + + /** + * Removes an ASObject specified by a namespace URI and a + * local name. + * @param namespaceURI The namespace URI of the ASObject to + * be removed. + * @param localName The local name of the ASObject to remove. + * @return The ASObject removed from this map if an + * ASObject with such a local name and namespace URI + * exists. + * @exception DOMException + * NOT_FOUND_ERR: Raised if there is no node with the specified + * namespaceURI and localName in this map. + *
NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly. + */ + public ASObject removeNamedItemNS(String namespaceURI, + String localName) + throws DOMException; + + /** + * Adds an ASObject using its nodeName + * attribute. If an ASObject with that name is already + * present in this map, it is replaced by the new one. + * @param newASObject The ASObject to be inserted in the map + * with its nodeName as the key. + * @return If the new node replaces an existing one, the replaced node is + * returned, otherwise null. + * @exception DOMException + * WRONG_DOCUMENT_ERR: Raised if arg was created from a + * different ASModel than the one that created this map. + *
NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly. + *
HIERARCHY_REQUEST_ERR: Raised if an attempt is made to add a node + * doesn't belong in this ASNamedObjectMap. + */ + public ASObject setNamedItem(ASObject newASObject) + throws DOMException; + + /** + * Adds an ASObject using its namespaceURI and + * localName. If an ASObject with the same + * namespaceURI and localName is already + * present in this map, it is replaced by the new one. + * @param newASObject The ASObject to be inserted in the + * map.The ASObject will later be accessible using the + * value of its namespaceURI and localName + * attributes. + * @return If the new node replaces an existing one, the replaced node is + * returned, otherwise null. + * @exception DOMException + * WRONG_DOCUMENT_ERR: Raised if arg was + * created from a different ASModel than the one that + * created this map. + *
NO_MODIFICATION_ALLOWED_ERR: Raised if this map is + * readonly. + *
HIERARCHY_REQUEST_ERR: Raised if an attempt is made + * to add a node doesn't belong in this ASNamedObjectMap. + */ + public ASObject setNamedItemNS(ASObject newASObject) + throws DOMException; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASNotationDeclaration.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASNotationDeclaration.java new file mode 100644 index 0000000..f971e05 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASNotationDeclaration.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * This interface represents a notation declaration. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASNotationDeclaration extends ASObject { + /** + * the URI reference representing the system identifier for the notation + * declaration, if present, null otherwise. + */ + public String getSystemId(); + /** + * the URI reference representing the system identifier for the notation + * declaration, if present, null otherwise. + */ + public void setSystemId(String systemId); + + /** + * The string representing the public identifier for this notation + * declaration, if present; null otherwise. + */ + public String getPublicId(); + /** + * The string representing the public identifier for this notation + * declaration, if present; null otherwise. + */ + public void setPublicId(String publicId); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASObject.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASObject.java new file mode 100644 index 0000000..ce125c4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASObject.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * The ASObject interface is analogous to a Node in + * , e.g., an element declaration. + *

Opaque. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASObject { + // ASObjectType + /** + * The node is an ASElementDeclaration. + */ + public static final short AS_ELEMENT_DECLARATION = 1; + /** + * The node is an ASAttributeDeclaration. + */ + public static final short AS_ATTRIBUTE_DECLARATION = 2; + /** + * The node is a ASNotationDeclaration. + */ + public static final short AS_NOTATION_DECLARATION = 3; + /** + * The node is an ASEntityDeclaration. + */ + public static final short AS_ENTITY_DECLARATION = 4; + /** + * The node is a ASContentModel. + */ + public static final short AS_CONTENTMODEL = 5; + /** + * The node is a ASModel. + */ + public static final short AS_MODEL = 6; + + /** + * A code representing the underlying object as defined above. + */ + public short getAsNodeType(); + + /** + * The ASModel object associated with this + * ASObject. For a node of type AS_MODEL, this + * is null. + */ + public ASModel getOwnerASModel(); + /** + * The ASModel object associated with this + * ASObject. For a node of type AS_MODEL, this + * is null. + */ + public void setOwnerASModel(ASModel ownerASModel); + + /** + * The name of this ASObject depending on the + * ASObject type. + */ + public String getNodeName(); + /** + * The name of this ASObject depending on the + * ASObject type. + */ + public void setNodeName(String nodeName); + + /** + * The namespace prefix of this node, or null if it is + * unspecified. + */ + public String getPrefix(); + /** + * The namespace prefix of this node, or null if it is + * unspecified. + */ + public void setPrefix(String prefix); + + /** + * Returns the local part of the qualified name of this + * ASObject. + */ + public String getLocalName(); + /** + * Returns the local part of the qualified name of this + * ASObject. + */ + public void setLocalName(String localName); + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespaceURI(); + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public void setNamespaceURI(String namespaceURI); + + /** + * Creates a copy of this ASObject. See text for + * cloneNode off of Node but substitute AS + * functionality. + * @param deep Setting the deep flag on, causes the whole + * subtree to be duplicated. Setting it to false only + * duplicates its immediate child nodes. + * @return Cloned ASObject. + */ + public ASObject cloneASObject(boolean deep); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASObjectList.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASObjectList.java new file mode 100644 index 0000000..111f6e2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ASObjectList.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * The ASObjectList interface provides the abstraction of an + * ordered collection of AS nodes, without defining or constraining how this + * collection is implemented. ASObjectList objects in the DOM + * AS are live. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ASObjectList { + /** + * The number of ASObjects in the list. The range of valid + * child node indices is 0 to length-1 inclusive. + */ + public int getLength(); + + /** + * Returns the indexth item in the collection. The index + * starts at 0. If index is greater than or equal to the + * number of nodes in the list, this returns null. + * @param index index into the collection. + * @return The ASObject at the indexth position + * in the ASObjectList, or null if that is + * not a valid index. + */ + public ASObject item(int index); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/CharacterDataEditAS.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/CharacterDataEditAS.java new file mode 100644 index 0000000..02c3af5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/CharacterDataEditAS.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * This interface extends the NodeEditAS interface with + * additional methods for document editing. An object implementing this + * interface must also implement NodeEditAS interface. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface CharacterDataEditAS extends NodeEditAS { + /** + * true if content only whitespace; false for + * non-whitespace. + */ + public boolean getIsWhitespaceOnly(); + + /** + * Determines if data can be set. + * @param offset Offset. + * @param count Argument to be set. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canSetData(int offset, + int count); + + /** + * Determines if data can be appended. + * @param arg Argument to be appended. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canAppendData(String arg); + + /** + * Determines if data can be replaced. + * @param offset Offset. + * @param count Replacement. + * @param arg Argument to be set. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canReplaceData(int offset, + int count, + String arg); + + /** + * Determines if data can be inserted. + * @param offset Offset. + * @param arg Argument to be set. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canInsertData(int offset, + String arg); + + /** + * Determines if data can be deleted. + * @param offset Offset. + * @param count Number of 16-bit units to delete. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canDeleteData(int offset, + int count); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASBuilder.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASBuilder.java new file mode 100644 index 0000000..d7a620b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASBuilder.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSParser; + +/** + * @deprecated + * An Abstract Schema parser interface. + *

DOMASBuilder provides an API for parsing Abstract Schemas + * and building the corresponding ASModel tree. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface DOMASBuilder extends LSParser { + /** + * Associate an ASModel with a LSParser. This + * ASModel will be used by the " + * validate-if-schema" and " + * datatype-normalization" options during the load of a new + * Document. + */ + public ASModel getAbstractSchema(); + /** + * Associate an ASModel with a LSParser. This + * ASModel will be used by the " + * validate-if-schema" and " + * datatype-normalization" options during the load of a new + * Document. + */ + public void setAbstractSchema(ASModel abstractSchema); + + /** + * Parse a Abstract Schema from a location identified by an URI reference. + * @param uri The location of the Abstract Schema to be read. + * @return The newly created Abstract Schema. + * @exception DOMASException + * Exceptions raised by parseASURI() originate with the + * installed ErrorHandler, and thus depend on the implementation of + * the DOMErrorHandler interfaces. The default error + * handlers will raise a DOMASException if any form of + * Abstract Schema inconsistencies or warning occurs during the parse, + * but application defined errorHandlers are not required to do so. + *
WRONG_MIME_TYPE_ERR: Raised when mimeTypeCheck is + * true and the input source has an incorrect MIME Type. + * See the attribute mimeTypeCheck. + * @exception DOMSystemException + * Exceptions raised by parseURI() originate with the + * installed ErrorHandler, and thus depend on the implementation of + * the DOMErrorHandler interfaces. The default error + * handlers will raise a DOMSystemException if any form I/O or other + * system error occurs during the parse, but application defined error + * handlers are not required to do so. + */ + public ASModel parseASURI(String uri) + throws DOMASException, Exception; + + /** + * Parse a Abstract Schema from a location identified by an + * LSInput. + * @param is The LSInput from which the source + * Abstract Schema is to be read. + * @return The newly created ASModel. + * @exception DOMASException + * Exceptions raised by parseASURI() originate with the + * installed ErrorHandler, and thus depend on the implementation of + * the DOMErrorHandler interfaces. The default error + * handlers will raise a DOMASException if any form of + * Abstract Schema inconsistencies or warning occurs during the parse, + * but application defined errorHandlers are not required to do so. + *
Raise a WRONG_MIME_TYPE_ERR when mimeTypeCheck is + * true and the inputsource has an incorrect MIME Type. + * See attribute mimeTypeCheck. + * @exception DOMSystemException + * Exceptions raised by parseURI() originate with the + * installed ErrorHandler, and thus depend on the implementation of + * the DOMErrorHandler interfaces. The default error + * handlers will raise a DOMSystemException if any form I/O or other + * system error occurs during the parse, but application defined error + * handlers are not required to do so. + */ + public ASModel parseASInputSource(LSInput is) + throws DOMASException, Exception; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASException.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASException.java new file mode 100644 index 0000000..42033ac --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASException.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * Abstract Schemas operations may throw a DOMSystemException as + * described in their descriptions. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public class DOMASException extends RuntimeException { + public DOMASException(short code, String message) { + super(message); + this.code = code; + } + public short code; + // ASExceptionCode + /** + * If an element declaration already exists with the same name within an + * AS_CHOICE operator. + */ + public static final short DUPLICATE_NAME_ERR = 1; + /** + * If the type of the ASObject is neither an + * ASContentModel nor an ASElementDeclaration. + */ + public static final short TYPE_ERR = 2; + /** + * If the DocumentEditAS related to the node does not have + * any active ASModel and wfValidityCheckLevel + * is set to PARTIAL or STRICT_VALIDITY_CHECK. + */ + public static final short NO_AS_AVAILABLE = 3; + /** + * When mimeTypeCheck is true and the input + * source has an incorrect MIME Type. See the attribute + * mimeTypeCheck. + */ + public static final short WRONG_MIME_TYPE_ERR = 4; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASWriter.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASWriter.java new file mode 100644 index 0000000..4dafbb6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMASWriter.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +import org.w3c.dom.ls.LSSerializer; + +/** + * @deprecated + * A Abstract Schema serialization interface. + *

DOMASWriters provides an API for serializing Abstract Schemas out in + * the form of a source Abstract Schema. The Abstract Schema is written to + * an output stream, the type of which depends on the specific language + * bindings in use. + *

DOMASWriter is a generic Abstract Schema serialization interface. It + * can be applied to both an internal Abstract Schema and/or an external + * Abstract Schema. DOMASWriter is applied to serialize a single Abstract + * Schema. Serializing a document with an active Internal Abstract Schema + * will serialize this internal Abstract Schema with the document as it is + * part of the Document (see LSSerializer). + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface DOMASWriter extends LSSerializer { + /** + * Write out the specified Abstract Schema to the specified destination. + * Does it write a DTD or an XML Schema (or something else)? Is it + * possible to use this method to convert a DTD to an XML Schema? + * @param destination The destination for the data to be written. + * @param model The Abstract Schema to serialize. + * @exception DOMSystemException + * This exception will be raised in response to any sort of IO or system + * error that occurs while writing to the destination. It may wrap an + * underlying system exception. + */ + public void writeASModel(java.io.OutputStream destination, + ASModel model) + throws Exception; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMImplementationAS.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMImplementationAS.java new file mode 100644 index 0000000..30baa90 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DOMImplementationAS.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * This interface allows creation of an ASModel. The expectation + * is that an instance of the DOMImplementationAS interface can + * be obtained by using binding-specific casting methods on an instance of + * the DOMImplementation interface when the DOM implementation + * supports the feature "AS-EDIT". + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface DOMImplementationAS { + /** + * Creates an ASModel. + * @param isNamespaceAware Allow creation of ASModel with + * this attribute set to a specific value. + * @return A null return indicates failure.what is a + * failure? Could be a system error. + */ + public ASModel createAS(boolean isNamespaceAware); + + /** + * Creates an DOMASBuilder.Do we need the method since we + * already have DOMImplementationLS.createDOMParser? + * @return a DOMASBuilder + */ + public DOMASBuilder createDOMASBuilder(); + + /** + * Creates an DOMASWriter. + * @return a DOMASWriter + */ + public DOMASWriter createDOMASWriter(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/DocumentAS.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DocumentAS.java new file mode 100644 index 0000000..4ed13e6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DocumentAS.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +import org.w3c.dom.DOMException; + +/** + * @deprecated + * This interface extends the Document interface with additional + * methods for both document and AS editing. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface DocumentAS { + /** + * The active external ASModel. Note that the active external + * ASModel is responsible for consulting the internal + * ASModel, so if an attribute is declared in the internal + * ASModel and the corresponding ownerElements + * points to a ASElementDeclarations defined in the active + * external ASModel, changing the active external ASModel will cause the + * ownerElements to be recomputed. If the + * ownerElements is not defined in the newly active + * external ASModel, the ownerElements will be an empty + * node list. + */ + public ASModel getActiveASModel(); + /** + * The active external ASModel. Note that the active external + * ASModel is responsible for consulting the internal + * ASModel, so if an attribute is declared in the internal + * ASModel and the corresponding ownerElements + * points to a ASElementDeclarations defined in the active + * external ASModel, changing the active external ASModel will cause the + * ownerElements to be recomputed. If the + * ownerElements is not defined in the newly active + * external ASModel, the ownerElements will be an empty + * node list. + */ + public void setActiveASModel(ASModel activeASModel); + + /** + * A list of ASObjects of type AS_MODELs + * associated with a document. The addAS method associates + * a ASModel with a document. + */ + public ASObjectList getBoundASModels(); + /** + * A list of ASObjects of type AS_MODELs + * associated with a document. The addAS method associates + * a ASModel with a document. + */ + public void setBoundASModels(ASObjectList boundASModels); + + /** + * Retrieve the internal ASModel of a document. + * @return ASModel. + */ + public ASModel getInternalAS(); + + /** + * Sets the internal subset ASModel of a document. This could + * be null as a mechanism for "removal". + * @param as ASModel to be the internal subset of the + * document. + */ + public void setInternalAS(ASModel as); + + /** + * Associate a ASModel with a document. Can be invoked + * multiple times to result in a list of ASModels. Note + * that only one internal ASModel is associated with the + * document, however, and that only one of the possible list of + * ASModels is active at any one time. + * @param as ASModel to be associated with the document. + */ + public void addAS(ASModel as); + + /** + * Removes a ASModel associated with a document. Can be + * invoked multiple times to remove a number of these in the list of + * ASModels. + * @param as The ASModel to be removed. + */ + public void removeAS(ASModel as); + + /** + * Gets the AS editing object describing this elementThis method needs to + * be changed and others added. + * @return ASElementDeclaration object if the implementation supports " + * AS-EDIT" feature. Otherwise null. + * @exception DOMException + * NOT_FOUND_ERR: Raised if no ASModel is present. + */ + public ASElementDeclaration getElementDeclaration() + throws DOMException; + + /** + * Validates the document against the ASModel. + * @exception DOMASException + * + */ + public void validate() + throws DOMASException; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/DocumentEditAS.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DocumentEditAS.java new file mode 100644 index 0000000..27ebaef --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/DocumentEditAS.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +/** + * @deprecated + * This interface extends the NodeEditAS interface with + * additional methods for both document and AS editing. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface DocumentEditAS extends NodeEditAS { + /** + * An attribute specifying whether continuous checking for the validity of + * the document is enforced or not. Setting this to true + * will result in an exception being thrown, i.e., + * VALIDATION_ERR, for documents that are invalid at the + * time of the call. If the document is invalid, then this attribute + * will remain false. This attribute is false + * by default.Add VALIDATION_ERR code to the list of constants in + * DOMASException. + */ + public boolean getContinuousValidityChecking(); + /** + * An attribute specifying whether continuous checking for the validity of + * the document is enforced or not. Setting this to true + * will result in an exception being thrown, i.e., + * VALIDATION_ERR, for documents that are invalid at the + * time of the call. If the document is invalid, then this attribute + * will remain false. This attribute is false + * by default.Add VALIDATION_ERR code to the list of constants in + * DOMASException. + */ + public void setContinuousValidityChecking(boolean continuousValidityChecking); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/ElementEditAS.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ElementEditAS.java new file mode 100644 index 0000000..c92610d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/ElementEditAS.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +import org.w3c.dom.Attr; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * @deprecated + * This interface extends the Element interface with additional + * methods for guided document editing. An object implementing this + * interface must also implement NodeEditAS interface. + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface ElementEditAS extends NodeEditAS { + /** + * The list of qualified element names defined in the abstract schema. + */ + public NodeList getDefinedElementTypes(); + + /** + * Determines element content type. + * @return Constant for one of EMPTY_CONTENTTYPE, ANY_CONTENTTYPE, + * MIXED_CONTENTTYPE, ELEMENTS_CONTENTTYPE. + */ + public short contentType(); + + /** + * Determines if the value for specified attribute can be set. + * @param attrname Name of attribute. + * @param attrval Value to be assigned to the attribute. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canSetAttribute(String attrname, + String attrval); + + /** + * Determines if an attribute node can be added with respect to the + * validity check level.This is an attribute node, there is no need for + * canSetAttributreNodeNS! + * @param attrNode Node in which the attribute can possibly + * be set. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canSetAttributeNode(Attr attrNode); + + /** + * Determines if the attribute with given namespace and qualified name can + * be created if not already present in the attribute list of the + * element. If the attribute with same qualified name and namespaceURI + * is already present in the elements attribute list it tests for the + * value of the attribute and its prefix to the new value. See DOM core + * setAttributeNS. + * @param name Qualified name of attribute. + * @param attrval Value to be assigned to the attribute. + * @param namespaceURI namespaceURI of namespace. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canSetAttributeNS(String name, + String attrval, + String namespaceURI); + + /** + * Verifies if an attribute by the given name can be removed. + * @param attrname Name of attribute. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canRemoveAttribute(String attrname); + + /** + * Verifies if an attribute by the given local name and namespace can be + * removed. + * @param attrname Local name of the attribute to be removed. + * @param namespaceURI The namespace URI of the attribute to remove. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canRemoveAttributeNS(String attrname, + String namespaceURI); + + /** + * Determines if an attribute node can be removed. + * @param attrNode The Attr node to remove from the + * attribute list. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canRemoveAttributeNode(Node attrNode); + + /** + * Returns an NodeList containing the possible + * Element names that can appear as children of this type + * of element. + * @return List of possible children element types of this element. + */ + public NodeList getChildElements(); + + /** + * Returns an NodeList containing the possible + * Element names that can appear as a parent of this type + * of element. + * @return List of possible parent element types of this element. + */ + public NodeList getParentElements(); + + /** + * Returns an NodeList containing all the possible + * Attrs that can appear with this type of element. + * @return List of possible attributes of this element. + */ + public NodeList getAttributeList(); + + /** + * Determines if this element is defined in the currently active AS. + * @param elemTypeName Name of element. + * @return A boolean that is true if the element is defined, + * false otherwise. + */ + public boolean isElementDefined(String elemTypeName); + + /** + * Determines if this element in this namespace is defined in the + * currently active AS. + * @param elemTypeName Name of element. + * @param namespaceURI namespaceURI of namespace. + * @param name Qualified name of namespace. This is for sub-elements. + * @return A boolean that is true if the element is defined, + * false otherwise. + */ + public boolean isElementDefinedNS(String elemTypeName, + String namespaceURI, + String name); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/dom3/as/NodeEditAS.java b/resources/xerces2-j-src/org/apache/xerces/dom3/as/NodeEditAS.java new file mode 100644 index 0000000..53953e2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/dom3/as/NodeEditAS.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2001 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. + * See W3C License http://www.w3.org/Consortium/Legal/ for more details. + */ + +package org.apache.xerces.dom3.as; + +import org.w3c.dom.Node; + +/** + * @deprecated + * This interface extends a Node from with additional methods + * for guided document editing. The expectation is that an instance of the + * DOMImplementationAS interface can be obtained by using + * binding-specific casting methods on an instance of the + * DOMImplementation interface when the DOM implementation + * supports the feature "AS-DOC". + *

See also the Document Object Model (DOM) Level 3 Abstract Schemas and Load +and Save Specification. + */ +public interface NodeEditAS { + // ASCheckType + /** + * Check for well-formedness of this node. + */ + public static final short WF_CHECK = 1; + /** + * Check for namespace well-formedness includes WF_CHECK. + */ + public static final short NS_WF_CHECK = 2; + /** + * Checks for whether this node is partially valid. It includes + * NS_WF_CHECK. + */ + public static final short PARTIAL_VALIDITY_CHECK = 3; + /** + * Checks for strict validity of the node with respect to active AS which + * by definition includes NS_WF_CHECK. + */ + public static final short STRICT_VALIDITY_CHECK = 4; + + /** + * Determines whether the insertBefore operation from the + * Node interface would make this document invalid with + * respect to the currently active AS. Describe "valid" when referring + * to partially completed documents. + * @param newChild Node to be inserted. + * @param refChild Reference Node. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canInsertBefore(Node newChild, + Node refChild); + + /** + * Has the same arguments as RemoveChild. + * @param oldChild Node to be removed. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canRemoveChild(Node oldChild); + + /** + * Has the same arguments as ReplaceChild. + * @param newChild New Node. + * @param oldChild Node to be replaced. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canReplaceChild(Node newChild, + Node oldChild); + + /** + * Has the same arguments as AppendChild. + * @param newChild Node to be appended. + * @return true if no reason it can't be done; + * false if it can't be done. + */ + public boolean canAppendChild(Node newChild); + + /** + * Determines if the Node is valid relative to currently active AS. It + * doesn't normalize before checking if the document is valid. To do so, + * one would need to explicitly call a normalize method. + * @param deep Setting the deep flag on causes the + * isNodeValid method to check for the whole subtree of + * the current node for validity. Setting it to false + * only checks the current node and its immediate child nodes. The + * validate method on the DocumentAS + * interface, however, checks to determine whether the entire document + * is valid. + * @param wFValidityCheckLevel Flag to tell at what level validity and + * well-formedness checking is done. + * @return true if the node is valid/well-formed in the + * current context and check level defined by + * wfValidityCheckLevel, false if not. + * @exception DOMASException + * NO_AS_AVAILABLE: Raised if the + * DocumentEditAS related to this node does not have any + * active ASModel and wfValidityCheckLevel + * is set to PARTIAL or STRICT_VALIDITY_CHECK + * . + */ + public boolean isNodeValid(boolean deep, + short wFValidityCheckLevel) + throws DOMASException; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/Constants.java b/resources/xerces2-j-src/org/apache/xerces/impl/Constants.java new file mode 100644 index 0000000..2b4fb3e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/Constants.java @@ -0,0 +1,696 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * Commonly used constants. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public final class Constants { + + // + // Constants + // + // Schema Types: + public static final String NS_XMLSCHEMA = "http://www.w3.org/2001/XMLSchema".intern(); + public static final String NS_DTD = "http://www.w3.org/TR/REC-xml".intern(); + + // Schema Versions: + public static final String W3C_XML_SCHEMA10_NS_URI = "http://www.w3.org/XML/XMLSchema/v1.0".intern(); + + // sax features + + /** SAX feature prefix ("http://xml.org/sax/features/"). */ + public static final String SAX_FEATURE_PREFIX = "http://xml.org/sax/features/"; + + /** Namespaces feature ("namespaces"). */ + public static final String NAMESPACES_FEATURE = "namespaces"; + + /** Namespace prefixes feature ("namespace-prefixes"). */ + public static final String NAMESPACE_PREFIXES_FEATURE = "namespace-prefixes"; + + /** String interning feature ("string-interning"). */ + public static final String STRING_INTERNING_FEATURE = "string-interning"; + + /** Validation feature ("validation"). */ + public static final String VALIDATION_FEATURE = "validation"; + + /** External general entities feature ("external-general-entities "). */ + public static final String EXTERNAL_GENERAL_ENTITIES_FEATURE = "external-general-entities"; + + /** External parameter entities feature ("external-parameter-entities "). */ + public static final String EXTERNAL_PARAMETER_ENTITIES_FEATURE = "external-parameter-entities"; + + /** Lexical handler parameter entities feature ("lexical-handler/parameter-entities"). */ + public static final String LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE = "lexical-handler/parameter-entities"; + + /** Is standalone feature ("is-standalone"). */ + public static final String IS_STANDALONE_FEATURE = "is-standalone"; + + /** Resolve DTD URIs feature ("resolve-dtd-uris"). */ + public static final String RESOLVE_DTD_URIS_FEATURE = "resolve-dtd-uris"; + + /** Use Attributes2 feature ("use-attributes2"). */ + public static final String USE_ATTRIBUTES2_FEATURE = "use-attributes2"; + + /** Use Locator2 feature ("use-locator2"). */ + public static final String USE_LOCATOR2_FEATURE = "use-locator2"; + + /** Use EntityResolver2 feature ("use-entity-resolver2"). */ + public static final String USE_ENTITY_RESOLVER2_FEATURE = "use-entity-resolver2"; + + /** Unicode normalization checking feature ("unicode-normalization-checking"). */ + public static final String UNICODE_NORMALIZATION_CHECKING_FEATURE = "unicode-normalization-checking"; + + /** xmlns URIs feature ("xmlns-uris"). */ + public static final String XMLNS_URIS_FEATURE = "xmlns-uris"; + + /** XML 1.1 feature ("xml-1.1"). */ + public static final String XML_11_FEATURE = "xml-1.1"; + + /** Allow unparsed entity and notation declaration events to be sent after the end DTD event ("allow-dtd-events-after-endDTD") */ + public static final String ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE = "allow-dtd-events-after-endDTD"; + + // sax properties + + /** SAX property prefix ("http://xml.org/sax/properties/"). */ + public static final String SAX_PROPERTY_PREFIX = "http://xml.org/sax/properties/"; + + /** Declaration handler property ("declaration-handler"). */ + public static final String DECLARATION_HANDLER_PROPERTY = "declaration-handler"; + + /** Lexical handler property ("lexical-handler"). */ + public static final String LEXICAL_HANDLER_PROPERTY = "lexical-handler"; + + /** DOM node property ("dom-node"). */ + public static final String DOM_NODE_PROPERTY = "dom-node"; + + /** XML string property ("xml-string"). */ + public static final String XML_STRING_PROPERTY = "xml-string"; + + /** Document XML version property ("document-xml-version"). */ + public static final String DOCUMENT_XML_VERSION_PROPERTY = "document-xml-version"; + + + // + // JAXP properties + // + + /** JAXP property prefix ("http://java.sun.com/xml/jaxp/properties/"). */ + public static final String JAXP_PROPERTY_PREFIX = + "http://java.sun.com/xml/jaxp/properties/"; + + /** JAXP schemaSource property: when used internally may include DTD sources (DOM) */ + public static final String SCHEMA_SOURCE = "schemaSource"; + + /** JAXP schemaSource language: when used internally may include DTD namespace (DOM) */ + public static final String SCHEMA_LANGUAGE = "schemaLanguage"; + + + // + // DOM features + // + + /** Comments feature ("include-comments"). */ + public static final String INCLUDE_COMMENTS_FEATURE = "include-comments"; + + /** Create cdata nodes feature ("create-cdata-nodes"). */ + public static final String CREATE_CDATA_NODES_FEATURE = "create-cdata-nodes"; + + /** Feature id: load as infoset. */ + public static final String LOAD_AS_INFOSET = "load-as-infoset"; + + + // + // Constants: DOM Level 3 feature ids + // + + public static final String DOM_CANONICAL_FORM = "canonical-form"; + public static final String DOM_CDATA_SECTIONS ="cdata-sections"; + public static final String DOM_COMMENTS = "comments"; + + // REVISIT: this feature seems to have no effect for Xerces + public static final String DOM_CHARSET_OVERRIDES_XML_ENCODING = + "charset-overrides-xml-encoding"; + + public static final String DOM_DATATYPE_NORMALIZATION = "datatype-normalization"; + public static final String DOM_ENTITIES = "entities"; + public static final String DOM_INFOSET = "infoset"; + public static final String DOM_NAMESPACES = "namespaces"; + public static final String DOM_NAMESPACE_DECLARATIONS = "namespace-declarations"; + public static final String DOM_SUPPORTED_MEDIATYPES_ONLY = + "supported-media-types-only"; + + public static final String DOM_VALIDATE_IF_SCHEMA = "validate-if-schema"; + public static final String DOM_VALIDATE = "validate"; + public static final String DOM_ELEMENT_CONTENT_WHITESPACE = + "element-content-whitespace"; + + // DOM Level 3 features defined in Core: + public static final String DOM_DISCARD_DEFAULT_CONTENT = "discard-default-content"; + public static final String DOM_NORMALIZE_CHARACTERS = "normalize-characters"; + public static final String DOM_CHECK_CHAR_NORMALIZATION = "check-character-normalization"; + public static final String DOM_WELLFORMED = "well-formed"; + public static final String DOM_SPLIT_CDATA = "split-cdata-sections"; + + // Load and Save + public static final String DOM_FORMAT_PRETTY_PRINT = "format-pretty-print"; + public static final String DOM_XMLDECL = "xml-declaration"; + public static final String DOM_UNKNOWNCHARS = "unknown-characters"; + public static final String DOM_CERTIFIED = "certified"; + public static final String DOM_DISALLOW_DOCTYPE = "disallow-doctype"; + public static final String DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS = "ignore-unknown-character-denormalizations"; + + // DOM Properties + public static final String DOM_RESOURCE_RESOLVER = "resource-resolver"; + public static final String DOM_ERROR_HANDLER = "error-handler"; + public static final String DOM_SCHEMA_TYPE = "schema-type"; + public static final String DOM_SCHEMA_LOCATION = "schema-location"; + + // XSModel + public static final String DOM_PSVI = "psvi"; + + + // xerces features + + /** Xerces features prefix ("http://apache.org/xml/features/"). */ + public static final String XERCES_FEATURE_PREFIX = "http://apache.org/xml/features/"; + + /** Schema validation feature ("validation/schema"). */ + public static final String SCHEMA_VALIDATION_FEATURE = "validation/schema"; + + /** Expose schema normalized values */ + public static final String SCHEMA_NORMALIZED_VALUE = "validation/schema/normalized-value"; + + /** Send schema default value via characters() */ + public static final String SCHEMA_ELEMENT_DEFAULT = "validation/schema/element-default"; + + /** Schema full constraint checking ("validation/schema-full-checking"). */ + public static final String SCHEMA_FULL_CHECKING = "validation/schema-full-checking"; + + /** Augment Post-Schema-Validation-Infoset */ + public static final String SCHEMA_AUGMENT_PSVI = "validation/schema/augment-psvi"; + + /** Dynamic validation feature ("validation/dynamic"). */ + public static final String DYNAMIC_VALIDATION_FEATURE = "validation/dynamic"; + + /** Warn on duplicate attribute declaration feature ("validation/warn-on-duplicate-attdef"). */ + public static final String WARN_ON_DUPLICATE_ATTDEF_FEATURE = "validation/warn-on-duplicate-attdef"; + + /** Warn on undeclared element feature ("validation/warn-on-undeclared-elemdef"). */ + public static final String WARN_ON_UNDECLARED_ELEMDEF_FEATURE = "validation/warn-on-undeclared-elemdef"; + + /** Warn on duplicate entity declaration feature ("warn-on-duplicate-entitydef"). */ + public static final String WARN_ON_DUPLICATE_ENTITYDEF_FEATURE = "warn-on-duplicate-entitydef"; + + /** Allow Java encoding names feature ("allow-java-encodings"). */ + public static final String ALLOW_JAVA_ENCODINGS_FEATURE = "allow-java-encodings"; + + /** Disallow DOCTYPE declaration feature ("disallow-doctype-decl"). */ + public static final String DISALLOW_DOCTYPE_DECL_FEATURE = "disallow-doctype-decl"; + + /** Continue after fatal error feature ("continue-after-fatal-error"). */ + public static final String CONTINUE_AFTER_FATAL_ERROR_FEATURE = "continue-after-fatal-error"; + + /** Load dtd grammar when nonvalidating feature ("nonvalidating/load-dtd-grammar"). */ + public static final String LOAD_DTD_GRAMMAR_FEATURE = "nonvalidating/load-dtd-grammar"; + + /** Load external dtd when nonvalidating feature ("nonvalidating/load-external-dtd"). */ + public static final String LOAD_EXTERNAL_DTD_FEATURE = "nonvalidating/load-external-dtd"; + + /** Defer node expansion feature ("dom/defer-node-expansion"). */ + public static final String DEFER_NODE_EXPANSION_FEATURE = "dom/defer-node-expansion"; + + /** Create entity reference nodes feature ("dom/create-entity-ref-nodes"). */ + public static final String CREATE_ENTITY_REF_NODES_FEATURE = "dom/create-entity-ref-nodes"; + + /** Include ignorable whitespace feature ("dom/include-ignorable-whitespace"). */ + public static final String INCLUDE_IGNORABLE_WHITESPACE = "dom/include-ignorable-whitespace"; + + /** Default attribute values feature ("validation/default-attribute-values"). */ + public static final String DEFAULT_ATTRIBUTE_VALUES_FEATURE = "validation/default-attribute-values"; + + /** Validate content models feature ("validation/validate-content-models"). */ + public static final String VALIDATE_CONTENT_MODELS_FEATURE = "validation/validate-content-models"; + + /** Validate datatypes feature ("validation/validate-datatypes"). */ + public static final String VALIDATE_DATATYPES_FEATURE = "validation/validate-datatypes"; + + /** Balance syntax trees feature ("validation/balance-syntax-trees"). */ + public static final String BALANCE_SYNTAX_TREES = "validation/balance-syntax-trees"; + + /** Notify character references feature (scanner/notify-char-refs"). */ + public static final String NOTIFY_CHAR_REFS_FEATURE = "scanner/notify-char-refs"; + + /** Notify built-in (&amp;, etc.) references feature (scanner/notify-builtin-refs"). */ + public static final String NOTIFY_BUILTIN_REFS_FEATURE = "scanner/notify-builtin-refs"; + + /** Standard URI conformant feature ("standard-uri-conformant"). */ + public static final String STANDARD_URI_CONFORMANT_FEATURE = "standard-uri-conformant"; + + /** Generate synthetic annotations feature ("generate-synthetic-annotations"). */ + public static final String GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE = "generate-synthetic-annotations"; + + /** Validate annotations feature ("validate-annotations"). */ + public static final String VALIDATE_ANNOTATIONS_FEATURE = "validate-annotations"; + + /** Honour all schemaLocations feature ("honour-all-schemaLocations"). */ + public static final String HONOUR_ALL_SCHEMALOCATIONS_FEATURE = "honour-all-schemaLocations"; + + /** Namespace growth feature ("namespace-growth"). */ + public static final String NAMESPACE_GROWTH_FEATURE = "namespace-growth"; + + /** Tolerate duplicates feature ("internal/tolerate-duplicates"). */ + public static final String TOLERATE_DUPLICATES_FEATURE = "internal/tolerate-duplicates"; + + /** String interned feature ("internal/strings-interned"). */ + public static final String STRINGS_INTERNED_FEATURE = "internal/strings-interned"; + + /** XInclude processing feature ("xinclude"). */ + public static final String XINCLUDE_FEATURE = "xinclude"; + + /** XInclude fixup base URIs feature ("xinclude/fixup-base-uris"). */ + public static final String XINCLUDE_FIXUP_BASE_URIS_FEATURE = "xinclude/fixup-base-uris"; + + /** XInclude fixup language feature ("xinclude/fixup-language"). */ + public static final String XINCLUDE_FIXUP_LANGUAGE_FEATURE = "xinclude/fixup-language"; + + /** + * Feature to ignore xsi:type attributes on elements during validation, + * until a global element declaration is found. ("validation/schema/ignore-xsi-type-until-elemdecl") + * If this feature is on when validating a document, then beginning at the validation root + * element, xsi:type attributes are ignored until a global element declaration is + * found for an element. Once a global element declaration has been found, xsi:type + * attributes will start being processed for the sub-tree beginning at the element for + * which the declaration was found. + * + * Suppose an element A has two element children, B and C. + * + * If a global element declaration is found for A, xsi:type attributes on A, B and C, + * and all of B and C's descendents, will be processed. + * + * If no global element declaration is found for A or B, but one is found for C, + * then xsi:type attributes will be ignored on A and B (and any descendents of B, + * until a global element declaration is found), but xsi:type attributes will be + * processed for C and all of C's descendents. + * + * Once xsi:type attributes stop being ignored for a subtree, they do not start + * being ignored again, even if more elements are encountered for which no global + * element declaration can be found. + */ + public static final String IGNORE_XSI_TYPE_FEATURE = "validation/schema/ignore-xsi-type-until-elemdecl"; + + /** Perform checking of ID/IDREFs ("validation/id-idref-checking") */ + public static final String ID_IDREF_CHECKING_FEATURE = "validation/id-idref-checking"; + + /** Feature to ignore errors caused by identity constraints ("validation/identity-constraint-checking") */ + public static final String IDC_CHECKING_FEATURE = "validation/identity-constraint-checking"; + + /** Feature to ignore errors caused by unparsed entities ("validation/unparsed-entity-checking") */ + public static final String UNPARSED_ENTITY_CHECKING_FEATURE = "validation/unparsed-entity-checking"; + + /** + * Internal feature. When set to true the schema validator will only use + * schema components from the grammar pool provided. + */ + public static final String USE_GRAMMAR_POOL_ONLY_FEATURE = "internal/validation/schema/use-grammar-pool-only"; + + /** Internal performance related feature: + * false - the parser settings (features/properties) have not changed between 2 parses + * true - the parser settings have changed between 2 parses + * NOTE: this feature should only be set by the parser configuration. + */ + public static final String PARSER_SETTINGS = "internal/parser-settings"; + + // xerces properties + + /** Xerces properties prefix ("http://apache.org/xml/properties/"). */ + public static final String XERCES_PROPERTY_PREFIX = "http://apache.org/xml/properties/"; + + /** Current element node property ("dom/current-element-node"). */ + public static final String CURRENT_ELEMENT_NODE_PROPERTY = "dom/current-element-node"; + + /** Document class name property ("dom/document-class-name"). */ + public static final String DOCUMENT_CLASS_NAME_PROPERTY = "dom/document-class-name"; + + /** Symbol table property ("internal/symbol-table"). */ + public static final String SYMBOL_TABLE_PROPERTY = "internal/symbol-table"; + + /** Error reporter property ("internal/error-reporter"). */ + public static final String ERROR_REPORTER_PROPERTY = "internal/error-reporter"; + + /** Error handler property ("internal/error-handler"). */ + public static final String ERROR_HANDLER_PROPERTY = "internal/error-handler"; + + /** XInclude handler property ("internal/xinclude-handler"). */ + public static final String XINCLUDE_HANDLER_PROPERTY = "internal/xinclude-handler"; + + /** XPointer handler property ("internal/xpointer-handler"). */ + public static final String XPOINTER_HANDLER_PROPERTY = "internal/xpointer-handler"; + + /** Entity manager property ("internal/entity-manager"). */ + public static final String ENTITY_MANAGER_PROPERTY = "internal/entity-manager"; + + /** Input buffer size property ("input-buffer-size"). */ + public static final String BUFFER_SIZE_PROPERTY = "input-buffer-size"; + + /** Security manager property ("security-manager"). */ + public static final String SECURITY_MANAGER_PROPERTY = "security-manager"; + + /** Locale property ("locale"). */ + public static final String LOCALE_PROPERTY = "locale"; + + /** Entity resolver property ("internal/entity-resolver"). */ + public static final String ENTITY_RESOLVER_PROPERTY = "internal/entity-resolver"; + + /** Grammar pool property ("internal/grammar-pool"). */ + public static final String XMLGRAMMAR_POOL_PROPERTY = "internal/grammar-pool"; + + /** Datatype validator factory ("internal/datatype-validator-factory"). */ + public static final String DATATYPE_VALIDATOR_FACTORY_PROPERTY = "internal/datatype-validator-factory"; + + /** Document scanner property ("internal/document-scanner"). */ + public static final String DOCUMENT_SCANNER_PROPERTY = "internal/document-scanner"; + + /** DTD scanner property ("internal/dtd-scanner"). */ + public static final String DTD_SCANNER_PROPERTY = "internal/dtd-scanner"; + + /** DTD processor property ("internal/dtd-processor"). */ + public static final String DTD_PROCESSOR_PROPERTY = "internal/dtd-processor"; + + /** Validator property ("internal/validator"). */ + public static final String VALIDATOR_PROPERTY = "internal/validator"; + + /** Validator property ("internal/validator/dtd"). */ + public static final String DTD_VALIDATOR_PROPERTY = "internal/validator/dtd"; + + /** Validator property ("internal/validator/schema"). */ + public static final String SCHEMA_VALIDATOR_PROPERTY = "internal/validator/schema"; + + /** No namespace schema location property ("schema/external-schemaLocation"). */ + public static final String SCHEMA_LOCATION = "schema/external-schemaLocation"; + + /** Schema location property ("schema/external-noNamespaceSchemaLocation"). */ + public static final String SCHEMA_NONS_LOCATION = "schema/external-noNamespaceSchemaLocation"; + + /** Namespace binder property ("internal/namespace-binder"). */ + public static final String NAMESPACE_BINDER_PROPERTY = "internal/namespace-binder"; + + /** Namespace context property ("internal/namespace-context"). */ + public static final String NAMESPACE_CONTEXT_PROPERTY = "internal/namespace-context"; + + /** Validation manager property ("internal/validation-manager"). */ + public static final String VALIDATION_MANAGER_PROPERTY = "internal/validation-manager"; + + /** Schema type for the root element in a document ("validation/schema/root-type-definition"). */ + public static final String ROOT_TYPE_DEFINITION_PROPERTY = "validation/schema/root-type-definition"; + + /** Schema element declaration for the root element in a document ("validation/schema/root-element-declaration"). */ + public static final String ROOT_ELEMENT_DECLARATION_PROPERTY = "validation/schema/root-element-declaration"; + + /** Schema element declaration for the root element in a document ("internal/validation/schema/dv-factory"). */ + public static final String SCHEMA_DV_FACTORY_PROPERTY = "internal/validation/schema/dv-factory"; + + // general constants + + /** Element PSVI is stored in augmentations using string "ELEMENT_PSVI" */ + public final static String ELEMENT_PSVI = "ELEMENT_PSVI"; + + /** Attribute PSVI is stored in augmentations using string "ATTRIBUTE_PSVI" */ + public final static String ATTRIBUTE_PSVI = "ATTRIBUTE_PSVI"; + + /** + * Boolean indicating whether an attribute is declared in the DTD is stored + * in augmentations using the string "ATTRIBUTE_DECLARED". The absence of this + * augmentation indicates that the attribute was not declared in the DTD. + */ + public final static String ATTRIBUTE_DECLARED = "ATTRIBUTE_DECLARED"; + + /** + * Boolean indicating whether an entity referenced in the document has + * not been read is stored in augmentations using the string "ENTITY_SKIPPED". + * The absence of this augmentation indicates that the entity had a + * declaration and was expanded. + */ + public final static String ENTITY_SKIPPED = "ENTITY_SKIPPED"; + + /** + * Boolean indicating whether a character is a probable white space + * character (ch <= 0x20) that was the replacement text of a character + * reference is stored in augmentations using the string "CHAR_REF_PROBABLE_WS". + * The absence of this augmentation indicates that the character is not + * probable white space and/or was not included from a character reference. + */ + public final static String CHAR_REF_PROBABLE_WS = "CHAR_REF_PROBABLE_WS"; + + // XML version constants + public final static short XML_VERSION_ERROR = -1; + public final static short XML_VERSION_1_0 = 1; + public final static short XML_VERSION_1_1 = 2; + + // Constant to enable Schema 1.1 support + public final static boolean SCHEMA_1_1_SUPPORT = false; + public final static short SCHEMA_VERSION_1_0 = 1; + public final static short SCHEMA_VERSION_1_0_EXTENDED = 2; + + // private + + /** SAX features. */ + private static final String[] fgSAXFeatures = { + NAMESPACES_FEATURE, + NAMESPACE_PREFIXES_FEATURE, + STRING_INTERNING_FEATURE, + VALIDATION_FEATURE, + EXTERNAL_GENERAL_ENTITIES_FEATURE, + EXTERNAL_PARAMETER_ENTITIES_FEATURE, + }; + + /** SAX properties. */ + private static final String[] fgSAXProperties = { + DECLARATION_HANDLER_PROPERTY, + LEXICAL_HANDLER_PROPERTY, + DOM_NODE_PROPERTY, + XML_STRING_PROPERTY, + }; + + /** Xerces features. */ + private static final String[] fgXercesFeatures = { + SCHEMA_VALIDATION_FEATURE, + SCHEMA_FULL_CHECKING, + DYNAMIC_VALIDATION_FEATURE, + WARN_ON_DUPLICATE_ATTDEF_FEATURE, + WARN_ON_UNDECLARED_ELEMDEF_FEATURE, + ALLOW_JAVA_ENCODINGS_FEATURE, + CONTINUE_AFTER_FATAL_ERROR_FEATURE, + LOAD_DTD_GRAMMAR_FEATURE, + LOAD_EXTERNAL_DTD_FEATURE, + //DEFER_NODE_EXPANSION_FEATURE, + CREATE_ENTITY_REF_NODES_FEATURE, + INCLUDE_IGNORABLE_WHITESPACE, + //GRAMMAR_ACCESS_FEATURE, + DEFAULT_ATTRIBUTE_VALUES_FEATURE, + VALIDATE_CONTENT_MODELS_FEATURE, + VALIDATE_DATATYPES_FEATURE, + BALANCE_SYNTAX_TREES, + NOTIFY_CHAR_REFS_FEATURE, + NOTIFY_BUILTIN_REFS_FEATURE, + DISALLOW_DOCTYPE_DECL_FEATURE, + STANDARD_URI_CONFORMANT_FEATURE, + GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE, + VALIDATE_ANNOTATIONS_FEATURE, + HONOUR_ALL_SCHEMALOCATIONS_FEATURE, + XINCLUDE_FEATURE, + XINCLUDE_FIXUP_BASE_URIS_FEATURE, + XINCLUDE_FIXUP_LANGUAGE_FEATURE, + IGNORE_XSI_TYPE_FEATURE, + ID_IDREF_CHECKING_FEATURE, + IDC_CHECKING_FEATURE, + UNPARSED_ENTITY_CHECKING_FEATURE, + NAMESPACE_GROWTH_FEATURE, + TOLERATE_DUPLICATES_FEATURE, + STRINGS_INTERNED_FEATURE, + }; + + /** Xerces properties. */ + private static final String[] fgXercesProperties = { + CURRENT_ELEMENT_NODE_PROPERTY, + DOCUMENT_CLASS_NAME_PROPERTY, + SYMBOL_TABLE_PROPERTY, + ERROR_HANDLER_PROPERTY, + ERROR_REPORTER_PROPERTY, + ENTITY_MANAGER_PROPERTY, + ENTITY_RESOLVER_PROPERTY, + XMLGRAMMAR_POOL_PROPERTY, + DATATYPE_VALIDATOR_FACTORY_PROPERTY, + DOCUMENT_SCANNER_PROPERTY, + DTD_SCANNER_PROPERTY, + VALIDATOR_PROPERTY, + SCHEMA_LOCATION, + SCHEMA_NONS_LOCATION, + VALIDATION_MANAGER_PROPERTY, + BUFFER_SIZE_PROPERTY, + SECURITY_MANAGER_PROPERTY, + LOCALE_PROPERTY, + ROOT_TYPE_DEFINITION_PROPERTY, + ROOT_ELEMENT_DECLARATION_PROPERTY, + SCHEMA_DV_FACTORY_PROPERTY, + }; + + /** Empty enumeration. */ + private static final Enumeration fgEmptyEnumeration = new ArrayEnumeration(new Object[] {}); + + // + // Constructors + // + + /** This class cannot be instantiated. */ + private Constants() {} + + // + // Public methods + // + + // sax + + /** Returns an enumeration of the SAX features. */ + public static Enumeration getSAXFeatures() { + return fgSAXFeatures.length > 0 + ? new ArrayEnumeration(fgSAXFeatures) : fgEmptyEnumeration; + } // getSAXFeatures():Enumeration + + /** Returns an enumeration of the SAX properties. */ + public static Enumeration getSAXProperties() { + return fgSAXProperties.length > 0 + ? new ArrayEnumeration(fgSAXProperties) : fgEmptyEnumeration; + } // getSAXProperties():Enumeration + + // xerces + + /** Returns an enumeration of the Xerces features. */ + public static Enumeration getXercesFeatures() { + return fgXercesFeatures.length > 0 + ? new ArrayEnumeration(fgXercesFeatures) : fgEmptyEnumeration; + } // getXercesFeatures():Enumeration + + /** Returns an enumeration of the Xerces properties. */ + public static Enumeration getXercesProperties() { + return fgXercesProperties.length > 0 + ? new ArrayEnumeration(fgXercesProperties) : fgEmptyEnumeration; + } // getXercesProperties():Enumeration + + // + // Classes + // + + /** + * An array enumeration. + * + * @author Andy Clark, IBM + */ + static class ArrayEnumeration + implements Enumeration { + + // + // Data + // + + /** Array. */ + private Object[] array; + + /** Index. */ + private int index; + + // + // Constructors + // + + /** Constructs an array enumeration. */ + public ArrayEnumeration(Object[] array) { + this.array = array; + } // (Object[]) + + // + // Enumeration methods + // + + /** + * Tests if this enumeration contains more elements. + * + * @return true if this enumeration contains more elements; + * false otherwise. + * @since JDK1.0 + */ + public boolean hasMoreElements() { + return index < array.length; + } // hasMoreElement():boolean + + /** + * Returns the next element of this enumeration. + * + * @return the next element of this enumeration. + * @exception NoSuchElementException if no more elements exist. + * @since JDK1.0 + */ + public Object nextElement() { + if (index < array.length) { + return array[index++]; + } + throw new NoSuchElementException(); + } // nextElement():Object + + } // class ArrayEnumeration + + // + // MAIN + // + + /** Prints all of the constants to standard output. */ + public static void main(String[] argv) { + + print("SAX features:", SAX_FEATURE_PREFIX, fgSAXFeatures); + print("SAX properties:", SAX_PROPERTY_PREFIX, fgSAXProperties); + print("Xerces features:", XERCES_FEATURE_PREFIX, fgXercesFeatures); + print("Xerces properties:", XERCES_PROPERTY_PREFIX, fgXercesProperties); + + } // main(String[]) + + /** Prints a list of features/properties. */ + private static void print(String header, String prefix, Object[] array) { + System.out.print(header); + if (array.length > 0) { + System.out.println(); + for (int i = 0; i < array.length; i++) { + System.out.print(" "); + System.out.print(prefix); + System.out.println(array[i]); + } + } + else { + System.out.println(" none."); + } + } // print(String,String,Object[]) + +} // class Constants diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/ExternalSubsetResolver.java b/resources/xerces2-j-src/org/apache/xerces/impl/ExternalSubsetResolver.java new file mode 100644 index 0000000..707dad7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/ExternalSubsetResolver.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.IOException; + +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLDTDDescription; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + *

This interface extends XMLEntityResolver providing + * a method to resolve external subsets for documents which do not + * explicitly provide one. The application can register an object that + * implements this interface with the parser configuration. If registered, + * it will be queried to locate an external subset when none is provided, + * even for documents that do not contain DOCTYPE declarations. If the + * registered external subset resolver does not provide an external subset + * for a given document, it should return null.

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public interface ExternalSubsetResolver + extends XMLEntityResolver { + + // + // ExternalSubsetResolver methods + // + + /** + *

Locates an external subset for documents which do not explicitly + * provide one. If no external subset is provided, this method should + * return null.

+ * + * @param grammarDescription a description of the DTD + * + * @throws XNIException Thrown on general error. + * @throws IOException Thrown if resolved entity stream cannot be + * opened or some other i/o error occurs. + */ + public XMLInputSource getExternalSubset(XMLDTDDescription grammarDescription) + throws XNIException, IOException; + +} // interface ExternalSubsetResolver diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/RevalidationHandler.java b/resources/xerces2-j-src/org/apache/xerces/impl/RevalidationHandler.java new file mode 100644 index 0000000..8e31a1b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/RevalidationHandler.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.parser.XMLDocumentFilter; +/** + * DOM Revalidation handler adds additional functionality to XMLDocumentHandler + * + * @xerces.internal + * @author Elena Litani, IBM + * @version $Id$ + */ +public interface RevalidationHandler extends XMLDocumentFilter { + + /** + * Character content. + * + * @param data The character data. + * @param augs Augmentations + * @return True if data is whitespace only + */ + public boolean characterData(String data, Augmentations augs); + + +} // interface DOMRevalidationHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/Version.java b/resources/xerces2-j-src/org/apache/xerces/impl/Version.java new file mode 100644 index 0000000..b235961 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/Version.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +/** + * This class defines the version number of the parser. + * + * @version $Id$ + */ +public class Version { + + // + // Data + // + + /** Version string. + * @deprecated getVersion() should be used instead. */ + public static String fVersion = "@@VERSION@@"; + + private static final String fImmutableVersion = "@@VERSION@@"; + + // public methods + + /* Print out the version information. + * @return the version of the parser. + */ + public static String getVersion() { + return fImmutableVersion; + } // getVersion(): String + + // + // MAIN + // + + /** + * Prints out the version number to System.out. This is needed + * for the build system. + */ + public static void main(String argv[]) { + System.out.println(fVersion); + } + +} // class Version diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XML11DTDScannerImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/XML11DTDScannerImpl.java new file mode 100644 index 0000000..c8c39d2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XML11DTDScannerImpl.java @@ -0,0 +1,254 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.IOException; + +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; + +/** + * This class is responsible for scanning the declarations found + * in the internal and external subsets of a DTD in an XML document. + * The scanner acts as the sources for the DTD information which is + * communicated to the DTD handlers. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/scanner/notify-char-refs
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-manager
  • + *
+ * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * @author Glenn Marcy, IBM + * @author Eric Ye, IBM + * + * @version $Id$ + */ +public class XML11DTDScannerImpl + extends XMLDTDScannerImpl { + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + + // + // Constructors + // + + /** Default constructor. */ + public XML11DTDScannerImpl() {super();} // () + + /** Constructor for he use of non-XMLComponentManagers. */ + public XML11DTDScannerImpl(SymbolTable symbolTable, + XMLErrorReporter errorReporter, XMLEntityManager entityManager) { + super(symbolTable, errorReporter, entityManager); + } + + // + // XMLDTDScanner methods + // + + // + // XMLScanner methods + // + // NOTE: this is a carbon copy of the code in XML11DocumentScannerImpl; + // we need to override these methods in both places. Ah for + // multiple inheritance... + // This needs to be refactored!!! - NG + /** + * Scans public ID literal. + * + * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" + * [13] PubidChar::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] + * + * The returned string is normalized according to the following rule, + * from http://www.w3.org/TR/REC-xml#dt-pubid: + * + * Before a match is attempted, all strings of white space in the public + * identifier must be normalized to single space characters (#x20), and + * leading and trailing white space must be removed. + * + * @param literal The string to fill in with the public ID literal. + * @return True on success. + * + * Note: This method uses fStringBuffer, anything in it at + * the time of calling is lost. + */ + protected boolean scanPubidLiteral(XMLString literal) + throws IOException, XNIException + { + int quote = fEntityScanner.scanChar(); + if (quote != '\'' && quote != '"') { + reportFatalError("QuoteRequiredInPublicID", null); + return false; + } + + fStringBuffer.clear(); + // skip leading whitespace + boolean skipSpace = true; + boolean dataok = true; + while (true) { + int c = fEntityScanner.scanChar(); + // REVISIT: it could really only be \n or 0x20; all else is normalized, no? - neilg + if (c == ' ' || c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) { + if (!skipSpace) { + // take the first whitespace as a space and skip the others + fStringBuffer.append(' '); + skipSpace = true; + } + } + else if (c == quote) { + if (skipSpace) { + // if we finished on a space let's trim it + fStringBuffer.length--; + } + literal.setValues(fStringBuffer); + break; + } + else if (XMLChar.isPubid(c)) { + fStringBuffer.append((char)c); + skipSpace = false; + } + else if (c == -1) { + reportFatalError("PublicIDUnterminated", null); + return false; + } + else { + dataok = false; + reportFatalError("InvalidCharInPublicID", + new Object[]{Integer.toHexString(c)}); + } + } + return dataok; + } + + /** + * Normalize whitespace in an XMLString converting all whitespace + * characters to space characters. + */ + protected void normalizeWhitespace(XMLString value) { + int end = value.offset + value.length; + for (int i = value.offset; i < end; ++i) { + int c = value.ch[i]; + if (XMLChar.isSpace(c)) { + value.ch[i] = ' '; + } + } + } + + /** + * Normalize whitespace in an XMLString converting all whitespace + * characters to space characters. + */ + protected void normalizeWhitespace(XMLString value, int fromIndex) { + int end = value.offset + value.length; + for (int i = value.offset + fromIndex; i < end; ++i) { + int c = value.ch[i]; + if (XMLChar.isSpace(c)) { + value.ch[i] = ' '; + } + } + } + + /** + * Checks whether this string would be unchanged by normalization. + * + * @return -1 if the value would be unchanged by normalization, + * otherwise the index of the first whitespace character which + * would be transformed. + */ + protected int isUnchangedByNormalization(XMLString value) { + int end = value.offset + value.length; + for (int i = value.offset; i < end; ++i) { + int c = value.ch[i]; + if (XMLChar.isSpace(c)) { + return i - value.offset; + } + } + return -1; + } + + // returns true if the given character is not + // valid with respect to the version of + // XML understood by this scanner. + protected boolean isInvalid(int value) { + return (!XML11Char.isXML11Valid(value)); + } // isInvalid(int): boolean + + // returns true if the given character is not + // valid or may not be used outside a character reference + // with respect to the version of XML understood by this scanner. + protected boolean isInvalidLiteral(int value) { + return (!XML11Char.isXML11ValidLiteral(value)); + } // isInvalidLiteral(int): boolean + + // returns true if the given character is + // a valid nameChar with respect to the version of + // XML understood by this scanner. + protected boolean isValidNameChar(int value) { + return (XML11Char.isXML11Name(value)); + } // isValidNameChar(int): boolean + + // returns true if the given character is + // a valid nameStartChar with respect to the version of + // XML understood by this scanner. + protected boolean isValidNameStartChar(int value) { + return (XML11Char.isXML11NameStart(value)); + } // isValidNameStartChar(int): boolean + + // returns true if the given character is + // a valid NCName character with respect to the version of + // XML understood by this scanner. + protected boolean isValidNCName(int value) { + return (XML11Char.isXML11NCName(value)); + } // isValidNCName(int): boolean + + // returns true if the given character is + // a valid high surrogate for a nameStartChar + // with respect to the version of XML understood + // by this scanner. + protected boolean isValidNameStartHighSurrogate(int value) { + return XML11Char.isXML11NameHighSurrogate(value); + } // isValidNameStartHighSurrogate(int): boolean + + // note that, according to 4.3.4 of the XML 1.1 spec, XML 1.1 + // documents may invoke 1.0 entities; thus either version decl (or none!) + // is allowed to appear in this context + protected boolean versionSupported(String version) { + return version.equals("1.1") || version.equals ("1.0"); + } // versionSupported(String): boolean + + // returns the error message key for unsupported + // versions of XML with respect to the version of + // XML understood by this scanner. + protected String getVersionNotSupportedKey () { + return "VersionNotSupported11"; + } // getVersionNotSupportedKey: String + +} // class XML11DTDScannerImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XML11DocumentScannerImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/XML11DocumentScannerImpl.java new file mode 100644 index 0000000..ce93297 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XML11DocumentScannerImpl.java @@ -0,0 +1,548 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.IOException; + +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; + +/** + * This class is responsible for scanning XML document structure + * and content. The scanner acts as the source for the document + * information which is communicated to the document handler. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/nonvalidating/load-external-dtd
  • + *
  • http://apache.org/xml/features/scanner/notify-char-refs
  • + *
  • http://apache.org/xml/features/scanner/notify-builtin-refs
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-manager
  • + *
  • http://apache.org/xml/properties/internal/dtd-scanner
  • + *
+ * + * @xerces.internal + * + * @author Glenn Marcy, IBM + * @author Andy Clark, IBM + * @author Arnaud Le Hors, IBM + * @author Eric Ye, IBM + * + * @version $Id$ + */ +public class XML11DocumentScannerImpl + extends XMLDocumentScannerImpl { + + /** String. */ + private final XMLString fString = new XMLString(); + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + private final XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); + private final XMLStringBuffer fStringBuffer3 = new XMLStringBuffer(); + + // + // Constructors + // + + /** Default constructor. */ + public XML11DocumentScannerImpl() {super();} // () + + // + // overridden methods + // + + // XMLDocumentFragmentImpl methods + + /** + * Scans element content. + * + * @return Returns the next character on the stream. + */ + protected int scanContent() throws IOException, XNIException { + + XMLString content = fString; + int c = fEntityScanner.scanContent(content); + if (c == '\r' || c == 0x85 || c == 0x2028) { + // happens when there is the character reference + // but scanContent doesn't do entity expansions... + // is this *really* necessary??? - NG + fEntityScanner.scanChar(); + fStringBuffer.clear(); + fStringBuffer.append(fString); + fStringBuffer.append((char)c); + content = fStringBuffer; + c = -1; + } + if (fDocumentHandler != null && content.length > 0) { + fDocumentHandler.characters(content, null); + } + + if (c == ']' && fString.length == 0) { + fStringBuffer.clear(); + fStringBuffer.append((char)fEntityScanner.scanChar()); + // remember where we are in case we get an endEntity before we + // could flush the buffer out - this happens when we're parsing an + // entity which ends with a ] + fInScanContent = true; + // + // We work on a single character basis to handle cases such as: + // ']]]>' which we might otherwise miss. + // + if (fEntityScanner.skipChar(']')) { + fStringBuffer.append(']'); + while (fEntityScanner.skipChar(']')) { + fStringBuffer.append(']'); + } + if (fEntityScanner.skipChar('>')) { + reportFatalError("CDEndInContent", null); + } + } + if (fDocumentHandler != null && fStringBuffer.length != 0) { + fDocumentHandler.characters(fStringBuffer, null); + } + fInScanContent = false; + c = -1; + } + return c; + + } // scanContent():int + + /** + * Scans an attribute value and normalizes whitespace converting all + * whitespace characters to space characters. + * + * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'" + * + * @param value The XMLString to fill in with the value. + * @param nonNormalizedValue The XMLString to fill in with the + * non-normalized value. + * @param atName The name of the attribute being parsed (for error msgs). + * @param checkEntities true if undeclared entities should be reported as VC violation, + * false if undeclared entities should be reported as WFC violation. + * @param eleName The name of element to which this attribute belongs. + * + * @return true if the non-normalized and normalized value are the same + * + * Note: This method uses fStringBuffer2, anything in it + * at the time of calling is lost. + **/ + protected boolean scanAttributeValue(XMLString value, + XMLString nonNormalizedValue, + String atName, + boolean checkEntities,String eleName) + throws IOException, XNIException + { + // quote + int quote = fEntityScanner.peekChar(); + if (quote != '\'' && quote != '"') { + reportFatalError("OpenQuoteExpected", new Object[]{eleName,atName}); + } + + fEntityScanner.scanChar(); + int entityDepth = fEntityDepth; + + int c = fEntityScanner.scanLiteral(quote, value); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** scanLiteral -> \"" + + value.toString() + "\""); + } + + int fromIndex = 0; + if (c == quote && (fromIndex = isUnchangedByNormalization(value)) == -1) { + /** Both the non-normalized and normalized attribute values are equal. **/ + nonNormalizedValue.setValues(value); + int cquote = fEntityScanner.scanChar(); + if (cquote != quote) { + reportFatalError("CloseQuoteExpected", new Object[]{eleName,atName}); + } + return true; + } + fStringBuffer2.clear(); + fStringBuffer2.append(value); + normalizeWhitespace(value, fromIndex); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** normalizeWhitespace -> \"" + + value.toString() + "\""); + } + if (c != quote) { + fScanningAttribute = true; + fStringBuffer.clear(); + do { + fStringBuffer.append(value); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value2: \"" + + fStringBuffer.toString() + "\""); + } + if (c == '&') { + fEntityScanner.skipChar('&'); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append('&'); + } + if (fEntityScanner.skipChar('#')) { + if (entityDepth == fEntityDepth) { + fStringBuffer2.append('#'); + } + int ch = scanCharReferenceValue(fStringBuffer, fStringBuffer2); + if (ch != -1) { + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value3: \"" + + fStringBuffer.toString() + + "\""); + } + } + } + else { + String entityName = fEntityScanner.scanName(); + if (entityName == null) { + reportFatalError("NameRequiredInReference", null); + } + else if (entityDepth == fEntityDepth) { + fStringBuffer2.append(entityName); + } + if (!fEntityScanner.skipChar(';')) { + reportFatalError("SemicolonRequiredInReference", + new Object []{entityName}); + } + else if (entityDepth == fEntityDepth) { + fStringBuffer2.append(';'); + } + if (entityName == fAmpSymbol) { + fStringBuffer.append('&'); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value5: \"" + + fStringBuffer.toString() + + "\""); + } + } + else if (entityName == fAposSymbol) { + fStringBuffer.append('\''); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value7: \"" + + fStringBuffer.toString() + + "\""); + } + } + else if (entityName == fLtSymbol) { + fStringBuffer.append('<'); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value9: \"" + + fStringBuffer.toString() + + "\""); + } + } + else if (entityName == fGtSymbol) { + fStringBuffer.append('>'); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueB: \"" + + fStringBuffer.toString() + + "\""); + } + } + else if (entityName == fQuotSymbol) { + fStringBuffer.append('"'); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueD: \"" + + fStringBuffer.toString() + + "\""); + } + } + else { + if (fEntityManager.isExternalEntity(entityName)) { + reportFatalError("ReferenceToExternalEntity", + new Object[] { entityName }); + } + else { + if (!fEntityManager.isDeclaredEntity(entityName)) { + //WFC & VC: Entity Declared + if (checkEntities) { + if (fValidation) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "EntityNotDeclared", + new Object[]{entityName}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + else { + reportFatalError("EntityNotDeclared", + new Object[]{entityName}); + } + } + fEntityManager.startEntity(entityName, true); + } + } + } + } + else if (c == '<') { + reportFatalError("LessthanInAttValue", + new Object[] { eleName, atName }); + fEntityScanner.scanChar(); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append((char)c); + } + } + else if (c == '%' || c == ']') { + fEntityScanner.scanChar(); + fStringBuffer.append((char)c); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append((char)c); + } + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueF: \"" + + fStringBuffer.toString() + "\""); + } + } + // note that none of these characters should ever get through + // XML11EntityScanner. Not sure why + // this check was originally necessary. - NG + else if (c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) { + fEntityScanner.scanChar(); + fStringBuffer.append(' '); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append('\n'); + } + } + else if (c != -1 && XMLChar.isHighSurrogate(c)) { + fStringBuffer3.clear(); + if (scanSurrogates(fStringBuffer3)) { + fStringBuffer.append(fStringBuffer3); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append(fStringBuffer3); + } + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueI: \"" + + fStringBuffer.toString() + + "\""); + } + } + } + else if (c != -1 && isInvalidLiteral(c)) { + reportFatalError("InvalidCharInAttValue", + new Object[] {eleName, atName, Integer.toString(c, 16)}); + fEntityScanner.scanChar(); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append((char)c); + } + } + c = fEntityScanner.scanLiteral(quote, value); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append(value); + } + normalizeWhitespace(value); + } while (c != quote || entityDepth != fEntityDepth); + fStringBuffer.append(value); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueN: \"" + + fStringBuffer.toString() + "\""); + } + value.setValues(fStringBuffer); + fScanningAttribute = false; + } + nonNormalizedValue.setValues(fStringBuffer2); + + // quote + int cquote = fEntityScanner.scanChar(); + if (cquote != quote) { + reportFatalError("CloseQuoteExpected", new Object[]{eleName,atName}); + } + return nonNormalizedValue.equals(value.ch, value.offset, value.length); + } // scanAttributeValue() + + // + // XMLScanner methods + // + // NOTE: this is a carbon copy of the code in XML11DTDScannerImpl; + // we need to override these methods in both places. + // this needs to be refactored!!! - NG + /** + * Scans public ID literal. + * + * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" + * [13] PubidChar::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] + * + * The returned string is normalized according to the following rule, + * from http://www.w3.org/TR/REC-xml#dt-pubid: + * + * Before a match is attempted, all strings of white space in the public + * identifier must be normalized to single space characters (#x20), and + * leading and trailing white space must be removed. + * + * @param literal The string to fill in with the public ID literal. + * @return True on success. + * + * Note: This method uses fStringBuffer, anything in it at + * the time of calling is lost. + */ + protected boolean scanPubidLiteral(XMLString literal) + throws IOException, XNIException + { + int quote = fEntityScanner.scanChar(); + if (quote != '\'' && quote != '"') { + reportFatalError("QuoteRequiredInPublicID", null); + return false; + } + + fStringBuffer.clear(); + // skip leading whitespace + boolean skipSpace = true; + boolean dataok = true; + while (true) { + int c = fEntityScanner.scanChar(); + // REVISIT: none of these except \n and 0x20 should make it past the entity scanner + if (c == ' ' || c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) { + if (!skipSpace) { + // take the first whitespace as a space and skip the others + fStringBuffer.append(' '); + skipSpace = true; + } + } + else if (c == quote) { + if (skipSpace) { + // if we finished on a space let's trim it + fStringBuffer.length--; + } + literal.setValues(fStringBuffer); + break; + } + else if (XMLChar.isPubid(c)) { + fStringBuffer.append((char)c); + skipSpace = false; + } + else if (c == -1) { + reportFatalError("PublicIDUnterminated", null); + return false; + } + else { + dataok = false; + reportFatalError("InvalidCharInPublicID", + new Object[]{Integer.toHexString(c)}); + } + } + return dataok; + } + + /** + * Normalize whitespace in an XMLString converting all whitespace + * characters to space characters. + */ + protected void normalizeWhitespace(XMLString value) { + int end = value.offset + value.length; + for (int i = value.offset; i < end; ++i) { + int c = value.ch[i]; + if (XMLChar.isSpace(c)) { + value.ch[i] = ' '; + } + } + } + + /** + * Normalize whitespace in an XMLString converting all whitespace + * characters to space characters. + */ + protected void normalizeWhitespace(XMLString value, int fromIndex) { + int end = value.offset + value.length; + for (int i = value.offset + fromIndex; i < end; ++i) { + int c = value.ch[i]; + if (XMLChar.isSpace(c)) { + value.ch[i] = ' '; + } + } + } + + /** + * Checks whether this string would be unchanged by normalization. + * + * @return -1 if the value would be unchanged by normalization, + * otherwise the index of the first whitespace character which + * would be transformed. + */ + protected int isUnchangedByNormalization(XMLString value) { + int end = value.offset + value.length; + for (int i = value.offset; i < end; ++i) { + int c = value.ch[i]; + if (XMLChar.isSpace(c)) { + return i - value.offset; + } + } + return -1; + } + + // returns true if the given character is not + // valid with respect to the version of + // XML understood by this scanner. + protected boolean isInvalid(int value) { + return (XML11Char.isXML11Invalid(value)); + } // isInvalid(int): boolean + + // returns true if the given character is not + // valid or may not be used outside a character reference + // with respect to the version of XML understood by this scanner. + protected boolean isInvalidLiteral(int value) { + return (!XML11Char.isXML11ValidLiteral(value)); + } // isInvalidLiteral(int): boolean + + // returns true if the given character is + // a valid nameChar with respect to the version of + // XML understood by this scanner. + protected boolean isValidNameChar(int value) { + return (XML11Char.isXML11Name(value)); + } // isValidNameChar(int): boolean + + // returns true if the given character is + // a valid nameStartChar with respect to the version of + // XML understood by this scanner. + protected boolean isValidNameStartChar(int value) { + return (XML11Char.isXML11NameStart(value)); + } // isValidNameStartChar(int): boolean + + // returns true if the given character is + // a valid NCName character with respect to the version of + // XML understood by this scanner. + protected boolean isValidNCName(int value) { + return (XML11Char.isXML11NCName(value)); + } // isValidNCName(int): boolean + + // returns true if the given character is + // a valid high surrogate for a nameStartChar + // with respect to the version of XML understood + // by this scanner. + protected boolean isValidNameStartHighSurrogate(int value) { + return XML11Char.isXML11NameHighSurrogate(value); + } // isValidNameStartHighSurrogate(int): boolean + + protected boolean versionSupported(String version) { + return (version.equals("1.1") || version.equals("1.0")); + } // versionSupported(String): boolean + + // returns the error message key for unsupported + // versions of XML with respect to the version of + // XML understood by this scanner. + protected String getVersionNotSupportedKey () { + return "VersionNotSupported11"; + } // getVersionNotSupportedKey: String + +} // class XML11DocumentScannerImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XML11EntityScanner.java b/resources/xerces2-j-src/org/apache/xerces/impl/XML11EntityScanner.java new file mode 100644 index 0000000..0194205 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XML11EntityScanner.java @@ -0,0 +1,1423 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.EOFException; +import java.io.IOException; + +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLString; + +/** + * Implements the entity scanner methods in + * the context of XML 1.1. + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * @author Neil Graham, IBM + * @version $Id$ + */ +public class XML11EntityScanner + extends XMLEntityScanner { + + // + // Constructors + // + + /** Default constructor. */ + public XML11EntityScanner() { + super(); + } // () + + // + // XMLEntityScanner methods + // + + /** + * Returns the next character on the input. + *

+ * Note: The character is not consumed. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int peekChar() throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // peek at character + int c = fCurrentEntity.ch[fCurrentEntity.position]; + + // return peeked character + if (fCurrentEntity.isExternal()) { + return (c != '\r' && c != 0x85 && c != 0x2028) ? c : '\n'; + } + else { + return c; + } + + } // peekChar():int + + /** + * Returns the next character on the input. + *

+ * Note: The character is consumed. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int scanChar() throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan character + int c = fCurrentEntity.ch[fCurrentEntity.position++]; + boolean external = false; + if (c == '\n' || + ((c == '\r' || c == 0x85 || c == 0x2028) && (external = fCurrentEntity.isExternal()))) { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = (char)c; + load(1, false); + } + if (c == '\r' && external) { + int cc = fCurrentEntity.ch[fCurrentEntity.position++]; + if (cc != '\n' && cc != 0x85) { + fCurrentEntity.position--; + } + } + c = '\n'; + } + + // return character that was scanned + fCurrentEntity.columnNumber++; + return c; + + } // scanChar():int + + /** + * Returns a string matching the NMTOKEN production appearing immediately + * on the input as a symbol, or null if NMTOKEN Name string is present. + *

+ * Note: The NMTOKEN characters are consumed. + *

+ * Note: The string returned must be a symbol. The + * SymbolTable can be used for this purpose. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.SymbolTable + * @see org.apache.xerces.util.XML11Char#isXML11Name + */ + public String scanNmtoken() throws IOException { + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan nmtoken + int offset = fCurrentEntity.position; + + do { + char ch = fCurrentEntity.ch[fCurrentEntity.position]; + if (XML11Char.isXML11Name(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + else if (XML11Char.isXML11NameHighSurrogate(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + --fCurrentEntity.startPosition; + --fCurrentEntity.position; + break; + } + } + char ch2 = fCurrentEntity.ch[fCurrentEntity.position]; + if ( !XMLChar.isLowSurrogate(ch2) || + !XML11Char.isXML11Name(XMLChar.supplemental(ch, ch2)) ) { + --fCurrentEntity.position; + break; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + else { + break; + } + } + while (true); + + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + + // return nmtoken + String symbol = null; + if (length > 0) { + symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); + } + return symbol; + + } // scanNmtoken():String + + /** + * Returns a string matching the Name production appearing immediately + * on the input as a symbol, or null if no Name string is present. + *

+ * Note: The Name characters are consumed. + *

+ * Note: The string returned must be a symbol. The + * SymbolTable can be used for this purpose. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.SymbolTable + * @see org.apache.xerces.util.XML11Char#isXML11Name + * @see org.apache.xerces.util.XML11Char#isXML11NameStart + */ + public String scanName() throws IOException { + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan name + int offset = fCurrentEntity.position; + char ch = fCurrentEntity.ch[offset]; + + if (XML11Char.isXML11NameStart(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + offset = 0; + if (load(1, false)) { + fCurrentEntity.columnNumber++; + String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); + return symbol; + } + } + } + else if (XML11Char.isXML11NameHighSurrogate(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + offset = 0; + if (load(1, false)) { + --fCurrentEntity.position; + --fCurrentEntity.startPosition; + return null; + } + } + char ch2 = fCurrentEntity.ch[fCurrentEntity.position]; + if ( !XMLChar.isLowSurrogate(ch2) || + !XML11Char.isXML11NameStart(XMLChar.supplemental(ch, ch2)) ) { + --fCurrentEntity.position; + return null; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + fCurrentEntity.ch[1] = ch2; + offset = 0; + if (load(2, false)) { + fCurrentEntity.columnNumber += 2; + String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2); + return symbol; + } + } + } + else { + return null; + } + + do { + ch = fCurrentEntity.ch[fCurrentEntity.position]; + if (XML11Char.isXML11Name(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + else if (XML11Char.isXML11NameHighSurrogate(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + --fCurrentEntity.position; + --fCurrentEntity.startPosition; + break; + } + } + char ch2 = fCurrentEntity.ch[fCurrentEntity.position]; + if ( !XMLChar.isLowSurrogate(ch2) || + !XML11Char.isXML11Name(XMLChar.supplemental(ch, ch2)) ) { + --fCurrentEntity.position; + break; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + else { + break; + } + } + while (true); + + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + + // return name + String symbol = null; + if (length > 0) { + symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); + } + return symbol; + + } // scanName():String + + /** + * Returns a string matching the NCName production appearing immediately + * on the input as a symbol, or null if no NCName string is present. + *

+ * Note: The NCName characters are consumed. + *

+ * Note: The string returned must be a symbol. The + * SymbolTable can be used for this purpose. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.SymbolTable + * @see org.apache.xerces.util.XML11Char#isXML11NCName + * @see org.apache.xerces.util.XML11Char#isXML11NCNameStart + */ + public String scanNCName() throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan name + int offset = fCurrentEntity.position; + char ch = fCurrentEntity.ch[offset]; + + if (XML11Char.isXML11NCNameStart(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + offset = 0; + if (load(1, false)) { + fCurrentEntity.columnNumber++; + String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); + return symbol; + } + } + } + else if (XML11Char.isXML11NameHighSurrogate(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + offset = 0; + if (load(1, false)) { + --fCurrentEntity.position; + --fCurrentEntity.startPosition; + return null; + } + } + char ch2 = fCurrentEntity.ch[fCurrentEntity.position]; + if ( !XMLChar.isLowSurrogate(ch2) || + !XML11Char.isXML11NCNameStart(XMLChar.supplemental(ch, ch2)) ) { + --fCurrentEntity.position; + return null; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + fCurrentEntity.ch[1] = ch2; + offset = 0; + if (load(2, false)) { + fCurrentEntity.columnNumber += 2; + String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2); + return symbol; + } + } + } + else { + return null; + } + + do { + ch = fCurrentEntity.ch[fCurrentEntity.position]; + if (XML11Char.isXML11NCName(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + else if (XML11Char.isXML11NameHighSurrogate(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + --fCurrentEntity.startPosition; + --fCurrentEntity.position; + break; + } + } + char ch2 = fCurrentEntity.ch[fCurrentEntity.position]; + if ( !XMLChar.isLowSurrogate(ch2) || + !XML11Char.isXML11NCName(XMLChar.supplemental(ch, ch2)) ) { + --fCurrentEntity.position; + break; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + else { + break; + } + } + while (true); + + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + + // return name + String symbol = null; + if (length > 0) { + symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); + } + return symbol; + + } // scanNCName():String + + /** + * Scans a qualified name from the input, setting the fields of the + * QName structure appropriately. + *

+ * Note: The qualified name characters are consumed. + *

+ * Note: The strings used to set the values of the + * QName structure must be symbols. The SymbolTable can be used for + * this purpose. + * + * @param qname The qualified name structure to fill. + * + * @return Returns true if a qualified name appeared immediately on + * the input and was scanned, false otherwise. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.SymbolTable + * @see org.apache.xerces.util.XML11Char#isXML11Name + * @see org.apache.xerces.util.XML11Char#isXML11NameStart + */ + public boolean scanQName(QName qname) throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan qualified name + int offset = fCurrentEntity.position; + char ch = fCurrentEntity.ch[offset]; + + if (XML11Char.isXML11NCNameStart(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + offset = 0; + if (load(1, false)) { + fCurrentEntity.columnNumber++; + String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); + qname.setValues(null, name, name, null); + return true; + } + } + } + else if (XML11Char.isXML11NameHighSurrogate(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + offset = 0; + if (load(1, false)) { + --fCurrentEntity.startPosition; + --fCurrentEntity.position; + return false; + } + } + char ch2 = fCurrentEntity.ch[fCurrentEntity.position]; + if ( !XMLChar.isLowSurrogate(ch2) || + !XML11Char.isXML11NCNameStart(XMLChar.supplemental(ch, ch2)) ) { + --fCurrentEntity.position; + return false; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = ch; + fCurrentEntity.ch[1] = ch2; + offset = 0; + if (load(2, false)) { + fCurrentEntity.columnNumber += 2; + String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2); + qname.setValues(null, name, name, null); + return true; + } + } + } + else { + return false; + } + + int index = -1; + boolean sawIncompleteSurrogatePair = false; + do { + ch = fCurrentEntity.ch[fCurrentEntity.position]; + if (XML11Char.isXML11Name(ch)) { + if (ch == ':') { + if (index != -1) { + break; + } + index = fCurrentEntity.position; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + if (index != -1) { + index = index - offset; + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + else if (XML11Char.isXML11NameHighSurrogate(ch)) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + if (index != -1) { + index = index - offset; + } + offset = 0; + if (load(length, false)) { + sawIncompleteSurrogatePair = true; + --fCurrentEntity.startPosition; + --fCurrentEntity.position; + break; + } + } + char ch2 = fCurrentEntity.ch[fCurrentEntity.position]; + if ( !XMLChar.isLowSurrogate(ch2) || + !XML11Char.isXML11Name(XMLChar.supplemental(ch, ch2)) ) { + sawIncompleteSurrogatePair = true; + --fCurrentEntity.position; + break; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + if (index != -1) { + index = index - offset; + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + else { + break; + } + } + while (true); + + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + + if (length > 0) { + String prefix = null; + String localpart = null; + String rawname = fSymbolTable.addSymbol(fCurrentEntity.ch, + offset, length); + if (index != -1) { + int prefixLength = index - offset; + prefix = fSymbolTable.addSymbol(fCurrentEntity.ch, + offset, prefixLength); + int len = length - prefixLength - 1; + int startLocal = index +1; + if (!XML11Char.isXML11NCNameStart(fCurrentEntity.ch[startLocal]) && + (!XML11Char.isXML11NameHighSurrogate(fCurrentEntity.ch[startLocal]) || + sawIncompleteSurrogatePair)){ + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "IllegalQName", + null, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + localpart = fSymbolTable.addSymbol(fCurrentEntity.ch, + index + 1, len); + + } + else { + localpart = rawname; + } + qname.setValues(prefix, localpart, rawname, null); + return true; + } + return false; + + } // scanQName(QName):boolean + + /** + * Scans a range of parsed character data, setting the fields of the + * XMLString structure, appropriately. + *

+ * Note: The characters are consumed. + *

+ * Note: This method does not guarantee to return + * the longest run of parsed character data. This method may return + * before markup due to reaching the end of the input buffer or any + * other reason. + *

+ * Note: The fields contained in the XMLString + * structure are not guaranteed to remain valid upon subsequent calls + * to the entity scanner. Therefore, the caller is responsible for + * immediately using the returned character data or making a copy of + * the character data. + * + * @param content The content structure to fill. + * + * @return Returns the next character on the input, if known. This + * value may be -1 but this does note designate + * end of file. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int scanContent(XMLString content) throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; + load(1, false); + fCurrentEntity.position = 0; + fCurrentEntity.startPosition = 0; + } + + // normalize newlines + int offset = fCurrentEntity.position; + int c = fCurrentEntity.ch[offset]; + int newlines = 0; + boolean external = fCurrentEntity.isExternal(); + if (c == '\n' || ((c == '\r' || c == 0x85 || c == 0x2028) && external)) { + do { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if ((c == '\r' ) && external) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + int cc = fCurrentEntity.ch[fCurrentEntity.position]; + if (cc == '\n' || cc == 0x85) { + fCurrentEntity.position++; + offset++; + } + /*** NEWLINE NORMALIZATION ***/ + else { + newlines++; + } + } + else if (c == '\n' || ((c == 0x85 || c == 0x2028) && external)) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + } + else { + fCurrentEntity.position--; + break; + } + } while (fCurrentEntity.position < fCurrentEntity.count - 1); + for (int i = offset; i < fCurrentEntity.position; i++) { + fCurrentEntity.ch[i] = '\n'; + } + int length = fCurrentEntity.position - offset; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + content.setValues(fCurrentEntity.ch, offset, length); + return -1; + } + } + + // inner loop, scanning for content + if (external) { + while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (!XML11Char.isXML11Content(c) || c == 0x85 || c == 0x2028) { + fCurrentEntity.position--; + break; + } + } + } + else { + while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + // In internal entities control characters are allowed to appear unescaped. + if (!XML11Char.isXML11InternalEntityContent(c)) { + fCurrentEntity.position--; + break; + } + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + content.setValues(fCurrentEntity.ch, offset, length); + + // return next character + if (fCurrentEntity.position != fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position]; + // REVISIT: Does this need to be updated to fix the + // #x0D ^#x0A newline normalization problem? -Ac + if ((c == '\r' || c == 0x85 || c == 0x2028) && external) { + c = '\n'; + } + } + else { + c = -1; + } + return c; + + } // scanContent(XMLString):int + + /** + * Scans a range of attribute value data, setting the fields of the + * XMLString structure, appropriately. + *

+ * Note: The characters are consumed. + *

+ * Note: This method does not guarantee to return + * the longest run of attribute value data. This method may return + * before the quote character due to reaching the end of the input + * buffer or any other reason. + *

+ * Note: The fields contained in the XMLString + * structure are not guaranteed to remain valid upon subsequent calls + * to the entity scanner. Therefore, the caller is responsible for + * immediately using the returned character data or making a copy of + * the character data. + * + * @param quote The quote character that signifies the end of the + * attribute value data. + * @param content The content structure to fill. + * + * @return Returns the next character on the input, if known. This + * value may be -1 but this does note designate + * end of file. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int scanLiteral(int quote, XMLString content) + throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; + load(1, false); + fCurrentEntity.startPosition = 0; + fCurrentEntity.position = 0; + } + + // normalize newlines + int offset = fCurrentEntity.position; + int c = fCurrentEntity.ch[offset]; + int newlines = 0; + boolean external = fCurrentEntity.isExternal(); + if (c == '\n' || ((c == '\r' || c == 0x85 || c == 0x2028) && external)) { + do { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if ((c == '\r' ) && external) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + int cc = fCurrentEntity.ch[fCurrentEntity.position]; + if (cc == '\n' || cc == 0x85) { + fCurrentEntity.position++; + offset++; + } + /*** NEWLINE NORMALIZATION ***/ + else { + newlines++; + } + } + else if (c == '\n' || ((c == 0x85 || c == 0x2028) && external)) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + } + else { + fCurrentEntity.position--; + break; + } + } while (fCurrentEntity.position < fCurrentEntity.count - 1); + for (int i = offset; i < fCurrentEntity.position; i++) { + fCurrentEntity.ch[i] = '\n'; + } + int length = fCurrentEntity.position - offset; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + content.setValues(fCurrentEntity.ch, offset, length); + return -1; + } + } + + // scan literal value + if (external) { + while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == quote || c == '%' || !XML11Char.isXML11Content(c) + || c == 0x85 || c == 0x2028) { + fCurrentEntity.position--; + break; + } + } + } + else { + while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + // In internal entities control characters are allowed to appear unescaped. + if ((c == quote && !fCurrentEntity.literal) + || c == '%' || !XML11Char.isXML11InternalEntityContent(c)) { + fCurrentEntity.position--; + break; + } + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + content.setValues(fCurrentEntity.ch, offset, length); + + // return next character + if (fCurrentEntity.position != fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position]; + // NOTE: We don't want to accidentally signal the + // end of the literal if we're expanding an + // entity appearing in the literal. -Ac + if (c == quote && fCurrentEntity.literal) { + c = -1; + } + } + else { + c = -1; + } + return c; + + } // scanLiteral(int,XMLString):int + + /** + * Scans a range of character data up to the specicied delimiter, + * setting the fields of the XMLString structure, appropriately. + *

+ * Note: The characters are consumed. + *

+ * Note: This assumes that the internal buffer is + * at least the same size, or bigger, than the length of the delimiter + * and that the delimiter contains at least one character. + *

+ * Note: This method does not guarantee to return + * the longest run of character data. This method may return before + * the delimiter due to reaching the end of the input buffer or any + * other reason. + *

+ * Note: The fields contained in the XMLString + * structure are not guaranteed to remain valid upon subsequent calls + * to the entity scanner. Therefore, the caller is responsible for + * immediately using the returned character data or making a copy of + * the character data. + * + * @param delimiter The string that signifies the end of the character + * data to be scanned. + * @param buffer The XMLStringBuffer to fill. + * + * @return Returns true if there is more data to scan, false otherwise. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean scanData(String delimiter, XMLStringBuffer buffer) + throws IOException { + + boolean done = false; + int delimLen = delimiter.length(); + char charAt0 = delimiter.charAt(0); + boolean external = fCurrentEntity.isExternal(); + do { + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + boolean bNextEntity = false; + + while ((fCurrentEntity.position >= fCurrentEntity.count - delimLen) + && (!bNextEntity)) + { + System.arraycopy(fCurrentEntity.ch, + fCurrentEntity.position, + fCurrentEntity.ch, + 0, + fCurrentEntity.count - fCurrentEntity.position); + + bNextEntity = load(fCurrentEntity.count - fCurrentEntity.position, false); + fCurrentEntity.position = 0; + fCurrentEntity.startPosition = 0; + } + + if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) { + // something must be wrong with the input: e.g., file ends an unterminated comment + int length = fCurrentEntity.count - fCurrentEntity.position; + buffer.append (fCurrentEntity.ch, fCurrentEntity.position, length); + fCurrentEntity.columnNumber += fCurrentEntity.count; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = fCurrentEntity.count; + fCurrentEntity.startPosition = fCurrentEntity.count; + load(0,true); + return false; + } + + // normalize newlines + int offset = fCurrentEntity.position; + int c = fCurrentEntity.ch[offset]; + int newlines = 0; + if (c == '\n' || ((c == '\r' || c == 0x85 || c == 0x2028) && external)) { + do { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if ((c == '\r' ) && external) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + int cc = fCurrentEntity.ch[fCurrentEntity.position]; + if (cc == '\n' || cc == 0x85) { + fCurrentEntity.position++; + offset++; + } + /*** NEWLINE NORMALIZATION ***/ + else { + newlines++; + } + } + else if (c == '\n' || ((c == 0x85 || c == 0x2028) && external)) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + fCurrentEntity.count = newlines; + if (load(newlines, false)) { + break; + } + } + } + else { + fCurrentEntity.position--; + break; + } + } while (fCurrentEntity.position < fCurrentEntity.count - 1); + for (int i = offset; i < fCurrentEntity.position; i++) { + fCurrentEntity.ch[i] = '\n'; + } + int length = fCurrentEntity.position - offset; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + buffer.append(fCurrentEntity.ch, offset, length); + return true; + } + } + + // iterate over buffer looking for delimiter + if (external) { + OUTER: while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == charAt0) { + // looks like we just hit the delimiter + int delimOffset = fCurrentEntity.position - 1; + for (int i = 1; i < delimLen; i++) { + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.position -= i; + break OUTER; + } + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (delimiter.charAt(i) != c) { + fCurrentEntity.position--; + break; + } + } + if (fCurrentEntity.position == delimOffset + delimLen) { + done = true; + break; + } + } + else if (c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) { + fCurrentEntity.position--; + break; + } + // In external entities control characters cannot appear + // as literals so do not skip over them. + else if (!XML11Char.isXML11ValidLiteral(c)) { + fCurrentEntity.position--; + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + buffer.append(fCurrentEntity.ch, offset, length); + return true; + } + } + } + else { + OUTER: while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == charAt0) { + // looks like we just hit the delimiter + int delimOffset = fCurrentEntity.position - 1; + for (int i = 1; i < delimLen; i++) { + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.position -= i; + break OUTER; + } + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (delimiter.charAt(i) != c) { + fCurrentEntity.position--; + break; + } + } + if (fCurrentEntity.position == delimOffset + delimLen) { + done = true; + break; + } + } + else if (c == '\n') { + fCurrentEntity.position--; + break; + } + // Control characters are allowed to appear as literals + // in internal entities. + else if (!XML11Char.isXML11Valid(c)) { + fCurrentEntity.position--; + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + buffer.append(fCurrentEntity.ch, offset, length); + return true; + } + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + if (done) { + length -= delimLen; + } + buffer.append(fCurrentEntity.ch, offset, length); + + // return true if string was skipped + } while (!done); + return !done; + + } // scanData(String,XMLString) + + /** + * Skips a character appearing immediately on the input. + *

+ * Note: The character is consumed only if it matches + * the specified character. + * + * @param c The character to skip. + * + * @return Returns true if the character was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean skipChar(int c) throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip character + int cc = fCurrentEntity.ch[fCurrentEntity.position]; + if (cc == c) { + fCurrentEntity.position++; + if (c == '\n') { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + } + else { + fCurrentEntity.columnNumber++; + } + return true; + } + else if (c == '\n' && ((cc == 0x2028 || cc == 0x85) && fCurrentEntity.isExternal())) { + fCurrentEntity.position++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + return true; + } + else if (c == '\n' && (cc == '\r' ) && fCurrentEntity.isExternal()) { + // handle newlines + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = (char)cc; + load(1, false); + } + int ccc = fCurrentEntity.ch[++fCurrentEntity.position]; + if (ccc == '\n' || ccc == 0x85) { + fCurrentEntity.position++; + } + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + return true; + } + + // character was not skipped + return false; + + } // skipChar(int):boolean + + /** + * Skips space characters appearing immediately on the input. + *

+ * Note: The characters are consumed only if they are + * space characters. + * + * @return Returns true if at least one space character was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.XMLChar#isSpace + * @see org.apache.xerces.util.XML11Char#isXML11Space + */ + public boolean skipSpaces() throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip spaces + int c = fCurrentEntity.ch[fCurrentEntity.position]; + + // External -- Match: S + 0x85 + 0x2028, and perform end of line normalization + if (fCurrentEntity.isExternal()) { + if (XML11Char.isXML11Space(c)) { + do { + boolean entityChanged = false; + // handle newlines + if (c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = (char)c; + entityChanged = load(1, true); + if (!entityChanged) { + // the load change the position to be 1, + // need to restore it when entity not changed + fCurrentEntity.startPosition = 0; + fCurrentEntity.position = 0; + } + } + if (c == '\r') { + // REVISIT: Does this need to be updated to fix the + // #x0D ^#x0A newline normalization problem? -Ac + int cc = fCurrentEntity.ch[++fCurrentEntity.position]; + if (cc != '\n' && cc != 0x85 ) { + fCurrentEntity.position--; + } + } + } + else { + fCurrentEntity.columnNumber++; + } + // load more characters, if needed + if (!entityChanged) + fCurrentEntity.position++; + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + } while (XML11Char.isXML11Space(c = fCurrentEntity.ch[fCurrentEntity.position])); + return true; + } + } + // Internal -- Match: S (only) + else if (XMLChar.isSpace(c)) { + do { + boolean entityChanged = false; + // handle newlines + if (c == '\n') { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = (char)c; + entityChanged = load(1, true); + if (!entityChanged) { + // the load change the position to be 1, + // need to restore it when entity not changed + fCurrentEntity.startPosition = 0; + fCurrentEntity.position = 0; + } + } + } + else { + fCurrentEntity.columnNumber++; + } + // load more characters, if needed + if (!entityChanged) + fCurrentEntity.position++; + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position])); + return true; + } + + // no spaces were found + return false; + + } // skipSpaces():boolean + + /** + * Skips the specified string appearing immediately on the input. + *

+ * Note: The characters are consumed only if they are + * space characters. + * + * @param s The string to skip. + * + * @return Returns true if the string was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean skipString(String s) throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip string + final int length = s.length(); + for (int i = 0; i < length; i++) { + char c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c != s.charAt(i)) { + fCurrentEntity.position -= i + 1; + return false; + } + if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) { + System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1); + // REVISIT: Can a string to be skipped cross an + // entity boundary? -Ac + if (load(i + 1, false)) { + fCurrentEntity.startPosition -= i + 1; + fCurrentEntity.position -= i + 1; + return false; + } + } + } + fCurrentEntity.columnNumber += length; + return true; + + } // skipString(String):boolean + +} // class XML11EntityScanner + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XML11NSDocumentScannerImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/XML11NSDocumentScannerImpl.java new file mode 100644 index 0000000..4c3aaec --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XML11NSDocumentScannerImpl.java @@ -0,0 +1,842 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.IOException; + +import org.apache.xerces.impl.dtd.XMLDTDValidatorFilter; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + * The scanner acts as the source for the document + * information which is communicated to the document handler. + * + * This class scans an XML document, checks if document has a DTD, and if + * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform + * namespace binding. + * + * Note: This scanner should only be used when the namespace processing is on! + * + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces {true} -- if the value of this + * feature is set to false this scanner must not be used.
  • + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/nonvalidating/load-external-dtd
  • + *
  • http://apache.org/xml/features/scanner/notify-char-refs
  • + *
  • http://apache.org/xml/features/scanner/notify-builtin-refs
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-manager
  • + *
  • http://apache.org/xml/properties/internal/dtd-scanner
  • + *
+ * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XML11NSDocumentScannerImpl extends XML11DocumentScannerImpl { + + /** + * If is true, the dtd validator is no longer in the pipeline + * and the scanner should bind namespaces + */ + protected boolean fBindNamespaces; + + /** + * If validating parser, make sure we report an error in the + * scanner if DTD grammar is missing. + */ + protected boolean fPerformValidation; + + // private data + // + + /** DTD validator */ + private XMLDTDValidatorFilter fDTDValidator; + + /** + * Saw spaces after element name or between attributes. + * + * This is reserved for the case where scanning of a start element spans + * several methods, as is the case when scanning the start of a root element + * where a DTD external subset may be read after scanning the element name. + */ + private boolean fSawSpace; + + /** + * The scanner is responsible for removing DTD validator + * from the pipeline if it is not needed. + * + * @param validator the DTD validator from the pipeline + */ + public void setDTDValidator(XMLDTDValidatorFilter validator) { + fDTDValidator = validator; + } + + /** + * Scans a start element. This method will handle the binding of + * namespace information and notifying the handler of the start + * of the element. + *

+ *

+     * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
+     * [40] STag ::= '<' Name (S Attribute)* S? '>'
+     * 
+ *

+ * Note: This method assumes that the leading + * '<' character has been consumed. + *

+ * Note: This method uses the fElementQName and + * fAttributes variables. The contents of these variables will be + * destroyed. The caller should copy important information out of + * these variables before calling this method. + * + * @return True if element is empty. (i.e. It matches + * production [44]. + */ + protected boolean scanStartElement() throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) + System.out.println(">>> scanStartElementNS()"); + + // Note: namespace processing is on by default + fEntityScanner.scanQName(fElementQName); + // REVISIT - [Q] Why do we need this local variable? -- mrglavas + String rawname = fElementQName.rawname; + if (fBindNamespaces) { + fNamespaceContext.pushContext(); + if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) { + if (fPerformValidation) { + fErrorReporter.reportError( + XMLMessageFormatter.XML_DOMAIN, + "MSG_GRAMMAR_NOT_FOUND", + new Object[] { rawname }, + XMLErrorReporter.SEVERITY_ERROR); + + if (fDoctypeName == null + || !fDoctypeName.equals(rawname)) { + fErrorReporter.reportError( + XMLMessageFormatter.XML_DOMAIN, + "RootElementTypeMustMatchDoctypedecl", + new Object[] { fDoctypeName, rawname }, + XMLErrorReporter.SEVERITY_ERROR); + } + } + } + } + + // push element stack + fCurrentElement = fElementStack.pushElement(fElementQName); + + // attributes + boolean empty = false; + fAttributes.removeAllAttributes(); + do { + // spaces + boolean sawSpace = fEntityScanner.skipSpaces(); + + // end tag? + int c = fEntityScanner.peekChar(); + if (c == '>') { + fEntityScanner.scanChar(); + break; + } else if (c == '/') { + fEntityScanner.scanChar(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError( + "ElementUnterminated", + new Object[] { rawname }); + } + empty = true; + break; + } else if (!isValidNameStartChar(c) || !sawSpace) { + // Second chance. Check if this character is a high + // surrogate of a valid name start character. + if (!isValidNameStartHighSurrogate(c) || !sawSpace) { + reportFatalError( + "ElementUnterminated", + new Object[] { rawname }); + } + } + + // attributes + scanAttribute(fAttributes); + + } while (true); + + if (fBindNamespaces) { + // REVISIT: is it required? forbit xmlns prefix for element + if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "ElementXMLNSPrefix", + new Object[] { fElementQName.rawname }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind the element + String prefix = + fElementQName.prefix != null + ? fElementQName.prefix + : XMLSymbols.EMPTY_STRING; + // assign uri to the element + fElementQName.uri = fNamespaceContext.getURI(prefix); + // make sure that object in the element stack is updated as well + fCurrentElement.uri = fElementQName.uri; + + if (fElementQName.prefix == null && fElementQName.uri != null) { + fElementQName.prefix = XMLSymbols.EMPTY_STRING; + // making sure that the object in the element stack is updated too. + fCurrentElement.prefix = XMLSymbols.EMPTY_STRING; + } + if (fElementQName.prefix != null && fElementQName.uri == null) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "ElementPrefixUnbound", + new Object[] { + fElementQName.prefix, + fElementQName.rawname }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind attributes (xmlns are already bound bellow) + int length = fAttributes.getLength(); + for (int i = 0; i < length; i++) { + fAttributes.getName(i, fAttributeQName); + + String aprefix = + fAttributeQName.prefix != null + ? fAttributeQName.prefix + : XMLSymbols.EMPTY_STRING; + String uri = fNamespaceContext.getURI(aprefix); + // REVISIT: try removing the first "if" and see if it is faster. + // + if (fAttributeQName.uri != null + && fAttributeQName.uri == uri) { + continue; + } + if (aprefix != XMLSymbols.EMPTY_STRING) { + fAttributeQName.uri = uri; + if (uri == null) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "AttributePrefixUnbound", + new Object[] { + fElementQName.rawname, + fAttributeQName.rawname, + aprefix }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + fAttributes.setURI(i, uri); + } + } + + if (length > 1) { + QName name = fAttributes.checkDuplicatesNS(); + if (name != null) { + if (name.uri != null) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNSNotUnique", + new Object[] { + fElementQName.rawname, + name.localpart, + name.uri }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } else { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNotUnique", + new Object[] { + fElementQName.rawname, + name.rawname }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + } + } + + // call handler + if (fDocumentHandler != null) { + if (empty) { + + //decrease the markup depth.. + fMarkupDepth--; + + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError( + "ElementEntityMismatch", + new Object[] { fCurrentElement.rawname }); + } + + fDocumentHandler.emptyElement(fElementQName, fAttributes, null); + + if (fBindNamespaces) { + fNamespaceContext.popContext(); + } + //pop the element off the stack.. + fElementStack.popElement(fElementQName); + } else { + fDocumentHandler.startElement(fElementQName, fAttributes, null); + } + } + + if (DEBUG_CONTENT_SCANNING) + System.out.println("<<< scanStartElement(): " + empty); + return empty; + + } // scanStartElement():boolean + + /** + * Scans the name of an element in a start or empty tag. + * + * @see #scanStartElement() + */ + protected void scanStartElementName () + throws IOException, XNIException { + // Note: namespace processing is on by default + fEntityScanner.scanQName(fElementQName); + // Must skip spaces here because the DTD scanner + // would consume them at the end of the external subset. + fSawSpace = fEntityScanner.skipSpaces(); + } // scanStartElementName() + + /** + * Scans the remainder of a start or empty tag after the element name. + * + * @see #scanStartElement + * @return True if element is empty. + */ + protected boolean scanStartElementAfterName() + throws IOException, XNIException { + + // REVISIT - [Q] Why do we need this local variable? -- mrglavas + String rawname = fElementQName.rawname; + if (fBindNamespaces) { + fNamespaceContext.pushContext(); + if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) { + if (fPerformValidation) { + fErrorReporter.reportError( + XMLMessageFormatter.XML_DOMAIN, + "MSG_GRAMMAR_NOT_FOUND", + new Object[] { rawname }, + XMLErrorReporter.SEVERITY_ERROR); + + if (fDoctypeName == null + || !fDoctypeName.equals(rawname)) { + fErrorReporter.reportError( + XMLMessageFormatter.XML_DOMAIN, + "RootElementTypeMustMatchDoctypedecl", + new Object[] { fDoctypeName, rawname }, + XMLErrorReporter.SEVERITY_ERROR); + } + } + } + } + + // push element stack + fCurrentElement = fElementStack.pushElement(fElementQName); + + // attributes + boolean empty = false; + fAttributes.removeAllAttributes(); + do { + + // end tag? + int c = fEntityScanner.peekChar(); + if (c == '>') { + fEntityScanner.scanChar(); + break; + } else if (c == '/') { + fEntityScanner.scanChar(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError( + "ElementUnterminated", + new Object[] { rawname }); + } + empty = true; + break; + } else if (!isValidNameStartChar(c) || !fSawSpace) { + // Second chance. Check if this character is a high + // surrogate of a valid name start character. + if (!isValidNameStartHighSurrogate(c) || !fSawSpace) { + reportFatalError( + "ElementUnterminated", + new Object[] { rawname }); + } + } + + // attributes + scanAttribute(fAttributes); + + // spaces + fSawSpace = fEntityScanner.skipSpaces(); + + } while (true); + + if (fBindNamespaces) { + // REVISIT: is it required? forbit xmlns prefix for element + if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "ElementXMLNSPrefix", + new Object[] { fElementQName.rawname }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind the element + String prefix = + fElementQName.prefix != null + ? fElementQName.prefix + : XMLSymbols.EMPTY_STRING; + // assign uri to the element + fElementQName.uri = fNamespaceContext.getURI(prefix); + // make sure that object in the element stack is updated as well + fCurrentElement.uri = fElementQName.uri; + + if (fElementQName.prefix == null && fElementQName.uri != null) { + fElementQName.prefix = XMLSymbols.EMPTY_STRING; + // making sure that the object in the element stack is updated too. + fCurrentElement.prefix = XMLSymbols.EMPTY_STRING; + } + if (fElementQName.prefix != null && fElementQName.uri == null) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "ElementPrefixUnbound", + new Object[] { + fElementQName.prefix, + fElementQName.rawname }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind attributes (xmlns are already bound bellow) + int length = fAttributes.getLength(); + for (int i = 0; i < length; i++) { + fAttributes.getName(i, fAttributeQName); + + String aprefix = + fAttributeQName.prefix != null + ? fAttributeQName.prefix + : XMLSymbols.EMPTY_STRING; + String uri = fNamespaceContext.getURI(aprefix); + // REVISIT: try removing the first "if" and see if it is faster. + // + if (fAttributeQName.uri != null + && fAttributeQName.uri == uri) { + continue; + } + if (aprefix != XMLSymbols.EMPTY_STRING) { + fAttributeQName.uri = uri; + if (uri == null) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "AttributePrefixUnbound", + new Object[] { + fElementQName.rawname, + fAttributeQName.rawname, + aprefix }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + fAttributes.setURI(i, uri); + } + } + + if (length > 1) { + QName name = fAttributes.checkDuplicatesNS(); + if (name != null) { + if (name.uri != null) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNSNotUnique", + new Object[] { + fElementQName.rawname, + name.localpart, + name.uri }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } else { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNotUnique", + new Object[] { + fElementQName.rawname, + name.rawname }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + } + } + + // call handler + if (fDocumentHandler != null) { + if (empty) { + + //decrease the markup depth.. + fMarkupDepth--; + + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError( + "ElementEntityMismatch", + new Object[] { fCurrentElement.rawname }); + } + + fDocumentHandler.emptyElement(fElementQName, fAttributes, null); + + if (fBindNamespaces) { + fNamespaceContext.popContext(); + } + //pop the element off the stack.. + fElementStack.popElement(fElementQName); + } else { + fDocumentHandler.startElement(fElementQName, fAttributes, null); + } + } + + if (DEBUG_CONTENT_SCANNING) + System.out.println("<<< scanStartElementAfterName(): " + empty); + return empty; + + } // scanStartElementAfterName() + + /** + * Scans an attribute. + *

+ *

+     * [41] Attribute ::= Name Eq AttValue
+     * 
+ *

+ * Note: This method assumes that the next + * character on the stream is the first character of the attribute + * name. + *

+ * Note: This method uses the fAttributeQName and + * fQName variables. The contents of these variables will be + * destroyed. + * + * @param attributes The attributes list for the scanned attribute. + */ + protected void scanAttribute(XMLAttributesImpl attributes) + throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) + System.out.println(">>> scanAttribute()"); + + // name + fEntityScanner.scanQName(fAttributeQName); + + // equals + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('=')) { + reportFatalError( + "EqRequiredInAttribute", + new Object[] { + fCurrentElement.rawname, + fAttributeQName.rawname }); + } + fEntityScanner.skipSpaces(); + + // content + int attrIndex; + + if (fBindNamespaces) { + attrIndex = attributes.getLength(); + attributes.addAttributeNS( + fAttributeQName, + XMLSymbols.fCDATASymbol, + null); + } else { + int oldLen = attributes.getLength(); + attrIndex = + attributes.addAttribute( + fAttributeQName, + XMLSymbols.fCDATASymbol, + null); + + // WFC: Unique Att Spec + if (oldLen == attributes.getLength()) { + reportFatalError( + "AttributeNotUnique", + new Object[] { + fCurrentElement.rawname, + fAttributeQName.rawname }); + } + } + + // Scan attribute value and return true if the non-normalized and normalized value are the same + boolean isSameNormalizedAttr = scanAttributeValue(this.fTempString, fTempString2, + fAttributeQName.rawname, fIsEntityDeclaredVC, fCurrentElement.rawname); + + String value = fTempString.toString(); + attributes.setValue(attrIndex, value); + // If the non-normalized and normalized value are the same, avoid creating a new string. + if (!isSameNormalizedAttr) { + attributes.setNonNormalizedValue(attrIndex, fTempString2.toString()); + } + attributes.setSpecified(attrIndex, true); + + // record namespace declarations if any. + if (fBindNamespaces) { + + String localpart = fAttributeQName.localpart; + String prefix = + fAttributeQName.prefix != null + ? fAttributeQName.prefix + : XMLSymbols.EMPTY_STRING; + // when it's of form xmlns="..." or xmlns:prefix="...", + // it's a namespace declaration. but prefix:xmlns="..." isn't. + if (prefix == XMLSymbols.PREFIX_XMLNS + || prefix == XMLSymbols.EMPTY_STRING + && localpart == XMLSymbols.PREFIX_XMLNS) { + + // get the internalized value of this attribute + String uri = fSymbolTable.addSymbol(value); + + // 1. "xmlns" can't be bound to any namespace + if (prefix == XMLSymbols.PREFIX_XMLNS + && localpart == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[] { fAttributeQName }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 2. the namespace for "xmlns" can't be bound to any prefix + if (uri == NamespaceContext.XMLNS_URI) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[] { fAttributeQName }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 3. "xml" can't be bound to any other namespace than it's own + if (localpart == XMLSymbols.PREFIX_XML) { + if (uri != NamespaceContext.XML_URI) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[] { fAttributeQName }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + // 4. the namespace for "xml" can't be bound to any other prefix + else { + if (uri == NamespaceContext.XML_URI) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[] { fAttributeQName }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + + prefix = + localpart != XMLSymbols.PREFIX_XMLNS + ? localpart + : XMLSymbols.EMPTY_STRING; + + // Declare prefix in context. Removing the association between a prefix and a + // namespace name is permitted in XML 1.1, so if the uri value is the empty string, + // the prefix is being unbound. -- mrglavas + fNamespaceContext.declarePrefix( + prefix, + uri.length() != 0 ? uri : null); + // bind namespace attribute to a namespace + attributes.setURI( + attrIndex, + fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS)); + + } else { + // attempt to bind attribute + if (fAttributeQName.prefix != null) { + attributes.setURI( + attrIndex, + fNamespaceContext.getURI(fAttributeQName.prefix)); + } + } + } + + if (DEBUG_CONTENT_SCANNING) + System.out.println("<<< scanAttribute()"); + } // scanAttribute(XMLAttributes) + + /** + * Scans an end element. + *

+ *

+     * [42] ETag ::= '</' Name S? '>'
+     * 
+ *

+ * Note: This method uses the fElementQName variable. + * The contents of this variable will be destroyed. The caller should + * copy the needed information out of this variable before calling + * this method. + * + * @return The element depth. + */ + protected int scanEndElement() throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) + System.out.println(">>> scanEndElement()"); + + // pop context + fElementStack.popElement(fElementQName); + + // Take advantage of the fact that next string _should_ be "fElementQName.rawName", + //In scanners most of the time is consumed on checks done for XML characters, we can + // optimize on it and avoid the checks done for endElement, + //we will also avoid symbol table lookup - neeraj.bajaj@sun.com + + // this should work both for namespace processing true or false... + + //REVISIT: if the string is not the same as expected.. we need to do better error handling.. + //We can skip this for now... In any case if the string doesn't match -- document is not well formed. + if (!fEntityScanner.skipString(fElementQName.rawname)) { + reportFatalError( + "ETagRequired", + new Object[] { fElementQName.rawname }); + } + + // end + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError( + "ETagUnterminated", + new Object[] { fElementQName.rawname }); + } + fMarkupDepth--; + + //we have increased the depth for two markup "<" characters + fMarkupDepth--; + + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError( + "ElementEntityMismatch", + new Object[] { fCurrentElement.rawname }); + } + + // call handler + if (fDocumentHandler != null) { + + fDocumentHandler.endElement(fElementQName, null); + if (fBindNamespaces) { + fNamespaceContext.popContext(); + } + + } + + return fMarkupDepth; + + } // scanEndElement():int + + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + super.reset(componentManager); + fPerformValidation = false; + fBindNamespaces = false; + } + + /** Creates a content dispatcher. */ + protected Dispatcher createContentDispatcher() { + return new NS11ContentDispatcher(); + } // createContentDispatcher():Dispatcher + + /** + * Dispatcher to handle content scanning. + */ + protected final class NS11ContentDispatcher extends ContentDispatcher { + /** + * Scan for root element hook. This method is a hook for + * subclasses to add code that handles scanning for the root + * element. This method will also attempt to remove DTD validator + * from the pipeline, if there is no DTD grammar. If DTD validator + * is no longer in the pipeline bind namespaces in the scanner. + * + * + * @return True if the caller should stop and return true which + * allows the scanner to switch to a new scanning + * dispatcher. A return value of false indicates that + * the content dispatcher should continue as normal. + */ + protected boolean scanRootElementHook() + throws IOException, XNIException { + + if (fExternalSubsetResolver != null && !fSeenDoctypeDecl + && !fDisallowDoctype && (fValidation || fLoadExternalDTD)) { + scanStartElementName(); + resolveExternalSubsetAndRead(); + reconfigurePipeline(); + if (scanStartElementAfterName()) { + setScannerState(SCANNER_STATE_TRAILING_MISC); + setDispatcher(fTrailingMiscDispatcher); + return true; + } + } + else { + reconfigurePipeline(); + if (scanStartElement()) { + setScannerState(SCANNER_STATE_TRAILING_MISC); + setDispatcher(fTrailingMiscDispatcher); + return true; + } + } + return false; + + } // scanRootElementHook():boolean + + /** + * Re-configures pipeline by removing the DTD validator + * if no DTD grammar exists. If no validator exists in the + * pipeline or there is no DTD grammar, namespace binding + * is performed by the scanner in the enclosing class. + */ + private void reconfigurePipeline() { + if (fDTDValidator == null) { + fBindNamespaces = true; + } + else if (!fDTDValidator.hasGrammar()) { + fBindNamespaces = true; + fPerformValidation = fDTDValidator.validate(); + // re-configure pipeline + XMLDocumentSource source = fDTDValidator.getDocumentSource(); + XMLDocumentHandler handler = fDTDValidator.getDocumentHandler(); + source.setDocumentHandler(handler); + if (handler != null) + handler.setDocumentSource(source); + fDTDValidator.setDocumentSource(null); + fDTDValidator.setDocumentHandler(null); + } + } // reconfigurePipeline() + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XML11NamespaceBinder.java b/resources/xerces2-j-src/org/apache/xerces/impl/XML11NamespaceBinder.java new file mode 100644 index 0000000..78835fe --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XML11NamespaceBinder.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + + +/** + * This class performs namespace binding on the startElement and endElement + * method calls in accordance with Namespaces in XML 1.1. It extends the standard, + * Namespace-1.0-compliant binder in order to do this. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XML11NamespaceBinder extends XMLNamespaceBinder { + + // + // Constants + // + + // + // Data + // + + // + // Constructors + // + + /** Default constructor. */ + public XML11NamespaceBinder() { + } // () + // + // Public methods + // + + // + // Protected methods + // + + // returns true iff the given prefix is bound to "" *and* + // this is disallowed by the version of XML namespaces in use. + protected boolean prefixBoundToNullURI(String uri, String localpart) { + return false; + } // prefixBoundToNullURI(String, String): boolean + +} // class XML11NamespaceBinder diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLDTDScannerImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLDTDScannerImpl.java new file mode 100644 index 0000000..1a2d530 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLDTDScannerImpl.java @@ -0,0 +1,2138 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.IOException; + +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDScanner; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * This class is responsible for scanning the declarations found + * in the internal and external subsets of a DTD in an XML document. + * The scanner acts as the sources for the DTD information which is + * communicated to the DTD handlers. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/scanner/notify-char-refs
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-manager
  • + *
+ * + * @xerces.internal + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * @author Glenn Marcy, IBM + * @author Eric Ye, IBM + * + * @version $Id$ + */ +public class XMLDTDScannerImpl + extends XMLScanner + implements XMLDTDScanner, XMLComponent, XMLEntityHandler { + + // + // Constants + // + + // scanner states + + /** Scanner state: end of input. */ + protected static final int SCANNER_STATE_END_OF_INPUT = 0; + + /** Scanner state: text declaration. */ + protected static final int SCANNER_STATE_TEXT_DECL = 1; + + /** Scanner state: markup declaration. */ + protected static final int SCANNER_STATE_MARKUP_DECL = 2; + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + VALIDATION, + NOTIFY_CHAR_REFS, + }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { + null, + Boolean.FALSE, + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + ERROR_REPORTER, + ENTITY_MANAGER, + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { + null, + null, + null, + }; + + // debugging + + /** Debug scanner state. */ + private static final boolean DEBUG_SCANNER_STATE = false; + + // + // Data + // + + // handlers + + /** DTD handler. */ + protected XMLDTDHandler fDTDHandler; + + /** DTD content model handler. */ + protected XMLDTDContentModelHandler fDTDContentModelHandler; + + // state + + /** Scanner state. */ + protected int fScannerState; + + /** Standalone. */ + protected boolean fStandalone; + + /** Seen external DTD. */ + protected boolean fSeenExternalDTD; + + /** Seen a parameter entity reference. */ + protected boolean fSeenPEReferences; + + // private data + + /** Start DTD called. */ + private boolean fStartDTDCalled; + + /** + * Stack of content operators (either '|' or ',') in children + * content. + */ + private int[] fContentStack = new int[5]; + + /** Size of content stack. */ + private int fContentDepth; + + /** Parameter entity stack to check well-formedness. */ + private int[] fPEStack = new int[5]; + + + /** Parameter entity stack to report start/end entity calls. */ + private boolean[] fPEReport = new boolean[5]; + + /** Number of opened parameter entities. */ + private int fPEDepth; + + /** Markup depth. */ + private int fMarkUpDepth; + + /** Number of opened external entities. */ + private int fExtEntityDepth; + + /** Number of opened include sections. */ + private int fIncludeSectDepth; + + // temporary variables + + /** Array of 3 strings. */ + private final String[] fStrings = new String[3]; + + /** String. */ + private final XMLString fString = new XMLString(); + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); + + /** Literal text. */ + private final XMLString fLiteral = new XMLString(); + + /** Literal text. */ + private final XMLString fLiteral2 = new XMLString(); + + /** Enumeration values. */ + private String[] fEnumeration = new String[5]; + + /** Enumeration values count. */ + private int fEnumerationCount; + + /** Ignore conditional section buffer. */ + private final XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128); + + // + // Constructors + // + + /** Default constructor. */ + public XMLDTDScannerImpl() {} // () + + /** Constructor for he use of non-XMLComponentManagers. */ + public XMLDTDScannerImpl(SymbolTable symbolTable, + XMLErrorReporter errorReporter, XMLEntityManager entityManager) { + fSymbolTable = symbolTable; + fErrorReporter = errorReporter; + fEntityManager = entityManager; + entityManager.setProperty(SYMBOL_TABLE, fSymbolTable); + } + + // + // XMLDTDScanner methods + // + + /** + * Sets the input source. + * + * @param inputSource The input source or null. + * + * @throws IOException Thrown on i/o error. + */ + public void setInputSource(XMLInputSource inputSource) throws IOException { + if (inputSource == null) { + // no system id was available + if (fDTDHandler != null) { + fDTDHandler.startDTD(null, null); + fDTDHandler.endDTD(null); + } + return; + } + fEntityManager.setEntityHandler(this); + fEntityManager.startDTDEntity(inputSource); + } // setInputSource(XMLInputSource) + + /** + * Scans the external subset of the document. + * + * @param complete True if the scanner should scan the document + * completely, pushing all events to the registered + * document handler. A value of false indicates that + * that the scanner should only scan the next portion + * of the document and return. A scanner instance is + * permitted to completely scan a document if it does + * not support this "pull" scanning model. + * + * @return True if there is more to scan, false otherwise. + */ + public boolean scanDTDExternalSubset(boolean complete) + throws IOException, XNIException { + + fEntityManager.setEntityHandler(this); + if (fScannerState == SCANNER_STATE_TEXT_DECL) { + fSeenExternalDTD = true; + boolean textDecl = scanTextDecl(); + if (fScannerState == SCANNER_STATE_END_OF_INPUT) { + return false; + } + else { + // next state is markup decls regardless of whether there + // is a TextDecl or not + setScannerState(SCANNER_STATE_MARKUP_DECL); + if (textDecl && !complete) { + return true; + } + } + } + // keep dispatching "events" + do { + if (!scanDecls(complete)) { + return false; + } + } while (complete); + + // return that there is more to scan + return true; + + } // scanDTDExternalSubset(boolean):boolean + + /** + * Scans the internal subset of the document. + * + * @param complete True if the scanner should scan the document + * completely, pushing all events to the registered + * document handler. A value of false indicates that + * that the scanner should only scan the next portion + * of the document and return. A scanner instance is + * permitted to completely scan a document if it does + * not support this "pull" scanning model. + * @param standalone True if the document was specified as standalone. + * This value is important for verifying certain + * well-formedness constraints. + * @param hasExternalSubset True if the document has an external DTD. + * This allows the scanner to properly notify + * the handler of the end of the DTD in the + * absence of an external subset. + * + * @return True if there is more to scan, false otherwise. + */ + public boolean scanDTDInternalSubset(boolean complete, boolean standalone, + boolean hasExternalSubset) + throws IOException, XNIException { + // reset entity scanner + fEntityScanner = fEntityManager.getEntityScanner(); + fEntityManager.setEntityHandler(this); + fStandalone = standalone; + if (fScannerState == SCANNER_STATE_TEXT_DECL) { + // call handler + if (fDTDHandler != null) { + fDTDHandler.startDTD(fEntityScanner, null); + fStartDTDCalled = true; + } + // set starting state for internal subset + setScannerState(SCANNER_STATE_MARKUP_DECL); + } + // keep dispatching "events" + do { + if (!scanDecls(complete)) { + // call handler + if (fDTDHandler != null && hasExternalSubset == false) { + fDTDHandler.endDTD(null); + } + // we're done, set starting state for external subset + setScannerState(SCANNER_STATE_TEXT_DECL); + return false; + } + } while (complete); + + // return that there is more to scan + return true; + + } // scanDTDInternalSubset(boolean,boolean,boolean):boolean + + // + // XMLComponent methods + // + + /** + * reset + * + * @param componentManager + */ + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + super.reset(componentManager); + init(); + + } // reset(XMLComponentManager) + + // this is made for something like XMLDTDLoader--XMLComponentManager-free operation... + public void reset() { + super.reset(); + init(); + } + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + // + // XMLDTDSource methods + // + + /** + * setDTDHandler + * + * @param dtdHandler + */ + public void setDTDHandler(XMLDTDHandler dtdHandler) { + fDTDHandler = dtdHandler; + } // setDTDHandler(XMLDTDHandler) + + /** + * getDTDHandler + * + * @return the XMLDTDHandler + */ + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } // getDTDHandler(): XMLDTDHandler + + // + // XMLDTDContentModelSource methods + // + + /** + * setDTDContentModelHandler + * + * @param dtdContentModelHandler + */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler + dtdContentModelHandler) { + fDTDContentModelHandler = dtdContentModelHandler; + } // setDTDContentModelHandler + + /** + * getDTDContentModelHandler + * + * @return XMLDTDContentModelHandler + */ + public XMLDTDContentModelHandler getDTDContentModelHandler() { + return fDTDContentModelHandler ; + } // setDTDContentModelHandler + + // + // XMLEntityHandler methods + // + + /** + * This method notifies of the start of an entity. The DTD has the + * pseudo-name of "[dtd]" parameter entity names start with '%'; and + * general entities are just specified by their name. + * + * @param name The name of the entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startEntity(String name, + XMLResourceIdentifier identifier, + String encoding, Augmentations augs) throws XNIException { + + super.startEntity(name, identifier, encoding, augs); + + boolean dtdEntity = name.equals("[dtd]"); + if (dtdEntity) { + // call handler + if (fDTDHandler != null && !fStartDTDCalled ) { + fDTDHandler.startDTD(fEntityScanner, null); + } + if (fDTDHandler != null) { + fDTDHandler.startExternalSubset(identifier,null); + } + fEntityManager.startExternalSubset(); + fExtEntityDepth++; + } + else if (name.charAt(0) == '%') { + pushPEStack(fMarkUpDepth, fReportEntity); + if (fEntityScanner.isExternal()) { + fExtEntityDepth++; + } + } + + // call handler + if (fDTDHandler != null && !dtdEntity && fReportEntity) { + fDTDHandler.startParameterEntity(name, identifier, encoding, augs); + } + + } // startEntity(String,XMLResourceIdentifier,String) + + /** + * This method notifies the end of an entity. The DTD has the pseudo-name + * of "[dtd]" parameter entity names start with '%'; and general entities + * are just specified by their name. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endEntity(String name, Augmentations augs) + throws XNIException { + + super.endEntity(name, augs); + + // if there is no data after the doctype + // + if (fScannerState == SCANNER_STATE_END_OF_INPUT) + return; + + // Handle end of PE + boolean reportEntity = fReportEntity; + if (name.startsWith("%")) { + reportEntity = peekReportEntity(); + // check well-formedness of the enity + int startMarkUpDepth = popPEStack(); + // throw fatalError if this entity was incomplete and + // was a freestanding decl + if(startMarkUpDepth == 0 && + startMarkUpDepth < fMarkUpDepth) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL", + new Object[]{ fEntityManager.fCurrentEntity.name}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + if (startMarkUpDepth != fMarkUpDepth) { + reportEntity = false; + if (fValidation) { + // Proper nesting of parameter entities is a Validity Constraint + // and must not be enforced when validation is off + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "ImproperDeclarationNesting", + new Object[]{ name }, + XMLErrorReporter.SEVERITY_ERROR); + } + } + if (fEntityScanner.isExternal()) { + fExtEntityDepth--; + } + // call handler + if (fDTDHandler != null && reportEntity) { + fDTDHandler.endParameterEntity(name, augs); + } + } + // end DTD + else if (name.equals("[dtd]")) { + if (fIncludeSectDepth != 0) { + reportFatalError("IncludeSectUnterminated", null); + } + fScannerState = SCANNER_STATE_END_OF_INPUT; + // call handler + fEntityManager.endExternalSubset(); + if (fDTDHandler != null) { + fDTDHandler.endExternalSubset(null); + fDTDHandler.endDTD(null); + } + fExtEntityDepth--; + } + + } // endEntity(String) + + // helper methods + + /** + * Sets the scanner state. + * + * @param state The new scanner state. + */ + protected final void setScannerState(int state) { + + fScannerState = state; + if (DEBUG_SCANNER_STATE) { + System.out.print("### setScannerState: "); + System.out.print(getScannerStateName(state)); + System.out.println(); + } + + } // setScannerState(int) + + // + // Private methods + // + + /** Returns the scanner state name. */ + private static String getScannerStateName(int state) { + + if (DEBUG_SCANNER_STATE) { + switch (state) { + case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT"; + case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL"; + case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL"; + } + } + + return "??? ("+state+')'; + + } // getScannerStateName(int):String + + protected final boolean scanningInternalSubset() { + return fExtEntityDepth == 0; + } + + /** + * start a parameter entity dealing with the textdecl if there is any + * + * @param name The name of the parameter entity to start (without the '%') + * @param literal Whether this is happening within a literal + * + * @return The name of the parameter entity (with the '%') + */ + protected String startPE(String name, boolean literal) + throws IOException, XNIException { + int depth = fPEDepth; + String pName = "%"+name; + if (!fSeenPEReferences) { + fSeenPEReferences = true; + fEntityManager.notifyHasPEReferences(); + } + if (fValidation && !fEntityManager.isDeclaredEntity(pName)) { + fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared", + new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); + } + fEntityManager.startEntity(fSymbolTable.addSymbol(pName), + literal); + // if we actually got a new entity and it's external + // parse text decl if there is any + if (depth != fPEDepth && fEntityScanner.isExternal()) { + scanTextDecl(); + } + return pName; + } + + /** + * Dispatch an XML "event". + * + * @return true if a TextDecl was scanned. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown on parse error. + * + */ + protected final boolean scanTextDecl() + throws IOException, XNIException { + + // scan XMLDecl + boolean textDecl = false; + if (fEntityScanner.skipString("starts with "xml". (e.g. xmlfoo) + * + * @param target The PI target + * @param data The string to fill in with the data + */ + protected final void scanPIData(String target, XMLString data) + throws IOException, XNIException { + + super.scanPIData(target, data); + fMarkUpDepth--; + + // call handler + if (fDTDHandler != null) { + fDTDHandler.processingInstruction(target, data, null); + } + + } // scanPIData(String) + + /** + * Scans a comment. + *

+ *

+     * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
+     * 
+ *

+ * Note: Called after scanning past '<!--' + */ + protected final void scanComment() throws IOException, XNIException { + + fReportEntity = false; + scanComment(fStringBuffer); + fMarkUpDepth--; + + // call handler + if (fDTDHandler != null) { + fDTDHandler.comment(fStringBuffer, null); + } + fReportEntity = true; + + } // scanComment() + + /** + * Scans an element declaration + *

+ *

+     * [45]    elementdecl    ::=    '<!ELEMENT' S Name S contentspec S? '>'
+     * [46]    contentspec    ::=    'EMPTY' | 'ANY' | Mixed | children  
+     * 
+ *

+ * Note: Called after scanning past '<!ELEMENT' + */ + protected final void scanElementDecl() throws IOException, XNIException { + + // spaces + fReportEntity = false; + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL", + null); + } + + // element name + String name = fEntityScanner.scanName(); + if (name == null) { + reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL", + null); + } + + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL", + new Object[]{name}); + } + + // content model + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.startContentModel(name, null); + } + String contentModel = null; + fReportEntity = true; + if (fEntityScanner.skipString("EMPTY")) { + contentModel = "EMPTY"; + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.empty(null); + } + } + else if (fEntityScanner.skipString("ANY")) { + contentModel = "ANY"; + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.any(null); + } + } + else { + if (!fEntityScanner.skipChar('(')) { + reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN", + new Object[]{name}); + } + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.startGroup(null); + } + fStringBuffer.clear(); + fStringBuffer.append('('); + fMarkUpDepth++; + skipSeparator(false, !scanningInternalSubset()); + + // Mixed content model + if (fEntityScanner.skipString("#PCDATA")) { + scanMixed(name); + } + else { // children content + scanChildren(name); + } + contentModel = fStringBuffer.toString(); + } + + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.endContentModel(null); + } + + fReportEntity = false; + skipSeparator(false, !scanningInternalSubset()); + // end + if (!fEntityScanner.skipChar('>')) { + reportFatalError("ElementDeclUnterminated", new Object[]{name}); + } + fReportEntity = true; + fMarkUpDepth--; + + // call handler + if (fDTDHandler != null) { + fDTDHandler.elementDecl(name, contentModel, null); + } + + } // scanElementDecl() + + /** + * scan Mixed content model + * This assumes the content model has been parsed up to #PCDATA and + * can simply append to fStringBuffer. + *

+     * [51]    Mixed    ::=    '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'  
+     *                       | '(' S? '#PCDATA' S? ')'  
+     * 
+ * + * @param elName The element type name this declaration is about. + * + * Note: Called after scanning past '(#PCDATA'. + */ + private final void scanMixed(String elName) + throws IOException, XNIException { + + String childName = null; + + fStringBuffer.append("#PCDATA"); + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.pcdata(null); + } + skipSeparator(false, !scanningInternalSubset()); + while (fEntityScanner.skipChar('|')) { + fStringBuffer.append('|'); + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE, + null); + } + skipSeparator(false, !scanningInternalSubset()); + + childName = fEntityScanner.scanName(); + if (childName == null) { + reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT", + new Object[]{elName}); + } + fStringBuffer.append(childName); + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.element(childName, null); + } + skipSeparator(false, !scanningInternalSubset()); + } + // The following check must be done in a single call (as opposed to one + // for ')' and then one for '*') to guarantee that callbacks are + // properly nested. We do not want to trigger endEntity too early in + // case we cross the boundary of an entity between the two characters. + if (fEntityScanner.skipString(")*")) { + fStringBuffer.append(")*"); + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.endGroup(null); + fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE, + null); + } + } + else if (childName != null) { + reportFatalError("MixedContentUnterminated", + new Object[]{elName}); + } + else if (fEntityScanner.skipChar(')')){ + fStringBuffer.append(')'); + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.endGroup(null); + } + } + else { + reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN", + new Object[]{elName}); + } + fMarkUpDepth--; + // we are done + } + + /** + * scan children content model + * This assumes it can simply append to fStringBuffer. + *
+     * [47]    children  ::=    (choice | seq) ('?' | '*' | '+')? 
+     * [48]    cp        ::=    (Name | choice | seq) ('?' | '*' | '+')? 
+     * [49]    choice    ::=    '(' S? cp ( S? '|' S? cp )+ S? ')'
+     * [50]    seq       ::=    '(' S? cp ( S? ',' S? cp )* S? ')' 
+     * 
+ * + * @param elName The element type name this declaration is about. + * + * Note: Called after scanning past the first open + * paranthesis. + */ + private final void scanChildren(String elName) + throws IOException, XNIException { + + fContentDepth = 0; + pushContentStack(0); + int currentOp = 0; + int c; + while (true) { + if (fEntityScanner.skipChar('(')) { + fMarkUpDepth++; + fStringBuffer.append('('); + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.startGroup(null); + } + // push current op on stack and reset it + pushContentStack(currentOp); + currentOp = 0; + skipSeparator(false, !scanningInternalSubset()); + continue; + } + skipSeparator(false, !scanningInternalSubset()); + String childName = fEntityScanner.scanName(); + if (childName == null) { + reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN", + new Object[]{elName}); + return; + } + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.element(childName, null); + } + fStringBuffer.append(childName); + c = fEntityScanner.peekChar(); + if (c == '?' || c == '*' || c == '+') { + // call handler + if (fDTDContentModelHandler != null) { + short oc; + if (c == '?') { + oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE; + } + else if (c == '*') { + oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE; + } + else { + oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE; + } + fDTDContentModelHandler.occurrence(oc, null); + } + fEntityScanner.scanChar(); + fStringBuffer.append((char)c); + } + while (true) { + skipSeparator(false, !scanningInternalSubset()); + c = fEntityScanner.peekChar(); + if (c == ',' && currentOp != '|') { + currentOp = c; + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE, + null); + } + fEntityScanner.scanChar(); + fStringBuffer.append(','); + break; + } + else if (c == '|' && currentOp != ',') { + currentOp = c; + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE, + null); + } + fEntityScanner.scanChar(); + fStringBuffer.append('|'); + break; + } + else if (c != ')') { + reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN", + new Object[]{elName}); + } + // call handler + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.endGroup(null); + } + // restore previous op + currentOp = popContentStack(); + short oc; + // The following checks must be done in a single call (as + // opposed to one for ')' and then one for '?', '*', and '+') + // to guarantee that callbacks are properly nested. We do not + // want to trigger endEntity too early in case we cross the + // boundary of an entity between the two characters. + if (fEntityScanner.skipString(")?")) { + fStringBuffer.append(")?"); + // call handler + if (fDTDContentModelHandler != null) { + oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE; + fDTDContentModelHandler.occurrence(oc, null); + } + } + else if (fEntityScanner.skipString(")+")) { + fStringBuffer.append(")+"); + // call handler + if (fDTDContentModelHandler != null) { + oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE; + fDTDContentModelHandler.occurrence(oc, null); + } + } + else if (fEntityScanner.skipString(")*")) { + fStringBuffer.append(")*"); + // call handler + if (fDTDContentModelHandler != null) { + oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE; + fDTDContentModelHandler.occurrence(oc, null); + } + } + else { + // no occurrence specified + fEntityScanner.scanChar(); + fStringBuffer.append(')'); + } + fMarkUpDepth--; + if (fContentDepth == 0) { + return; + } + } + skipSeparator(false, !scanningInternalSubset()); + } + } + + /** + * Scans an attlist declaration + *

+ *

+     * [52]  AttlistDecl    ::=   '<!ATTLIST' S Name AttDef* S? '>' 
+     * [53]  AttDef         ::=   S Name S AttType S DefaultDecl 
+     * 
+ *

+ * Note: Called after scanning past '<!ATTLIST' + */ + protected final void scanAttlistDecl() throws IOException, XNIException { + + // spaces + fReportEntity = false; + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL", + null); + } + + // element name + String elName = fEntityScanner.scanName(); + if (elName == null) { + reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL", + null); + } + + // call handler + if (fDTDHandler != null) { + fDTDHandler.startAttlist(elName, null); + } + + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + // no space, is it the end yet? + if (fEntityScanner.skipChar('>')) { + // yes, stop here + // call handler + if (fDTDHandler != null) { + fDTDHandler.endAttlist(null); + } + fMarkUpDepth--; + return; + } + else { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF", + new Object[]{elName}); + } + } + + // definitions + while (!fEntityScanner.skipChar('>')) { + String name = fEntityScanner.scanName(); + if (name == null) { + reportFatalError("AttNameRequiredInAttDef", + new Object[]{elName}); + } + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF", + new Object[]{elName, name}); + } + // type + String type = scanAttType(elName, name); + + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF", + new Object[]{elName, name}); + } + + // default decl + String defaultType = scanAttDefaultDecl(elName, name, + type, + fLiteral, fLiteral2); + // REVISIT: Should we do anything with the non-normalized + // default attribute value? -Ac + // yes--according to bug 5073. - neilg + + // call handler + if (fDTDHandler != null) { + String[] enumeration = null; + if (fEnumerationCount != 0) { + enumeration = new String[fEnumerationCount]; + System.arraycopy(fEnumeration, 0, enumeration, + 0, fEnumerationCount); + } + // Determine whether the default value to be passed should be null. + // REVISIT: should probably check whether fLiteral.ch is null instead. LM. + if (defaultType!=null && (defaultType.equals("#REQUIRED") || + defaultType.equals("#IMPLIED"))) { + fDTDHandler.attributeDecl(elName, name, type, enumeration, + defaultType, null, null, null); + } + else { + fDTDHandler.attributeDecl(elName, name, type, enumeration, + defaultType, fLiteral, fLiteral2, null); + } + } + skipSeparator(false, !scanningInternalSubset()); + } + + // call handler + if (fDTDHandler != null) { + fDTDHandler.endAttlist(null); + } + fMarkUpDepth--; + fReportEntity = true; + + } // scanAttlistDecl() + + /** + * Scans an attribute type definition + *

+ *

+     * [54]  AttType        ::=   StringType | TokenizedType | EnumeratedType  
+     * [55]  StringType     ::=   'CDATA' 
+     * [56]  TokenizedType  ::=   'ID'
+     *                          | 'IDREF'
+     *                          | 'IDREFS'
+     *                          | 'ENTITY'
+     *                          | 'ENTITIES'
+     *                          | 'NMTOKEN'
+     *                          | 'NMTOKENS'
+     * [57]  EnumeratedType ::=    NotationType | Enumeration  
+     * [58]  NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
+     * [59]  Enumeration    ::=    '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' 
+     * 
+ *

+ * Note: Called after scanning past '<!ATTLIST' + * + * @param elName The element type name this declaration is about. + * @param atName The attribute name this declaration is about. + */ + private final String scanAttType(String elName, String atName) + throws IOException, XNIException { + + String type = null; + fEnumerationCount = 0; + /* + * Watchout: the order here is important: when a string happens to + * be a substring of another string, the longer one needs to be + * looked for first!! + */ + if (fEntityScanner.skipString("CDATA")) { + type = "CDATA"; + } + else if (fEntityScanner.skipString("IDREFS")) { + type = "IDREFS"; + } + else if (fEntityScanner.skipString("IDREF")) { + type = "IDREF"; + } + else if (fEntityScanner.skipString("ID")) { + type = "ID"; + } + else if (fEntityScanner.skipString("ENTITY")) { + type = "ENTITY"; + } + else if (fEntityScanner.skipString("ENTITIES")) { + type = "ENTITIES"; + } + else if (fEntityScanner.skipString("NMTOKENS")) { + type = "NMTOKENS"; + } + else if (fEntityScanner.skipString("NMTOKEN")) { + type = "NMTOKEN"; + } + else if (fEntityScanner.skipString("NOTATION")) { + type = "NOTATION"; + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE", + new Object[]{elName, atName}); + } + // open paren + int c = fEntityScanner.scanChar(); + if (c != '(') { + reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE", + new Object[]{elName, atName}); + } + fMarkUpDepth++; + do { + skipSeparator(false, !scanningInternalSubset()); + String aName = fEntityScanner.scanName(); + if (aName == null) { + reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE", + new Object[]{elName, atName}); + c = skipInvalidEnumerationValue(); + if (c == '|') { + continue; + } + break; + } + ensureEnumerationSize(fEnumerationCount + 1); + fEnumeration[fEnumerationCount++] = aName; + skipSeparator(false, !scanningInternalSubset()); + c = fEntityScanner.scanChar(); + } while (c == '|'); + if (c != ')') { + reportFatalError("NotationTypeUnterminated", + new Object[]{elName, atName}); + } + fMarkUpDepth--; + } + else { // Enumeration + type = "ENUMERATION"; + // open paren + int c = fEntityScanner.scanChar(); + if (c != '(') { +// "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL", + reportFatalError("AttTypeRequiredInAttDef", + new Object[]{elName, atName}); + } + fMarkUpDepth++; + do { + skipSeparator(false, !scanningInternalSubset()); + String token = fEntityScanner.scanNmtoken(); + if (token == null) { + reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION", + new Object[]{elName, atName}); + c = skipInvalidEnumerationValue(); + if (c == '|') { + continue; + } + break; + } + ensureEnumerationSize(fEnumerationCount + 1); + fEnumeration[fEnumerationCount++] = token; + skipSeparator(false, !scanningInternalSubset()); + c = fEntityScanner.scanChar(); + } while (c == '|'); + if (c != ')') { + reportFatalError("EnumerationUnterminated", + new Object[]{elName, atName}); + } + fMarkUpDepth--; + } + return type; + + } // scanAttType():String + + + /** + * Scans an attribute default declaration + *

+ *

+     * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
+     * 
+ * + * @param elName + * @param atName The name of the attribute being scanned. + * @param type + * @param defaultVal The string to fill in with the default value. + * @param nonNormalizedDefaultVal + */ + protected final String scanAttDefaultDecl(String elName, String atName, + String type, + XMLString defaultVal, + XMLString nonNormalizedDefaultVal) + throws IOException, XNIException { + + String defaultType = null; + fString.clear(); + defaultVal.clear(); + if (fEntityScanner.skipString("#REQUIRED")) { + defaultType = "#REQUIRED"; + } + else if (fEntityScanner.skipString("#IMPLIED")) { + defaultType = "#IMPLIED"; + } + else { + if (fEntityScanner.skipString("#FIXED")) { + defaultType = "#FIXED"; + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL", + new Object[]{elName, atName}); + } + } + // AttValue + boolean isVC = !fStandalone && (fSeenExternalDTD || fSeenPEReferences); + scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName, isVC, elName); + } + return defaultType; + + } // ScanAttDefaultDecl + + /** + * Scans an entity declaration + *

+ *

+     * [70]    EntityDecl  ::=    GEDecl | PEDecl 
+     * [71]    GEDecl      ::=    '<!ENTITY' S Name S EntityDef S? '>' 
+     * [72]    PEDecl      ::=    '<!ENTITY' S '%' S Name S PEDef S? '>' 
+     * [73]    EntityDef   ::=    EntityValue | (ExternalID NDataDecl?) 
+     * [74]    PEDef       ::=    EntityValue | ExternalID 
+     * [75]    ExternalID  ::=    'SYSTEM' S SystemLiteral 
+     *                          | 'PUBLIC' S PubidLiteral S SystemLiteral  
+     * [76]    NDataDecl   ::=    S 'NDATA' S Name 
+     * 
+ *

+ * Note: Called after scanning past '<!ENTITY' + */ + private final void scanEntityDecl() throws IOException, XNIException { + + boolean isPEDecl = false; + boolean sawPERef = false; + fReportEntity = false; + if (fEntityScanner.skipSpaces()) { + if (!fEntityScanner.skipChar('%')) { + isPEDecl = false; // + } + else if (skipSeparator(true, !scanningInternalSubset())) { + // + isPEDecl = true; + } + else if (scanningInternalSubset()) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_PEDECL", + null); + isPEDecl = true; + } + else if (fEntityScanner.peekChar() == '%') { + // is legal + skipSeparator(false, !scanningInternalSubset()); + isPEDecl = true; + } + else { + sawPERef = true; + } + } + else if (scanningInternalSubset() || !fEntityScanner.skipChar('%')) { + // or + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL", + null); + isPEDecl = false; + } + else if (fEntityScanner.skipSpaces()) { + // + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL", + null); + isPEDecl = false; + } + else { + sawPERef = true; + } + if (sawPERef) { + while (true) { + String peName = fEntityScanner.scanName(); + if (peName == null) { + reportFatalError("NameRequiredInPEReference", null); + } + else if (!fEntityScanner.skipChar(';')) { + reportFatalError("SemicolonRequiredInPEReference", + new Object[]{peName}); + } + else { + startPE(peName, false); + } + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('%')) + break; + if (!isPEDecl) { + if (skipSeparator(true, !scanningInternalSubset())) { + isPEDecl = true; + break; + } + isPEDecl = fEntityScanner.skipChar('%'); + } + } + } + + // name + String name = null; + if(fNamespaces) { + name = fEntityScanner.scanNCName(); + } else { + name = fEntityScanner.scanName(); + } + if (name == null) { + reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null); + } + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + if(fNamespaces && fEntityScanner.peekChar() == ':') { + fEntityScanner.scanChar(); + XMLStringBuffer colonName = new XMLStringBuffer(name); + colonName.append(':'); + String str = fEntityScanner.scanName(); + if (str != null) + colonName.append(str); + reportFatalError("ColonNotLegalWithNS", new Object[] {colonName.toString()}); + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL", + new Object[]{name}); + } + } else { + reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL", + new Object[]{name}); + } + } + + // external id + scanExternalID(fStrings, false); + String systemId = fStrings[0]; + String publicId = fStrings[1]; + + String notation = null; + // NDATA + boolean sawSpace = skipSeparator(true, !scanningInternalSubset()); + if (!isPEDecl && fEntityScanner.skipString("NDATA")) { + // check whether there was space before NDATA + if (!sawSpace) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL", + new Object[]{name}); + } + + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL", + new Object[]{name}); + } + notation = fEntityScanner.scanName(); + if (notation == null) { + reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL", + new Object[]{name}); + } + } + + // count of direct and indirect references to parameter entities in the value of the entity. + int paramEntityRefs = 0; + // internal entity + if (systemId == null) { + paramEntityRefs = scanEntityValue(fLiteral, fLiteral2); + // since we need it's value anyway, let's snag it so it doesn't get corrupted + // if a new load takes place before we store the entity values + fStringBuffer.clear(); + fStringBuffer2.clear(); + fStringBuffer.append(fLiteral.ch, fLiteral.offset, fLiteral.length); + fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset, fLiteral2.length); + } + + // skip possible trailing space + skipSeparator(false, !scanningInternalSubset()); + + // end + if (!fEntityScanner.skipChar('>')) { + reportFatalError("EntityDeclUnterminated", new Object[]{name}); + } + fMarkUpDepth--; + + // register entity and make callback + if (isPEDecl) { + name = "%" + name; + } + if (systemId != null) { + String baseSystemId = fEntityScanner.getBaseSystemId(); + if (notation != null) { + fEntityManager.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation); + } + else { + fEntityManager.addExternalEntity(name, publicId, systemId, + baseSystemId); + } + if (fDTDHandler != null) { + fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false)); + if (notation != null) { + fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier, + notation, null); + } + else { + fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null); + } + } + } + else { + fEntityManager.addInternalEntity(name, fStringBuffer.toString(), paramEntityRefs); + if (fDTDHandler != null) { + fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null); + } + } + fReportEntity = true; + + } // scanEntityDecl() + + /** + *

Scans an entity value.

+ * + *

Note: This method uses fString, fStringBuffer (through + * the use of scanCharReferenceValue), and fStringBuffer2, anything in them + * at the time of calling is lost.

+ * + * @param value The string to fill in with the value. + * @param nonNormalizedValue The string to fill in with the + * non-normalized value. + * + * @return Count of direct and indirect references to parameter entities in the value of the entity. + */ + protected final int scanEntityValue(XMLString value, + XMLString nonNormalizedValue) + throws IOException, XNIException + { + int quote = fEntityScanner.scanChar(); + if (quote != '\'' && quote != '"') { + reportFatalError("OpenQuoteMissingInDecl", null); + } + // store at which depth of entities we start + int entityDepth = fEntityDepth; + // count of direct and indirect references to parameter entities in the value of the entity. + int paramEntityRefs = 0; + + XMLString literal = fString; + XMLString literal2 = fString; + if (fEntityScanner.scanLiteral(quote, fString) != quote) { + fStringBuffer.clear(); + fStringBuffer2.clear(); + do { + fStringBuffer.append(fString); + fStringBuffer2.append(fString); + if (fEntityScanner.skipChar('&')) { + if (fEntityScanner.skipChar('#')) { + fStringBuffer2.append("&#"); + scanCharReferenceValue(fStringBuffer, fStringBuffer2); + } + else { + fStringBuffer.append('&'); + fStringBuffer2.append('&'); + String eName = fEntityScanner.scanName(); + if (eName == null) { + reportFatalError("NameRequiredInReference", + null); + } + else { + fStringBuffer.append(eName); + fStringBuffer2.append(eName); + } + if (!fEntityScanner.skipChar(';')) { + reportFatalError("SemicolonRequiredInReference", + new Object[]{eName}); + } + else { + fStringBuffer.append(';'); + fStringBuffer2.append(';'); + } + } + } + else if (fEntityScanner.skipChar('%')) { + while (true) { + fStringBuffer2.append('%'); + String peName = fEntityScanner.scanName(); + if (peName == null) { + reportFatalError("NameRequiredInPEReference", + null); + } + else if (!fEntityScanner.skipChar(';')) { + reportFatalError("SemicolonRequiredInPEReference", + new Object[]{peName}); + } + else { + if (scanningInternalSubset()) { + reportFatalError("PEReferenceWithinMarkup", + new Object[]{peName}); + } + fStringBuffer2.append(peName); + fStringBuffer2.append(';'); + } + final String pNameWithPct = startPE(peName, true); + paramEntityRefs += (fEntityManager.getParamEntityRefCount(pNameWithPct) + 1); + // REVISIT: [Q] Why do we skip spaces here? -Ac + // REVISIT: This will make returning the non- + // normalized value harder. -Ac + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('%')) + break; + } + } + else { + int c = fEntityScanner.peekChar(); + if (XMLChar.isHighSurrogate(c)) { + scanSurrogates(fStringBuffer2); + } + else if (isInvalidLiteral(c)) { + reportFatalError("InvalidCharInLiteral", + new Object[]{Integer.toHexString(c)}); + fEntityScanner.scanChar(); + } + // if it's not the delimiting quote or if it is but from a + // different entity than the one this literal started from, + // simply append the character to our buffer + else if (c != quote || entityDepth != fEntityDepth) { + fStringBuffer.append((char)c); + fStringBuffer2.append((char)c); + fEntityScanner.scanChar(); + } + } + } while (fEntityScanner.scanLiteral(quote, fString) != quote); + fStringBuffer.append(fString); + fStringBuffer2.append(fString); + literal = fStringBuffer; + literal2 = fStringBuffer2; + } + value.setValues(literal); + nonNormalizedValue.setValues(literal2); + if (!fEntityScanner.skipChar(quote)) { + reportFatalError("CloseQuoteMissingInDecl", null); + } + return paramEntityRefs; + } // scanEntityValue(XMLString,XMLString):int + + /** + * Scans a notation declaration + *

+ *

+     * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID|PublicID) S? '>'
+     * [83]  PublicID    ::= 'PUBLIC' S PubidLiteral  
+     * 
+ *

+ * Note: Called after scanning past '<!NOTATION' + */ + private final void scanNotationDecl() throws IOException, XNIException { + + // spaces + fReportEntity = false; + if (!skipSeparator(true, !scanningInternalSubset())) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL", + null); + } + + // notation name + String name = null; + if(fNamespaces) { + name = fEntityScanner.scanNCName(); + } else { + name = fEntityScanner.scanName(); + } + if (name == null) { + reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL", + null); + } + + // spaces + if (!skipSeparator(true, !scanningInternalSubset())) { + // check for invalid ":" + if(fNamespaces && fEntityScanner.peekChar() == ':') { + fEntityScanner.scanChar(); + XMLStringBuffer colonName = new XMLStringBuffer(name); + colonName.append(':'); + colonName.append(fEntityScanner.scanName()); + reportFatalError("ColonNotLegalWithNS", new Object[] {colonName.toString()}); + skipSeparator(true, !scanningInternalSubset()); + } else { + reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL", + new Object[]{name}); + } + } + + // external id + scanExternalID(fStrings, true); + String systemId = fStrings[0]; + String publicId = fStrings[1]; + String baseSystemId = fEntityScanner.getBaseSystemId(); + + if (systemId == null && publicId == null) { + reportFatalError("ExternalIDorPublicIDRequired", + new Object[]{name}); + } + + // skip possible trailing space + skipSeparator(false, !scanningInternalSubset()); + + // end + if (!fEntityScanner.skipChar('>')) { + reportFatalError("NotationDeclUnterminated", new Object[]{name}); + } + fMarkUpDepth--; + + // call handler + if (fDTDHandler != null) { + fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false)); + fDTDHandler.notationDecl(name, fResourceIdentifier, null); + } + fReportEntity = true; + + } // scanNotationDecl() + + /** + * Scans a conditional section. If it's a section to ignore the whole + * section gets scanned through and this method only returns after the + * closing bracket has been found. When it's an include section though, it + * returns to let the main loop take care of scanning it. In that case the + * end of the section if handled by the main loop (scanDecls). + *

+ *

+     * [61] conditionalSect   ::= includeSect | ignoreSect  
+     * [62] includeSect       ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
+     * [63] ignoreSect   ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
+     * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)* 
+     * [65] Ignore            ::=    Char* - (Char* ('<![' | ']]>') Char*)  
+     * 
+ *

+ * Note: Called after scanning past '<![' */ + private final void scanConditionalSect(int currPEDepth) + throws IOException, XNIException { + + fReportEntity = false; + skipSeparator(false, !scanningInternalSubset()); + + if (fEntityScanner.skipString("INCLUDE")) { + skipSeparator(false, !scanningInternalSubset()); + if(currPEDepth != fPEDepth && fValidation) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "INVALID_PE_IN_CONDITIONAL", + new Object[]{ fEntityManager.fCurrentEntity.name}, + XMLErrorReporter.SEVERITY_ERROR); + } + // call handler + if (!fEntityScanner.skipChar('[')) { + reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); + } + + if (fDTDHandler != null) { + fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE, + null); + } + fIncludeSectDepth++; + // just stop there and go back to the main loop + fReportEntity = true; + } + else if (fEntityScanner.skipString("IGNORE")) { + skipSeparator(false, !scanningInternalSubset()); + if(currPEDepth != fPEDepth && fValidation) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "INVALID_PE_IN_CONDITIONAL", + new Object[]{ fEntityManager.fCurrentEntity.name}, + XMLErrorReporter.SEVERITY_ERROR); + } + // call handler + if (fDTDHandler != null) { + fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE, + null); + } + if (!fEntityScanner.skipChar('[')) { + reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); + } + fReportEntity = true; + int initialDepth = ++fIncludeSectDepth; + if (fDTDHandler != null) { + fIgnoreConditionalBuffer.clear(); + } + while (true) { + if (fEntityScanner.skipChar('<')) { + if (fDTDHandler != null) { + fIgnoreConditionalBuffer.append('<'); + } + // + // These tests are split so that we handle cases like + // '<', etc. + // + if (fEntityScanner.skipChar(']')) { + if (fDTDHandler != null) { + fIgnoreConditionalBuffer.append(']'); + } + while (fEntityScanner.skipChar(']')) { + /* empty loop body */ + if (fDTDHandler != null) { + fIgnoreConditionalBuffer.append(']'); + } + } + if (fEntityScanner.skipChar('>')) { + if (fIncludeSectDepth-- == initialDepth) { + fMarkUpDepth--; + // call handler + if (fDTDHandler != null) { + fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0, + fIgnoreConditionalBuffer.length - 2); + fDTDHandler.ignoredCharacters(fLiteral, null); + fDTDHandler.endConditional(null); + } + return; + } else if(fDTDHandler != null) { + fIgnoreConditionalBuffer.append('>'); + } + } + } + } + else { + int c = fEntityScanner.scanChar(); + if (fScannerState == SCANNER_STATE_END_OF_INPUT) { + reportFatalError("IgnoreSectUnterminated", null); + return; + } + if (fDTDHandler != null) { + fIgnoreConditionalBuffer.append((char)c); + } + } + } + } + else { + reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); + } + + } // scanConditionalSect() + + /** + * Dispatch an XML "event". + * + * @param complete True if this method is intended to scan + * and dispatch as much as possible. + * + * @return True if there is more to scan. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown on parse error. + * + */ + protected final boolean scanDecls(boolean complete) + throws IOException, XNIException { + + skipSeparator(false, true); + boolean again = true; + while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) { + again = complete; + if (fEntityScanner.skipChar('<')) { + fMarkUpDepth++; + if (fEntityScanner.skipChar('?')) { + scanPI(); + } + else if (fEntityScanner.skipChar('!')) { + if (fEntityScanner.skipChar('-')) { + if (!fEntityScanner.skipChar('-')) { + reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", + null); + } else { + scanComment(); + } + } + else if (fEntityScanner.skipString("ELEMENT")) { + scanElementDecl(); + } + else if (fEntityScanner.skipString("ATTLIST")) { + scanAttlistDecl(); + } + else if (fEntityScanner.skipString("ENTITY")) { + scanEntityDecl(); + } + else if (fEntityScanner.skipString("NOTATION")) { + scanNotationDecl(); + } + else if (fEntityScanner.skipChar('[') && + !scanningInternalSubset()) { + scanConditionalSect(fPEDepth); + } + else { + fMarkUpDepth--; + reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", + null); + } + } + else { + fMarkUpDepth--; + reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); + } + } + else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) { + // end of conditional section? + if (!fEntityScanner.skipChar(']') + || !fEntityScanner.skipChar('>')) { + reportFatalError("IncludeSectUnterminated", null); + } + // call handler + if (fDTDHandler != null) { + fDTDHandler.endConditional(null); + } + // decreaseMarkupDepth(); + fIncludeSectDepth--; + fMarkUpDepth--; + } + else if (scanningInternalSubset() && + fEntityScanner.peekChar() == ']') { + // this is the end of the internal subset, let's stop here + return false; + } + else if (fEntityScanner.skipSpaces()) { + // simply skip + } + else { + reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); + // Skip the part in error + int ch; + do { + // Ignore the current character + fEntityScanner.scanChar(); + // Skip any separators + skipSeparator(false, true); + // Keeping getting the next character, + // until it's one of the expected ones + ch = fEntityScanner.peekChar(); + } while (ch != '<' && ch != ']' && !XMLChar.isSpace(ch)); + } + skipSeparator(false, true); + } + return fScannerState != SCANNER_STATE_END_OF_INPUT; + } + + /** + * Skip separator. This is typically just whitespace but it can also be one + * or more parameter entity references. + *

+ * If there are some it "expands them" by calling the corresponding entity + * from the entity manager. + *

+ * This is recursive and will process has many refs as possible. + * + * @param spaceRequired Specify whether some leading whitespace should be + * found + * @param lookForPERefs Specify whether parameter entity references should + * be looked for + * @return True if any leading whitespace was found or the end of a + * parameter entity was crossed. + */ + private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs) + throws IOException, XNIException + { + int depth = fPEDepth; + boolean sawSpace = fEntityScanner.skipSpaces(); + if (!lookForPERefs || !fEntityScanner.skipChar('%')) { + return !spaceRequired || sawSpace || (depth != fPEDepth); + } + while (true) { + String name = fEntityScanner.scanName(); + if (name == null) { + reportFatalError("NameRequiredInPEReference", null); + } + else if (!fEntityScanner.skipChar(';')) { + reportFatalError("SemicolonRequiredInPEReference", + new Object[]{name}); + } + startPE(name, false); + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('%')) + return true; + } + } + + + /* + * Element Children Content Stack + */ + private final void pushContentStack(int c) { + if (fContentStack.length == fContentDepth) { + int[] newStack = new int[fContentDepth * 2]; + System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth); + fContentStack = newStack; + } + fContentStack[fContentDepth++] = c; + } + + private final int popContentStack() { + return fContentStack[--fContentDepth]; + } + + + /* + * Parameter Entity Stack + */ + private final void pushPEStack(int depth, boolean report) { + if (fPEStack.length == fPEDepth) { + int[] newIntStack = new int[fPEDepth * 2]; + System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth); + fPEStack = newIntStack; + // report end/start calls + boolean[] newBooleanStack = new boolean[fPEDepth * 2]; + System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth); + fPEReport = newBooleanStack; + + } + fPEReport[fPEDepth] = report; + fPEStack[fPEDepth++] = depth; + } + + /** pop the stack */ + private final int popPEStack() { + return fPEStack[--fPEDepth]; + } + + /** look at the top of the stack */ + private final boolean peekReportEntity() { + return fPEReport[fPEDepth-1]; + } + + + /* + * Utility method + */ + private final void ensureEnumerationSize(int size) { + if (fEnumeration.length == size) { + String[] newEnum = new String[size * 2]; + System.arraycopy(fEnumeration, 0, newEnum, 0, size); + fEnumeration = newEnum; + } + } + + // private methods + private void init() { + // reset state related data + fStartDTDCalled = false; + fExtEntityDepth = 0; + fIncludeSectDepth = 0; + fMarkUpDepth = 0; + fPEDepth = 0; + + fStandalone = false; + fSeenExternalDTD = false; + fSeenPEReferences = false; + + // set starting state + setScannerState(SCANNER_STATE_TEXT_DECL); + } + + private int skipInvalidEnumerationValue() throws IOException { + int c; + do { + c = fEntityScanner.scanChar(); + } + while (c != '|' && c != ')'); + ensureEnumerationSize(fEnumerationCount + 1); + fEnumeration[fEnumerationCount++] = XMLSymbols.EMPTY_STRING; + return c; + } + +} // class XMLDTDScannerImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLDocumentFragmentScannerImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLDocumentFragmentScannerImpl.java new file mode 100644 index 0000000..7b5b447 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLDocumentFragmentScannerImpl.java @@ -0,0 +1,1869 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.CharConversionException; +import java.io.EOFException; +import java.io.IOException; + +import org.apache.xerces.impl.io.MalformedByteSequenceException; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.AugmentationsImpl; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentScanner; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * This class is responsible for scanning the structure and content + * of document fragments. The scanner acts as the source for the + * document information which is communicated to the document handler. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/scanner/notify-char-refs
  • + *
  • http://apache.org/xml/features/scanner/notify-builtin-refs
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-manager
  • + *
+ * + * @xerces.internal + * + * @author Glenn Marcy, IBM + * @author Andy Clark, IBM + * @author Arnaud Le Hors, IBM + * @author Eric Ye, IBM + * + * @version $Id$ + */ +public class XMLDocumentFragmentScannerImpl + extends XMLScanner + implements XMLDocumentScanner, XMLComponent, XMLEntityHandler { + + // + // Constants + // + + // scanner states + + /** Scanner state: start of markup. */ + protected static final int SCANNER_STATE_START_OF_MARKUP = 1; + + /** Scanner state: comment. */ + protected static final int SCANNER_STATE_COMMENT = 2; + + /** Scanner state: processing instruction. */ + protected static final int SCANNER_STATE_PI = 3; + + /** Scanner state: DOCTYPE. */ + protected static final int SCANNER_STATE_DOCTYPE = 4; + + /** Scanner state: root element. */ + protected static final int SCANNER_STATE_ROOT_ELEMENT = 6; + + /** Scanner state: content. */ + protected static final int SCANNER_STATE_CONTENT = 7; + + /** Scanner state: reference. */ + protected static final int SCANNER_STATE_REFERENCE = 8; + + /** Scanner state: end of input. */ + protected static final int SCANNER_STATE_END_OF_INPUT = 13; + + /** Scanner state: terminated. */ + protected static final int SCANNER_STATE_TERMINATED = 14; + + /** Scanner state: CDATA section. */ + protected static final int SCANNER_STATE_CDATA = 15; + + /** Scanner state: Text declaration. */ + protected static final int SCANNER_STATE_TEXT_DECL = 16; + + // feature identifiers + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: notify built-in refereces. */ + protected static final String NOTIFY_BUILTIN_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE; + + // property identifiers + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + NAMESPACES, + VALIDATION, + NOTIFY_BUILTIN_REFS, + NOTIFY_CHAR_REFS, + }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { + null, + null, + Boolean.FALSE, + Boolean.FALSE, + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + ERROR_REPORTER, + ENTITY_MANAGER, + ENTITY_RESOLVER, + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { + null, + null, + null, + null, + }; + + // debugging + + /** Debug scanner state. */ + private static final boolean DEBUG_SCANNER_STATE = false; + + /** Debug dispatcher. */ + private static final boolean DEBUG_DISPATCHER = false; + + /** Debug content dispatcher scanning. */ + protected static final boolean DEBUG_CONTENT_SCANNING = false; + + // + // Data + // + + // protected data + + /** Document handler. */ + protected XMLDocumentHandler fDocumentHandler; + + /** Entity stack. */ + protected int[] fEntityStack = new int[4]; + + /** Markup depth. */ + protected int fMarkupDepth; + + /** Scanner state. */ + protected int fScannerState; + + /** SubScanner state: inside scanContent method. */ + protected boolean fInScanContent = false; + + /** has external dtd */ + protected boolean fHasExternalDTD; + + /** Standalone. */ + protected boolean fStandalone; + + /** True if [Entity Declared] is a VC; false if it is a WFC. */ + protected boolean fIsEntityDeclaredVC; + + /** External subset resolver. **/ + protected ExternalSubsetResolver fExternalSubsetResolver; + + // element information + + /** Current element. */ + protected QName fCurrentElement; + + /** Element stack. */ + protected final ElementStack fElementStack = new ElementStack(); + + // other info + + /** Document system identifier. + * REVISIT: So what's this used for? - NG + * protected String fDocumentSystemId; + ******/ + + // features + + /** Notify built-in references. */ + protected boolean fNotifyBuiltInRefs = false; + + // dispatchers + + /** Active dispatcher. */ + protected Dispatcher fDispatcher; + + /** Content dispatcher. */ + protected final Dispatcher fContentDispatcher = createContentDispatcher(); + + // temporary variables + + /** Element QName. */ + protected final QName fElementQName = new QName(); + + /** Attribute QName. */ + protected final QName fAttributeQName = new QName(); + + /** Element attributes. */ + protected final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); + + /** String. */ + protected final XMLString fTempString = new XMLString(); + + /** String. */ + protected final XMLString fTempString2 = new XMLString(); + + /** Array of 3 strings. */ + private final String[] fStrings = new String[3]; + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); + + /** Another QName. */ + private final QName fQName = new QName(); + + /** Single character array. */ + private final char[] fSingleChar = new char[1]; + + /** + * Saw spaces after element name or between attributes. + * + * This is reserved for the case where scanning of a start element spans + * several methods, as is the case when scanning the start of a root element + * where a DTD external subset may be read after scanning the element name. + */ + private boolean fSawSpace; + + /** Reusable Augmentations. */ + private Augmentations fTempAugmentations = null; + + // + // Constructors + // + + /** Default constructor. */ + public XMLDocumentFragmentScannerImpl() {} // () + + // + // XMLDocumentScanner methods + // + + /** + * Sets the input source. + * + * @param inputSource The input source. + * + * @throws IOException Thrown on i/o error. + */ + public void setInputSource(XMLInputSource inputSource) throws IOException { + fEntityManager.setEntityHandler(this); + fEntityManager.startEntity("$fragment$", inputSource, false, true); + //fDocumentSystemId = fEntityManager.expandSystemId(inputSource.getSystemId()); + } // setInputSource(XMLInputSource) + + /** + * Scans a document. + * + * @param complete True if the scanner should scan the document + * completely, pushing all events to the registered + * document handler. A value of false indicates that + * that the scanner should only scan the next portion + * of the document and return. A scanner instance is + * permitted to completely scan a document if it does + * not support this "pull" scanning model. + * + * @return True if there is more to scan, false otherwise. + */ + public boolean scanDocument(boolean complete) + throws IOException, XNIException { + + // reset entity scanner + fEntityScanner = fEntityManager.getEntityScanner(); + + // keep dispatching "events" + fEntityManager.setEntityHandler(this); + do { + if (!fDispatcher.dispatch(complete)) { + return false; + } + } while (complete); + + // return success + return true; + + } // scanDocument(boolean):boolean + + // + // XMLComponent methods + // + + /** + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws SAXException Thrown by component on initialization error. + * For example, if a feature or property is + * required for the operation of the component, the + * component manager may throw a + * SAXNotRecognizedException or a + * SAXNotSupportedException. + */ + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + super.reset(componentManager); + + // other settings + //fDocumentSystemId = null; + + // sax features + fAttributes.setNamespaces(fNamespaces); + + // initialize vars + fMarkupDepth = 0; + fCurrentElement = null; + fElementStack.clear(); + fHasExternalDTD = false; + fStandalone = false; + fIsEntityDeclaredVC = false; + fInScanContent = false; + + // setup dispatcher + setScannerState(SCANNER_STATE_CONTENT); + setDispatcher(fContentDispatcher); + + + if (fParserSettings) { + // parser settings have changed. reset them. + + // xerces features + try { + fNotifyBuiltInRefs = componentManager.getFeature(NOTIFY_BUILTIN_REFS); + } catch (XMLConfigurationException e) { + fNotifyBuiltInRefs = false; + } + + // xerces properties + try { + Object resolver = componentManager.getProperty(ENTITY_RESOLVER); + fExternalSubsetResolver = (resolver instanceof ExternalSubsetResolver) ? + (ExternalSubsetResolver) resolver : null; + } + catch (XMLConfigurationException e) { + fExternalSubsetResolver = null; + } + } + + } // reset(XMLComponentManager) + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + + super.setFeature(featureId, state); + + // Xerces properties + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + if (suffixLength == Constants.NOTIFY_BUILTIN_REFS_FEATURE.length() && + featureId.endsWith(Constants.NOTIFY_BUILTIN_REFS_FEATURE)) { + fNotifyBuiltInRefs = state; + } + } + + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + super.setProperty(propertyId, value); + + // Xerces properties + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + if (suffixLength == Constants.ENTITY_MANAGER_PROPERTY.length() && + propertyId.endsWith(Constants.ENTITY_MANAGER_PROPERTY)) { + fEntityManager = (XMLEntityManager)value; + return; + } + if (suffixLength == Constants.ENTITY_RESOLVER_PROPERTY.length() && + propertyId.endsWith(Constants.ENTITY_RESOLVER_PROPERTY)) { + fExternalSubsetResolver = (value instanceof ExternalSubsetResolver) ? + (ExternalSubsetResolver) value : null; + return; + } + } + + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + // + // XMLDocumentSource methods + // + + /** + * setDocumentHandler + * + * @param documentHandler + */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + } // setDocumentHandler(XMLDocumentHandler) + + + /** Returns the document handler */ + public XMLDocumentHandler getDocumentHandler(){ + return fDocumentHandler; + } + + // + // XMLEntityHandler methods + // + + /** + * This method notifies of the start of an entity. The DTD has the + * pseudo-name of "[dtd]" parameter entity names start with '%'; and + * general entities are just specified by their name. + * + * @param name The name of the entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startEntity(String name, + XMLResourceIdentifier identifier, + String encoding, Augmentations augs) throws XNIException { + + // keep track of this entity before fEntityDepth is increased + if (fEntityDepth == fEntityStack.length) { + int[] entityarray = new int[fEntityStack.length * 2]; + System.arraycopy(fEntityStack, 0, entityarray, 0, fEntityStack.length); + fEntityStack = entityarray; + } + fEntityStack[fEntityDepth] = fMarkupDepth; + + super.startEntity(name, identifier, encoding, augs); + + // WFC: entity declared in external subset in standalone doc + if(fStandalone && fEntityManager.isEntityDeclInExternalSubset(name)) { + reportFatalError("MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", + new Object[]{name}); + } + + // call handler + if (fDocumentHandler != null && !fScanningAttribute) { + if (!name.equals("[xml]")) { + fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); + } + } + + } // startEntity(String,XMLResourceIdentifier,String) + + /** + * This method notifies the end of an entity. The DTD has the pseudo-name + * of "[dtd]" parameter entity names start with '%'; and general entities + * are just specified by their name. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endEntity(String name, Augmentations augs) throws XNIException { + + // flush possible pending output buffer - see scanContent + if (fInScanContent && fStringBuffer.length != 0 + && fDocumentHandler != null) { + fDocumentHandler.characters(fStringBuffer, null); + fStringBuffer.length = 0; // make sure we know it's been flushed + } + + super.endEntity(name, augs); + + // make sure markup is properly balanced + if (fMarkupDepth != fEntityStack[fEntityDepth]) { + reportFatalError("MarkupEntityMismatch", null); + } + + // call handler + if (fDocumentHandler != null && !fScanningAttribute) { + if (!name.equals("[xml]")) { + fDocumentHandler.endGeneralEntity(name, augs); + } + } + + } // endEntity(String) + + // + // Protected methods + // + + // dispatcher factory methods + + /** Creates a content dispatcher. */ + protected Dispatcher createContentDispatcher() { + return new FragmentContentDispatcher(); + } // createContentDispatcher():Dispatcher + + // scanning methods + + /** + * Scans an XML or text declaration. + *

+ *

+     * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
+     * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
+     * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
+     * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+     * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
+     *                 | ('"' ('yes' | 'no') '"'))
+     *
+     * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
+     * 
+ * + * @param scanningTextDecl True if a text declaration is to + * be scanned instead of an XML + * declaration. + */ + protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl) + throws IOException, XNIException { + + // scan decl + super.scanXMLDeclOrTextDecl(scanningTextDecl, fStrings); + fMarkupDepth--; + + // pseudo-attribute values + String version = fStrings[0]; + String encoding = fStrings[1]; + String standalone = fStrings[2]; + + // set standalone + fStandalone = standalone != null && standalone.equals("yes"); + fEntityManager.setStandalone(fStandalone); + + // set version on reader + fEntityScanner.setXMLVersion(version); + + // call handler + if (fDocumentHandler != null) { + if (scanningTextDecl) { + fDocumentHandler.textDecl(version, encoding, null); + } + else { + fDocumentHandler.xmlDecl(version, encoding, standalone, null); + } + } + + // set encoding on reader + if (encoding != null && !fEntityScanner.fCurrentEntity.isEncodingExternallySpecified()) { + fEntityScanner.setEncoding(encoding); + } + + } // scanXMLDeclOrTextDecl(boolean) + + /** + * Scans a processing data. This is needed to handle the situation + * where a document starts with a processing instruction whose + * target name starts with "xml". (e.g. xmlfoo) + * + * @param target The PI target + * @param data The string to fill in with the data + */ + protected void scanPIData(String target, XMLString data) + throws IOException, XNIException { + + super.scanPIData(target, data); + fMarkupDepth--; + + // call handler + if (fDocumentHandler != null) { + fDocumentHandler.processingInstruction(target, data, null); + } + + } // scanPIData(String) + + /** + * Scans a comment. + *

+ *

+     * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
+     * 
+ *

+ * Note: Called after scanning past '<!--' + */ + protected void scanComment() throws IOException, XNIException { + + scanComment(fStringBuffer); + fMarkupDepth--; + + // call handler + if (fDocumentHandler != null) { + fDocumentHandler.comment(fStringBuffer, null); + } + + } // scanComment() + + /** + * Scans a start element. This method will handle the binding of + * namespace information and notifying the handler of the start + * of the element. + *

+ *

+     * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
+     * [40] STag ::= '<' Name (S Attribute)* S? '>'
+     * 
+ *

+ * Note: This method assumes that the leading + * '<' character has been consumed. + *

+ * Note: This method uses the fElementQName and + * fAttributes variables. The contents of these variables will be + * destroyed. The caller should copy important information out of + * these variables before calling this method. + * + * @return True if element is empty. (i.e. It matches + * production [44]. + */ + protected boolean scanStartElement() + throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanStartElement()"); + + // name + if (fNamespaces) { + fEntityScanner.scanQName(fElementQName); + } + else { + String name = fEntityScanner.scanName(); + fElementQName.setValues(null, name, name, null); + } + String rawname = fElementQName.rawname; + + // push element stack + fCurrentElement = fElementStack.pushElement(fElementQName); + + // attributes + boolean empty = false; + fAttributes.removeAllAttributes(); + do { + // spaces + boolean sawSpace = fEntityScanner.skipSpaces(); + + // end tag? + int c = fEntityScanner.peekChar(); + if (c == '>') { + fEntityScanner.scanChar(); + break; + } + else if (c == '/') { + fEntityScanner.scanChar(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError("ElementUnterminated", + new Object[]{rawname}); + } + empty = true; + break; + } + else if (!isValidNameStartChar(c) || !sawSpace) { + // Second chance. Check if this character is a high + // surrogate of a valid name start character. + if (!isValidNameStartHighSurrogate(c) || !sawSpace) { + reportFatalError("ElementUnterminated", + new Object[] { rawname }); + } + } + + // attributes + scanAttribute(fAttributes); + + } while (true); + + // call handler + if (fDocumentHandler != null) { + if (empty) { + + //decrease the markup depth.. + fMarkupDepth--; + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError("ElementEntityMismatch", + new Object[]{fCurrentElement.rawname}); + } + + fDocumentHandler.emptyElement(fElementQName, fAttributes, null); + + //pop the element off the stack.. + fElementStack.popElement(fElementQName); + } + else { + fDocumentHandler.startElement(fElementQName, fAttributes, null); + } + } + + if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElement(): "+empty); + return empty; + + } // scanStartElement():boolean + + /** + * Scans the name of an element in a start or empty tag. + * + * @see #scanStartElement() + */ + protected void scanStartElementName () + throws IOException, XNIException { + // name + if (fNamespaces) { + fEntityScanner.scanQName(fElementQName); + } + else { + String name = fEntityScanner.scanName(); + fElementQName.setValues(null, name, name, null); + } + // Must skip spaces here because the DTD scanner + // would consume them at the end of the external subset. + fSawSpace = fEntityScanner.skipSpaces(); + } // scanStartElementName() + + /** + * Scans the remainder of a start or empty tag after the element name. + * + * @see #scanStartElement + * @return True if element is empty. + */ + protected boolean scanStartElementAfterName() + throws IOException, XNIException { + String rawname = fElementQName.rawname; + + // push element stack + fCurrentElement = fElementStack.pushElement(fElementQName); + + // attributes + boolean empty = false; + fAttributes.removeAllAttributes(); + do { + + // end tag? + int c = fEntityScanner.peekChar(); + if (c == '>') { + fEntityScanner.scanChar(); + break; + } + else if (c == '/') { + fEntityScanner.scanChar(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError("ElementUnterminated", + new Object[]{rawname}); + } + empty = true; + break; + } + else if (!isValidNameStartChar(c) || !fSawSpace) { + // Second chance. Check if this character is a high + // surrogate of a valid name start character. + if (!isValidNameStartHighSurrogate(c) || !fSawSpace) { + reportFatalError("ElementUnterminated", + new Object[] { rawname }); + } + } + + // attributes + scanAttribute(fAttributes); + + // spaces + fSawSpace = fEntityScanner.skipSpaces(); + + } while (true); + + // call handler + if (fDocumentHandler != null) { + if (empty) { + + //decrease the markup depth.. + fMarkupDepth--; + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError("ElementEntityMismatch", + new Object[]{fCurrentElement.rawname}); + } + + fDocumentHandler.emptyElement(fElementQName, fAttributes, null); + + //pop the element off the stack.. + fElementStack.popElement(fElementQName); + } + else { + fDocumentHandler.startElement(fElementQName, fAttributes, null); + } + } + + if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElementAfterName(): "+empty); + return empty; + } // scanStartElementAfterName() + + /** + * Scans an attribute. + *

+ *

+     * [41] Attribute ::= Name Eq AttValue
+     * 
+ *

+ * Note: This method assumes that the next + * character on the stream is the first character of the attribute + * name. + *

+ * Note: This method uses the fAttributeQName and + * fQName variables. The contents of these variables will be + * destroyed. + * + * @param attributes The attributes list for the scanned attribute. + */ + protected void scanAttribute(XMLAttributes attributes) + throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanAttribute()"); + + // name + if (fNamespaces) { + fEntityScanner.scanQName(fAttributeQName); + } + else { + String name = fEntityScanner.scanName(); + fAttributeQName.setValues(null, name, name, null); + } + + // equals + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('=')) { + reportFatalError("EqRequiredInAttribute", + new Object[]{fCurrentElement.rawname,fAttributeQName.rawname}); + } + fEntityScanner.skipSpaces(); + + // content + int oldLen = attributes.getLength(); + int attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null); + + // WFC: Unique Att Spec + if (oldLen == attributes.getLength()) { + reportFatalError("AttributeNotUnique", + new Object[]{fCurrentElement.rawname, + fAttributeQName.rawname}); + } + + // Scan attribute value and return true if the un-normalized and normalized value are the same + boolean isSameNormalizedAttr = scanAttributeValue(fTempString, fTempString2, + fAttributeQName.rawname, fIsEntityDeclaredVC, fCurrentElement.rawname); + + attributes.setValue(attrIndex, fTempString.toString()); + // If the non-normalized and normalized value are the same, avoid creating a new string. + if (!isSameNormalizedAttr) { + attributes.setNonNormalizedValue(attrIndex, fTempString2.toString()); + } + attributes.setSpecified(attrIndex, true); + + if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanAttribute()"); + } // scanAttribute(XMLAttributes) + + /** + * Scans element content. + * + * @return Returns the next character on the stream. + */ + protected int scanContent() throws IOException, XNIException { + + XMLString content = fTempString; + int c = fEntityScanner.scanContent(content); + if (c == '\r') { + // happens when there is the character reference + fEntityScanner.scanChar(); + fStringBuffer.clear(); + fStringBuffer.append(fTempString); + fStringBuffer.append((char)c); + content = fStringBuffer; + c = -1; + } + if (fDocumentHandler != null && content.length > 0) { + fDocumentHandler.characters(content, null); + } + + if (c == ']' && fTempString.length == 0) { + fStringBuffer.clear(); + fStringBuffer.append((char)fEntityScanner.scanChar()); + // remember where we are in case we get an endEntity before we + // could flush the buffer out - this happens when we're parsing an + // entity which ends with a ] + fInScanContent = true; + // + // We work on a single character basis to handle cases such as: + // ']]]>' which we might otherwise miss. + // + if (fEntityScanner.skipChar(']')) { + fStringBuffer.append(']'); + while (fEntityScanner.skipChar(']')) { + fStringBuffer.append(']'); + } + if (fEntityScanner.skipChar('>')) { + reportFatalError("CDEndInContent", null); + } + } + if (fDocumentHandler != null && fStringBuffer.length != 0) { + fDocumentHandler.characters(fStringBuffer, null); + } + fInScanContent = false; + c = -1; + } + return c; + + } // scanContent():int + + + /** + * Scans a CDATA section. + *

+ * Note: This method uses the fTempString and + * fStringBuffer variables. + * + * @param complete True if the CDATA section is to be scanned + * completely. + * + * @return True if CDATA is completely scanned. + */ + protected boolean scanCDATASection(boolean complete) + throws IOException, XNIException { + + // call handler + if (fDocumentHandler != null) { + fDocumentHandler.startCDATA(null); + } + + while (true) { + fStringBuffer.clear(); + if (!fEntityScanner.scanData("]]", fStringBuffer)) { + if (fDocumentHandler != null && fStringBuffer.length > 0) { + fDocumentHandler.characters(fStringBuffer, null); + } + int brackets = 0; + while (fEntityScanner.skipChar(']')) { + brackets++; + } + if (fDocumentHandler != null && brackets > 0) { + fStringBuffer.clear(); + if (brackets > XMLEntityManager.DEFAULT_BUFFER_SIZE) { + // Handle large sequences of ']' + int chunks = brackets / XMLEntityManager.DEFAULT_BUFFER_SIZE; + int remainder = brackets % XMLEntityManager.DEFAULT_BUFFER_SIZE; + for (int i = 0; i < XMLEntityManager.DEFAULT_BUFFER_SIZE; i++) { + fStringBuffer.append(']'); + } + for (int i = 0; i < chunks; i++) { + fDocumentHandler.characters(fStringBuffer, null); + } + if (remainder != 0) { + fStringBuffer.length = remainder; + fDocumentHandler.characters(fStringBuffer, null); + } + } + else { + for (int i = 0; i < brackets; i++) { + fStringBuffer.append(']'); + } + fDocumentHandler.characters(fStringBuffer, null); + } + } + if (fEntityScanner.skipChar('>')) { + break; + } + if (fDocumentHandler != null) { + fStringBuffer.clear(); + fStringBuffer.append("]]"); + fDocumentHandler.characters(fStringBuffer, null); + } + } + else { + if (fDocumentHandler != null) { + fDocumentHandler.characters(fStringBuffer, null); + } + int c = fEntityScanner.peekChar(); + if (c != -1 && isInvalidLiteral(c)) { + if (XMLChar.isHighSurrogate(c)) { + fStringBuffer.clear(); + scanSurrogates(fStringBuffer); + if (fDocumentHandler != null) { + fDocumentHandler.characters(fStringBuffer, null); + } + } + else { + reportFatalError("InvalidCharInCDSect", + new Object[]{Integer.toString(c,16)}); + fEntityScanner.scanChar(); + } + } + } + } + fMarkupDepth--; + + // call handler + if (fDocumentHandler != null) { + fDocumentHandler.endCDATA(null); + } + + return true; + + } // scanCDATASection(boolean):boolean + + /** + * Scans an end element. + *

+ *

+     * [42] ETag ::= '</' Name S? '>'
+     * 
+ *

+ * Note: This method uses the fElementQName variable. + * The contents of this variable will be destroyed. The caller should + * copy the needed information out of this variable before calling + * this method. + * + * @return The element depth. + */ + protected int scanEndElement() throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanEndElement()"); + + fElementStack.popElement(fElementQName) ; + + // Take advantage of the fact that next string _should_ be "fElementQName.rawName", + //In scanners most of the time is consumed on checks done for XML characters, we can + // optimize on it and avoid the checks done for endElement, + //we will also avoid symbol table lookup - neeraj.bajaj@sun.com + + // this should work both for namespace processing true or false... + + //REVISIT: if the string is not the same as expected.. we need to do better error handling.. + //We can skip this for now... In any case if the string doesn't match -- document is not well formed. + if (!fEntityScanner.skipString(fElementQName.rawname)) { + reportFatalError("ETagRequired", new Object[]{fElementQName.rawname}); + } + + // end + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError("ETagUnterminated", + new Object[]{fElementQName.rawname}); + } + fMarkupDepth--; + + //we have increased the depth for two markup "<" characters + fMarkupDepth--; + + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError("ElementEntityMismatch", + new Object[]{fCurrentElement.rawname}); + } + + // call handler + if (fDocumentHandler != null ) { + fDocumentHandler.endElement(fElementQName, null); + } + + return fMarkupDepth; + + } // scanEndElement():int + + /** + * Scans a character reference. + *

+ *

+     * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
+     * 
+ */ + protected void scanCharReference() + throws IOException, XNIException { + + fStringBuffer2.clear(); + int ch = scanCharReferenceValue(fStringBuffer2, null); + fMarkupDepth--; + if (ch != -1) { + // call handler + if (fDocumentHandler != null) { + if (fNotifyCharRefs) { + fDocumentHandler.startGeneralEntity(fCharRefLiteral, null, null, null); + } + Augmentations augs = null; + if (fValidation && ch <= 0x20) { + if (fTempAugmentations != null) { + fTempAugmentations.removeAllItems(); + } + else { + fTempAugmentations = new AugmentationsImpl(); + } + augs = fTempAugmentations; + augs.putItem(Constants.CHAR_REF_PROBABLE_WS, Boolean.TRUE); + } + fDocumentHandler.characters(fStringBuffer2, augs); + if (fNotifyCharRefs) { + fDocumentHandler.endGeneralEntity(fCharRefLiteral, null); + } + } + } + + } // scanCharReference() + + /** + * Scans an entity reference. + * + * @throws IOException Thrown if i/o error occurs. + * @throws XNIException Thrown if handler throws exception upon + * notification. + */ + protected void scanEntityReference() throws IOException, XNIException { + + // name + String name = fEntityScanner.scanName(); + if (name == null) { + reportFatalError("NameRequiredInReference", null); + return; + } + + // end + if (!fEntityScanner.skipChar(';')) { + reportFatalError("SemicolonRequiredInReference", new Object []{name}); + } + fMarkupDepth--; + + // handle built-in entities + if (name == fAmpSymbol) { + handleCharacter('&', fAmpSymbol); + } + else if (name == fLtSymbol) { + handleCharacter('<', fLtSymbol); + } + else if (name == fGtSymbol) { + handleCharacter('>', fGtSymbol); + } + else if (name == fQuotSymbol) { + handleCharacter('"', fQuotSymbol); + } + else if (name == fAposSymbol) { + handleCharacter('\'', fAposSymbol); + } + // start general entity + else if (fEntityManager.isUnparsedEntity(name)) { + reportFatalError("ReferenceToUnparsedEntity", new Object[]{name}); + } + else { + if (!fEntityManager.isDeclaredEntity(name)) { + if (fIsEntityDeclaredVC) { + if (fValidation) + fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared", + new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); + } + else { + reportFatalError("EntityNotDeclared", new Object[]{name}); + } + } + fEntityManager.startEntity(name, false); + } + + } // scanEntityReference() + + // utility methods + + /** + * Calls document handler with a single character resulting from + * built-in entity resolution. + * + * @param c + * @param entity built-in name + */ + private void handleCharacter(char c, String entity) throws XNIException { + if (fDocumentHandler != null) { + if (fNotifyBuiltInRefs) { + fDocumentHandler.startGeneralEntity(entity, null, null, null); + } + + fSingleChar[0] = c; + fTempString.setValues(fSingleChar, 0, 1); + fDocumentHandler.characters(fTempString, null); + + if (fNotifyBuiltInRefs) { + fDocumentHandler.endGeneralEntity(entity, null); + } + } + } // handleCharacter(char) + + /** + * Handles the end element. This method will make sure that + * the end element name matches the current element and notify + * the handler about the end of the element and the end of any + * relevent prefix mappings. + *

+ * Note: This method uses the fQName variable. + * The contents of this variable will be destroyed. + * + * @param element The element. + * + * @return The element depth. + * + * @throws XNIException Thrown if the handler throws a SAX exception + * upon notification. + * + */ + // REVISIT: need to remove this method. It's not called anymore, because + // the handling is done when the end tag is scanned. - SG + protected int handleEndElement(QName element, boolean isEmpty) + throws XNIException { + + fMarkupDepth--; + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError("ElementEntityMismatch", + new Object[]{fCurrentElement.rawname}); + } + // make sure the elements match + QName startElement = fQName; + fElementStack.popElement(startElement); + if (element.rawname != startElement.rawname) { + reportFatalError("ETagRequired", + new Object[]{startElement.rawname}); + } + + // bind namespaces + if (fNamespaces) { + element.uri = startElement.uri; + } + + // call handler + if (fDocumentHandler != null && !isEmpty) { + fDocumentHandler.endElement(element, null); + } + + return fMarkupDepth; + + } // callEndElement(QName,boolean):int + + // helper methods + + /** + * Sets the scanner state. + * + * @param state The new scanner state. + */ + protected final void setScannerState(int state) { + + fScannerState = state; + if (DEBUG_SCANNER_STATE) { + System.out.print("### setScannerState: "); + System.out.print(getScannerStateName(state)); + System.out.println(); + } + + } // setScannerState(int) + + /** + * Sets the dispatcher. + * + * @param dispatcher The new dispatcher. + */ + protected final void setDispatcher(Dispatcher dispatcher) { + fDispatcher = dispatcher; + if (DEBUG_DISPATCHER) { + System.out.print("%%% setDispatcher: "); + System.out.print(getDispatcherName(dispatcher)); + System.out.println(); + } + } + + // + // Private methods + // + + /** Returns the scanner state name. */ + protected String getScannerStateName(int state) { + + switch (state) { + case SCANNER_STATE_DOCTYPE: return "SCANNER_STATE_DOCTYPE"; + case SCANNER_STATE_ROOT_ELEMENT: return "SCANNER_STATE_ROOT_ELEMENT"; + case SCANNER_STATE_START_OF_MARKUP: return "SCANNER_STATE_START_OF_MARKUP"; + case SCANNER_STATE_COMMENT: return "SCANNER_STATE_COMMENT"; + case SCANNER_STATE_PI: return "SCANNER_STATE_PI"; + case SCANNER_STATE_CONTENT: return "SCANNER_STATE_CONTENT"; + case SCANNER_STATE_REFERENCE: return "SCANNER_STATE_REFERENCE"; + case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT"; + case SCANNER_STATE_TERMINATED: return "SCANNER_STATE_TERMINATED"; + case SCANNER_STATE_CDATA: return "SCANNER_STATE_CDATA"; + case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL"; + } + + return "??? ("+state+')'; + + } // getScannerStateName(int):String + + /** Returns the dispatcher name. */ + public String getDispatcherName(Dispatcher dispatcher) { + + if (DEBUG_DISPATCHER) { + if (dispatcher != null) { + String name = dispatcher.getClass().getName(); + int index = name.lastIndexOf('.'); + if (index != -1) { + name = name.substring(index + 1); + index = name.lastIndexOf('$'); + if (index != -1) { + name = name.substring(index + 1); + } + } + return name; + } + } + return "null"; + + } // getDispatcherName():String + + // + // Classes + // + + /** + * Element stack. This stack operates without synchronization, error + * checking, and it re-uses objects instead of throwing popped items + * away. + * + * @author Andy Clark, IBM + */ + protected static class ElementStack { + + // + // Data + // + + /** The stack data. */ + protected QName[] fElements; + + /** The size of the stack. */ + protected int fSize; + + // + // Constructors + // + + /** Default constructor. */ + public ElementStack() { + fElements = new QName[10]; + for (int i = 0; i < fElements.length; i++) { + fElements[i] = new QName(); + } + } // () + + // + // Public methods + // + + /** + * Pushes an element on the stack. + *

+ * Note: The QName values are copied into the + * stack. In other words, the caller does not orphan + * the element to the stack. Also, the QName object returned + * is not orphaned to the caller. It should be + * considered read-only. + * + * @param element The element to push onto the stack. + * + * @return Returns the actual QName object that stores the + */ + public QName pushElement(QName element) { + if (fSize == fElements.length) { + QName[] array = new QName[fElements.length * 2]; + System.arraycopy(fElements, 0, array, 0, fSize); + fElements = array; + for (int i = fSize; i < fElements.length; i++) { + fElements[i] = new QName(); + } + } + fElements[fSize].setValues(element); + return fElements[fSize++]; + } // pushElement(QName):QName + + /** + * Pops an element off of the stack by setting the values of + * the specified QName. + *

+ * Note: The object returned is not + * orphaned to the caller. Therefore, the caller should consider + * the object to be read-only. + */ + public void popElement(QName element) { + element.setValues(fElements[--fSize]); + } // popElement(QName) + + /** Clears the stack without throwing away existing QName objects. */ + public void clear() { + fSize = 0; + } // clear() + + } // class ElementStack + + /** + * This interface defines an XML "event" dispatching model. Classes + * that implement this interface are responsible for scanning parts + * of the XML document and dispatching callbacks. + * + * @xerces.internal + * + * @author Glenn Marcy, IBM + */ + protected interface Dispatcher { + + // + // Dispatcher methods + // + + /** + * Dispatch an XML "event". + * + * @param complete True if this dispatcher is intended to scan + * and dispatch as much as possible. + * + * @return True if there is more to dispatch either from this + * or a another dispatcher. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown on parse error. + */ + public boolean dispatch(boolean complete) + throws IOException, XNIException; + + } // interface Dispatcher + + /** + * Dispatcher to handle content scanning. + * + * @author Andy Clark, IBM + * @author Eric Ye, IBM + */ + protected class FragmentContentDispatcher + implements Dispatcher { + + // + // Dispatcher methods + // + + /** + * Dispatch an XML "event". + * + * @param complete True if this dispatcher is intended to scan + * and dispatch as much as possible. + * + * @return True if there is more to dispatch either from this + * or a another dispatcher. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown on parse error. + */ + public boolean dispatch(boolean complete) + throws IOException, XNIException { + try { + boolean again; + do { + again = false; + switch (fScannerState) { + case SCANNER_STATE_CONTENT: { + if (fEntityScanner.skipChar('<')) { + setScannerState(SCANNER_STATE_START_OF_MARKUP); + again = true; + } + else if (fEntityScanner.skipChar('&')) { + setScannerState(SCANNER_STATE_REFERENCE); + again = true; + } + else { + do { + int c = scanContent(); + if (c == '<') { + fEntityScanner.scanChar(); + setScannerState(SCANNER_STATE_START_OF_MARKUP); + break; + } + else if (c == '&') { + fEntityScanner.scanChar(); + setScannerState(SCANNER_STATE_REFERENCE); + break; + } + else if (c != -1 && isInvalidLiteral(c)) { + if (XMLChar.isHighSurrogate(c)) { + // special case: surrogates + fStringBuffer.clear(); + if (scanSurrogates(fStringBuffer)) { + // call handler + if (fDocumentHandler != null) { + fDocumentHandler.characters(fStringBuffer, null); + } + } + } + else { + reportFatalError("InvalidCharInContent", + new Object[] { + Integer.toString(c, 16)}); + fEntityScanner.scanChar(); + } + } + } while (complete); + } + break; + } + case SCANNER_STATE_START_OF_MARKUP: { + fMarkupDepth++; + if (fEntityScanner.skipChar('/')) { + if (scanEndElement() == 0) { + if (elementDepthIsZeroHook()) { + return true; + } + } + setScannerState(SCANNER_STATE_CONTENT); + } + else if (isValidNameStartChar(fEntityScanner.peekChar())) { + scanStartElement(); + setScannerState(SCANNER_STATE_CONTENT); + } + else if (fEntityScanner.skipChar('!')) { + if (fEntityScanner.skipChar('-')) { + if (!fEntityScanner.skipChar('-')) { + reportFatalError("InvalidCommentStart", + null); + } + setScannerState(SCANNER_STATE_COMMENT); + again = true; + } + else if (fEntityScanner.skipString("[CDATA[")) { + setScannerState(SCANNER_STATE_CDATA); + again = true; + } + else if (!scanForDoctypeHook()) { + reportFatalError("MarkupNotRecognizedInContent", + null); + } + } + else if (fEntityScanner.skipChar('?')) { + setScannerState(SCANNER_STATE_PI); + again = true; + } + else if (isValidNameStartHighSurrogate(fEntityScanner.peekChar())) { + scanStartElement(); + setScannerState(SCANNER_STATE_CONTENT); + } + else { + reportFatalError("MarkupNotRecognizedInContent", + null); + setScannerState(SCANNER_STATE_CONTENT); + } + break; + } + case SCANNER_STATE_COMMENT: { + scanComment(); + setScannerState(SCANNER_STATE_CONTENT); + break; + } + case SCANNER_STATE_PI: { + scanPI(); + setScannerState(SCANNER_STATE_CONTENT); + break; + } + case SCANNER_STATE_CDATA: { + scanCDATASection(complete); + setScannerState(SCANNER_STATE_CONTENT); + break; + } + case SCANNER_STATE_REFERENCE: { + fMarkupDepth++; + // NOTE: We need to set the state beforehand + // because the XMLEntityHandler#startEntity + // callback could set the state to + // SCANNER_STATE_TEXT_DECL and we don't want + // to override that scanner state. + setScannerState(SCANNER_STATE_CONTENT); + if (fEntityScanner.skipChar('#')) { + scanCharReference(); + } + else { + scanEntityReference(); + } + break; + } + case SCANNER_STATE_TEXT_DECL: { + // scan text decl + if (fEntityScanner.skipString(" + * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/nonvalidating/load-external-dtd
  • + *
  • http://apache.org/xml/features/scanner/notify-char-refs
  • + *
  • http://apache.org/xml/features/scanner/notify-builtin-refs
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-manager
  • + *
  • http://apache.org/xml/properties/internal/dtd-scanner
  • + *
+ * + * @xerces.internal + * + * @author Glenn Marcy, IBM + * @author Andy Clark, IBM + * @author Arnaud Le Hors, IBM + * @author Eric Ye, IBM + * + * @version $Id$ + */ +public class XMLDocumentScannerImpl + extends XMLDocumentFragmentScannerImpl { + + // + // Constants + // + + // scanner states + + /** Scanner state: XML declaration. */ + protected static final int SCANNER_STATE_XML_DECL = 0; + + /** Scanner state: prolog. */ + protected static final int SCANNER_STATE_PROLOG = 5; + + /** Scanner state: trailing misc. */ + protected static final int SCANNER_STATE_TRAILING_MISC = 12; + + /** Scanner state: DTD internal declarations. */ + protected static final int SCANNER_STATE_DTD_INTERNAL_DECLS = 17; + + /** Scanner state: open DTD external subset. */ + protected static final int SCANNER_STATE_DTD_EXTERNAL = 18; + + /** Scanner state: DTD external declarations. */ + protected static final int SCANNER_STATE_DTD_EXTERNAL_DECLS = 19; + + // feature identifiers + + /** Feature identifier: load external DTD. */ + protected static final String LOAD_EXTERNAL_DTD = + Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE; + + /** Feature identifier: load external DTD. */ + protected static final String DISALLOW_DOCTYPE_DECL_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE; + + // property identifiers + + /** Property identifier: DTD scanner. */ + protected static final String DTD_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY; + + /** property identifier: ValidationManager */ + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** property identifier: NamespaceContext */ + protected static final String NAMESPACE_CONTEXT = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY; + + + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + LOAD_EXTERNAL_DTD, + DISALLOW_DOCTYPE_DECL_FEATURE, + }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { + Boolean.TRUE, + Boolean.FALSE, + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + DTD_SCANNER, + VALIDATION_MANAGER, + NAMESPACE_CONTEXT, + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { + null, + null, + null, + }; + + // + // Data + // + + // properties + + /** DTD scanner. */ + protected XMLDTDScanner fDTDScanner; + /** Validation manager . */ + protected ValidationManager fValidationManager; + + // protected data + + /** Scanning DTD. */ + protected boolean fScanningDTD; + + // other info + + /** Doctype name. */ + protected String fDoctypeName; + + /** Doctype declaration public identifier. */ + protected String fDoctypePublicId; + + /** Doctype declaration system identifier. */ + protected String fDoctypeSystemId; + + /** Namespace support. */ + protected NamespaceContext fNamespaceContext = new NamespaceSupport(); + + // features + + /** Load external DTD. */ + protected boolean fLoadExternalDTD = true; + + /** Disallow doctype declaration. */ + protected boolean fDisallowDoctype = false; + + // state + + /** Seen doctype declaration. */ + protected boolean fSeenDoctypeDecl; + + // dispatchers + + /** XML declaration dispatcher. */ + protected final Dispatcher fXMLDeclDispatcher = new XMLDeclDispatcher(); + + /** Prolog dispatcher. */ + protected final Dispatcher fPrologDispatcher = new PrologDispatcher(); + + /** DTD dispatcher. */ + protected final Dispatcher fDTDDispatcher = new DTDDispatcher(); + + /** Trailing miscellaneous section dispatcher. */ + protected final Dispatcher fTrailingMiscDispatcher = new TrailingMiscDispatcher(); + + // temporary variables + + /** Array of 3 strings. */ + private final String[] fStrings = new String[3]; + + /** String. */ + private final XMLString fString = new XMLString(); + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + + /** External subset source. */ + private XMLInputSource fExternalSubsetSource = null; + + /** A DTD Description. */ + private final XMLDTDDescription fDTDDescription = new XMLDTDDescription(null, null, null, null, null); + + // + // Constructors + // + + /** Default constructor. */ + public XMLDocumentScannerImpl() {} // () + + // + // XMLDocumentScanner methods + // + + /** + * Sets the input source. + * + * @param inputSource The input source. + * + * @throws IOException Thrown on i/o error. + */ + public void setInputSource(XMLInputSource inputSource) throws IOException { + fEntityManager.setEntityHandler(this); + fEntityManager.startDocumentEntity(inputSource); + //fDocumentSystemId = fEntityManager.expandSystemId(inputSource.getSystemId()); + } // setInputSource(XMLInputSource) + + // + // XMLComponent methods + // + + /** + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws SAXException Thrown by component on initialization error. + * For example, if a feature or property is + * required for the operation of the component, the + * component manager may throw a + * SAXNotRecognizedException or a + * SAXNotSupportedException. + */ + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + super.reset(componentManager); + + // other settings + fDoctypeName = null; + fDoctypePublicId = null; + fDoctypeSystemId = null; + fSeenDoctypeDecl = false; + fScanningDTD = false; + fExternalSubsetSource = null; + + if (!fParserSettings) { + // parser settings have not been changed + fNamespaceContext.reset(); + // setup dispatcher + setScannerState(SCANNER_STATE_XML_DECL); + setDispatcher(fXMLDeclDispatcher); + return; + } + + // xerces features + try { + fLoadExternalDTD = componentManager.getFeature(LOAD_EXTERNAL_DTD); + } + catch (XMLConfigurationException e) { + fLoadExternalDTD = true; + } + try { + fDisallowDoctype = componentManager.getFeature(DISALLOW_DOCTYPE_DECL_FEATURE); + } + catch (XMLConfigurationException e) { + fDisallowDoctype = false; + } + + // xerces properties + fDTDScanner = (XMLDTDScanner)componentManager.getProperty(DTD_SCANNER); + try { + fValidationManager = (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER); + } + catch (XMLConfigurationException e) { + fValidationManager = null; + } + + try { + fNamespaceContext = (NamespaceContext)componentManager.getProperty(NAMESPACE_CONTEXT); + } + catch (XMLConfigurationException e) { } + if (fNamespaceContext == null) { + fNamespaceContext = new NamespaceSupport(); + } + fNamespaceContext.reset(); + + // setup dispatcher + setScannerState(SCANNER_STATE_XML_DECL); + setDispatcher(fXMLDeclDispatcher); + + } // reset(XMLComponentManager) + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + String[] featureIds = super.getRecognizedFeatures(); + int length = featureIds != null ? featureIds.length : 0; + String[] combinedFeatureIds = new String[length + RECOGNIZED_FEATURES.length]; + if (featureIds != null) { + System.arraycopy(featureIds, 0, combinedFeatureIds, 0, featureIds.length); + } + System.arraycopy(RECOGNIZED_FEATURES, 0, combinedFeatureIds, length, RECOGNIZED_FEATURES.length); + return combinedFeatureIds; + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + + super.setFeature(featureId, state); + + // Xerces properties + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() && + featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) { + fLoadExternalDTD = state; + return; + } + else if (suffixLength == Constants.DISALLOW_DOCTYPE_DECL_FEATURE.length() && + featureId.endsWith(Constants.DISALLOW_DOCTYPE_DECL_FEATURE)) { + fDisallowDoctype = state; + return; + } + } + + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + String[] propertyIds = super.getRecognizedProperties(); + int length = propertyIds != null ? propertyIds.length : 0; + String[] combinedPropertyIds = new String[length + RECOGNIZED_PROPERTIES.length]; + if (propertyIds != null) { + System.arraycopy(propertyIds, 0, combinedPropertyIds, 0, propertyIds.length); + } + System.arraycopy(RECOGNIZED_PROPERTIES, 0, combinedPropertyIds, length, RECOGNIZED_PROPERTIES.length); + return combinedPropertyIds; + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + super.setProperty(propertyId, value); + + // Xerces properties + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() && + propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) { + fDTDScanner = (XMLDTDScanner)value; + } + if (suffixLength == Constants.NAMESPACE_CONTEXT_PROPERTY.length() && + propertyId.endsWith(Constants.NAMESPACE_CONTEXT_PROPERTY)) { + if (value != null) { + fNamespaceContext = (NamespaceContext)value; + } + } + + return; + } + + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return super.getFeatureDefault(featureId); + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return super.getPropertyDefault(propertyId); + } // getPropertyDefault(String):Object + + // + // XMLEntityHandler methods + // + + /** + * This method notifies of the start of an entity. The DTD has the + * pseudo-name of "[dtd]" parameter entity names start with '%'; and + * general entities are just specified by their name. + * + * @param name The name of the entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startEntity(String name, + XMLResourceIdentifier identifier, + String encoding, Augmentations augs) throws XNIException { + + super.startEntity(name, identifier, encoding, augs); + + // prepare to look for a TextDecl if external general entity + if (!name.equals("[xml]") && fEntityScanner.isExternal()) { + setScannerState(SCANNER_STATE_TEXT_DECL); + } + + // call handler + if (fDocumentHandler != null && name.equals("[xml]")) { + fDocumentHandler.startDocument(fEntityScanner, encoding, fNamespaceContext, null); + } + + } // startEntity(String,identifier,String) + + /** + * This method notifies the end of an entity. The DTD has the pseudo-name + * of "[dtd]" parameter entity names start with '%'; and general entities + * are just specified by their name. + * + * @param name The name of the entity. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endEntity(String name, Augmentations augs) throws XNIException { + + super.endEntity(name, augs); + + // call handler + if (fDocumentHandler != null && name.equals("[xml]")) { + fDocumentHandler.endDocument(null); + } + + } // endEntity(String) + + // + // Protected methods + // + + // dispatcher factory methods + + /** Creates a content dispatcher. */ + protected Dispatcher createContentDispatcher() { + return new ContentDispatcher(); + } // createContentDispatcher():Dispatcher + + // scanning methods + + /** Scans a doctype declaration. */ + protected boolean scanDoctypeDecl() throws IOException, XNIException { + + // spaces + if (!fEntityScanner.skipSpaces()) { + reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL", + null); + } + + // root element name + fDoctypeName = fEntityScanner.scanName(); + if (fDoctypeName == null) { + reportFatalError("MSG_ROOT_ELEMENT_TYPE_REQUIRED", null); + } + + // external id + if (fEntityScanner.skipSpaces()) { + scanExternalID(fStrings, false); + fDoctypeSystemId = fStrings[0]; + fDoctypePublicId = fStrings[1]; + fEntityScanner.skipSpaces(); + } + + fHasExternalDTD = fDoctypeSystemId != null; + + // Attempt to locate an external subset with an external subset resolver. + if (!fHasExternalDTD && fExternalSubsetResolver != null) { + fDTDDescription.setValues(null, null, fEntityManager.getCurrentResourceIdentifier().getExpandedSystemId(), null); + fDTDDescription.setRootName(fDoctypeName); + fExternalSubsetSource = fExternalSubsetResolver.getExternalSubset(fDTDDescription); + fHasExternalDTD = fExternalSubsetSource != null; + } + + // call handler + if (fDocumentHandler != null) { + // NOTE: I don't like calling the doctypeDecl callback until + // end of the *full* doctype line (including internal + // subset) is parsed correctly but SAX2 requires that + // it knows the root element name and public and system + // identifier for the startDTD call. -Ac + if (fExternalSubsetSource == null) { + fDocumentHandler.doctypeDecl(fDoctypeName, fDoctypePublicId, fDoctypeSystemId, null); + } + else { + fDocumentHandler.doctypeDecl(fDoctypeName, fExternalSubsetSource.getPublicId(), fExternalSubsetSource.getSystemId(), null); + } + } + + // is there an internal subset? + boolean internalSubset = true; + if (!fEntityScanner.skipChar('[')) { + internalSubset = false; + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError("DoctypedeclUnterminated", new Object[]{fDoctypeName}); + } + fMarkupDepth--; + } + + return internalSubset; + + } // scanDoctypeDecl():boolean + + // + // Private methods + // + + /** Returns the scanner state name. */ + protected String getScannerStateName(int state) { + + switch (state) { + case SCANNER_STATE_XML_DECL: return "SCANNER_STATE_XML_DECL"; + case SCANNER_STATE_PROLOG: return "SCANNER_STATE_PROLOG"; + case SCANNER_STATE_TRAILING_MISC: return "SCANNER_STATE_TRAILING_MISC"; + case SCANNER_STATE_DTD_INTERNAL_DECLS: return "SCANNER_STATE_DTD_INTERNAL_DECLS"; + case SCANNER_STATE_DTD_EXTERNAL: return "SCANNER_STATE_DTD_EXTERNAL"; + case SCANNER_STATE_DTD_EXTERNAL_DECLS: return "SCANNER_STATE_DTD_EXTERNAL_DECLS"; + } + return super.getScannerStateName(state); + + } // getScannerStateName(int):String + + // + // Classes + // + + /** + * Dispatcher to handle XMLDecl scanning. + * + * @author Andy Clark, IBM + */ + protected final class XMLDeclDispatcher + implements Dispatcher { + + // + // Dispatcher methods + // + + /** + * Dispatch an XML "event". + * + * @param complete True if this dispatcher is intended to scan + * and dispatch as much as possible. + * + * @return True if there is more to dispatch either from this + * or a another dispatcher. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown on parse error. + */ + public boolean dispatch(boolean complete) + throws IOException, XNIException { + + // next dispatcher is prolog regardless of whether there + // is an XMLDecl in this document + setScannerState(SCANNER_STATE_PROLOG); + setDispatcher(fPrologDispatcher); + + // scan XMLDecl + try { + if (fEntityScanner.skipString("')) { + reportFatalError("DoctypedeclUnterminated", new Object[]{fDoctypeName}); + } + fMarkupDepth--; + + // scan external subset next + if (fDoctypeSystemId != null) { + fIsEntityDeclaredVC = !fStandalone; + if (readExternalSubset) { + setScannerState(SCANNER_STATE_DTD_EXTERNAL); + break; + } + } + else if (fExternalSubsetSource != null) { + fIsEntityDeclaredVC = !fStandalone; + if (readExternalSubset) { + // This handles the case of a DOCTYPE that only had an internal subset. + fDTDScanner.setInputSource(fExternalSubsetSource); + fExternalSubsetSource = null; + setScannerState(SCANNER_STATE_DTD_EXTERNAL_DECLS); + break; + } + } + // This document only has an internal subset. If it contains parameter entity + // references and standalone="no" then [Entity Declared] is a validity constraint. + else { + fIsEntityDeclaredVC = fEntityManager.hasPEReferences() && !fStandalone; + } + + // break out of this dispatcher. + setScannerState(SCANNER_STATE_PROLOG); + setDispatcher(fPrologDispatcher); + fEntityManager.setEntityHandler(XMLDocumentScannerImpl.this); + return true; + } + break; + } + case SCANNER_STATE_DTD_EXTERNAL: { + fDTDDescription.setValues(fDoctypePublicId, fDoctypeSystemId, null, null); + fDTDDescription.setRootName(fDoctypeName); + XMLInputSource xmlInputSource = + fEntityManager.resolveEntity(fDTDDescription); + fDTDScanner.setInputSource(xmlInputSource); + setScannerState(SCANNER_STATE_DTD_EXTERNAL_DECLS); + again = true; + break; + } + case SCANNER_STATE_DTD_EXTERNAL_DECLS: { + // REVISIT: Should there be a feature for + // the "complete" parameter? + boolean completeDTD = true; + boolean moreToScan = fDTDScanner.scanDTDExternalSubset(completeDTD); + if (!moreToScan) { + setScannerState(SCANNER_STATE_PROLOG); + setDispatcher(fPrologDispatcher); + fEntityManager.setEntityHandler(XMLDocumentScannerImpl.this); + return true; + } + break; + } + default: { + throw new XNIException("DTDDispatcher#dispatch: scanner state="+fScannerState+" ("+getScannerStateName(fScannerState)+')'); + } + } + } while (complete || again); + } + // encoding errors + catch (MalformedByteSequenceException e) { + fErrorReporter.reportError(e.getDomain(), e.getKey(), + e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e); + return false; + } + catch (CharConversionException e) { + fErrorReporter.reportError( + XMLMessageFormatter.XML_DOMAIN, + "CharConversionFailure", + null, + XMLErrorReporter.SEVERITY_FATAL_ERROR, e); + return false; + } + // premature end of file + catch (EOFException e) { + reportFatalError("PrematureEOF", null); + return false; + //throw e; + } + + // cleanup + finally { + fEntityManager.setEntityHandler(XMLDocumentScannerImpl.this); + } + + return true; + + } // dispatch(boolean):boolean + + } // class DTDDispatcher + + /** + * Dispatcher to handle content scanning. + * + * @author Andy Clark, IBM + * @author Eric Ye, IBM + */ + protected class ContentDispatcher + extends FragmentContentDispatcher { + + // + // Protected methods + // + + // hooks + + // NOTE: These hook methods are added so that the full document + // scanner can share the majority of code with this class. + + /** + * Scan for DOCTYPE hook. This method is a hook for subclasses + * to add code to handle scanning for a the "DOCTYPE" string + * after the string "Attempt to locate an external subset for a document that does not otherwise + * have one. If an external subset is located, then it is scanned.

+ */ + protected void resolveExternalSubsetAndRead() + throws IOException, XNIException { + + fDTDDescription.setValues(null, null, fEntityManager.getCurrentResourceIdentifier().getExpandedSystemId(), null); + fDTDDescription.setRootName(fElementQName.rawname); + XMLInputSource src = fExternalSubsetResolver.getExternalSubset(fDTDDescription); + + if (src != null) { + fDoctypeName = fElementQName.rawname; + fDoctypePublicId = src.getPublicId(); + fDoctypeSystemId = src.getSystemId(); + // call document handler + if (fDocumentHandler != null) { + // This inserts a doctypeDecl event into the stream though no + // DOCTYPE existed in the instance document. + fDocumentHandler.doctypeDecl(fDoctypeName, fDoctypePublicId, fDoctypeSystemId, null); + } + try { + if (fValidationManager == null || !fValidationManager.isCachedDTD()) { + fDTDScanner.setInputSource(src); + while (fDTDScanner.scanDTDExternalSubset(true)); + } + else { + // This sends startDTD and endDTD calls down the pipeline. + fDTDScanner.setInputSource(null); + } + } + finally { + fEntityManager.setEntityHandler(XMLDocumentScannerImpl.this); + } + } + } // resolveExternalSubsetAndRead() + + } // class ContentDispatcher + + /** + * Dispatcher to handle trailing miscellaneous section scanning. + * + * @author Andy Clark, IBM + * @author Eric Ye, IBM + */ + protected final class TrailingMiscDispatcher + implements Dispatcher { + + // + // Dispatcher methods + // + + /** + * Dispatch an XML "event". + * + * @param complete True if this dispatcher is intended to scan + * and dispatch as much as possible. + * + * @return True if there is more to dispatch either from this + * or a another dispatcher. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown on parse error. + */ + public boolean dispatch(boolean complete) + throws IOException, XNIException { + + try { + boolean again; + do { + again = false; + switch (fScannerState) { + case SCANNER_STATE_TRAILING_MISC: { + fEntityScanner.skipSpaces(); + if (fEntityScanner.skipChar('<')) { + setScannerState(SCANNER_STATE_START_OF_MARKUP); + again = true; + } + else { + setScannerState(SCANNER_STATE_CONTENT); + again = true; + } + break; + } + case SCANNER_STATE_START_OF_MARKUP: { + fMarkupDepth++; + if (fEntityScanner.skipChar('?')) { + setScannerState(SCANNER_STATE_PI); + again = true; + } + else if (fEntityScanner.skipChar('!')) { + setScannerState(SCANNER_STATE_COMMENT); + again = true; + } + else if (fEntityScanner.skipChar('/')) { + reportFatalError("MarkupNotRecognizedInMisc", + null); + again = true; + } + else if (isValidNameStartChar(fEntityScanner.peekChar())) { + reportFatalError("MarkupNotRecognizedInMisc", + null); + scanStartElement(); + setScannerState(SCANNER_STATE_CONTENT); + } + else if (isValidNameStartHighSurrogate(fEntityScanner.peekChar())) { + reportFatalError("MarkupNotRecognizedInMisc", + null); + scanStartElement(); + setScannerState(SCANNER_STATE_CONTENT); + } + else { + reportFatalError("MarkupNotRecognizedInMisc", + null); + } + break; + } + case SCANNER_STATE_PI: { + scanPI(); + setScannerState(SCANNER_STATE_TRAILING_MISC); + break; + } + case SCANNER_STATE_COMMENT: { + if (!fEntityScanner.skipString("--")) { + reportFatalError("InvalidCommentStart", null); + } + scanComment(); + setScannerState(SCANNER_STATE_TRAILING_MISC); + break; + } + case SCANNER_STATE_CONTENT: { + int ch = fEntityScanner.peekChar(); + if (ch == -1) { + setScannerState(SCANNER_STATE_TERMINATED); + return false; + } + reportFatalError("ContentIllegalInTrailingMisc", + null); + fEntityScanner.scanChar(); + setScannerState(SCANNER_STATE_TRAILING_MISC); + break; + } + case SCANNER_STATE_REFERENCE: { + reportFatalError("ReferenceIllegalInTrailingMisc", + null); + setScannerState(SCANNER_STATE_TRAILING_MISC); + break; + } + case SCANNER_STATE_TERMINATED: { + return false; + } + } + } while (complete || again); + } + // encoding errors + catch (MalformedByteSequenceException e) { + fErrorReporter.reportError(e.getDomain(), e.getKey(), + e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e); + return false; + } + catch (CharConversionException e) { + fErrorReporter.reportError( + XMLMessageFormatter.XML_DOMAIN, + "CharConversionFailure", + null, + XMLErrorReporter.SEVERITY_FATAL_ERROR, e); + return false; + } + catch (EOFException e) { + // NOTE: This is the only place we're allowed to reach + // the real end of the document stream. Unless the + // end of file was reached prematurely. + if (fMarkupDepth != 0) { + reportFatalError("PrematureEOF", null); + return false; + //throw e; + } + + setScannerState(SCANNER_STATE_TERMINATED); + return false; + } + + return true; + + } // dispatch(boolean):boolean + + } // class TrailingMiscDispatcher + +} // class XMLDocumentScannerImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityDescription.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityDescription.java new file mode 100644 index 0000000..71135ae --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityDescription.java @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import org.apache.xerces.xni.XMLResourceIdentifier; + +/** + *

This interface describes the properties of entities--their + * physical location and their name.

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public interface XMLEntityDescription extends XMLResourceIdentifier { + + /** + * Sets the name of the entity. + * + * @param name the name of the entity + */ + public void setEntityName(String name); + + /** + * Returns the name of the entity. + * + * @return the name of the entity + */ + public String getEntityName(); + +} // XMLEntityDescription diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityHandler.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityHandler.java new file mode 100644 index 0000000..ce44da6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityHandler.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; + +/** + * The entity handler interface defines methods to report information + * about the start and end of entities. + * + * @xerces.internal + * + * @see org.apache.xerces.impl.XMLEntityScanner + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLEntityHandler { + + // + // XMLEntityHandler methods + // + + /** + * This method notifies of the start of an entity. The DTD has the + * pseudo-name of "[dtd]" parameter entity names start with '%'; and + * general entities are just specified by their name. + * + * @param name The name of the entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startEntity(String name, + XMLResourceIdentifier identifier, + String encoding, Augmentations augs) throws XNIException; + + /** + * This method notifies the end of an entity. The DTD has the pseudo-name + * of "[dtd]" parameter entity names start with '%'; and general entities + * are just specified by their name. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endEntity(String name, Augmentations augs) throws XNIException; + +} // interface XMLEntityHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityManager.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityManager.java new file mode 100644 index 0000000..a2ff2ee --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityManager.java @@ -0,0 +1,3296 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Stack; +import java.util.StringTokenizer; + +import org.apache.xerces.impl.io.ASCIIReader; +import org.apache.xerces.impl.io.Latin1Reader; +import org.apache.xerces.impl.io.UCSReader; +import org.apache.xerces.impl.io.UTF16Reader; +import org.apache.xerces.impl.io.UTF8Reader; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.util.AugmentationsImpl; +import org.apache.xerces.util.EncodingMap; +import org.apache.xerces.util.HTTPInputSource; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.URI; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLEntityDescriptionImpl; +import org.apache.xerces.util.XMLResourceIdentifierImpl; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * The entity manager handles the registration of general and parameter + * entities; resolves entities; and starts entities. The entity manager + * is a central component in a standard parser configuration and this + * class works directly with the entity scanner to manage the underlying + * xni. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/validation
  • + *
  • http://xml.org/sax/features/external-general-entities
  • + *
  • http://xml.org/sax/features/external-parameter-entities
  • + *
  • http://apache.org/xml/features/allow-java-encodings
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-resolver
  • + *
+ * + * @xerces.internal + * + * @author Andy Clark, IBM + * @author Arnaud Le Hors, IBM + * + * @version $Id$ + */ +public class XMLEntityManager + implements XMLComponent, XMLEntityResolver { + + // + // Constants + // + + /** Default buffer size (2048). */ + public static final int DEFAULT_BUFFER_SIZE = 2048; + + /** Default buffer size before we've finished with the XMLDecl: */ + public static final int DEFAULT_XMLDECL_BUFFER_SIZE = 64; + + /** Default internal entity buffer size (512). */ + public static final int DEFAULT_INTERNAL_BUFFER_SIZE = 512; + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: external general entities. */ + protected static final String EXTERNAL_GENERAL_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE; + + /** Feature identifier: external parameter entities. */ + protected static final String EXTERNAL_PARAMETER_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE; + + /** Feature identifier: allow Java encodings. */ + protected static final String ALLOW_JAVA_ENCODINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; + + /** Feature identifier: warn on duplicate EntityDef */ + protected static final String WARN_ON_DUPLICATE_ENTITYDEF = + Constants.XERCES_FEATURE_PREFIX +Constants.WARN_ON_DUPLICATE_ENTITYDEF_FEATURE; + + /** Feature identifier: standard uri conformant */ + protected static final String STANDARD_URI_CONFORMANT = + Constants.XERCES_FEATURE_PREFIX +Constants.STANDARD_URI_CONFORMANT_FEATURE; + + protected static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + // property identifiers + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + // property identifier: ValidationManager + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** property identifier: buffer size. */ + protected static final String BUFFER_SIZE = + Constants.XERCES_PROPERTY_PREFIX + Constants.BUFFER_SIZE_PROPERTY; + + /** property identifier: security manager. */ + protected static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + VALIDATION, + EXTERNAL_GENERAL_ENTITIES, + EXTERNAL_PARAMETER_ENTITIES, + ALLOW_JAVA_ENCODINGS, + WARN_ON_DUPLICATE_ENTITYDEF, + STANDARD_URI_CONFORMANT + }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { + null, + Boolean.TRUE, + Boolean.TRUE, + Boolean.FALSE, + Boolean.FALSE, + Boolean.FALSE + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + ERROR_REPORTER, + ENTITY_RESOLVER, + VALIDATION_MANAGER, + BUFFER_SIZE, + SECURITY_MANAGER, + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { + null, + null, + null, + null, + new Integer(DEFAULT_BUFFER_SIZE), + null, + }; + + private static final String XMLEntity = "[xml]".intern(); + private static final String DTDEntity = "[dtd]".intern(); + + // debugging + + /** + * Debug printing of buffer. This debugging flag works best when you + * resize the DEFAULT_BUFFER_SIZE down to something reasonable like + * 64 characters. + */ + private static final boolean DEBUG_BUFFER = false; + + /** Debug some basic entities. */ + private static final boolean DEBUG_ENTITIES = false; + + /** Debug switching readers for encodings. */ + private static final boolean DEBUG_ENCODINGS = false; + + // should be diplayed trace resolving messages + private static final boolean DEBUG_RESOLVER = false; + + // + // Data + // + + // features + + /** + * Validation. This feature identifier is: + * http://xml.org/sax/features/validation + */ + protected boolean fValidation; + + /** + * External general entities. This feature identifier is: + * http://xml.org/sax/features/external-general-entities + */ + protected boolean fExternalGeneralEntities = true; + + /** + * External parameter entities. This feature identifier is: + * http://xml.org/sax/features/external-parameter-entities + */ + protected boolean fExternalParameterEntities = true; + + /** + * Allow Java encoding names. This feature identifier is: + * http://apache.org/xml/features/allow-java-encodings + */ + protected boolean fAllowJavaEncodings; + + /** warn on duplicate Entity declaration. + * http://apache.org/xml/features/warn-on-duplicate-entitydef + */ + protected boolean fWarnDuplicateEntityDef; + + /** + * standard uri conformant (strict uri). + * http://apache.org/xml/features/standard-uri-conformant + */ + protected boolean fStrictURI; + + // properties + + /** + * Symbol table. This property identifier is: + * http://apache.org/xml/properties/internal/symbol-table + */ + protected SymbolTable fSymbolTable; + + /** + * Error reporter. This property identifier is: + * http://apache.org/xml/properties/internal/error-reporter + */ + protected XMLErrorReporter fErrorReporter; + + /** + * Entity resolver. This property identifier is: + * http://apache.org/xml/properties/internal/entity-resolver + */ + protected XMLEntityResolver fEntityResolver; + + /** + * Validation manager. This property identifier is: + * http://apache.org/xml/properties/internal/validation-manager + */ + protected ValidationManager fValidationManager; + + // settings + + /** + * Buffer size. We get this value from a property. The default size + * is used if the input buffer size property is not specified. + * REVISIT: do we need a property for internal entity buffer size? + */ + protected int fBufferSize = DEFAULT_BUFFER_SIZE; + + // stores defaults for entity expansion limit if it has + // been set on the configuration. + protected SecurityManager fSecurityManager = null; + + /** + * True if the document entity is standalone. This should really + * only be set by the document source (e.g. XMLDocumentScanner). + */ + protected boolean fStandalone; + + /** + * True if the current document contains parameter entity references. + */ + protected boolean fHasPEReferences; + + // are the entities being parsed in the external subset? + // NOTE: this *is not* the same as whether they're external entities! + protected boolean fInExternalSubset = false; + + // handlers + + /** Entity handler. */ + protected XMLEntityHandler fEntityHandler; + + // scanner + + /** Current entity scanner. */ + protected XMLEntityScanner fEntityScanner; + + /** XML 1.0 entity scanner. */ + protected XMLEntityScanner fXML10EntityScanner; + + /** XML 1.1 entity scanner. */ + protected XMLEntityScanner fXML11EntityScanner; + + // entity expansion limit (contains useful data if and only if + // fSecurityManager is non-null) + protected int fEntityExpansionLimit = 0; + // entity currently being expanded: + protected int fEntityExpansionCount = 0; + + // entities + + /** Entities. */ + protected final Hashtable fEntities = new Hashtable(); + + /** Entity stack. */ + protected final Stack fEntityStack = new Stack(); + + /** Current entity. */ + protected ScannedEntity fCurrentEntity; + + // shared context + + /** Shared declared entities. */ + protected Hashtable fDeclaredEntities; + + // temp vars + + /** Resource identifier. */ + private final XMLResourceIdentifierImpl fResourceIdentifier = new XMLResourceIdentifierImpl(); + + /** Augmentations for entities. */ + private final Augmentations fEntityAugs = new AugmentationsImpl(); + + /** Pool of byte buffers for single byte and variable width encodings, such as US-ASCII and UTF-8. */ + private final ByteBufferPool fSmallByteBufferPool = new ByteBufferPool(fBufferSize); + + /** Pool of byte buffers for 2-byte encodings, such as UTF-16. **/ + private final ByteBufferPool fLargeByteBufferPool = new ByteBufferPool(fBufferSize << 1); + + /** Temporary storage for the current entity's byte buffer. */ + private byte[] fTempByteBuffer = null; + + /** Pool of character buffers. */ + private final CharacterBufferPool fCharacterBufferPool = new CharacterBufferPool(fBufferSize, DEFAULT_INTERNAL_BUFFER_SIZE); + + // + // Constructors + // + + /** Default constructor. */ + public XMLEntityManager() { + this(null); + } // () + + /** + * Constructs an entity manager that shares the specified entity + * declarations during each parse. + *

+ * REVISIT: We might want to think about the "right" + * way to expose the list of declared entities. For now, the knowledge + * how to access the entity declarations is implicit. + */ + public XMLEntityManager(XMLEntityManager entityManager) { + + // save shared entity declarations + fDeclaredEntities = entityManager != null + ? entityManager.getDeclaredEntities() : null; + + setScannerVersion(Constants.XML_VERSION_1_0); + } // (XMLEntityManager) + + // + // Public methods + // + + /** + * Sets whether the document entity is standalone. + * + * @param standalone True if document entity is standalone. + */ + public void setStandalone(boolean standalone) { + fStandalone = standalone; + } // setStandalone(boolean) + + /** Returns true if the document entity is standalone. */ + public boolean isStandalone() { + return fStandalone; + } // isStandalone():boolean + + /** + * Notifies the entity manager that the current document + * being processed contains parameter entity references. + */ + final void notifyHasPEReferences() { + fHasPEReferences = true; + } // notifyHasPEReferences + + /** + * Returns true if the document contains parameter entity references. + */ + final boolean hasPEReferences() { + return fHasPEReferences; + } // hasPEReferences():boolean + + /** + * Sets the entity handler. When an entity starts and ends, the + * entity handler is notified of the change. + * + * @param entityHandler The new entity handler. + */ + public void setEntityHandler(XMLEntityHandler entityHandler) { + fEntityHandler = entityHandler; + } // setEntityHandler(XMLEntityHandler) + + // this simply returns the fResourceIdentifier object; + // this should only be used with caution by callers that + // carefully manage the entity manager's behaviour, so that + // this doesn't returning meaningless or misleading data. + // @return a reference to the current fResourceIdentifier object + public XMLResourceIdentifier getCurrentResourceIdentifier() { + return fResourceIdentifier; + } + + // this simply returns the fCurrentEntity object; + // this should only be used with caution by callers that + // carefully manage the entity manager's behaviour, so that + // this doesn't returning meaningless or misleading data. + // @return a reference to the current fCurrentEntity object + public ScannedEntity getCurrentEntity() { + return fCurrentEntity; + } + + /** + * Adds an internal entity declaration. + *

+ * Note: This method ignores subsequent entity + * declarations. + *

+ * Note: The name should be a unique symbol. The + * SymbolTable can be used for this purpose. + * + * @param name The name of the entity. + * @param text The text of the entity. + * @param paramEntityRefs Count of direct and indirect references to parameter entities in the value of the entity. + * + * @see SymbolTable + */ + public void addInternalEntity(String name, String text, int paramEntityRefs) { + if (!fEntities.containsKey(name)) { + Entity entity = new InternalEntity(name, text, fInExternalSubset, paramEntityRefs); + fEntities.put(name, entity); + } + else{ + if(fWarnDuplicateEntityDef){ + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_DUPLICATE_ENTITY_DEFINITION", + new Object[]{ name }, + XMLErrorReporter.SEVERITY_WARNING ); + } + } + + } // addInternalEntity(String,String,int) + + /** + * Adds an internal entity declaration. + *

+ * Note: This method ignores subsequent entity + * declarations. + *

+ * Note: The name should be a unique symbol. The + * SymbolTable can be used for this purpose. + * + * @param name The name of the entity. + * @param text The text of the entity. + * + * @see SymbolTable + */ + public void addInternalEntity(String name, String text) { + addInternalEntity(name, text, 0); + } // addInternalEntity(String,String) + + /** + * Returns the number of direct and indirect references to parameter + * entities in the value of the entity. This value will only be + * non-zero for an internal parameter entity. + * + * @param entityName The name of the entity to check. + * @return Count of direct and indirect references to parameter entities in the value of the entity + */ + public int getParamEntityRefCount(String entityName) { + if (entityName != null && + entityName.length() > 0 && + entityName.charAt(0) == '%') { + final Entity entity = (Entity) fEntities.get(entityName); + if (entity != null && !entity.isExternal()) { + return ((InternalEntity) entity).paramEntityRefs; + } + } + return 0; + } // getParamEntityRefCount(String) + + /** + * Adds an external entity declaration. + *

+ * Note: This method ignores subsequent entity + * declarations. + *

+ * Note: The name should be a unique symbol. The + * SymbolTable can be used for this purpose. + * + * @param name The name of the entity. + * @param publicId The public identifier of the entity. + * @param literalSystemId The system identifier of the entity. + * @param baseSystemId The base system identifier of the entity. + * This is the system identifier of the entity + * where the entity being added and + * is used to expand the system identifier when + * the system identifier is a relative URI. + * When null the system identifier of the first + * external entity on the stack is used instead. + * + * @see SymbolTable + */ + public void addExternalEntity(String name, + String publicId, String literalSystemId, + String baseSystemId) throws IOException { + if (!fEntities.containsKey(name)) { + if (baseSystemId == null) { + // search for the first external entity on the stack + int size = fEntityStack.size(); + if (size == 0 && fCurrentEntity != null && fCurrentEntity.entityLocation != null) { + baseSystemId = fCurrentEntity.entityLocation.getExpandedSystemId(); + } + for (int i = size - 1; i >= 0 ; i--) { + ScannedEntity externalEntity = + (ScannedEntity)fEntityStack.elementAt(i); + if (externalEntity.entityLocation != null && externalEntity.entityLocation.getExpandedSystemId() != null) { + baseSystemId = externalEntity.entityLocation.getExpandedSystemId(); + break; + } + } + } + Entity entity = new ExternalEntity(name, + new XMLEntityDescriptionImpl(name, publicId, literalSystemId, baseSystemId, + expandSystemId(literalSystemId, baseSystemId, false)), null, fInExternalSubset); + fEntities.put(name, entity); + } + else{ + if(fWarnDuplicateEntityDef){ + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_DUPLICATE_ENTITY_DEFINITION", + new Object[]{ name }, + XMLErrorReporter.SEVERITY_WARNING ); + } + } + + } // addExternalEntity(String,String,String,String) + + /** + * Checks whether an entity given by name is external. + * + * @param entityName The name of the entity to check. + * @return True if the entity is external, false otherwise + * (including when the entity is not declared). + */ + public boolean isExternalEntity(String entityName) { + + Entity entity = (Entity)fEntities.get(entityName); + if (entity == null) { + return false; + } + return entity.isExternal(); + } + + /** + * Checks whether the declaration of an entity given by name is + // in the external subset. + * + * @param entityName The name of the entity to check. + * @return True if the entity was declared in the external subset, false otherwise + * (including when the entity is not declared). + */ + public boolean isEntityDeclInExternalSubset(String entityName) { + + Entity entity = (Entity)fEntities.get(entityName); + if (entity == null) { + return false; + } + return entity.isEntityDeclInExternalSubset(); + } + + /** + * Adds an unparsed entity declaration. + *

+ * Note: This method ignores subsequent entity + * declarations. + *

+ * Note: The name should be a unique symbol. The + * SymbolTable can be used for this purpose. + * + * @param name The name of the entity. + * @param publicId The public identifier of the entity. + * @param systemId The system identifier of the entity. + * @param notation The name of the notation. + * + * @see SymbolTable + */ + public void addUnparsedEntity(String name, + String publicId, String systemId, + String baseSystemId, String notation) { + if (!fEntities.containsKey(name)) { + Entity entity = new ExternalEntity(name, + new XMLEntityDescriptionImpl(name, publicId, systemId, baseSystemId, null), + notation, fInExternalSubset); + fEntities.put(name, entity); + } + else{ + if(fWarnDuplicateEntityDef){ + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_DUPLICATE_ENTITY_DEFINITION", + new Object[]{ name }, + XMLErrorReporter.SEVERITY_WARNING ); + } + } + } // addUnparsedEntity(String,String,String,String) + + /** + * Checks whether an entity given by name is unparsed. + * + * @param entityName The name of the entity to check. + * @return True if the entity is unparsed, false otherwise + * (including when the entity is not declared). + */ + public boolean isUnparsedEntity(String entityName) { + + Entity entity = (Entity)fEntities.get(entityName); + if (entity == null) { + return false; + } + return entity.isUnparsed(); + } + + /** + * Checks whether an entity given by name is declared. + * + * @param entityName The name of the entity to check. + * @return True if the entity is declared, false otherwise. + */ + public boolean isDeclaredEntity(String entityName) { + + Entity entity = (Entity)fEntities.get(entityName); + return entity != null; + } + + /** + * Resolves the specified public and system identifiers. This + * method first attempts to resolve the entity based on the + * EntityResolver registered by the application. If no entity + * resolver is registered or if the registered entity handler + * is unable to resolve the entity, then default entity + * resolution will occur. + * + * @param resourceIdentifier The XMLResourceIdentifier for the resource to resolve. + * + * @return Returns an input source that wraps the resolved entity. + * This method will never return null. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown by entity resolver to signal an error. + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) + throws IOException, XNIException { + if(resourceIdentifier == null ) return null; + String publicId = resourceIdentifier.getPublicId(); + String literalSystemId = resourceIdentifier.getLiteralSystemId(); + String baseSystemId = resourceIdentifier.getBaseSystemId(); + String expandedSystemId = resourceIdentifier.getExpandedSystemId(); + // if no base systemId given, assume that it's relative + // to the systemId of the current scanned entity + // Sometimes the system id is not (properly) expanded. + // We need to expand the system id if: + // a. the expanded one was null; or + // b. the base system id was null, but becomes non-null from the current entity. + boolean needExpand = (expandedSystemId == null); + // REVISIT: why would the baseSystemId ever be null? if we + // didn't have to make this check we wouldn't have to reuse the + // fXMLResourceIdentifier object... + if (baseSystemId == null && fCurrentEntity != null && fCurrentEntity.entityLocation != null) { + baseSystemId = fCurrentEntity.entityLocation.getExpandedSystemId(); + if (baseSystemId != null) + needExpand = true; + } + + // give the entity resolver a chance + XMLInputSource xmlInputSource = null; + if (fEntityResolver != null) { + if (needExpand) { + expandedSystemId = expandSystemId(literalSystemId, baseSystemId, false); + } + resourceIdentifier.setBaseSystemId(baseSystemId); + resourceIdentifier.setExpandedSystemId(expandedSystemId); + xmlInputSource = fEntityResolver.resolveEntity(resourceIdentifier); + } + + // do default resolution + // REVISIT: what's the correct behavior if the user provided an entity + // resolver (fEntityResolver != null), but resolveEntity doesn't return + // an input source (xmlInputSource == null)? + // do we do default resolution, or do we just return null? -SG + if (xmlInputSource == null) { + // REVISIT: when systemId is null, I think we should return null. + // is this the right solution? -SG + //if (systemId != null) + xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId); + } + + if (DEBUG_RESOLVER) { + System.err.println("XMLEntityManager.resolveEntity(" + publicId + ")"); + System.err.println(" = " + xmlInputSource); + } + + return xmlInputSource; + + } // resolveEntity(XMLResourceIdentifier):XMLInputSource + + /** + * Starts a named entity. + * + * @param entityName The name of the entity to start. + * @param literal True if this entity is started within a literal + * value. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown by entity handler to signal an error. + */ + public void startEntity(String entityName, boolean literal) + throws IOException, XNIException { + + // was entity declared? + Entity entity = (Entity)fEntities.get(entityName); + if (entity == null) { + if (fEntityHandler != null) { + String encoding = null; + fResourceIdentifier.clear(); + fEntityAugs.removeAllItems(); + fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE); + fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding, fEntityAugs); + fEntityAugs.removeAllItems(); + fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE); + fEntityHandler.endEntity(entityName, fEntityAugs); + } + return; + } + + // should we skip external entities? + boolean external = entity.isExternal(); + if (external && (fValidationManager == null || !fValidationManager.isCachedDTD())) { + boolean unparsed = entity.isUnparsed(); + boolean parameter = entityName.startsWith("%"); + boolean general = !parameter; + if (unparsed || (general && !fExternalGeneralEntities) || + (parameter && !fExternalParameterEntities)) { + if (fEntityHandler != null) { + fResourceIdentifier.clear(); + final String encoding = null; + ExternalEntity externalEntity = (ExternalEntity)entity; + //REVISIT: since we're storing expandedSystemId in the + // externalEntity, how could this have got here if it wasn't already + // expanded??? - neilg + String extLitSysId = (externalEntity.entityLocation != null ? externalEntity.entityLocation.getLiteralSystemId() : null); + String extBaseSysId = (externalEntity.entityLocation != null ? externalEntity.entityLocation.getBaseSystemId() : null); + String expandedSystemId = expandSystemId(extLitSysId, extBaseSysId, false); + fResourceIdentifier.setValues( + (externalEntity.entityLocation != null ? externalEntity.entityLocation.getPublicId() : null), + extLitSysId, extBaseSysId, expandedSystemId); + fEntityAugs.removeAllItems(); + fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE); + fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding, fEntityAugs); + fEntityAugs.removeAllItems(); + fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE); + fEntityHandler.endEntity(entityName, fEntityAugs); + } + return; + } + } + + // is entity recursive? + int size = fEntityStack.size(); + for (int i = size; i >= 0; i--) { + Entity activeEntity = i == size + ? fCurrentEntity + : (Entity)fEntityStack.elementAt(i); + if (activeEntity.name == entityName) { + StringBuffer path = new StringBuffer(entityName); + for (int j = i + 1; j < size; j++) { + activeEntity = (Entity)fEntityStack.elementAt(j); + path.append(" -> "); + path.append(activeEntity.name); + } + path.append(" -> "); + path.append(fCurrentEntity.name); + path.append(" -> "); + path.append(entityName); + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "RecursiveReference", + new Object[] { entityName, path.toString() }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + if (fEntityHandler != null) { + fResourceIdentifier.clear(); + final String encoding = null; + if (external) { + ExternalEntity externalEntity = (ExternalEntity)entity; + // REVISIT: for the same reason above... + String extLitSysId = (externalEntity.entityLocation != null ? externalEntity.entityLocation.getLiteralSystemId() : null); + String extBaseSysId = (externalEntity.entityLocation != null ? externalEntity.entityLocation.getBaseSystemId() : null); + String expandedSystemId = expandSystemId(extLitSysId, extBaseSysId, false); + fResourceIdentifier.setValues( + (externalEntity.entityLocation != null ? externalEntity.entityLocation.getPublicId() : null), + extLitSysId, extBaseSysId, expandedSystemId); + } + fEntityAugs.removeAllItems(); + fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE); + fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding, fEntityAugs); + fEntityAugs.removeAllItems(); + fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE); + fEntityHandler.endEntity(entityName, fEntityAugs); + } + return; + } + } + + // resolve external entity + XMLInputSource xmlInputSource = null; + if (external) { + ExternalEntity externalEntity = (ExternalEntity)entity; + xmlInputSource = resolveEntity(externalEntity.entityLocation); + } + + // wrap internal entity + else { + InternalEntity internalEntity = (InternalEntity)entity; + Reader reader = new StringReader(internalEntity.text); + xmlInputSource = new XMLInputSource(null, null, null, reader, null); + } + + // start the entity + startEntity(entityName, xmlInputSource, literal, external); + + } // startEntity(String,boolean) + + /** + * Starts the document entity. The document entity has the "[xml]" + * pseudo-name. + * + * @param xmlInputSource The input source of the document entity. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown by entity handler to signal an error. + */ + public void startDocumentEntity(XMLInputSource xmlInputSource) + throws IOException, XNIException { + startEntity(XMLEntity, xmlInputSource, false, true); + } // startDocumentEntity(XMLInputSource) + + /** + * Starts the DTD entity. The DTD entity has the "[dtd]" + * pseudo-name. + * + * @param xmlInputSource The input source of the DTD entity. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown by entity handler to signal an error. + */ + public void startDTDEntity(XMLInputSource xmlInputSource) + throws IOException, XNIException { + startEntity(DTDEntity, xmlInputSource, false, true); + } // startDTDEntity(XMLInputSource) + + // indicate start of external subset so that + // location of entity decls can be tracked + public void startExternalSubset() { + fInExternalSubset = true; + } + + public void endExternalSubset() { + fInExternalSubset = false; + } + + /** + * Starts an entity. + *

+ * This method can be used to insert an application defined XML + * entity stream into the parsing stream. + * + * @param name The name of the entity. + * @param xmlInputSource The input source of the entity. + * @param literal True if this entity is started within a + * literal value. + * @param isExternal whether this entity should be treated as an internal or external entity. + * + * @throws IOException Thrown on i/o error. + * @throws XNIException Thrown by entity handler to signal an error. + */ + public void startEntity(String name, + XMLInputSource xmlInputSource, + boolean literal, boolean isExternal) + throws IOException, XNIException { + + String encoding = setupCurrentEntity(name, xmlInputSource, literal, isExternal); + + // when entity expansion limit is set by the Application, we need to + // check for the entity expansion limit set by the parser, if number of entity + // expansions exceeds the entity expansion limit, parser will throw fatal error. + // Note that this is intentionally unbalanced; it counts + // the number of expansions *per document*. + if (fSecurityManager != null) { + fEntityExpansionCount += getParamEntityRefCount(name); + if (fEntityExpansionCount++ > fEntityExpansionLimit) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "EntityExpansionLimitExceeded", + new Object[]{new Integer(fEntityExpansionLimit) }, + XMLErrorReporter.SEVERITY_FATAL_ERROR ); + // is there anything better to do than reset the counter? + // at least one can envision debugging applications where this might + // be useful... + fEntityExpansionCount = 0; + } + } + + // call handler + if (fEntityHandler != null) { + fEntityHandler.startEntity(name, fResourceIdentifier, encoding, null); + } + + } // startEntity(String,XMLInputSource) + + /** + * This method uses the passed-in XMLInputSource to make + * fCurrentEntity usable for reading. + * @param name name of the entity (XML is it's the document entity) + * @param xmlInputSource the input source, with sufficient information + * to begin scanning characters. + * @param literal True if this entity is started within a + * literal value. + * @param isExternal whether this entity should be treated as an internal or external entity. + * @throws IOException if anything can't be read + * XNIException If any parser-specific goes wrong. + * @return the encoding of the new entity or null if a character stream was employed + */ + public String setupCurrentEntity(String name, XMLInputSource xmlInputSource, + boolean literal, boolean isExternal) + throws IOException, XNIException { + // get information + + final String publicId = xmlInputSource.getPublicId(); + String literalSystemId = xmlInputSource.getSystemId(); + String baseSystemId = xmlInputSource.getBaseSystemId(); + String encoding = xmlInputSource.getEncoding(); + final boolean encodingExternallySpecified = (encoding != null); + Boolean isBigEndian = null; + fTempByteBuffer = null; + + // create reader + InputStream stream = null; + Reader reader = xmlInputSource.getCharacterStream(); + // First chance checking strict URI + String expandedSystemId = expandSystemId(literalSystemId, baseSystemId, fStrictURI); + if (baseSystemId == null) { + baseSystemId = expandedSystemId; + } + if (reader == null) { + stream = xmlInputSource.getByteStream(); + if (stream == null) { + URL location = new URL(expandedSystemId); + URLConnection connect = location.openConnection(); + if (!(connect instanceof HttpURLConnection)) { + stream = connect.getInputStream(); + } + else { + boolean followRedirects = true; + + // setup URLConnection if we have an HTTPInputSource + if (xmlInputSource instanceof HTTPInputSource) { + final HttpURLConnection urlConnection = (HttpURLConnection) connect; + final HTTPInputSource httpInputSource = (HTTPInputSource) xmlInputSource; + + // set request properties + Iterator propIter = httpInputSource.getHTTPRequestProperties(); + while (propIter.hasNext()) { + Map.Entry entry = (Map.Entry) propIter.next(); + urlConnection.setRequestProperty((String) entry.getKey(), (String) entry.getValue()); + } + + // set preference for redirection + followRedirects = httpInputSource.getFollowHTTPRedirects(); + if (!followRedirects) { + urlConnection.setInstanceFollowRedirects(followRedirects); + } + } + + stream = connect.getInputStream(); + + // REVISIT: If the URLConnection has external encoding + // information, we should be reading it here. It's located + // in the charset parameter of Content-Type. -- mrglavas + + if (followRedirects) { + String redirect = connect.getURL().toString(); + // E43: Check if the URL was redirected, and then + // update literal and expanded system IDs if needed. + if (!redirect.equals(expandedSystemId)) { + literalSystemId = redirect; + expandedSystemId = redirect; + } + } + } + } + // wrap this stream in RewindableInputStream + RewindableInputStream rewindableStream = new RewindableInputStream(stream); + stream = rewindableStream; + + // perform auto-detect of encoding if necessary + if (encoding == null) { + // read first four bytes and determine encoding + final byte[] b4 = new byte[4]; + int count = 0; + for (; count<4; count++ ) { + b4[count] = (byte)rewindableStream.readAndBuffer(); + } + if (count == 4) { + final EncodingInfo info = getEncodingInfo(b4, count); + encoding = info.autoDetectedEncoding; + final String readerEncoding = info.readerEncoding; + isBigEndian = info.isBigEndian; + stream.reset(); + if (info.hasBOM) { + // Special case UTF-8 files with BOM created by Microsoft + // tools. It's more efficient to consume the BOM than make + // the reader perform extra checks. -Ac + if (readerEncoding == "UTF-8") { + // UTF-8 BOM: 0xEF 0xBB 0xBF + stream.skip(3); + } + // It's also more efficient to consume the UTF-16 BOM. + else if (readerEncoding == "UTF-16") { + // UTF-16 BE BOM: 0xFE 0xFF + // UTF-16 LE BOM: 0xFF 0xFE + stream.skip(2); + } + } + reader = createReader(stream, readerEncoding, isBigEndian); + } + else { + reader = createReader(stream, encoding, isBigEndian); + } + } + + // use specified encoding + else { + encoding = encoding.toUpperCase(Locale.ENGLISH); + + // If encoding is UTF-8, consume BOM if one is present. + if (encoding.equals("UTF-8")) { + final int[] b3 = new int[3]; + int count = 0; + for (; count < 3; ++count) { + b3[count] = rewindableStream.readAndBuffer(); + if (b3[count] == -1) + break; + } + if (count == 3) { + if (b3[0] != 0xEF || b3[1] != 0xBB || b3[2] != 0xBF) { + // First three bytes are not BOM, so reset. + stream.reset(); + } + } + else { + stream.reset(); + } + reader = createReader(stream, "UTF-8", isBigEndian); + } + // If encoding is UTF-16, we still need to read the first + // four bytes, in order to discover the byte order. + else if (encoding.equals("UTF-16")) { + final int[] b4 = new int[4]; + int count = 0; + for (; count < 4; ++count) { + b4[count] = rewindableStream.readAndBuffer(); + if (b4[count] == -1) + break; + } + stream.reset(); + if (count >= 2) { + final int b0 = b4[0]; + final int b1 = b4[1]; + if (b0 == 0xFE && b1 == 0xFF) { + // UTF-16, big-endian + isBigEndian = Boolean.TRUE; + stream.skip(2); + } + else if (b0 == 0xFF && b1 == 0xFE) { + // UTF-16, little-endian + isBigEndian = Boolean.FALSE; + stream.skip(2); + } + else if (count == 4) { + final int b2 = b4[2]; + final int b3 = b4[3]; + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { + // UTF-16, big-endian, no BOM + isBigEndian = Boolean.TRUE; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { + // UTF-16, little-endian, no BOM + isBigEndian = Boolean.FALSE; + } + } + } + reader = createReader(stream, "UTF-16", isBigEndian); + } + // If encoding is UCS-4, we still need to read the first four bytes + // in order to discover the byte order. + else if (encoding.equals("ISO-10646-UCS-4")) { + final int[] b4 = new int[4]; + int count = 0; + for (; count < 4; ++count) { + b4[count] = rewindableStream.readAndBuffer(); + if (b4[count] == -1) + break; + } + stream.reset(); + + // Ignore unusual octet order for now. + if (count == 4) { + // UCS-4, big endian (1234) + if (b4[0] == 0x00 && b4[1] == 0x00 && b4[2] == 0x00 && b4[3] == 0x3C) { + isBigEndian = Boolean.TRUE; + } + // UCS-4, little endian (1234) + else if (b4[0] == 0x3C && b4[1] == 0x00 && b4[2] == 0x00 && b4[3] == 0x00) { + isBigEndian = Boolean.FALSE; + } + } + reader = createReader(stream, encoding, isBigEndian); + } + // If encoding is UCS-2, we still need to read the first four bytes + // in order to discover the byte order. + else if (encoding.equals("ISO-10646-UCS-2")) { + final int[] b4 = new int[4]; + int count = 0; + for (; count < 4; ++count) { + b4[count] = rewindableStream.readAndBuffer(); + if (b4[count] == -1) + break; + } + stream.reset(); + + if (count == 4) { + // UCS-2, big endian + if (b4[0] == 0x00 && b4[1] == 0x3C && b4[2] == 0x00 && b4[3] == 0x3F) { + isBigEndian = Boolean.TRUE; + } + // UCS-2, little endian + else if (b4[0] == 0x3C && b4[1] == 0x00 && b4[2] == 0x3F && b4[3] == 0x00) { + isBigEndian = Boolean.FALSE; + } + } + reader = createReader(stream, encoding, isBigEndian); + } + else { + reader = createReader(stream, encoding, isBigEndian); + } + } + + // read one character at a time so we don't jump too far + // ahead, converting characters from the byte stream in + // the wrong encoding + if (DEBUG_ENCODINGS) { + System.out.println("$$$ no longer wrapping reader in OneCharReader"); + } + //reader = new OneCharReader(reader); + } + + // We've seen a new Reader. + // Push it on the stack so we can close it later. + fReaderStack.push(reader); + + // push entity on stack + if (fCurrentEntity != null) { + fEntityStack.push(fCurrentEntity); + } + + // create entity + fCurrentEntity = new ScannedEntity(name, + new XMLResourceIdentifierImpl(publicId, literalSystemId, baseSystemId, expandedSystemId), + stream, reader, fTempByteBuffer, encoding, literal, false, isExternal); + fCurrentEntity.setEncodingExternallySpecified(encodingExternallySpecified); + fEntityScanner.setCurrentEntity(fCurrentEntity); + fResourceIdentifier.setValues(publicId, literalSystemId, baseSystemId, expandedSystemId); + return encoding; + } //setupCurrentEntity(String, XMLInputSource, boolean, boolean): String + + // set version of scanner to use + public void setScannerVersion(short version) { + if(version == Constants.XML_VERSION_1_0) { + if(fXML10EntityScanner == null) { + fXML10EntityScanner = new XMLEntityScanner(); + } + fXML10EntityScanner.reset(fSymbolTable, this, fErrorReporter); + fEntityScanner = fXML10EntityScanner; + fEntityScanner.setCurrentEntity(fCurrentEntity); + } else { + if(fXML11EntityScanner == null) { + fXML11EntityScanner = new XML11EntityScanner(); + } + fXML11EntityScanner.reset(fSymbolTable, this, fErrorReporter); + fEntityScanner = fXML11EntityScanner; + fEntityScanner.setCurrentEntity(fCurrentEntity); + } + } // setScannerVersion(short) + + /** Returns the entity scanner. */ + public XMLEntityScanner getEntityScanner() { + if(fEntityScanner == null) { + // default to 1.0 + if(fXML10EntityScanner == null) { + fXML10EntityScanner = new XMLEntityScanner(); + } + fXML10EntityScanner.reset(fSymbolTable, this, fErrorReporter); + fEntityScanner = fXML10EntityScanner; + } + return fEntityScanner; + } // getEntityScanner():XMLEntityScanner + + // A stack containing all the open readers + protected Stack fReaderStack = new Stack(); + + /** + * Close all opened InputStreams and Readers opened by this parser. + */ + public void closeReaders() { + // close all readers + for (int i = fReaderStack.size()-1; i >= 0; i--) { + try { + ((Reader)fReaderStack.pop()).close(); + } catch (IOException e) { + // ignore + } + } + } + + // + // XMLComponent methods + // + + /** + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws SAXException Thrown by component on initialization error. + * For example, if a feature or property is + * required for the operation of the component, the + * component manager may throw a + * SAXNotRecognizedException or a + * SAXNotSupportedException. + */ + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + boolean parser_settings; + try { + parser_settings = componentManager.getFeature(PARSER_SETTINGS); + } catch (XMLConfigurationException e) { + parser_settings = true; + } + + if (!parser_settings) { + // parser settings have not been changed + reset(); + return; + } + + // sax features + try { + fValidation = componentManager.getFeature(VALIDATION); + } + catch (XMLConfigurationException e) { + fValidation = false; + } + try { + fExternalGeneralEntities = componentManager.getFeature(EXTERNAL_GENERAL_ENTITIES); + } + catch (XMLConfigurationException e) { + fExternalGeneralEntities = true; + } + try { + fExternalParameterEntities = componentManager.getFeature(EXTERNAL_PARAMETER_ENTITIES); + } + catch (XMLConfigurationException e) { + fExternalParameterEntities = true; + } + + // xerces features + try { + fAllowJavaEncodings = componentManager.getFeature(ALLOW_JAVA_ENCODINGS); + } + catch (XMLConfigurationException e) { + fAllowJavaEncodings = false; + } + + try { + fWarnDuplicateEntityDef = componentManager.getFeature(WARN_ON_DUPLICATE_ENTITYDEF); + } + catch (XMLConfigurationException e) { + fWarnDuplicateEntityDef = false; + } + + try { + fStrictURI = componentManager.getFeature(STANDARD_URI_CONFORMANT); + } + catch (XMLConfigurationException e) { + fStrictURI = false; + } + + // xerces properties + fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE); + fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); + try { + fEntityResolver = (XMLEntityResolver)componentManager.getProperty(ENTITY_RESOLVER); + } + catch (XMLConfigurationException e) { + fEntityResolver = null; + } + try { + fValidationManager = (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER); + } + catch (XMLConfigurationException e) { + fValidationManager = null; + } + try { + fSecurityManager = (SecurityManager)componentManager.getProperty(SECURITY_MANAGER); + } + catch (XMLConfigurationException e) { + fSecurityManager = null; + } + + // reset general state + reset(); + + } // reset(XMLComponentManager) + + // reset general state. Should not be called other than by + // a class acting as a component manager but not + // implementing that interface for whatever reason. + public void reset() { + fEntityExpansionLimit = (fSecurityManager != null)?fSecurityManager.getEntityExpansionLimit():0; + + // initialize state + fStandalone = false; + fHasPEReferences = false; + fEntities.clear(); + fEntityStack.removeAllElements(); + fEntityExpansionCount = 0; + + fCurrentEntity = null; + // reset scanner + if(fXML10EntityScanner != null){ + fXML10EntityScanner.reset(fSymbolTable, this, fErrorReporter); + } + if(fXML11EntityScanner != null) { + fXML11EntityScanner.reset(fSymbolTable, this, fErrorReporter); + } + + // DEBUG + if (DEBUG_ENTITIES) { + addInternalEntity("text", "Hello, World."); + addInternalEntity("empty-element", ""); + addInternalEntity("balanced-element", ""); + addInternalEntity("balanced-element-with-text", "Hello, World"); + addInternalEntity("balanced-element-with-entity", "&text;"); + addInternalEntity("unbalanced-entity", ""); + addInternalEntity("recursive-entity", "&recursive-entity2;"); + addInternalEntity("recursive-entity2", "&recursive-entity3;"); + addInternalEntity("recursive-entity3", "&recursive-entity;"); + try { + addExternalEntity("external-text", null, "external-text.ent", "test/external-text.xml"); + addExternalEntity("external-balanced-element", null, "external-balanced-element.ent", "test/external-balanced-element.xml"); + addExternalEntity("one", null, "ent/one.ent", "test/external-entity.xml"); + addExternalEntity("two", null, "ent/two.ent", "test/ent/one.xml"); + } + catch (IOException ex) { + // should never happen + } + } + + // copy declared entities + if (fDeclaredEntities != null) { + Iterator entries = fDeclaredEntities.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + Object key = entry.getKey(); + Object value = entry.getValue(); + fEntities.put(key, value); + } + } + fEntityHandler = null; + + } // reset(XMLComponentManager) + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + + // xerces features + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + if (suffixLength == Constants.ALLOW_JAVA_ENCODINGS_FEATURE.length() && + featureId.endsWith(Constants.ALLOW_JAVA_ENCODINGS_FEATURE)) { + fAllowJavaEncodings = state; + } + } + + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // Xerces properties + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SYMBOL_TABLE_PROPERTY.length() && + propertyId.endsWith(Constants.SYMBOL_TABLE_PROPERTY)) { + fSymbolTable = (SymbolTable)value; + return; + } + if (suffixLength == Constants.ERROR_REPORTER_PROPERTY.length() && + propertyId.endsWith(Constants.ERROR_REPORTER_PROPERTY)) { + fErrorReporter = (XMLErrorReporter)value; + return; + } + if (suffixLength == Constants.ENTITY_RESOLVER_PROPERTY.length() && + propertyId.endsWith(Constants.ENTITY_RESOLVER_PROPERTY)) { + fEntityResolver = (XMLEntityResolver)value; + return; + } + if (suffixLength == Constants.BUFFER_SIZE_PROPERTY.length() && + propertyId.endsWith(Constants.BUFFER_SIZE_PROPERTY)) { + Integer bufferSize = (Integer)value; + if (bufferSize != null && + bufferSize.intValue() > DEFAULT_XMLDECL_BUFFER_SIZE) { + fBufferSize = bufferSize.intValue(); + fEntityScanner.setBufferSize(fBufferSize); + fSmallByteBufferPool.setBufferSize(fBufferSize); + fLargeByteBufferPool.setBufferSize(fBufferSize << 1); + fCharacterBufferPool.setExternalBufferSize(fBufferSize); + } + } + if (suffixLength == Constants.SECURITY_MANAGER_PROPERTY.length() && + propertyId.endsWith(Constants.SECURITY_MANAGER_PROPERTY)) { + fSecurityManager = (SecurityManager)value; + fEntityExpansionLimit = (fSecurityManager != null)?fSecurityManager.getEntityExpansionLimit():0; + } + } + + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + // + // Public static methods + // + + // current value of the "user.dir" property + private static String gUserDir; + // cached URI object for the current value of the escaped "user.dir" property stored as a URI + private static URI gUserDirURI; + // which ASCII characters need to be escaped + private static final boolean gNeedEscaping[] = new boolean[128]; + // the first hex character if a character needs to be escaped + private static final char gAfterEscaping1[] = new char[128]; + // the second hex character if a character needs to be escaped + private static final char gAfterEscaping2[] = new char[128]; + private static final char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + // initialize the above 3 arrays + static { + for (int i = 0; i <= 0x1f; i++) { + gNeedEscaping[i] = true; + gAfterEscaping1[i] = gHexChs[i >> 4]; + gAfterEscaping2[i] = gHexChs[i & 0xf]; + } + gNeedEscaping[0x7f] = true; + gAfterEscaping1[0x7f] = '7'; + gAfterEscaping2[0x7f] = 'F'; + char[] escChs = {' ', '<', '>', '#', '%', '"', '{', '}', + '|', '\\', '^', '~', '[', ']', '`'}; + int len = escChs.length; + char ch; + for (int i = 0; i < len; i++) { + ch = escChs[i]; + gNeedEscaping[ch] = true; + gAfterEscaping1[ch] = gHexChs[ch >> 4]; + gAfterEscaping2[ch] = gHexChs[ch & 0xf]; + } + } + + private static PrivilegedAction GET_USER_DIR_SYSTEM_PROPERTY = new PrivilegedAction() { + public Object run() { + return System.getProperty("user.dir"); + } + }; + + // To escape the "user.dir" system property, by using %HH to represent + // special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', '#', '%' + // and '"'. It's a static method, so needs to be synchronized. + // this method looks heavy, but since the system property isn't expected + // to change often, so in most cases, we only need to return the URI + // that was escaped before. + // According to the URI spec, non-ASCII characters (whose value >= 128) + // need to be escaped too. + // REVISIT: don't know how to escape non-ASCII characters, especially + // which encoding to use. Leave them for now. + private static synchronized URI getUserDir() throws URI.MalformedURIException { + // get the user.dir property + String userDir = ""; + try { + userDir = (String) AccessController.doPrivileged(GET_USER_DIR_SYSTEM_PROPERTY); + } + catch (SecurityException se) {} + + // return empty string if property value is empty string. + if (userDir.length() == 0) + return new URI("file", "", "", null, null); + + // compute the new escaped value if the new property value doesn't + // match the previous one + if (gUserDirURI != null && userDir.equals(gUserDir)) { + return gUserDirURI; + } + + // record the new value as the global property value + gUserDir = userDir; + + char separator = java.io.File.separatorChar; + userDir = userDir.replace(separator, '/'); + + int len = userDir.length(), ch; + StringBuffer buffer = new StringBuffer(len*3); + // change C:/blah to /C:/blah + if (len >= 2 && userDir.charAt(1) == ':') { + ch = Character.toUpperCase(userDir.charAt(0)); + if (ch >= 'A' && ch <= 'Z') { + buffer.append('/'); + } + } + + // for each character in the path + int i = 0; + for (; i < len; i++) { + ch = userDir.charAt(i); + // if it's not an ASCII character, break here, and use UTF-8 encoding + if (ch >= 128) + break; + if (gNeedEscaping[ch]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[ch]); + buffer.append(gAfterEscaping2[ch]); + // record the fact that it's escaped + } + else { + buffer.append((char)ch); + } + } + + // we saw some non-ascii character + if (i < len) { + // get UTF-8 bytes for the remaining sub-string + byte[] bytes = null; + byte b; + try { + bytes = userDir.substring(i).getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException e) { + // should never happen + return new URI("file", "", userDir, null, null); + } + len = bytes.length; + + // for each byte + for (i = 0; i < len; i++) { + b = bytes[i]; + // for non-ascii character: make it positive, then escape + if (b < 0) { + ch = b + 256; + buffer.append('%'); + buffer.append(gHexChs[ch >> 4]); + buffer.append(gHexChs[ch & 0xf]); + } + else if (gNeedEscaping[b]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[b]); + buffer.append(gAfterEscaping2[b]); + } + else { + buffer.append((char)b); + } + } + } + + // change blah/blah to blah/blah/ + if (!userDir.endsWith("/")) + buffer.append('/'); + + gUserDirURI = new URI("file", "", buffer.toString(), null, null); + + return gUserDirURI; + } + + /** + * Absolutizes a URI using the current value + * of the "user.dir" property as the base URI. If + * the URI is already absolute, this is a no-op. + * + * @param uri the URI to absolutize + */ + public static void absolutizeAgainstUserDir(URI uri) + throws URI.MalformedURIException { + uri.absolutize(getUserDir()); + } + + /** + * Expands a system id and returns the system id as a URI, if + * it can be expanded. A return value of null means that the + * identifier is already expanded. An exception thrown + * indicates a failure to expand the id. + * + * @param systemId The systemId to be expanded. + * + * @return Returns the URI string representing the expanded system + * identifier. A null value indicates that the given + * system identifier is already expanded. + * + */ + public static String expandSystemId(String systemId, String baseSystemId, + boolean strict) + throws URI.MalformedURIException { + + // check if there is a system id before + // trying to expand it. + if (systemId == null) { + return null; + } + + // system id has to be a valid URI + if (strict) { + return expandSystemIdStrictOn(systemId, baseSystemId); + } + + // Assume the URIs are well-formed. If it turns out they're not, try fixing them up. + try { + return expandSystemIdStrictOff(systemId, baseSystemId); + } + catch (URI.MalformedURIException e) { + // continue on... + } + + // check for bad parameters id + if (systemId.length() == 0) { + return systemId; + } + + // normalize id + String id = fixURI(systemId); + + // normalize base + URI base = null; + URI uri = null; + try { + if (baseSystemId == null || baseSystemId.length() == 0 || + baseSystemId.equals(systemId)) { + base = getUserDir(); + } + else { + try { + base = new URI(fixURI(baseSystemId).trim()); + } + catch (URI.MalformedURIException e) { + if (baseSystemId.indexOf(':') != -1) { + // for xml schemas we might have baseURI with + // a specified drive + base = new URI("file", "", fixURI(baseSystemId).trim(), null, null); + } + else { + base = new URI(getUserDir(), fixURI(baseSystemId)); + } + } + } + // expand id + uri = new URI(base, id.trim()); + } + catch (Exception e) { + // let it go through + + } + + if (uri == null) { + return systemId; + } + return uri.toString(); + + } // expandSystemId(String,String,boolean):String + + /** + * Helper method for expandSystemId(String,String,boolean):String + */ + private static String expandSystemIdStrictOn(String systemId, String baseSystemId) + throws URI.MalformedURIException { + + URI systemURI = new URI(systemId, true); + // If it's already an absolute one, return it + if (systemURI.isAbsoluteURI()) { + return systemId; + } + + // If there isn't a base URI, use the working directory + URI baseURI = null; + if (baseSystemId == null || baseSystemId.length() == 0) { + baseURI = getUserDir(); + } + else { + baseURI = new URI(baseSystemId, true); + if (!baseURI.isAbsoluteURI()) { + // assume "base" is also a relative uri + baseURI.absolutize(getUserDir()); + } + } + + // absolutize the system identifier using the base URI + systemURI.absolutize(baseURI); + + // return the string rep of the new uri (an absolute one) + return systemURI.toString(); + + // if any exception is thrown, it'll get thrown to the caller. + + } // expandSystemIdStrictOn(String,String):String + + /** + * Helper method for expandSystemId(String,String,boolean):String + */ + private static String expandSystemIdStrictOff(String systemId, String baseSystemId) + throws URI.MalformedURIException { + + URI systemURI = new URI(systemId, true); + // If it's already an absolute one, return it + if (systemURI.isAbsoluteURI()) { + if (systemURI.getScheme().length() > 1) { + return systemId; + } + /** + * If the scheme's length is only one character, + * it's likely that this was intended as a file + * path. Fixing this up in expandSystemId to + * maintain backwards compatibility. + */ + throw new URI.MalformedURIException(); + } + + // If there isn't a base URI, use the working directory + URI baseURI = null; + if (baseSystemId == null || baseSystemId.length() == 0) { + baseURI = getUserDir(); + } + else { + baseURI = new URI(baseSystemId, true); + if (!baseURI.isAbsoluteURI()) { + // assume "base" is also a relative uri + baseURI.absolutize(getUserDir()); + } + } + + // absolutize the system identifier using the base URI + systemURI.absolutize(baseURI); + + // return the string rep of the new uri (an absolute one) + return systemURI.toString(); + + // if any exception is thrown, it'll get thrown to the caller. + + } // expandSystemIdStrictOff(String,String):String + + public static OutputStream createOutputStream(String uri) throws IOException { + // URI was specified. Handle relative URIs. + final String expanded = XMLEntityManager.expandSystemId(uri, null, true); + final URL url = new URL(expanded != null ? expanded : uri); + OutputStream out = null; + String protocol = url.getProtocol(); + String host = url.getHost(); + // Use FileOutputStream if this URI is for a local file. + if (protocol.equals("file") + && (host == null || host.length() == 0 || host.equals("localhost"))) { + File file = new File(getPathWithoutEscapes(url.getPath())); + if (!file.exists()) { + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + parent.mkdirs(); + } + } + out = new FileOutputStream(file); + } + // Try to write to some other kind of URI. Some protocols + // won't support this, though HTTP should work. + else { + URLConnection urlCon = url.openConnection(); + urlCon.setDoInput(false); + urlCon.setDoOutput(true); + urlCon.setUseCaches(false); // Enable tunneling. + if (urlCon instanceof HttpURLConnection) { + // The DOM L3 REC says if we are writing to an HTTP URI + // it is to be done with an HTTP PUT. + HttpURLConnection httpCon = (HttpURLConnection) urlCon; + httpCon.setRequestMethod("PUT"); + } + out = urlCon.getOutputStream(); + } + return out; + } + + private static String getPathWithoutEscapes(String origPath) { + if (origPath != null && origPath.length() != 0 && origPath.indexOf('%') != -1) { + // Locate the escape characters + StringTokenizer tokenizer = new StringTokenizer(origPath, "%"); + StringBuffer result = new StringBuffer(origPath.length()); + int size = tokenizer.countTokens(); + result.append(tokenizer.nextToken()); + for(int i = 1; i < size; ++i) { + String token = tokenizer.nextToken(); + // Decode the 2 digit hexadecimal number following % in '%nn' + result.append((char)Integer.valueOf(token.substring(0, 2), 16).intValue()); + result.append(token.substring(2)); + } + return result.toString(); + } + return origPath; + } + + // + // Protected methods + // + + /** + * Ends an entity. + * + * @throws XNIException Thrown by entity handler to signal an error. + */ + void endEntity() throws XNIException { + + // call handler + if (DEBUG_BUFFER) { + System.out.print("(endEntity: "); + print(fCurrentEntity); + System.out.println(); + } + if (fEntityHandler != null) { + fEntityHandler.endEntity(fCurrentEntity.name, null); + } + + // Close the reader for the current entity once we're + // done with it, and remove it from our stack. If parsing + // is halted at some point, the rest of the readers on + // the stack will be closed during cleanup. + try { + fCurrentEntity.reader.close(); + } + catch (IOException e) { + // ignore + } + // REVISIT: We should never encounter underflow if the calls + // to startEntity and endEntity are balanced, but guard + // against the EmptyStackException for now. -- mrglavas + if (!fReaderStack.isEmpty()) { + fReaderStack.pop(); + } + + // Release the character buffer back to the pool for reuse + fCharacterBufferPool.returnBuffer(fCurrentEntity.fCharacterBuffer); + + // Release the byte buffer back to the pool for reuse + if (fCurrentEntity.fByteBuffer != null) { + if (fCurrentEntity.fByteBuffer.length == fBufferSize) { + fSmallByteBufferPool.returnBuffer(fCurrentEntity.fByteBuffer); + } + else { + fLargeByteBufferPool.returnBuffer(fCurrentEntity.fByteBuffer); + } + } + + // Pop entity stack. + fCurrentEntity = fEntityStack.size() > 0 + ? (ScannedEntity)fEntityStack.pop() : null; + fEntityScanner.setCurrentEntity(fCurrentEntity); + if (DEBUG_BUFFER) { + System.out.print(")endEntity: "); + print(fCurrentEntity); + System.out.println(); + } + + } // endEntity() + + /** + * Returns the IANA encoding name that is auto-detected from + * the bytes specified, with the endian-ness of that encoding where appropriate. + * + * @param b4 The first four bytes of the input. + * @param count The number of bytes actually read. + * @return an instance of EncodingInfo which represents the auto-detected encoding. + */ + protected EncodingInfo getEncodingInfo(byte[] b4, int count) { + + if (count < 2) { + return EncodingInfo.UTF_8; + } + + // UTF-16, with BOM + int b0 = b4[0] & 0xFF; + int b1 = b4[1] & 0xFF; + if (b0 == 0xFE && b1 == 0xFF) { + // UTF-16, big-endian + return EncodingInfo.UTF_16_BIG_ENDIAN_WITH_BOM; + } + if (b0 == 0xFF && b1 == 0xFE) { + // UTF-16, little-endian + return EncodingInfo.UTF_16_LITTLE_ENDIAN_WITH_BOM; + } + + // default to UTF-8 if we don't have enough bytes to make a + // good determination of the encoding + if (count < 3) { + return EncodingInfo.UTF_8; + } + + // UTF-8 with a BOM + int b2 = b4[2] & 0xFF; + if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { + return EncodingInfo.UTF_8_WITH_BOM; + } + + // default to UTF-8 if we don't have enough bytes to make a + // good determination of the encoding + if (count < 4) { + return EncodingInfo.UTF_8; + } + + // other encodings + int b3 = b4[3] & 0xFF; + if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { + // UCS-4, big endian (1234) + return EncodingInfo.UCS_4_BIG_ENDIAN; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { + // UCS-4, little endian (4321) + return EncodingInfo.UCS_4_LITTLE_ENDIAN; + } + if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { + // UCS-4, unusual octet order (2143) + // REVISIT: What should this be? + return EncodingInfo.UCS_4_UNUSUAL_BYTE_ORDER; + } + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { + // UCS-4, unusual octect order (3412) + // REVISIT: What should this be? + return EncodingInfo.UCS_4_UNUSUAL_BYTE_ORDER; + } + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { + // UTF-16, big-endian, no BOM + // (or could turn out to be UCS-2... + // REVISIT: What should this be? + return EncodingInfo.UTF_16_BIG_ENDIAN; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { + // UTF-16, little-endian, no BOM + // (or could turn out to be UCS-2... + return EncodingInfo.UTF_16_LITTLE_ENDIAN; + } + if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { + // EBCDIC + // a la xerces1, return CP037 instead of EBCDIC here + return EncodingInfo.EBCDIC; + } + + // default encoding + return EncodingInfo.UTF_8; + + } // getEncodingName(byte[],int):Object[] + + /** + * Creates a reader capable of reading the given input stream in + * the specified encoding. + * + * @param inputStream The input stream. + * @param encoding The encoding name that the input stream is + * encoded using. If the user has specified that + * Java encoding names are allowed, then the + * encoding name may be a Java encoding name; + * otherwise, it is an ianaEncoding name. + * @param isBigEndian For encodings (like uCS-4), whose names cannot + * specify a byte order, this tells whether the order is bigEndian. Null means + * unknown or not relevant. + * + * @return Returns a reader. + */ + protected Reader createReader(InputStream inputStream, String encoding, Boolean isBigEndian) + throws IOException { + + // if the encoding is UTF-8 use the optimized UTF-8 reader + if (encoding == "UTF-8" || encoding == null) { + return createUTF8Reader(inputStream); + } + + // If the encoding is UTF-16 use the optimized UTF-16 reader + if (encoding == "UTF-16" && isBigEndian != null) { + return createUTF16Reader(inputStream, isBigEndian.booleanValue()); + } + + // try to use an optimized reader + String ENCODING = encoding.toUpperCase(Locale.ENGLISH); + if (ENCODING.equals("UTF-8")) { + return createUTF8Reader(inputStream); + } + if (ENCODING.equals("UTF-16BE")) { + return createUTF16Reader(inputStream, true); + } + if (ENCODING.equals("UTF-16LE")) { + return createUTF16Reader(inputStream, false); + } + if (ENCODING.equals("ISO-10646-UCS-4")) { + if(isBigEndian != null) { + boolean isBE = isBigEndian.booleanValue(); + if(isBE) { + return new UCSReader(inputStream, UCSReader.UCS4BE); + } else { + return new UCSReader(inputStream, UCSReader.UCS4LE); + } + } else { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "EncodingByteOrderUnsupported", + new Object[] { encoding }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + if (ENCODING.equals("ISO-10646-UCS-2")) { + if(isBigEndian != null) { // should never happen with this encoding... + boolean isBE = isBigEndian.booleanValue(); + if(isBE) { + return new UCSReader(inputStream, UCSReader.UCS2BE); + } else { + return new UCSReader(inputStream, UCSReader.UCS2LE); + } + } else { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "EncodingByteOrderUnsupported", + new Object[] { encoding }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + + // check for valid name + boolean validIANA = XMLChar.isValidIANAEncoding(encoding); + boolean validJava = XMLChar.isValidJavaEncoding(encoding); + if (!validIANA || (fAllowJavaEncodings && !validJava)) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "EncodingDeclInvalid", + new Object[] { encoding }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + // NOTE: AndyH suggested that, on failure, we use ISO Latin 1 + // because every byte is a valid ISO Latin 1 character. + // It may not translate correctly but if we failed on + // the encoding anyway, then we're expecting the content + // of the document to be bad. This will just prevent an + // invalid UTF-8 sequence to be detected. This is only + // important when continue-after-fatal-error is turned + // on. -Ac + return createLatin1Reader(inputStream); + } + + // try to use a Java reader + String javaEncoding = EncodingMap.getIANA2JavaMapping(ENCODING); + if (javaEncoding == null) { + if (fAllowJavaEncodings) { + javaEncoding = encoding; + } + else { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "EncodingDeclInvalid", + new Object[] { encoding }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + // see comment above. + return createLatin1Reader(inputStream); + } + } + else if (javaEncoding.equals("ASCII")) { + return createASCIIReader(inputStream); + } + else if (javaEncoding.equals("ISO8859_1")) { + return createLatin1Reader(inputStream); + } + if (DEBUG_ENCODINGS) { + System.out.print("$$$ creating Java InputStreamReader: encoding="+javaEncoding); + if (javaEncoding == encoding) { + System.out.print(" (IANA encoding)"); + } + System.out.println(); + } + return new InputStreamReader(inputStream, javaEncoding); + + } // createReader(InputStream,String, Boolean): Reader + + /** Create a new UTF-8 reader from the InputStream. **/ + private Reader createUTF8Reader(InputStream stream) { + if (DEBUG_ENCODINGS) { + System.out.println("$$$ creating UTF8Reader"); + } + if (fTempByteBuffer == null) { + fTempByteBuffer = fSmallByteBufferPool.getBuffer(); + } + return new UTF8Reader(stream, + fTempByteBuffer, + fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), + fErrorReporter.getLocale()); + } // createUTF8Reader(InputStream):Reader + + /** Create a new UTF-16 reader from the InputStream. **/ + private Reader createUTF16Reader(InputStream stream, boolean isBigEndian) { + if (DEBUG_ENCODINGS) { + System.out.println("$$$ creating UTF16Reader"); + } + if (fTempByteBuffer == null) { + fTempByteBuffer = fLargeByteBufferPool.getBuffer(); + } + // The cached buffer is too small, we need a larger one. + else if (fTempByteBuffer.length == fBufferSize) { + fSmallByteBufferPool.returnBuffer(fTempByteBuffer); + fTempByteBuffer = fLargeByteBufferPool.getBuffer(); + } + return new UTF16Reader(stream, + fTempByteBuffer, + isBigEndian, + fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), + fErrorReporter.getLocale()); + } // createUTF16Reader(InputStream):Reader + + /** Create a new ASCII reader from the InputStream. **/ + private Reader createASCIIReader(InputStream stream) { + if (DEBUG_ENCODINGS) { + System.out.println("$$$ creating ASCIIReader"); + } + if (fTempByteBuffer == null) { + fTempByteBuffer = fSmallByteBufferPool.getBuffer(); + } + return new ASCIIReader(stream, + fTempByteBuffer, + fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), + fErrorReporter.getLocale()); + } // createASCIIReader(InputStream):Reader + + /** Create a new ISO-8859-1 reader from the InputStream. **/ + private Reader createLatin1Reader(InputStream stream) { + if (DEBUG_ENCODINGS) { + System.out.println("$$$ creating Latin1Reader"); + } + if (fTempByteBuffer == null) { + fTempByteBuffer = fSmallByteBufferPool.getBuffer(); + } + return new Latin1Reader(stream, fTempByteBuffer); + } // createLatin1Reader(InputStream):Reader + + // + // Protected static methods + // + + /** + * Fixes a platform dependent filename to standard URI form. + * + * @param str The string to fix. + * + * @return Returns the fixed URI string. + */ + protected static String fixURI(String str) { + + // handle platform dependent strings + str = str.replace(java.io.File.separatorChar, '/'); + + StringBuffer sb = null; + + // Windows fix + if (str.length() >= 2) { + char ch1 = str.charAt(1); + // change "C:blah" to "file:///C:blah" + if (ch1 == ':') { + char ch0 = Character.toUpperCase(str.charAt(0)); + if (ch0 >= 'A' && ch0 <= 'Z') { + sb = new StringBuffer(str.length() + 8); + sb.append("file:///"); + } + } + // change "//blah" to "file://blah" + else if (ch1 == '/' && str.charAt(0) == '/') { + sb = new StringBuffer(str.length() + 5); + sb.append("file:"); + } + } + + int pos = str.indexOf(' '); + // there is no space in the string + // we just append "str" to the end of sb + if (pos < 0) { + if (sb != null) { + sb.append(str); + str = sb.toString(); + } + } + // otherwise, convert all ' ' to "%20". + // Note: the following algorithm might not be very performant, + // but people who want to use invalid URI's have to pay the price. + else { + if (sb == null) + sb = new StringBuffer(str.length()); + // put characters before ' ' into the string buffer + for (int i = 0; i < pos; i++) + sb.append(str.charAt(i)); + // and %20 for the space + sb.append("%20"); + // for the remamining part, also convert ' ' to "%20". + for (int i = pos+1; i < str.length(); i++) { + if (str.charAt(i) == ' ') + sb.append("%20"); + else + sb.append(str.charAt(i)); + } + str = sb.toString(); + } + + // done + return str; + + } // fixURI(String):String + + // + // Package visible methods + // + + /** + * Returns the hashtable of declared entities. + *

+ * REVISIT: + * This should be done the "right" way by designing a better way to + * enumerate the declared entities. For now, this method is needed + * by the constructor that takes an XMLEntityManager parameter. + */ + Hashtable getDeclaredEntities() { + return fEntities; + } // getDeclaredEntities():Hashtable + + /** Prints the contents of the buffer. */ + static final void print(ScannedEntity currentEntity) { + if (DEBUG_BUFFER) { + if (currentEntity != null) { + System.out.print('['); + System.out.print(currentEntity.count); + System.out.print(' '); + System.out.print(currentEntity.position); + if (currentEntity.count > 0) { + System.out.print(" \""); + for (int i = 0; i < currentEntity.count; i++) { + if (i == currentEntity.position) { + System.out.print('^'); + } + char c = currentEntity.ch[i]; + switch (c) { + case '\n': { + System.out.print("\\n"); + break; + } + case '\r': { + System.out.print("\\r"); + break; + } + case '\t': { + System.out.print("\\t"); + break; + } + case '\\': { + System.out.print("\\\\"); + break; + } + default: { + System.out.print(c); + } + } + } + if (currentEntity.position == currentEntity.count) { + System.out.print('^'); + } + System.out.print('"'); + } + System.out.print(']'); + System.out.print(" @ "); + System.out.print(currentEntity.lineNumber); + System.out.print(','); + System.out.print(currentEntity.columnNumber); + } + else { + System.out.print("*NO CURRENT ENTITY*"); + } + } + } // print(ScannedEntity) + + // + // Classes + // + + /** + * Entity information. + * + * @xerces.internal + * + * @author Andy Clark, IBM + */ + public static abstract class Entity { + + // + // Data + // + + /** Entity name. */ + public String name; + + // whether this entity's declaration was found in the internal + // or external subset + public boolean inExternalSubset; + + // + // Constructors + // + + /** Default constructor. */ + public Entity() { + clear(); + } // () + + /** Constructs an entity. */ + public Entity(String name, boolean inExternalSubset) { + this.name = name; + this.inExternalSubset = inExternalSubset; + } // (String) + + // + // Public methods + // + + /** Returns true if this entity was declared in the external subset. */ + public boolean isEntityDeclInExternalSubset () { + return inExternalSubset; + } + + /** Returns true if this is an external entity. */ + public abstract boolean isExternal(); + + /** Returns true if this is an unparsed entity. */ + public abstract boolean isUnparsed(); + + /** Clears the entity. */ + public void clear() { + name = null; + inExternalSubset = false; + } // clear() + + /** Sets the values of the entity. */ + public void setValues(Entity entity) { + name = entity.name; + inExternalSubset = entity.inExternalSubset; + } // setValues(Entity) + + } // class Entity + + /** + * Internal entity. + * + * @xerces.internal + * + * @author Andy Clark, IBM + */ + protected static class InternalEntity + extends Entity { + + // + // Data + // + + /** Text value of entity. */ + public String text; + + /** Count of direct and indirect references to parameter entities in the value of the entity. */ + public int paramEntityRefs; + + // + // Constructors + // + + /** Default constructor. */ + public InternalEntity() { + clear(); + } // () + + /** Constructs an internal entity. */ + public InternalEntity(String name, String text, boolean inExternalSubset) { + super(name,inExternalSubset); + this.text = text; + } // (String,String) + + /** Constructs an internal entity. */ + public InternalEntity(String name, String text, boolean inExternalSubset, int paramEntityRefs) { + this(name, text, inExternalSubset); + this.paramEntityRefs = paramEntityRefs; + } // (String,String,int) + + // + // Entity methods + // + + /** Returns true if this is an external entity. */ + public final boolean isExternal() { + return false; + } // isExternal():boolean + + /** Returns true if this is an unparsed entity. */ + public final boolean isUnparsed() { + return false; + } // isUnparsed():boolean + + /** Clears the entity. */ + public void clear() { + super.clear(); + text = null; + } // clear() + + /** Sets the values of the entity. */ + public void setValues(Entity entity) { + super.setValues(entity); + text = null; + } // setValues(Entity) + + /** Sets the values of the entity. */ + public void setValues(InternalEntity entity) { + super.setValues(entity); + text = entity.text; + } // setValues(InternalEntity) + + } // class InternalEntity + + /** + * External entity. + * + * @xerces.internal + * + * @author Andy Clark, IBM + */ + protected static class ExternalEntity + extends Entity { + + // + // Data + // + + /** container for all relevant entity location information. */ + public XMLResourceIdentifier entityLocation; + + /** Notation name for unparsed entity. */ + public String notation; + + // + // Constructors + // + + /** Default constructor. */ + public ExternalEntity() { + clear(); + } // () + + /** Constructs an internal entity. */ + public ExternalEntity(String name, XMLResourceIdentifier entityLocation, + String notation, boolean inExternalSubset) { + super(name,inExternalSubset); + this.entityLocation = entityLocation; + this.notation = notation; + } // (String,XMLResourceIdentifier, String) + + // + // Entity methods + // + + /** Returns true if this is an external entity. */ + public final boolean isExternal() { + return true; + } // isExternal():boolean + + /** Returns true if this is an unparsed entity. */ + public final boolean isUnparsed() { + return notation != null; + } // isUnparsed():boolean + + /** Clears the entity. */ + public void clear() { + super.clear(); + entityLocation = null; + notation = null; + } // clear() + + /** Sets the values of the entity. */ + public void setValues(Entity entity) { + super.setValues(entity); + entityLocation = null; + notation = null; + } // setValues(Entity) + + /** Sets the values of the entity. */ + public void setValues(ExternalEntity entity) { + super.setValues(entity); + entityLocation = entity.entityLocation; + notation = entity.notation; + } // setValues(ExternalEntity) + + } // class ExternalEntity + + /** + * Entity state. + * + * @xerces.internal + * + * @author Andy Clark, IBM + */ + public class ScannedEntity + extends Entity { + + // + // Data + // + + // i/o + + /** Input stream. */ + public InputStream stream; + + /** Reader. */ + public Reader reader; + + // locator information + + /** entity location information */ + public XMLResourceIdentifier entityLocation; + + /** Line number. */ + public int lineNumber = 1; + + /** Column number. */ + public int columnNumber = 1; + + // encoding + + /** Auto-detected encoding. */ + public String encoding; + + /** + * Encoding has been set externally, for example + * using a SAX InputSource or a DOM LSInput. + */ + boolean externallySpecifiedEncoding = false; + + // version + + /** XML version. **/ + public String xmlVersion = "1.0"; + + // status + + /** True if in a literal. */ + public boolean literal; + + // whether this is an external or internal scanned entity + public boolean isExternal; + + // buffer + + /** Character buffer. */ + public char[] ch = null; + + /** Position in character buffer. */ + public int position; + + /** Base character offset for computing absolute character offset. */ + public int baseCharOffset; + + /** Start position in character buffer. */ + public int startPosition; + + /** Count of characters in buffer. */ + public int count; + + // to allow the reader/inputStream to behave efficiently: + public boolean mayReadChunks; + + /** Character buffer container. */ + private CharacterBuffer fCharacterBuffer; + + /** Byte buffer. */ + private byte [] fByteBuffer; + + // + // Constructors + // + + /** Constructs a scanned entity. */ + public ScannedEntity(String name, + XMLResourceIdentifier entityLocation, + InputStream stream, Reader reader, byte [] byteBuffer, + String encoding, boolean literal, boolean mayReadChunks, boolean isExternal) { + super(name,XMLEntityManager.this.fInExternalSubset); + this.entityLocation = entityLocation; + this.stream = stream; + this.reader = reader; + this.encoding = encoding; + this.literal = literal; + this.mayReadChunks = mayReadChunks; + this.isExternal = isExternal; + this.fCharacterBuffer = fCharacterBufferPool.getBuffer(isExternal); + this.ch = fCharacterBuffer.ch; + this.fByteBuffer = byteBuffer; + } // (StringXMLResourceIdentifier,InputStream,Reader,String,boolean, boolean) + + // + // Entity methods + // + + /** Returns true if this is an external entity. */ + public final boolean isExternal() { + return isExternal; + } // isExternal():boolean + + /** Returns true if this is an unparsed entity. */ + public final boolean isUnparsed() { + return false; + } // isUnparsed():boolean + + public void setReader(InputStream stream, String encoding, Boolean isBigEndian) throws IOException { + fTempByteBuffer = fByteBuffer; + reader = createReader(stream, encoding, isBigEndian); + fByteBuffer = fTempByteBuffer; + } + + // return the expanded system ID of the + // first external entity on the stack, null + // otherwise. + public String getExpandedSystemId() { + + // search for the first external entity on the stack + int size = fEntityStack.size(); + for (int i = size - 1; i >= 0; --i) { + ScannedEntity externalEntity = + (ScannedEntity)fEntityStack.elementAt(i); + + if (externalEntity.entityLocation != null && + externalEntity.entityLocation.getExpandedSystemId() != null) { + return externalEntity.entityLocation.getExpandedSystemId(); + } + } + return null; + } + + // return literal systemId of + // nearest external entity + public String getLiteralSystemId() { + // search for the first external entity on the stack + int size = fEntityStack.size(); + for (int i = size - 1; i >= 0; --i) { + ScannedEntity externalEntity = + (ScannedEntity)fEntityStack.elementAt(i); + + if (externalEntity.entityLocation != null && + externalEntity.entityLocation.getLiteralSystemId() != null) { + return externalEntity.entityLocation.getLiteralSystemId(); + } + } + return null; + } + + // return line number of position in most + // recent external entity + public int getLineNumber() { + // search for the first external entity on the stack + int size = fEntityStack.size(); + for (int i = size - 1; i >= 0 ; --i) { + ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i); + if (firstExternalEntity.isExternal()) { + return firstExternalEntity.lineNumber; + } + } + return -1; + } + + // return column number of position in most + // recent external entity + public int getColumnNumber() { + // search for the first external entity on the stack + int size = fEntityStack.size(); + for (int i = size - 1; i >= 0; --i) { + ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i); + if (firstExternalEntity.isExternal()) { + return firstExternalEntity.columnNumber; + } + } + return -1; + } + + // return character offset of position in most + // recent external entity + public int getCharacterOffset() { + // search for the first external entity on the stack + int size = fEntityStack.size(); + for (int i = size - 1; i >= 0; --i) { + ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i); + if (firstExternalEntity.isExternal()) { + return firstExternalEntity.baseCharOffset + (firstExternalEntity.position - firstExternalEntity.startPosition); + } + } + return -1; + } + + // return encoding of most recent external entity + public String getEncoding() { + // search for the first external entity on the stack + int size = fEntityStack.size(); + for (int i = size - 1; i >= 0; --i) { + ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i); + if (firstExternalEntity.isExternal()) { + return firstExternalEntity.encoding; + } + } + return null; + } + + // return xml version of most recent external entity + public String getXMLVersion() { + // search for the first external entity on the stack + int size = fEntityStack.size(); + for (int i = size - 1; i >= 0; --i) { + ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i); + if (firstExternalEntity.isExternal()) { + return firstExternalEntity.xmlVersion; + } + } + return null; + } + + /** Returns whether the encoding of this entity was externally specified. **/ + public boolean isEncodingExternallySpecified() { + return externallySpecifiedEncoding; + } + + /** Sets whether the encoding of this entity was externally specified. **/ + public void setEncodingExternallySpecified(boolean value) { + externallySpecifiedEncoding = value; + } + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + + StringBuffer str = new StringBuffer(); + str.append("name=\"").append(name).append('"'); + str.append(",ch="); + str.append(ch); + str.append(",position=").append(position); + str.append(",count=").append(count); + str.append(",baseCharOffset=").append(baseCharOffset); + str.append(",startPosition=").append(startPosition); + return str.toString(); + + } // toString():String + + } // class ScannedEntity + + /** + * Information about auto-detectable encodings. + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + */ + private static class EncodingInfo { + + /** UTF-8 **/ + public static final EncodingInfo UTF_8 = new EncodingInfo("UTF-8", null, false); + + /** UTF-8, with BOM **/ + public static final EncodingInfo UTF_8_WITH_BOM = new EncodingInfo("UTF-8", null, true); + + /** UTF-16, big-endian **/ + public static final EncodingInfo UTF_16_BIG_ENDIAN = new EncodingInfo("UTF-16BE", "UTF-16", Boolean.TRUE, false); + + /** UTF-16, big-endian with BOM **/ + public static final EncodingInfo UTF_16_BIG_ENDIAN_WITH_BOM = new EncodingInfo("UTF-16BE", "UTF-16", Boolean.TRUE, true); + + /** UTF-16, little-endian **/ + public static final EncodingInfo UTF_16_LITTLE_ENDIAN = new EncodingInfo("UTF-16LE", "UTF-16", Boolean.FALSE, false); + + /** UTF-16, little-endian with BOM **/ + public static final EncodingInfo UTF_16_LITTLE_ENDIAN_WITH_BOM = new EncodingInfo("UTF-16LE", "UTF-16", Boolean.FALSE, true); + + /** UCS-4, big-endian **/ + public static final EncodingInfo UCS_4_BIG_ENDIAN = new EncodingInfo("ISO-10646-UCS-4", Boolean.TRUE, false); + + /** UCS-4, little-endian **/ + public static final EncodingInfo UCS_4_LITTLE_ENDIAN = new EncodingInfo("ISO-10646-UCS-4", Boolean.FALSE, false); + + /** UCS-4, unusual byte-order (2143) or (3412) **/ + public static final EncodingInfo UCS_4_UNUSUAL_BYTE_ORDER = new EncodingInfo("ISO-10646-UCS-4", null, false); + + /** EBCDIC **/ + public static final EncodingInfo EBCDIC = new EncodingInfo("CP037", null, false); + + public final String autoDetectedEncoding; + public final String readerEncoding; + public final Boolean isBigEndian; + public final boolean hasBOM; + + private EncodingInfo(String autoDetectedEncoding, Boolean isBigEndian, boolean hasBOM) { + this(autoDetectedEncoding, autoDetectedEncoding, isBigEndian, hasBOM); + } // (String,Boolean,boolean) + + private EncodingInfo(String autoDetectedEncoding, String readerEncoding, Boolean isBigEndian, boolean hasBOM) { + this.autoDetectedEncoding = autoDetectedEncoding; + this.readerEncoding = readerEncoding; + this.isBigEndian = isBigEndian; + this.hasBOM = hasBOM; + } // (String,String,Boolean,boolean) + + } // class EncodingInfo + + /** + * Pool of byte buffers for the java.io.Readers. + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + */ + private static final class ByteBufferPool { + + private static final int DEFAULT_POOL_SIZE = 3; + + private int fPoolSize; + private int fBufferSize; + private byte[][] fByteBufferPool; + private int fDepth; + + public ByteBufferPool(int bufferSize) { + this(DEFAULT_POOL_SIZE, bufferSize); + } + + public ByteBufferPool(int poolSize, int bufferSize) { + fPoolSize = poolSize; + fBufferSize = bufferSize; + fByteBufferPool = new byte[fPoolSize][]; + fDepth = 0; + } + + /** Retrieves a byte buffer from the pool. **/ + public byte[] getBuffer() { + return (fDepth > 0) ? fByteBufferPool[--fDepth] : new byte[fBufferSize]; + } + + /** Returns byte buffer to pool. **/ + public void returnBuffer(byte[] buffer) { + if (fDepth < fByteBufferPool.length) { + fByteBufferPool[fDepth++] = buffer; + } + } + + /** Sets the size of the buffers and dumps the old pool. **/ + public void setBufferSize(int bufferSize) { + fBufferSize = bufferSize; + fByteBufferPool = new byte[fPoolSize][]; + fDepth = 0; + } + } + + /** + * Buffer used in entity manager to reuse character arrays instead + * of creating new ones every time. + * + * @xerces.internal + * + * @author Ankit Pasricha, IBM + */ + private static final class CharacterBuffer { + + /** character buffer */ + private final char[] ch; + + /** whether the buffer is for an external or internal scanned entity */ + private final boolean isExternal; + + public CharacterBuffer(boolean isExternal, int size) { + this.isExternal = isExternal; + ch = new char[size]; + } + } + + /** + * Stores a number of character buffers and provides it to the entity + * manager to use when an entity is seen. + * + * @xerces.internal + * + * @author Ankit Pasricha, IBM + */ + private static final class CharacterBufferPool { + + private static final int DEFAULT_POOL_SIZE = 3; + + private CharacterBuffer[] fInternalBufferPool; + private CharacterBuffer[] fExternalBufferPool; + + private int fExternalBufferSize; + private int fInternalBufferSize; + private int fPoolSize; + + private int fInternalTop; + private int fExternalTop; + + public CharacterBufferPool(int externalBufferSize, int internalBufferSize) { + this(DEFAULT_POOL_SIZE, externalBufferSize, internalBufferSize); + } + + public CharacterBufferPool(int poolSize, int externalBufferSize, int internalBufferSize) { + fExternalBufferSize = externalBufferSize; + fInternalBufferSize = internalBufferSize; + fPoolSize = poolSize; + init(); + } + + /** Initializes buffer pool. **/ + private void init() { + fInternalBufferPool = new CharacterBuffer[fPoolSize]; + fExternalBufferPool = new CharacterBuffer[fPoolSize]; + fInternalTop = -1; + fExternalTop = -1; + } + + /** Retrieves buffer from pool. **/ + public CharacterBuffer getBuffer(boolean external) { + if (external) { + if (fExternalTop > -1) { + return (CharacterBuffer)fExternalBufferPool[fExternalTop--]; + } + else { + return new CharacterBuffer(true, fExternalBufferSize); + } + } + else { + if (fInternalTop > -1) { + return (CharacterBuffer)fInternalBufferPool[fInternalTop--]; + } + else { + return new CharacterBuffer(false, fInternalBufferSize); + } + } + } + + /** Returns buffer to pool. **/ + public void returnBuffer(CharacterBuffer buffer) { + if (buffer.isExternal) { + if (fExternalTop < fExternalBufferPool.length - 1) { + fExternalBufferPool[++fExternalTop] = buffer; + } + } + else if (fInternalTop < fInternalBufferPool.length - 1) { + fInternalBufferPool[++fInternalTop] = buffer; + } + } + + /** Sets the size of external buffers and dumps the old pool. **/ + public void setExternalBufferSize(int bufferSize) { + fExternalBufferSize = bufferSize; + fExternalBufferPool = new CharacterBuffer[fPoolSize]; + fExternalTop = -1; + } + } + + /** + * This class wraps the byte inputstreams we're presented with. + * We need it because java.io.InputStreams don't provide + * functionality to reread processed bytes, and they have a habit + * of reading more than one character when you call their read() + * methods. This means that, once we discover the true (declared) + * encoding of a document, we can neither backtrack to read the + * whole doc again nor start reading where we are with a new + * reader. + * + * This class allows rewinding an inputStream by allowing a mark + * to be set, and the stream reset to that position. The + * class assumes that it needs to read one character per + * invocation when it's read() method is inovked, but uses the + * underlying InputStream's read(char[], offset length) method--it + * won't buffer data read this way! + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @author Glenn Marcy, IBM + */ + protected final class RewindableInputStream extends InputStream { + + private InputStream fInputStream; + private byte[] fData; + private int fStartOffset; + private int fEndOffset; + private int fOffset; + private int fLength; + private int fMark; + + public RewindableInputStream(InputStream is) { + fData = new byte[DEFAULT_XMLDECL_BUFFER_SIZE]; + fInputStream = is; + fStartOffset = 0; + fEndOffset = -1; + fOffset = 0; + fLength = 0; + fMark = 0; + } + + public void setStartOffset(int offset) { + fStartOffset = offset; + } + + public void rewind() { + fOffset = fStartOffset; + } + + public int readAndBuffer() throws IOException { + if (fOffset == fData.length) { + byte[] newData = new byte[fOffset << 1]; + System.arraycopy(fData, 0, newData, 0, fOffset); + fData = newData; + } + final int b = fInputStream.read(); + if (b == -1) { + fEndOffset = fOffset; + return -1; + } + fData[fLength++] = (byte)b; + fOffset++; + return b & 0xff; + } + + public int read() throws IOException { + if (fOffset < fLength) { + return fData[fOffset++] & 0xff; + } + if (fOffset == fEndOffset) { + return -1; + } + if (fCurrentEntity.mayReadChunks) { + return fInputStream.read(); + } + return readAndBuffer(); + } + + public int read(byte[] b, int off, int len) throws IOException { + final int bytesLeft = fLength - fOffset; + if (bytesLeft == 0) { + if (fOffset == fEndOffset) { + return -1; + } + // better get some more for the voracious reader... + if (fCurrentEntity.mayReadChunks) { + return fInputStream.read(b, off, len); + } + int returnedVal = readAndBuffer(); + if (returnedVal == -1) { + fEndOffset = fOffset; + return -1; + } + b[off] = (byte)returnedVal; + return 1; + } + if (len < bytesLeft) { + if (len <= 0) { + return 0; + } + } + else { + len = bytesLeft; + } + if (b != null) { + System.arraycopy(fData, fOffset, b, off, len); + } + fOffset += len; + return len; + } + + public long skip(long n) + throws IOException + { + int bytesLeft; + if (n <= 0) { + return 0; + } + bytesLeft = fLength - fOffset; + if (bytesLeft == 0) { + if (fOffset == fEndOffset) { + return 0; + } + return fInputStream.skip(n); + } + if (n <= bytesLeft) { + fOffset += n; + return n; + } + fOffset += bytesLeft; + if (fOffset == fEndOffset) { + return bytesLeft; + } + n -= bytesLeft; + /* + * In a manner of speaking, when this class isn't permitting more + * than one byte at a time to be read, it is "blocking". The + * available() method should indicate how much can be read without + * blocking, so while we're in this mode, it should only indicate + * that bytes in its buffer are available; otherwise, the result of + * available() on the underlying InputStream is appropriate. + */ + return fInputStream.skip(n) + bytesLeft; + } + + public int available() throws IOException { + final int bytesLeft = fLength - fOffset; + if (bytesLeft == 0) { + if (fOffset == fEndOffset) { + return -1; + } + return fCurrentEntity.mayReadChunks ? fInputStream.available() + : 0; + } + return bytesLeft; + } + + public void mark(int howMuch) { + fMark = fOffset; + } + + public void reset() { + fOffset = fMark; + } + + public boolean markSupported() { + return true; + } + + public void close() throws IOException { + if (fInputStream != null) { + fInputStream.close(); + fInputStream = null; + } + } + } // end of RewindableInputStream class + +} // class XMLEntityManager diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityScanner.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityScanner.java new file mode 100644 index 0000000..1e3e404 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLEntityScanner.java @@ -0,0 +1,1794 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.EOFException; +import java.io.IOException; +import java.util.Locale; + +import org.apache.xerces.impl.io.UCSReader; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLString; + +/** + * Implements the entity scanner methods. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @author Neil Graham, IBM + * @version $Id$ + */ +public class XMLEntityScanner implements XMLLocator { + + // constants + private static final boolean DEBUG_ENCODINGS = false; + private static final boolean DEBUG_BUFFER = false; + + /** + * To signal the end of the document entity, this exception will be thrown. + */ + private static final EOFException END_OF_DOCUMENT_ENTITY = new EOFException() { + private static final long serialVersionUID = 980337771224675268L; + public Throwable fillInStackTrace() { + return this; + } + }; + + // + // Data + // + + private XMLEntityManager fEntityManager = null; + protected XMLEntityManager.ScannedEntity fCurrentEntity = null; + + protected SymbolTable fSymbolTable = null; + + protected int fBufferSize = XMLEntityManager.DEFAULT_BUFFER_SIZE; + + /** + * Error reporter. This property identifier is: + * http://apache.org/xml/properties/internal/error-reporter + */ + protected XMLErrorReporter fErrorReporter; + // + // Constructors + // + + /** Default constructor. */ + public XMLEntityScanner() { + } // () + + // + // XMLEntityScanner methods + // + + /** + * Returns the base system identifier of the currently scanned + * entity, or null if none is available. + */ + public final String getBaseSystemId() { + return (fCurrentEntity != null && fCurrentEntity.entityLocation != null) ? fCurrentEntity.entityLocation.getExpandedSystemId() : null; + } // getBaseSystemId():String + + /** + * Sets the encoding of the scanner. This method is used by the + * scanners if the XMLDecl or TextDecl line contains an encoding + * pseudo-attribute. + *

+ * Note: The underlying character reader on the + * current entity will be changed to accomodate the new encoding. + * However, the new encoding is ignored if the current reader was + * not constructed from an input stream (e.g. an external entity + * that is resolved directly to the appropriate java.io.Reader + * object). + * + * @param encoding The IANA encoding name of the new encoding. + * + * @throws IOException Thrown if the new encoding is not supported. + * + * @see org.apache.xerces.util.EncodingMap + */ + public final void setEncoding(String encoding) throws IOException { + + if (DEBUG_ENCODINGS) { + System.out.println("$$$ setEncoding: "+encoding); + } + + if (fCurrentEntity.stream != null) { + // if the encoding is the same, don't change the reader and + // re-use the original reader used by the OneCharReader + // NOTE: Besides saving an object, this overcomes deficiencies + // in the UTF-16 reader supplied with the standard Java + // distribution (up to and including 1.3). The UTF-16 + // decoder buffers 8K blocks even when only asked to read + // a single char! -Ac + if (fCurrentEntity.encoding == null || + !fCurrentEntity.encoding.equals(encoding)) { + // UTF-16 is a bit of a special case. If the encoding is UTF-16, + // and we know the endian-ness, we shouldn't change readers. + // If it's ISO-10646-UCS-(2|4), then we'll have to deduce + // the endian-ness from the encoding we presently have. + if(fCurrentEntity.encoding != null && fCurrentEntity.encoding.startsWith("UTF-16")) { + String ENCODING = encoding.toUpperCase(Locale.ENGLISH); + if(ENCODING.equals("UTF-16")) return; + if(ENCODING.equals("ISO-10646-UCS-4")) { + if(fCurrentEntity.encoding.equals("UTF-16BE")) { + fCurrentEntity.reader = new UCSReader(fCurrentEntity.stream, UCSReader.UCS4BE); + } else { + fCurrentEntity.reader = new UCSReader(fCurrentEntity.stream, UCSReader.UCS4LE); + } + return; + } + if(ENCODING.equals("ISO-10646-UCS-2")) { + if(fCurrentEntity.encoding.equals("UTF-16BE")) { + fCurrentEntity.reader = new UCSReader(fCurrentEntity.stream, UCSReader.UCS2BE); + } else { + fCurrentEntity.reader = new UCSReader(fCurrentEntity.stream, UCSReader.UCS2LE); + } + return; + } + } + // wrap a new reader around the input stream, changing + // the encoding + if (DEBUG_ENCODINGS) { + System.out.println("$$$ creating new reader from stream: "+ + fCurrentEntity.stream); + } + //fCurrentEntity.stream.reset(); + fCurrentEntity.setReader(fCurrentEntity.stream, encoding, null); + fCurrentEntity.encoding = encoding; + } else { + if (DEBUG_ENCODINGS) + System.out.println("$$$ reusing old reader on stream"); + } + } + + } // setEncoding(String) + + /** + * Sets the XML version. This method is used by the + * scanners to report the value of the version pseudo-attribute + * in an XML or text declaration. + * + * @param xmlVersion the XML version of the current entity + */ + public final void setXMLVersion(String xmlVersion) { + fCurrentEntity.xmlVersion = xmlVersion; + } // setXMLVersion(String) + + /** Returns true if the current entity being scanned is external. */ + public final boolean isExternal() { + return fCurrentEntity.isExternal(); + } // isExternal():boolean + + /** + * Returns the next character on the input. + *

+ * Note: The character is not consumed. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int peekChar() throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(peekChar: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // peek at character + int c = fCurrentEntity.ch[fCurrentEntity.position]; + + // return peeked character + if (DEBUG_BUFFER) { + System.out.print(")peekChar: "); + XMLEntityManager.print(fCurrentEntity); + if (fCurrentEntity.isExternal()) { + System.out.println(" -> '"+(c!='\r'?(char)c:'\n')+"'"); + } + else { + System.out.println(" -> '"+(char)c+"'"); + } + } + if (fCurrentEntity.isExternal()) { + return c != '\r' ? c : '\n'; + } + else { + return c; + } + + } // peekChar():int + + /** + * Returns the next character on the input. + *

+ * Note: The character is consumed. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int scanChar() throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(scanChar: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan character + int c = fCurrentEntity.ch[fCurrentEntity.position++]; + boolean external = false; + if (c == '\n' || + (c == '\r' && (external = fCurrentEntity.isExternal()))) { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = (char)c; + load(1, false); + } + if (c == '\r' && external) { + if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') { + fCurrentEntity.position--; + } + c = '\n'; + } + } + + // return character that was scanned + if (DEBUG_BUFFER) { + System.out.print(")scanChar: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> '"+(char)c+"'"); + } + fCurrentEntity.columnNumber++; + return c; + + } // scanChar():int + + /** + * Returns a string matching the NMTOKEN production appearing immediately + * on the input as a symbol, or null if NMTOKEN Name string is present. + *

+ * Note: The NMTOKEN characters are consumed. + *

+ * Note: The string returned must be a symbol. The + * SymbolTable can be used for this purpose. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.SymbolTable + * @see org.apache.xerces.util.XMLChar#isName + */ + public String scanNmtoken() throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(scanNmtoken: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan nmtoken + int offset = fCurrentEntity.position; + while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + + // return nmtoken + String symbol = null; + if (length > 0) { + symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); + } + if (DEBUG_BUFFER) { + System.out.print(")scanNmtoken: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> "+String.valueOf(symbol)); + } + return symbol; + + } // scanNmtoken():String + + /** + * Returns a string matching the Name production appearing immediately + * on the input as a symbol, or null if no Name string is present. + *

+ * Note: The Name characters are consumed. + *

+ * Note: The string returned must be a symbol. The + * SymbolTable can be used for this purpose. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.SymbolTable + * @see org.apache.xerces.util.XMLChar#isName + * @see org.apache.xerces.util.XMLChar#isNameStart + */ + public String scanName() throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(scanName: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan name + int offset = fCurrentEntity.position; + if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[offset]; + offset = 0; + if (load(1, false)) { + fCurrentEntity.columnNumber++; + String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); + if (DEBUG_BUFFER) { + System.out.print(")scanName: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> "+String.valueOf(symbol)); + } + return symbol; + } + } + while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + + // return name + String symbol = null; + if (length > 0) { + symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); + } + if (DEBUG_BUFFER) { + System.out.print(")scanName: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> "+String.valueOf(symbol)); + } + return symbol; + + } // scanName():String + + /** + * Returns a string matching the NCName production appearing immediately + * on the input as a symbol, or null if no NCName string is present. + *

+ * Note: The NCName characters are consumed. + *

+ * Note: The string returned must be a symbol. The + * SymbolTable can be used for this purpose. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.SymbolTable + * @see org.apache.xerces.util.XMLChar#isNCName + * @see org.apache.xerces.util.XMLChar#isNCNameStart + */ + public String scanNCName() throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(scanNCName: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan name + int offset = fCurrentEntity.position; + if (XMLChar.isNCNameStart(fCurrentEntity.ch[offset])) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[offset]; + offset = 0; + if (load(1, false)) { + fCurrentEntity.columnNumber++; + String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); + if (DEBUG_BUFFER) { + System.out.print(")scanNCName: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> "+String.valueOf(symbol)); + } + return symbol; + } + } + while (XMLChar.isNCName(fCurrentEntity.ch[fCurrentEntity.position])) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + + // return name + String symbol = null; + if (length > 0) { + symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); + } + if (DEBUG_BUFFER) { + System.out.print(")scanNCName: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> "+String.valueOf(symbol)); + } + return symbol; + + } // scanNCName():String + + /** + * Scans a qualified name from the input, setting the fields of the + * QName structure appropriately. + *

+ * Note: The qualified name characters are consumed. + *

+ * Note: The strings used to set the values of the + * QName structure must be symbols. The SymbolTable can be used for + * this purpose. + * + * @param qname The qualified name structure to fill. + * + * @return Returns true if a qualified name appeared immediately on + * the input and was scanned, false otherwise. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.SymbolTable + * @see org.apache.xerces.util.XMLChar#isName + * @see org.apache.xerces.util.XMLChar#isNameStart + */ + public boolean scanQName(QName qname) throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(scanQName, "+qname+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan qualified name + int offset = fCurrentEntity.position; + if (XMLChar.isNCNameStart(fCurrentEntity.ch[offset])) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[offset]; + offset = 0; + if (load(1, false)) { + fCurrentEntity.columnNumber++; + String name = + fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); + qname.setValues(null, name, name, null); + if (DEBUG_BUFFER) { + System.out.print(")scanQName, "+qname+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> true"); + } + return true; + } + } + int index = -1; + while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) { + char c = fCurrentEntity.ch[fCurrentEntity.position]; + + if (c == ':') { + if (index != -1) { + break; + } + index = fCurrentEntity.position; + } + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fCurrentEntity.ch.length) { + // bad luck we have to resize our buffer + resizeBuffer(offset, length); + } + else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + if (index != -1) { + index = index - offset; + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + if (length > 0) { + String prefix = null; + String localpart = null; + String rawname = fSymbolTable.addSymbol(fCurrentEntity.ch, + offset, length); + if (index != -1) { + int prefixLength = index - offset; + prefix = fSymbolTable.addSymbol(fCurrentEntity.ch, + offset, prefixLength); + int len = length - prefixLength - 1; + int startLocal = index +1; + if (!XMLChar.isNCNameStart(fCurrentEntity.ch[startLocal])){ + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "IllegalQName", + null, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + localpart = fSymbolTable.addSymbol(fCurrentEntity.ch, + startLocal, len); + + } + else { + localpart = rawname; + } + qname.setValues(prefix, localpart, rawname, null); + if (DEBUG_BUFFER) { + System.out.print(")scanQName, "+qname+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> true"); + } + return true; + } + } + + // no qualified name found + if (DEBUG_BUFFER) { + System.out.print(")scanQName, "+qname+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> false"); + } + return false; + + } // scanQName(QName):boolean + + /** + * Scans a range of parsed character data, setting the fields of the + * XMLString structure, appropriately. + *

+ * Note: The characters are consumed. + *

+ * Note: This method does not guarantee to return + * the longest run of parsed character data. This method may return + * before markup due to reaching the end of the input buffer or any + * other reason. + *

+ * Note: The fields contained in the XMLString + * structure are not guaranteed to remain valid upon subsequent calls + * to the entity scanner. Therefore, the caller is responsible for + * immediately using the returned character data or making a copy of + * the character data. + * + * @param content The content structure to fill. + * + * @return Returns the next character on the input, if known. This + * value may be -1 but this does note designate + * end of file. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int scanContent(XMLString content) throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(scanContent: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; + load(1, false); + fCurrentEntity.position = 0; + fCurrentEntity.startPosition = 0; + } + + // normalize newlines + int offset = fCurrentEntity.position; + int c = fCurrentEntity.ch[offset]; + int newlines = 0; + boolean external = fCurrentEntity.isExternal(); + if (c == '\n' || (c == '\r' && external)) { + if (DEBUG_BUFFER) { + System.out.print("[newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + do { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == '\r' && external) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { + fCurrentEntity.position++; + offset++; + } + /*** NEWLINE NORMALIZATION ***/ + else { + newlines++; + } + } + else if (c == '\n') { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + } + else { + fCurrentEntity.position--; + break; + } + } while (fCurrentEntity.position < fCurrentEntity.count - 1); + for (int i = offset; i < fCurrentEntity.position; i++) { + fCurrentEntity.ch[i] = '\n'; + } + int length = fCurrentEntity.position - offset; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + content.setValues(fCurrentEntity.ch, offset, length); + if (DEBUG_BUFFER) { + System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + return -1; + } + if (DEBUG_BUFFER) { + System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + } + + // inner loop, scanning for content + while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (!XMLChar.isContent(c)) { + fCurrentEntity.position--; + break; + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + content.setValues(fCurrentEntity.ch, offset, length); + + // return next character + if (fCurrentEntity.position != fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position]; + // REVISIT: Does this need to be updated to fix the + // #x0D ^#x0A newline normalization problem? -Ac + if (c == '\r' && external) { + c = '\n'; + } + } + else { + c = -1; + } + if (DEBUG_BUFFER) { + System.out.print(")scanContent: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> '"+(char)c+"'"); + } + return c; + + } // scanContent(XMLString):int + + /** + * Scans a range of attribute value data, setting the fields of the + * XMLString structure, appropriately. + *

+ * Note: The characters are consumed. + *

+ * Note: This method does not guarantee to return + * the longest run of attribute value data. This method may return + * before the quote character due to reaching the end of the input + * buffer or any other reason. + *

+ * Note: The fields contained in the XMLString + * structure are not guaranteed to remain valid upon subsequent calls + * to the entity scanner. Therefore, the caller is responsible for + * immediately using the returned character data or making a copy of + * the character data. + * + * @param quote The quote character that signifies the end of the + * attribute value data. + * @param content The content structure to fill. + * + * @return Returns the next character on the input, if known. This + * value may be -1 but this does note designate + * end of file. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int scanLiteral(int quote, XMLString content) + throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(scanLiteral, '"+(char)quote+"': "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; + load(1, false); + fCurrentEntity.position = 0; + fCurrentEntity.startPosition = 0; + } + + // normalize newlines + int offset = fCurrentEntity.position; + int c = fCurrentEntity.ch[offset]; + int newlines = 0; + boolean external = fCurrentEntity.isExternal(); + if (c == '\n' || (c == '\r' && external)) { + if (DEBUG_BUFFER) { + System.out.print("[newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + do { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == '\r' && external) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { + fCurrentEntity.position++; + offset++; + } + /*** NEWLINE NORMALIZATION ***/ + else { + newlines++; + } + /***/ + } + else if (c == '\n') { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + } + else { + fCurrentEntity.position--; + break; + } + } while (fCurrentEntity.position < fCurrentEntity.count - 1); + for (int i = offset; i < fCurrentEntity.position; i++) { + fCurrentEntity.ch[i] = '\n'; + } + int length = fCurrentEntity.position - offset; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + content.setValues(fCurrentEntity.ch, offset, length); + if (DEBUG_BUFFER) { + System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + return -1; + } + if (DEBUG_BUFFER) { + System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + } + + // scan literal value + while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if ((c == quote && + (!fCurrentEntity.literal || external)) + || c == '%' || !XMLChar.isContent(c)) { + fCurrentEntity.position--; + break; + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + content.setValues(fCurrentEntity.ch, offset, length); + + // return next character + if (fCurrentEntity.position != fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position]; + // NOTE: We don't want to accidentally signal the + // end of the literal if we're expanding an + // entity appearing in the literal. -Ac + if (c == quote && fCurrentEntity.literal) { + c = -1; + } + } + else { + c = -1; + } + if (DEBUG_BUFFER) { + System.out.print(")scanLiteral, '"+(char)quote+"': "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> '"+(char)c+"'"); + } + return c; + + } // scanLiteral(int,XMLString):int + + /** + * Scans a range of character data up to the specified delimiter, + * setting the fields of the XMLString structure, appropriately. + *

+ * Note: The characters are consumed. + *

+ * Note: This assumes that the internal buffer is + * at least the same size, or bigger, than the length of the delimiter + * and that the delimiter contains at least one character. + *

+ * Note: This method does not guarantee to return + * the longest run of character data. This method may return before + * the delimiter due to reaching the end of the input buffer or any + * other reason. + *

+ * Note: The fields contained in the XMLString + * structure are not guaranteed to remain valid upon subsequent calls + * to the entity scanner. Therefore, the caller is responsible for + * immediately using the returned character data or making a copy of + * the character data. + * + * @param delimiter The string that signifies the end of the character + * data to be scanned. + * @param buffer The XMLStringBuffer to fill. + * + * @return Returns true if there is more data to scan, false otherwise. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean scanData(String delimiter, XMLStringBuffer buffer) + throws IOException { + + // REVISIT: This method does not need to use a string buffer. + // The change would avoid the array copies and increase + // performance. -Ac + // + // Currently, this method is called for scanning CDATA + // sections, comments, and processing instruction data. + // So if this code is updated to NOT buffer, the scanning + // code for comments and processing instructions will + // need to be updated to do its own buffering. The code + // for CDATA sections is safe as-is. -Ac + + boolean found = false; + int delimLen = delimiter.length(); + char charAt0 = delimiter.charAt(0); + boolean external = fCurrentEntity.isExternal(); + if (DEBUG_BUFFER) { + System.out.print("(scanData: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + boolean bNextEntity = false; + + while ((fCurrentEntity.position > fCurrentEntity.count - delimLen) + && (!bNextEntity)) + { + System.arraycopy(fCurrentEntity.ch, + fCurrentEntity.position, + fCurrentEntity.ch, + 0, + fCurrentEntity.count - fCurrentEntity.position); + + bNextEntity = load(fCurrentEntity.count - fCurrentEntity.position, false); + fCurrentEntity.position = 0; + fCurrentEntity.startPosition = 0; + } + + if (fCurrentEntity.position > fCurrentEntity.count - delimLen) { + // something must be wrong with the input: e.g., file ends in an unterminated comment + int length = fCurrentEntity.count - fCurrentEntity.position; + buffer.append (fCurrentEntity.ch, fCurrentEntity.position, length); + fCurrentEntity.columnNumber += fCurrentEntity.count; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = fCurrentEntity.count; + fCurrentEntity.startPosition = fCurrentEntity.count; + load(0,true); + return false; + } + + // normalize newlines + int offset = fCurrentEntity.position; + int c = fCurrentEntity.ch[offset]; + int newlines = 0; + if (c == '\n' || (c == '\r' && external)) { + if (DEBUG_BUFFER) { + System.out.print("[newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + do { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == '\r' && external) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + if (load(newlines, false)) { + break; + } + } + if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { + fCurrentEntity.position++; + offset++; + } + /*** NEWLINE NORMALIZATION ***/ + else { + newlines++; + } + } + else if (c == '\n') { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + fCurrentEntity.position = newlines; + fCurrentEntity.startPosition = newlines; + fCurrentEntity.count = newlines; + if (load(newlines, false)) { + break; + } + } + } + else { + fCurrentEntity.position--; + break; + } + } while (fCurrentEntity.position < fCurrentEntity.count - 1); + for (int i = offset; i < fCurrentEntity.position; i++) { + fCurrentEntity.ch[i] = '\n'; + } + int length = fCurrentEntity.position - offset; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + buffer.append(fCurrentEntity.ch, offset, length); + if (DEBUG_BUFFER) { + System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + return true; + } + if (DEBUG_BUFFER) { + System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + } + + // iterate over buffer looking for delimiter + OUTER: while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == charAt0) { + // looks like we just hit the delimiter + int delimOffset = fCurrentEntity.position - 1; + for (int i = 1; i < delimLen; i++) { + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.position -= i; + break OUTER; + } + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (delimiter.charAt(i) != c) { + fCurrentEntity.position--; + break; + } + } + if (fCurrentEntity.position == delimOffset + delimLen) { + found = true; + break; + } + } + else if (c == '\n' || (external && c == '\r')) { + fCurrentEntity.position--; + break; + } + else if (XMLChar.isInvalid(c)) { + fCurrentEntity.position--; + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + buffer.append(fCurrentEntity.ch, offset, length); + return true; + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + if (found) { + length -= delimLen; + } + buffer.append (fCurrentEntity.ch, offset, length); + + // return true if string was skipped + if (DEBUG_BUFFER) { + System.out.print(")scanData: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> " + !found); + } + return !found; + + } // scanData(String,XMLString):boolean + + /** + * Skips a character appearing immediately on the input. + *

+ * Note: The character is consumed only if it matches + * the specified character. + * + * @param c The character to skip. + * + * @return Returns true if the character was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean skipChar(int c) throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(skipChar, '"+(char)c+"': "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip character + int cc = fCurrentEntity.ch[fCurrentEntity.position]; + if (cc == c) { + fCurrentEntity.position++; + if (c == '\n') { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + } + else { + fCurrentEntity.columnNumber++; + } + if (DEBUG_BUFFER) { + System.out.print(")skipChar, '"+(char)c+"': "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> true"); + } + return true; + } + else if (c == '\n' && cc == '\r' && fCurrentEntity.isExternal()) { + // handle newlines + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = (char)cc; + load(1, false); + } + fCurrentEntity.position++; + if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { + fCurrentEntity.position++; + } + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (DEBUG_BUFFER) { + System.out.print(")skipChar, '"+(char)c+"': "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> true"); + } + return true; + } + + // character was not skipped + if (DEBUG_BUFFER) { + System.out.print(")skipChar, '"+(char)c+"': "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> false"); + } + return false; + + } // skipChar(int):boolean + + /** + * Skips space characters appearing immediately on the input. + *

+ * Note: The characters are consumed only if they are + * space characters. + * + * @return Returns true if at least one space character was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.XMLChar#isSpace + */ + public boolean skipSpaces() throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(skipSpaces: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip spaces + int c = fCurrentEntity.ch[fCurrentEntity.position]; + if (XMLChar.isSpace(c)) { + boolean external = fCurrentEntity.isExternal(); + do { + boolean entityChanged = false; + // handle newlines + if (c == '\n' || (external && c == '\r')) { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = (char)c; + entityChanged = load(1, true); + if (!entityChanged) { + // the load change the position to be 1, + // need to restore it when entity not changed + fCurrentEntity.position = 0; + fCurrentEntity.startPosition = 0; + } + } + if (c == '\r' && external) { + // REVISIT: Does this need to be updated to fix the + // #x0D ^#x0A newline normalization problem? -Ac + if (fCurrentEntity.ch[++fCurrentEntity.position] != '\n') { + fCurrentEntity.position--; + } + } + /*** NEWLINE NORMALIZATION *** + else { + if (fCurrentEntity.ch[fCurrentEntity.position + 1] == '\r' + && external) { + fCurrentEntity.position++; + } + } + /***/ + } + else { + fCurrentEntity.columnNumber++; + } + // load more characters, if needed + if (!entityChanged) + fCurrentEntity.position++; + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position])); + if (DEBUG_BUFFER) { + System.out.print(")skipSpaces: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> true"); + } + return true; + } + + // no spaces were found + if (DEBUG_BUFFER) { + System.out.print(")skipSpaces: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> false"); + } + return false; + + } // skipSpaces():boolean + + /** + * Skips space characters appearing immediately on the input that would + * match non-terminal S (0x09, 0x0A, 0x0D, 0x20) before end of line + * normalization is performed. This is useful when scanning structures + * such as the XMLDecl and TextDecl that can only contain US-ASCII + * characters. + *

+ * Note: The characters are consumed only if they would + * match non-terminal S before end of line normalization is performed. + * + * @return Returns true if at least one space character was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see org.apache.xerces.util.XMLChar#isSpace + */ + public final boolean skipDeclSpaces() throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(skipDeclSpaces: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip spaces + int c = fCurrentEntity.ch[fCurrentEntity.position]; + if (XMLChar.isSpace(c)) { + boolean external = fCurrentEntity.isExternal(); + do { + boolean entityChanged = false; + // handle newlines + if (c == '\n' || (external && c == '\r')) { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = (char)c; + entityChanged = load(1, true); + if (!entityChanged) { + // the load change the position to be 1, + // need to restore it when entity not changed + fCurrentEntity.position = 0; + fCurrentEntity.startPosition = 0; + } + } + if (c == '\r' && external) { + // REVISIT: Does this need to be updated to fix the + // #x0D ^#x0A newline normalization problem? -Ac + if (fCurrentEntity.ch[++fCurrentEntity.position] != '\n') { + fCurrentEntity.position--; + } + } + /*** NEWLINE NORMALIZATION *** + else { + if (fCurrentEntity.ch[fCurrentEntity.position + 1] == '\r' + && external) { + fCurrentEntity.position++; + } + } + /***/ + } + else { + fCurrentEntity.columnNumber++; + } + // load more characters, if needed + if (!entityChanged) + fCurrentEntity.position++; + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position])); + if (DEBUG_BUFFER) { + System.out.print(")skipDeclSpaces: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> true"); + } + return true; + } + + // no spaces were found + if (DEBUG_BUFFER) { + System.out.print(")skipDeclSpaces: "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> false"); + } + return false; + + } // skipDeclSpaces():boolean + + /** + * Skips the specified string appearing immediately on the input. + *

+ * Note: The characters are consumed only if they are + * space characters. + * + * @param s The string to skip. + * + * @return Returns true if the string was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean skipString(String s) throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(skipString, \""+s+"\": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip string + final int length = s.length(); + for (int i = 0; i < length; i++) { + char c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c != s.charAt(i)) { + fCurrentEntity.position -= i + 1; + if (DEBUG_BUFFER) { + System.out.print(")skipString, \""+s+"\": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> false"); + } + return false; + } + if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) { + System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1); + // REVISIT: Can a string to be skipped cross an + // entity boundary? -Ac + if (load(i + 1, false)) { + fCurrentEntity.startPosition -= i + 1; + fCurrentEntity.position -= i + 1; + if (DEBUG_BUFFER) { + System.out.print(")skipString, \""+s+"\": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> false"); + } + return false; + } + } + } + if (DEBUG_BUFFER) { + System.out.print(")skipString, \""+s+"\": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(" -> true"); + } + fCurrentEntity.columnNumber += length; + return true; + + } // skipString(String):boolean + + // + // Locator methods + // + + /** + * 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 + * triggering the event appears. + * + * @return A string containing the public identifier, or + * null if none is available. + */ + public final String getPublicId() { + return (fCurrentEntity != null && fCurrentEntity.entityLocation != null) ? fCurrentEntity.entityLocation.getPublicId() : null; + } // getPublicId():String + + /** + * Return the expanded system identifier for the current document event. + *

+ * The return value is the expanded 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. + * + * @return A string containing the expanded system identifier, or null + * if none is available. + */ + public final String getExpandedSystemId() { + if (fCurrentEntity != null) { + if (fCurrentEntity.entityLocation != null && + fCurrentEntity.entityLocation.getExpandedSystemId() != null ) { + return fCurrentEntity.entityLocation.getExpandedSystemId(); + } + else { + // get the current entity to return something appropriate: + return fCurrentEntity.getExpandedSystemId(); + } + } + return null; + } // getExpandedSystemId():String + + /** + * Return the literal system identifier for the current document event. + *

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

+ * @return A string containing the literal system identifier, or null + * if none is available. + */ + public final String getLiteralSystemId() { + if (fCurrentEntity != null) { + if (fCurrentEntity.entityLocation != null && + fCurrentEntity.entityLocation.getLiteralSystemId() != null ) { + return fCurrentEntity.entityLocation.getLiteralSystemId(); + } + else { + // get the current entity to do it: + return fCurrentEntity.getLiteralSystemId(); + } + } + return null; + } // getLiteralSystemId():String + + /** + * Returns 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 triggering the event appears. + *

+ * If possible, the line position of the first character after the + * text associated with the document event should be provided. + * The first line in the document is line 1. + * + * @return The line number, or -1 if none is available. + */ + public final int getLineNumber() { + if (fCurrentEntity != null) { + if (fCurrentEntity.isExternal()) { + return fCurrentEntity.lineNumber; + } + else { + // ask the current entity to return something appropriate: + return fCurrentEntity.getLineNumber(); + } + } + + return -1; + + } // getLineNumber():int + + /** + * Returns the column 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 column number + * in the document entity or external parsed entity where the + * markup triggering the event appears. + *

+ * If possible, the line position of the first character after the + * text associated with the document event should be provided. + * The first column in each line is column 1. + * + * @return The column number, or -1 if none is available. + */ + public final int getColumnNumber() { + if (fCurrentEntity != null) { + if (fCurrentEntity.isExternal()) { + return fCurrentEntity.columnNumber; + } + else { + // ask current entity to find appropriate column number + return fCurrentEntity.getColumnNumber(); + } + } + + return -1; + } // getColumnNumber():int + + /** + * Returns the character offset 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 character offset + * in the document entity or external parsed entity where the + * markup triggering the event appears. + *

+ * If possible, the character offset of the first character after the + * text associated with the document event should be provided. + * + * @return The character offset, or -1 if none is available. + */ + public final int getCharacterOffset() { + if (fCurrentEntity != null) { + if (fCurrentEntity.isExternal()) { + return fCurrentEntity.baseCharOffset + (fCurrentEntity.position - fCurrentEntity.startPosition); + } + else { + // ask current entity to find appropriate character offset + return fCurrentEntity.getCharacterOffset(); + } + } + + return -1; + } // getCharacterOffset():int + + /** + * Returns the encoding of the current entity. + * Note that, for a given entity, this value can only be + * considered final once the encoding declaration has been read (or once it + * has been determined that there is no such declaration) since, no encoding + * having been specified on the XMLInputSource, the parser + * will make an initial "guess" which could be in error. + */ + public final String getEncoding() { + if (fCurrentEntity != null) { + if (fCurrentEntity.isExternal()) { + return fCurrentEntity.encoding; + } + else { + // ask current entity to find appropriate encoding + return fCurrentEntity.getEncoding(); + } + } + return null; + } // getEncoding():String + + /** + * Returns the XML version of the current entity. This will normally be the + * value from the XML or text declaration or defaulted by the parser. Note that + * that this value may be different than the version of the processing rules + * applied to the current entity. For instance, an XML 1.1 document may refer to + * XML 1.0 entities. In such a case the rules of XML 1.1 are applied to the entire + * document. Also note that, for a given entity, this value can only be considered + * final once the XML or text declaration has been read or once it has been + * determined that there is no such declaration. + */ + public final String getXMLVersion() { + if (fCurrentEntity != null) { + if (fCurrentEntity.isExternal()) { + return fCurrentEntity.xmlVersion; + } + else { + // ask current entity to find the appropriate XML version + return fCurrentEntity.getXMLVersion(); + } + } + return null; + } // getXMLVersion():String + + // allow entity manager to tell us what the current entityis: + public final void setCurrentEntity(XMLEntityManager.ScannedEntity ent) { + fCurrentEntity = ent; + } + + // set buffer size: + public final void setBufferSize(int size) { + // REVISIT: Buffer size passed to entity scanner + // was not being kept in synch with the actual size + // of the buffers in each scanned entity. If any + // of the buffers were actually resized, it was possible + // that the parser would throw an ArrayIndexOutOfBoundsException + // for documents which contained names which are longer than + // the current buffer size. Conceivably the buffer size passed + // to entity scanner could be used to determine a minimum size + // for resizing, if doubling its size is smaller than this + // minimum. -- mrglavas + fBufferSize = size; + } + + // reset what little state we have... + public final void reset(SymbolTable symbolTable, XMLEntityManager entityManager, + XMLErrorReporter reporter) { + fCurrentEntity = null; + fSymbolTable = symbolTable; + fEntityManager = entityManager; + fErrorReporter = reporter; + } + + // + // Private methods + // + + /** + * Loads a chunk of text. + * + * @param offset The offset into the character buffer to + * read the next batch of characters. + * @param changeEntity True if the load should change entities + * at the end of the entity, otherwise leave + * the current entity in place and the entity + * boundary will be signaled by the return + * value. + * + * @returns Returns true if the entity changed as a result of this + * load operation. + */ + final boolean load(int offset, boolean changeEntity) + throws IOException { + if (DEBUG_BUFFER) { + System.out.print("(load, "+offset+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition); + // read characters + int length = fCurrentEntity.ch.length - offset; + if (!fCurrentEntity.mayReadChunks && length > XMLEntityManager.DEFAULT_XMLDECL_BUFFER_SIZE) { + length = XMLEntityManager.DEFAULT_XMLDECL_BUFFER_SIZE; + } + if (DEBUG_BUFFER) System.out.println(" length to try to read: "+length); + int count = fCurrentEntity.reader.read(fCurrentEntity.ch, offset, length); + if (DEBUG_BUFFER) System.out.println(" length actually read: "+count); + + // reset count and position + boolean entityChanged = false; + if (count != -1) { + if (count != 0) { + fCurrentEntity.count = count + offset; + fCurrentEntity.position = offset; + fCurrentEntity.startPosition = offset; + } + } + + // end of this entity + else { + fCurrentEntity.count = offset; + fCurrentEntity.position = offset; + fCurrentEntity.startPosition = offset; + entityChanged = true; + if (changeEntity) { + fEntityManager.endEntity(); + if (fCurrentEntity == null) { + throw END_OF_DOCUMENT_ENTITY; + } + // handle the trailing edges + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + } + } + if (DEBUG_BUFFER) { + System.out.print(")load, "+offset+": "); + XMLEntityManager.print(fCurrentEntity); + System.out.println(); + } + + return entityChanged; + + } // load(int, boolean):boolean + + /** + * This method is invoked to increase the size of the current entity's + * buffer if an XML name being scanned is too large to fit within + * the buffer at its current size. + */ + final void resizeBuffer(int offset, int length) { + char[] tmp = new char[fCurrentEntity.ch.length << 1]; + System.arraycopy(fCurrentEntity.ch, offset, + tmp, 0, length); + fCurrentEntity.ch = tmp; + } // resizeBuffer(int, int) + +} // class XMLEntityScanner + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLErrorReporter.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLErrorReporter.java new file mode 100644 index 0000000..f23da71 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLErrorReporter.java @@ -0,0 +1,615 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.util.Hashtable; +import java.util.Locale; + +import org.apache.xerces.util.DefaultErrorHandler; +import org.apache.xerces.util.ErrorHandlerProxy; +import org.apache.xerces.util.MessageFormatter; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLParseException; +import org.xml.sax.ErrorHandler; + +/** + * This class is a common element of all parser configurations and is + * used to report errors that occur. This component can be queried by + * parser components from the component manager using the following + * property ID: + *

+ *   http://apache.org/xml/properties/internal/error-reporter
+ * 
+ *

+ * Errors are separated into domains that categorize a class of errors. + * In a parser configuration, the parser would register a + * MessageFormatter for each domain that is capable of + * localizing error messages and formatting them based on information + * about the error. Any parser component can invent new error domains + * and register additional message formatters to localize messages in + * those domains. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://apache.org/xml/properties/internal/error-handler
  • + *
+ *

+ * This component can use the following features and properties but they + * are not required: + *

    + *
  • http://apache.org/xml/features/continue-after-fatal-error
  • + *
+ * + * @xerces.internal + * + * @see MessageFormatter + * + * @author Eric Ye, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XMLErrorReporter + implements XMLComponent { + + // + // Constants + // + + // severity + + /** + * Severity: warning. Warnings represent informational messages only + * that should not be considered serious enough to stop parsing or + * indicate an error in the document's validity. + */ + public static final short SEVERITY_WARNING = 0; + + /** + * Severity: error. Common causes of errors are document structure and/or + * content that that does not conform to the grammar rules specified for + * the document. These are typically validation errors. + */ + public static final short SEVERITY_ERROR = 1; + + /** + * Severity: fatal error. Fatal errors are errors in the syntax of the + * XML document or invalid byte sequences for a given encoding. The + * XML 1.0 Specification mandates that errors of this type are not + * recoverable. + *

+ * Note: The parser does have a "continue after fatal + * error" feature but it should be used with extreme caution and care. + */ + public static final short SEVERITY_FATAL_ERROR = 2; + + // feature identifiers + + /** Feature identifier: continue after fatal error. */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + // property identifiers + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + CONTINUE_AFTER_FATAL_ERROR, + }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { + null, + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + ERROR_HANDLER, + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { + null, + }; + + // + // Data + // + + /** The locale to be used to format error messages. */ + protected Locale fLocale; + + /** Mapping of Message formatters for domains. */ + protected Hashtable fMessageFormatters; + + /** Error handler. */ + protected XMLErrorHandler fErrorHandler; + + /** Document locator. */ + protected XMLLocator fLocator; + + /** Continue after fatal error feature. */ + protected boolean fContinueAfterFatalError; + + /** + * Default error handler. This error handler is only used in the + * absence of a registered error handler so that errors are not + * "swallowed" silently. This is one of the most common "problems" + * reported by users of the parser. + */ + protected XMLErrorHandler fDefaultErrorHandler; + + /** A SAX proxy to the error handler contained in this error reporter. */ + private ErrorHandler fSaxProxy = null; + + // + // Constructors + // + + /** Constructs an error reporter with a locator. */ + public XMLErrorReporter() { + + // REVISIT: [Q] Should the locator be passed to the reportError + // method? Otherwise, there is no way for a parser + // component to store information about where an + // error occurred so as to report it later. + // + // An example would be to record the location of + // IDREFs so that, at the end of the document, if + // there is no associated ID declared, the error + // could report the location information of the + // reference. -Ac + // + // NOTE: I added another reportError method that allows the + // caller to specify the location of the error being + // reported. -Ac + + fMessageFormatters = new Hashtable(); + + } // () + + // + // Methods + // + + /** + * Sets the current locale. + * + * @param locale The new locale. + */ + public void setLocale(Locale locale) { + fLocale = locale; + } // setLocale(Locale) + + /** + * Gets the current locale. + * + * @return the current Locale + */ + public Locale getLocale() { + return fLocale ; + } // getLocale(): Locale + + /** + * Sets the document locator. + * + * @param locator The locator. + */ + public void setDocumentLocator(XMLLocator locator) { + fLocator = locator; + } // setDocumentLocator(XMLLocator) + + /** + * Registers a message formatter for the specified domain. + *

+ * Note: Registering a message formatter for a domain + * when there is already a formatter registered will cause the previous + * formatter to be lost. This method replaces any previously registered + * message formatter for the specified domain. + * + * @param domain + * @param messageFormatter + */ + public void putMessageFormatter(String domain, + MessageFormatter messageFormatter) { + fMessageFormatters.put(domain, messageFormatter); + } // putMessageFormatter(String,MessageFormatter) + + /** + * Returns the message formatter associated with the specified domain, + * or null if no message formatter is registered for that domain. + * + * @param domain The domain of the message formatter. + */ + public MessageFormatter getMessageFormatter(String domain) { + return (MessageFormatter)fMessageFormatters.get(domain); + } // getMessageFormatter(String):MessageFormatter + + /** + * Removes the message formatter for the specified domain and + * returns the removed message formatter. + * + * @param domain The domain of the message formatter. + */ + public MessageFormatter removeMessageFormatter(String domain) { + return (MessageFormatter) fMessageFormatters.remove(domain); + } // removeMessageFormatter(String):MessageFormatter + + /** + * Reports an error. The error message passed to the error handler + * is formatted for the locale by the message formatter installed + * for the specified error domain. + * + * @param domain The error domain. + * @param key The key of the error message. + * @param arguments The replacement arguments for the error message, + * if needed. + * @param severity The severity of the error. + * @return The formatted error message. + * + * @see #SEVERITY_WARNING + * @see #SEVERITY_ERROR + * @see #SEVERITY_FATAL_ERROR + */ + public String reportError(String domain, String key, Object[] arguments, + short severity) throws XNIException { + return reportError(fLocator, domain, key, arguments, severity); + } // reportError(String,String,Object[],short):String + + /** + * Reports an error. The error message passed to the error handler + * is formatted for the locale by the message formatter installed + * for the specified error domain. + * + * @param domain The error domain. + * @param key The key of the error message. + * @param arguments The replacement arguments for the error message, + * if needed. + * @param severity The severity of the error. + * @param exception The exception to wrap. + * @return The formatted error message. + * + * @see #SEVERITY_WARNING + * @see #SEVERITY_ERROR + * @see #SEVERITY_FATAL_ERROR + */ + public String reportError(String domain, String key, Object[] arguments, + short severity, Exception exception) throws XNIException { + return reportError(fLocator, domain, key, arguments, severity, exception); + } // reportError(String,String,Object[],short,Exception):String + + /** + * Reports an error at a specific location. + * + * @param location The error location. + * @param domain The error domain. + * @param key The key of the error message. + * @param arguments The replacement arguments for the error message, + * if needed. + * @param severity The severity of the error. + * @return The formatted error message. + * + * @see #SEVERITY_WARNING + * @see #SEVERITY_ERROR + * @see #SEVERITY_FATAL_ERROR + */ + public String reportError(XMLLocator location, + String domain, String key, Object[] arguments, + short severity) throws XNIException { + return reportError(location, domain, key, arguments, severity, null); + } // reportError(XMLLocator,String,String,Object[],short):String + + /** + * Reports an error at a specific location. + * + * @param location The error location. + * @param domain The error domain. + * @param key The key of the error message. + * @param arguments The replacement arguments for the error message, + * if needed. + * @param severity The severity of the error. + * @param exception The exception to wrap. + * @return The formatted error message. + * + * @see #SEVERITY_WARNING + * @see #SEVERITY_ERROR + * @see #SEVERITY_FATAL_ERROR + */ + public String reportError(XMLLocator location, + String domain, String key, Object[] arguments, + short severity, Exception exception) throws XNIException { + + // REVISIT: [Q] Should we do anything about invalid severity + // parameter? -Ac + + // format error message and create parse exception + MessageFormatter messageFormatter = getMessageFormatter(domain); + String message; + if (messageFormatter != null) { + message = messageFormatter.formatMessage(fLocale, key, arguments); + } + else { + StringBuffer str = new StringBuffer(); + str.append(domain); + str.append('#'); + str.append(key); + int argCount = arguments != null ? arguments.length : 0; + if (argCount > 0) { + str.append('?'); + for (int i = 0; i < argCount; i++) { + str.append(arguments[i]); + if (i < argCount -1) { + str.append('&'); + } + } + } + message = str.toString(); + } + XMLParseException parseException = (exception != null) ? + new XMLParseException(location, message, exception) : + new XMLParseException(location, message); + + // get error handler + XMLErrorHandler errorHandler = fErrorHandler; + if (errorHandler == null) { + if (fDefaultErrorHandler == null) { + fDefaultErrorHandler = new DefaultErrorHandler(); + } + errorHandler = fDefaultErrorHandler; + } + + // call error handler + switch (severity) { + case SEVERITY_WARNING: { + errorHandler.warning(domain, key, parseException); + break; + } + case SEVERITY_ERROR: { + errorHandler.error(domain, key, parseException); + break; + } + case SEVERITY_FATAL_ERROR: { + errorHandler.fatalError(domain, key, parseException); + if (!fContinueAfterFatalError) { + throw parseException; + } + break; + } + } + return message; + + } // reportError(XMLLocator,String,String,Object[],short,Exception):String + + // + // XMLComponent methods + // + + /** + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws SAXException Thrown by component on initialization error. + * For example, if a feature or property is + * required for the operation of the component, the + * component manager may throw a + * SAXNotRecognizedException or a + * SAXNotSupportedException. + */ + public void reset(XMLComponentManager componentManager) + throws XNIException { + + // features + try { + fContinueAfterFatalError = componentManager.getFeature(CONTINUE_AFTER_FATAL_ERROR); + } + catch (XNIException e) { + fContinueAfterFatalError = false; + } + + // properties + fErrorHandler = (XMLErrorHandler)componentManager.getProperty(ERROR_HANDLER); + + } // reset(XMLComponentManager) + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + + // + // Xerces features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/continue-after-fatal-error + // Allows the parser to continue after a fatal error. + // Normally, a fatal error would stop the parse. + // + if (suffixLength == Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE.length() && + featureId.endsWith(Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE)) { + fContinueAfterFatalError = state; + } + } + + } // setFeature(String,boolean) + + // return state of given feature or false if unsupported. + public boolean getFeature(String featureId) + throws XMLConfigurationException { + + // + // Xerces features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/continue-after-fatal-error + // Allows the parser to continue after a fatal error. + // Normally, a fatal error would stop the parse. + // + if (suffixLength == Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE.length() && + featureId.endsWith(Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE)) { + return fContinueAfterFatalError ; + } + } + return false; + + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // + // Xerces properties + // + + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.ERROR_HANDLER_PROPERTY.length() && + propertyId.endsWith(Constants.ERROR_HANDLER_PROPERTY)) { + fErrorHandler = (XMLErrorHandler)value; + } + } + + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + /** + * Get the internal XMLErrrorHandler. + */ + public XMLErrorHandler getErrorHandler() { + return fErrorHandler; + } + + /** + * Gets the internal XMLErrorHandler + * as SAX ErrorHandler. + */ + public ErrorHandler getSAXErrorHandler() { + if (fSaxProxy == null) { + fSaxProxy = new ErrorHandlerProxy() { + protected XMLErrorHandler getErrorHandler() { + return fErrorHandler; + } + }; + } + return fSaxProxy; + } + +} // class XMLErrorReporter diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLNSDocumentScannerImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLNSDocumentScannerImpl.java new file mode 100644 index 0000000..8cb0332 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLNSDocumentScannerImpl.java @@ -0,0 +1,768 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.IOException; + +import org.apache.xerces.impl.dtd.XMLDTDValidatorFilter; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + * The scanner acts as the source for the document + * information which is communicated to the document handler. + * + * This class scans an XML document, checks if document has a DTD, and if + * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform + * namespace binding. + * + * Note: This scanner should only be used when the namespace processing is on! + * + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces {true} -- if the value of this + * feature is set to false this scanner must not be used.
  • + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/nonvalidating/load-external-dtd
  • + *
  • http://apache.org/xml/features/scanner/notify-char-refs
  • + *
  • http://apache.org/xml/features/scanner/notify-builtin-refs
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-manager
  • + *
  • http://apache.org/xml/properties/internal/dtd-scanner
  • + *
+ * + * @xerces.internal + * + * @author Elena Litani, IBM + * + * @version $Id$ + */ +public class XMLNSDocumentScannerImpl +extends XMLDocumentScannerImpl { + + /** If is true, the dtd validator is no longer in the pipeline + * and the scanner should bind namespaces */ + protected boolean fBindNamespaces; + + /** If validating parser, make sure we report an error in the + * scanner if DTD grammar is missing.*/ + protected boolean fPerformValidation; + + // private data + // + + /** DTD validator */ + private XMLDTDValidatorFilter fDTDValidator; + + /** + * Saw spaces after element name or between attributes. + * + * This is reserved for the case where scanning of a start element spans + * several methods, as is the case when scanning the start of a root element + * where a DTD external subset may be read after scanning the element name. + */ + private boolean fSawSpace; + + + /** + * The scanner is responsible for removing DTD validator + * from the pipeline if it is not needed. + * + * @param dtdValidator The DTDValidator + */ + public void setDTDValidator(XMLDTDValidatorFilter dtdValidator) { + fDTDValidator = dtdValidator; + } + + /** + * Scans a start element. This method will handle the binding of + * namespace information and notifying the handler of the start + * of the element. + *

+ *

+     * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
+     * [40] STag ::= '<' Name (S Attribute)* S? '>'
+     * 
+ *

+ * Note: This method assumes that the leading + * '<' character has been consumed. + *

+ * Note: This method uses the fElementQName and + * fAttributes variables. The contents of these variables will be + * destroyed. The caller should copy important information out of + * these variables before calling this method. + * + * @return True if element is empty. (i.e. It matches + * production [44]. + */ + protected boolean scanStartElement() + throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanStartElementNS()"); + + // Note: namespace processing is on by default + fEntityScanner.scanQName(fElementQName); + // REVISIT - [Q] Why do we need this temp variable? -- mrglavas + String rawname = fElementQName.rawname; + if (fBindNamespaces) { + fNamespaceContext.pushContext(); + if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) { + if (fPerformValidation) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_GRAMMAR_NOT_FOUND", + new Object[]{ rawname}, + XMLErrorReporter.SEVERITY_ERROR); + + if (fDoctypeName == null || !fDoctypeName.equals(rawname)) { + fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, + "RootElementTypeMustMatchDoctypedecl", + new Object[]{fDoctypeName, rawname}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + } + } + + // push element stack + fCurrentElement = fElementStack.pushElement(fElementQName); + + // attributes + boolean empty = false; + fAttributes.removeAllAttributes(); + do { + // spaces + boolean sawSpace = fEntityScanner.skipSpaces(); + + // end tag? + int c = fEntityScanner.peekChar(); + if (c == '>') { + fEntityScanner.scanChar(); + break; + } + else if (c == '/') { + fEntityScanner.scanChar(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError("ElementUnterminated", + new Object[]{rawname}); + } + empty = true; + break; + } + else if (!isValidNameStartChar(c) || !sawSpace) { + reportFatalError("ElementUnterminated", new Object[]{rawname}); + } + + // attributes + scanAttribute(fAttributes); + + } while (true); + + if (fBindNamespaces) { + // REVISIT: is it required? forbit xmlns prefix for element + if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "ElementXMLNSPrefix", + new Object[]{fElementQName.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind the element + String prefix = fElementQName.prefix != null + ? fElementQName.prefix : XMLSymbols.EMPTY_STRING; + // assign uri to the element + fElementQName.uri = fNamespaceContext.getURI(prefix); + // make sure that object in the element stack is updated as well + fCurrentElement.uri = fElementQName.uri; + + if (fElementQName.prefix == null && fElementQName.uri != null) { + fElementQName.prefix = XMLSymbols.EMPTY_STRING; + // making sure that the object in the element stack is updated too. + fCurrentElement.prefix = XMLSymbols.EMPTY_STRING; + } + if (fElementQName.prefix != null && fElementQName.uri == null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "ElementPrefixUnbound", + new Object[]{fElementQName.prefix, fElementQName.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind attributes (xmlns are already bound bellow) + int length = fAttributes.getLength(); + // fLength = 0; //initialize structure + for (int i = 0; i < length; i++) { + fAttributes.getName(i, fAttributeQName); + + String aprefix = fAttributeQName.prefix != null + ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; + String uri = fNamespaceContext.getURI(aprefix); + // REVISIT: try removing the first "if" and see if it is faster. + // + if (fAttributeQName.uri != null && fAttributeQName.uri == uri) { + // checkDuplicates(fAttributeQName, fAttributes); + continue; + } + if (aprefix != XMLSymbols.EMPTY_STRING) { + fAttributeQName.uri = uri; + if (uri == null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributePrefixUnbound", + new Object[]{fElementQName.rawname,fAttributeQName.rawname,aprefix}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + fAttributes.setURI(i, uri); + // checkDuplicates(fAttributeQName, fAttributes); + } + } + + if (length > 1) { + QName name = fAttributes.checkDuplicatesNS(); + if (name != null) { + if (name.uri != null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNSNotUnique", + new Object[]{fElementQName.rawname, name.localpart, name.uri}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + else { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNotUnique", + new Object[]{fElementQName.rawname, name.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + } + } + + + // call handler + if (fDocumentHandler != null) { + if (empty) { + + //decrease the markup depth.. + fMarkupDepth--; + + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError("ElementEntityMismatch", + new Object[]{fCurrentElement.rawname}); + } + + fDocumentHandler.emptyElement(fElementQName, fAttributes, null); + + if (fBindNamespaces) { + fNamespaceContext.popContext(); + } + //pop the element off the stack.. + fElementStack.popElement(fElementQName); + } else { + fDocumentHandler.startElement(fElementQName, fAttributes, null); + } + } + + if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElement(): "+empty); + return empty; + + } // scanStartElement():boolean + + /** + * Scans the name of an element in a start or empty tag. + * + * @see #scanStartElement() + */ + protected void scanStartElementName () + throws IOException, XNIException { + // Note: namespace processing is on by default + fEntityScanner.scanQName(fElementQName); + // Must skip spaces here because the DTD scanner + // would consume them at the end of the external subset. + fSawSpace = fEntityScanner.skipSpaces(); + } // scanStartElementName() + + /** + * Scans the remainder of a start or empty tag after the element name. + * + * @see #scanStartElement + * @return True if element is empty. + */ + protected boolean scanStartElementAfterName() + throws IOException, XNIException { + + // REVISIT - [Q] Why do we need this temp variable? -- mrglavas + String rawname = fElementQName.rawname; + if (fBindNamespaces) { + fNamespaceContext.pushContext(); + if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) { + if (fPerformValidation) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_GRAMMAR_NOT_FOUND", + new Object[]{ rawname}, + XMLErrorReporter.SEVERITY_ERROR); + + if (fDoctypeName == null || !fDoctypeName.equals(rawname)) { + fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, + "RootElementTypeMustMatchDoctypedecl", + new Object[]{fDoctypeName, rawname}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + } + } + + // push element stack + fCurrentElement = fElementStack.pushElement(fElementQName); + + // attributes + boolean empty = false; + fAttributes.removeAllAttributes(); + do { + + // end tag? + int c = fEntityScanner.peekChar(); + if (c == '>') { + fEntityScanner.scanChar(); + break; + } + else if (c == '/') { + fEntityScanner.scanChar(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError("ElementUnterminated", + new Object[]{rawname}); + } + empty = true; + break; + } + else if (!isValidNameStartChar(c) || !fSawSpace) { + reportFatalError("ElementUnterminated", new Object[]{rawname}); + } + + // attributes + scanAttribute(fAttributes); + + // spaces + fSawSpace = fEntityScanner.skipSpaces(); + + } while (true); + + if (fBindNamespaces) { + // REVISIT: is it required? forbit xmlns prefix for element + if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "ElementXMLNSPrefix", + new Object[]{fElementQName.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind the element + String prefix = fElementQName.prefix != null + ? fElementQName.prefix : XMLSymbols.EMPTY_STRING; + // assign uri to the element + fElementQName.uri = fNamespaceContext.getURI(prefix); + // make sure that object in the element stack is updated as well + fCurrentElement.uri = fElementQName.uri; + + if (fElementQName.prefix == null && fElementQName.uri != null) { + fElementQName.prefix = XMLSymbols.EMPTY_STRING; + // making sure that the object in the element stack is updated too. + fCurrentElement.prefix = XMLSymbols.EMPTY_STRING; + } + if (fElementQName.prefix != null && fElementQName.uri == null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "ElementPrefixUnbound", + new Object[]{fElementQName.prefix, fElementQName.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind attributes (xmlns are already bound bellow) + int length = fAttributes.getLength(); + // fLength = 0; //initialize structure + for (int i = 0; i < length; i++) { + fAttributes.getName(i, fAttributeQName); + + String aprefix = fAttributeQName.prefix != null + ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; + String uri = fNamespaceContext.getURI(aprefix); + // REVISIT: try removing the first "if" and see if it is faster. + // + if (fAttributeQName.uri != null && fAttributeQName.uri == uri) { + // checkDuplicates(fAttributeQName, fAttributes); + continue; + } + if (aprefix != XMLSymbols.EMPTY_STRING) { + fAttributeQName.uri = uri; + if (uri == null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributePrefixUnbound", + new Object[]{fElementQName.rawname,fAttributeQName.rawname,aprefix}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + fAttributes.setURI(i, uri); + // checkDuplicates(fAttributeQName, fAttributes); + } + } + + if (length > 1) { + QName name = fAttributes.checkDuplicatesNS(); + if (name != null) { + if (name.uri != null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNSNotUnique", + new Object[]{fElementQName.rawname, name.localpart, name.uri}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + else { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNotUnique", + new Object[]{fElementQName.rawname, name.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + } + } + + + // call handler + if (fDocumentHandler != null) { + if (empty) { + + //decrease the markup depth.. + fMarkupDepth--; + + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError("ElementEntityMismatch", + new Object[]{fCurrentElement.rawname}); + } + + fDocumentHandler.emptyElement(fElementQName, fAttributes, null); + + if (fBindNamespaces) { + fNamespaceContext.popContext(); + } + //pop the element off the stack.. + fElementStack.popElement(fElementQName); + } else { + fDocumentHandler.startElement(fElementQName, fAttributes, null); + } + } + + if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElementAfterName(): "+empty); + return empty; + } // scanStartElementAfterName() + + /** + * Scans an attribute. + *

+ *

+     * [41] Attribute ::= Name Eq AttValue
+     * 
+ *

+ * Note: This method assumes that the next + * character on the stream is the first character of the attribute + * name. + *

+ * Note: This method uses the fAttributeQName and + * fQName variables. The contents of these variables will be + * destroyed. + * + * @param attributes The attributes list for the scanned attribute. + */ + protected void scanAttribute(XMLAttributesImpl attributes) + throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanAttribute()"); + + // name + fEntityScanner.scanQName(fAttributeQName); + + // equals + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('=')) { + reportFatalError("EqRequiredInAttribute", + new Object[]{fCurrentElement.rawname,fAttributeQName.rawname}); + } + fEntityScanner.skipSpaces(); + + // content + int attrIndex; + + if (fBindNamespaces) { + attrIndex = attributes.getLength(); + attributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, null); + } + else { + int oldLen = attributes.getLength(); + attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null); + + // WFC: Unique Att Spec + if (oldLen == attributes.getLength()) { + reportFatalError("AttributeNotUnique", + new Object[]{fCurrentElement.rawname, + fAttributeQName.rawname}); + } + } + + // Scan attribute value and return true if the non-normalized and normalized value are the same + boolean isSameNormalizedAttr = scanAttributeValue(this.fTempString, fTempString2, + fAttributeQName.rawname, fIsEntityDeclaredVC, fCurrentElement.rawname); + + String value = fTempString.toString(); + attributes.setValue(attrIndex, value); + // If the non-normalized and normalized value are the same, avoid creating a new string. + if (!isSameNormalizedAttr) { + attributes.setNonNormalizedValue(attrIndex, fTempString2.toString()); + } + attributes.setSpecified(attrIndex, true); + + // record namespace declarations if any. + if (fBindNamespaces) { + + String localpart = fAttributeQName.localpart; + String prefix = fAttributeQName.prefix != null + ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; + // when it's of form xmlns="..." or xmlns:prefix="...", + // it's a namespace declaration. but prefix:xmlns="..." isn't. + if (prefix == XMLSymbols.PREFIX_XMLNS || + prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) { + + // get the internalized value of this attribute + String uri = fSymbolTable.addSymbol(value); + + // 1. "xmlns" can't be bound to any namespace + if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[]{fAttributeQName}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 2. the namespace for "xmlns" can't be bound to any prefix + if (uri == NamespaceContext.XMLNS_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[]{fAttributeQName}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 3. "xml" can't be bound to any other namespace than it's own + if (localpart == XMLSymbols.PREFIX_XML) { + if (uri != NamespaceContext.XML_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[]{fAttributeQName}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + // 4. the namespace for "xml" can't be bound to any other prefix + else { + if (uri ==NamespaceContext.XML_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[]{fAttributeQName}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + + prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING; + + // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix + // We should only report an error if there is a prefix, + // that is, the local part is not "xmlns". -SG + if (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "EmptyPrefixedAttName", + new Object[]{fAttributeQName}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // declare prefix in context + fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null); + // bind namespace attribute to a namespace + attributes.setURI(attrIndex, fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS)); + + } + else { + // attempt to bind attribute + if (fAttributeQName.prefix != null) { + attributes.setURI(attrIndex, fNamespaceContext.getURI(fAttributeQName.prefix)); + } + } + } + + if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanAttribute()"); + } // scanAttribute(XMLAttributes) + + + + /** + * Scans an end element. + *

+ *

+     * [42] ETag ::= '</' Name S? '>'
+     * 
+ *

+ * Note: This method uses the fElementQName variable. + * The contents of this variable will be destroyed. The caller should + * copy the needed information out of this variable before calling + * this method. + * + * @return The element depth. + */ + protected int scanEndElement() throws IOException, XNIException { + if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanEndElement()"); + + // pop context + fElementStack.popElement(fElementQName) ; + + // Take advantage of the fact that next string _should_ be "fElementQName.rawName", + //In scanners most of the time is consumed on checks done for XML characters, we can + // optimize on it and avoid the checks done for endElement, + //we will also avoid symbol table lookup - neeraj.bajaj@sun.com + + // this should work both for namespace processing true or false... + + //REVISIT: if the string is not the same as expected.. we need to do better error handling.. + //We can skip this for now... In any case if the string doesn't match -- document is not well formed. + if (!fEntityScanner.skipString(fElementQName.rawname)) { + reportFatalError("ETagRequired", new Object[]{fElementQName.rawname}); + } + + // end + fEntityScanner.skipSpaces(); + if (!fEntityScanner.skipChar('>')) { + reportFatalError("ETagUnterminated", + new Object[]{fElementQName.rawname}); + } + fMarkupDepth--; + + //we have increased the depth for two markup "<" characters + fMarkupDepth--; + + // check that this element was opened in the same entity + if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { + reportFatalError("ElementEntityMismatch", + new Object[]{fCurrentElement.rawname}); + } + + // call handler + if (fDocumentHandler != null ) { + + fDocumentHandler.endElement(fElementQName, null); + if (fBindNamespaces) { + fNamespaceContext.popContext(); + } + + } + + return fMarkupDepth; + + } // scanEndElement():int + + + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + super.reset(componentManager); + fPerformValidation = false; + fBindNamespaces = false; + } + + /** Creates a content dispatcher. */ + protected Dispatcher createContentDispatcher() { + return new NSContentDispatcher(); + } // createContentDispatcher():Dispatcher + + /** + * Dispatcher to handle content scanning. + */ + protected final class NSContentDispatcher + extends ContentDispatcher { + + /** + * Scan for root element hook. This method is a hook for + * subclasses to add code that handles scanning for the root + * element. This method will also attempt to remove DTD validator + * from the pipeline, if there is no DTD grammar. If DTD validator + * is no longer in the pipeline bind namespaces in the scanner. + * + * + * @return True if the caller should stop and return true which + * allows the scanner to switch to a new scanning + * dispatcher. A return value of false indicates that + * the content dispatcher should continue as normal. + */ + protected boolean scanRootElementHook() + throws IOException, XNIException { + + if (fExternalSubsetResolver != null && !fSeenDoctypeDecl + && !fDisallowDoctype && (fValidation || fLoadExternalDTD)) { + scanStartElementName(); + resolveExternalSubsetAndRead(); + reconfigurePipeline(); + if (scanStartElementAfterName()) { + setScannerState(SCANNER_STATE_TRAILING_MISC); + setDispatcher(fTrailingMiscDispatcher); + return true; + } + } + else { + reconfigurePipeline(); + if (scanStartElement()) { + setScannerState(SCANNER_STATE_TRAILING_MISC); + setDispatcher(fTrailingMiscDispatcher); + return true; + } + } + return false; + + } // scanRootElementHook():boolean + + /** + * Re-configures pipeline by removing the DTD validator + * if no DTD grammar exists. If no validator exists in the + * pipeline or there is no DTD grammar, namespace binding + * is performed by the scanner in the enclosing class. + */ + private void reconfigurePipeline() { + if (fDTDValidator == null) { + fBindNamespaces = true; + } + else if (!fDTDValidator.hasGrammar()) { + fBindNamespaces = true; + fPerformValidation = fDTDValidator.validate(); + // re-configure pipeline + XMLDocumentSource source = fDTDValidator.getDocumentSource(); + XMLDocumentHandler handler = fDTDValidator.getDocumentHandler(); + source.setDocumentHandler(handler); + if (handler != null) + handler.setDocumentSource(source); + fDTDValidator.setDocumentSource(null); + fDTDValidator.setDocumentHandler(null); + } + } // reconfigurePipeline() + } + +} // class XMLNSDocumentScannerImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLNamespaceBinder.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLNamespaceBinder.java new file mode 100644 index 0000000..70c0e70 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLNamespaceBinder.java @@ -0,0 +1,850 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentFilter; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + * This class performs namespace binding on the startElement and endElement + * method calls and passes all other methods through to the registered + * document handler. This class can be configured to only pass the + * start and end prefix mappings (start/endPrefixMapping). + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
+ * + * @xerces.internal + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XMLNamespaceBinder + implements XMLComponent, XMLDocumentFilter { + + // + // Constants + // + + // feature identifiers + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + // property identifiers + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + NAMESPACES, + }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { + null, + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + ERROR_REPORTER, + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { + null, + null, + }; + + // + // Data + // + + // features + + /** Namespaces. */ + protected boolean fNamespaces; + + // properties + + /** Symbol table. */ + protected SymbolTable fSymbolTable; + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + // handlers + + /** Document handler. */ + protected XMLDocumentHandler fDocumentHandler; + + protected XMLDocumentSource fDocumentSource; + + // settings + + /** Only pass start and end prefix mapping events. */ + protected boolean fOnlyPassPrefixMappingEvents; + + // shared context + + /** Namespace context. */ + private NamespaceContext fNamespaceContext; + + // temp vars + + /** Attribute QName. */ + private final QName fAttributeQName = new QName(); + + // + // Constructors + // + + /** Default constructor. */ + public XMLNamespaceBinder() { + } // () + + // + // Public methods + // + + // settings + + /** + * Sets whether the namespace binder only passes the prefix mapping + * events to the registered document handler or passes all document + * events. + * + * @param onlyPassPrefixMappingEvents True to pass only the prefix + * mapping events; false to pass + * all events. + */ + public void setOnlyPassPrefixMappingEvents(boolean onlyPassPrefixMappingEvents) { + fOnlyPassPrefixMappingEvents = onlyPassPrefixMappingEvents; + } // setOnlyPassPrefixMappingEvents(boolean) + + /** + * Returns true if the namespace binder only passes the prefix mapping + * events to the registered document handler; false if the namespace + * binder passes all document events. + */ + public boolean getOnlyPassPrefixMappingEvents() { + return fOnlyPassPrefixMappingEvents; + } // getOnlyPassPrefixMappingEvents():boolean + + // + // XMLComponent methods + // + + /** + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws SAXException Thrown by component on initialization error. + * For example, if a feature or property is + * required for the operation of the component, the + * component manager may throw a + * SAXNotRecognizedException or a + * SAXNotSupportedException. + */ + public void reset(XMLComponentManager componentManager) + throws XNIException { + + // features + try { + fNamespaces = componentManager.getFeature(NAMESPACES); + } + catch (XMLConfigurationException e) { + fNamespaces = true; + } + + // Xerces properties + fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE); + fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); + + } // reset(XMLComponentManager) + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property during parsing. + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // Xerces properties + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SYMBOL_TABLE_PROPERTY.length() && + propertyId.endsWith(Constants.SYMBOL_TABLE_PROPERTY)) { + fSymbolTable = (SymbolTable)value; + } + else if (suffixLength == Constants.ERROR_REPORTER_PROPERTY.length() && + propertyId.endsWith(Constants.ERROR_REPORTER_PROPERTY)) { + fErrorReporter = (XMLErrorReporter)value; + } + return; + } + + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + // + // XMLDocumentSource methods + // + + /** Sets the document handler to receive information about the document. */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + } // setDocumentHandler(XMLDocumentHandler) + + /** Returns the document handler */ + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } // setDocumentHandler(XMLDocumentHandler) + + + // + // XMLDocumentHandler methods + // + + /** Sets the document source */ + public void setDocumentSource(XMLDocumentSource source){ + fDocumentSource = source; + } // setDocumentSource + + /** Returns the document source */ + public XMLDocumentSource getDocumentSource (){ + return fDocumentSource; + } // getDocumentSource + + + /** + * This method notifies the start of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, + String encoding, Augmentations augs) + throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); + } + } // startEntity(String,String,String,String,String) + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

+ * Note: This method will never be called for the + * document entity; it is only called for external general entities + * referenced in document content. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) + throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.textDecl(version, encoding, augs); + } + } // textDecl(String,String) + + /** + * The start of the document. + * + * @param locator The system identifier of the entity if the entity + * is external, null otherwise. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param namespaceContext + * The namespace context in effect at the + * start of this document. + * This object represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException { + fNamespaceContext = namespaceContext; + + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); + } + } // startDocument(XMLLocator,String) + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) + throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.xmlDecl(version, encoding, standalone, augs); + } + } // xmlDecl(String,String,String) + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * otherwise. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void doctypeDecl(String rootElement, + String publicId, String systemId, Augmentations augs) + throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); + } + } // doctypeDecl(String,String,String) + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.comment(text, augs); + } + } // comment(XMLString) + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.processingInstruction(target, data, augs); + } + } // processingInstruction(String,XMLString) + + + /** + * Binds the namespaces. This method will handle calling the + * document handler to start the prefix mappings. + *

+ * Note: This method makes use of the + * fAttributeQName variable. Any contents of the variable will + * be destroyed. Caller should copy the values out of this + * temporary variable before calling this method. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + if (fNamespaces) { + handleStartElement(element, attributes, augs, false); + } + else if (fDocumentHandler != null) { + fDocumentHandler.startElement(element, attributes, augs); + } + + + } // startElement(QName,XMLAttributes) + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + if (fNamespaces) { + handleStartElement(element, attributes, augs, true); + handleEndElement(element, augs, true); + } + else if (fDocumentHandler != null) { + fDocumentHandler.emptyElement(element, attributes, augs); + } + + } // emptyElement(QName,XMLAttributes) + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.characters(text, augs); + } + } // characters(XMLString) + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.ignorableWhitespace(text, augs); + } + } // ignorableWhitespace(XMLString) + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException { + + if (fNamespaces) { + handleEndElement(element, augs, false); + } + else if (fDocumentHandler != null) { + fDocumentHandler.endElement(element, augs); + } + + } // endElement(QName) + + /** + * The start of a CDATA section. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.startCDATA(augs); + } + } // startCDATA() + + /** + * The end of a CDATA section. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.endCDATA(augs); + } + } // endCDATA() + + /** + * The end of the document. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDocument(Augmentations augs) throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.endDocument(augs); + } + } // endDocument() + + /** + * This method notifies the end of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augs) throws XNIException { + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + fDocumentHandler.endGeneralEntity(name, augs); + } + } // endEntity(String) + + // + // Protected methods + // + + /** Handles start element. */ + protected void handleStartElement(QName element, XMLAttributes attributes, + Augmentations augs, + boolean isEmpty) throws XNIException { + + // add new namespace context + fNamespaceContext.pushContext(); + + if (element.prefix == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "ElementXMLNSPrefix", + new Object[]{element.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // search for new namespace bindings + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + String localpart = attributes.getLocalName(i); + String prefix = attributes.getPrefix(i); + // when it's of form xmlns="..." or xmlns:prefix="...", + // it's a namespace declaration. but prefix:xmlns="..." isn't. + if (prefix == XMLSymbols.PREFIX_XMLNS || + prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) { + + // get the internalized value of this attribute + String uri = fSymbolTable.addSymbol(attributes.getValue(i)); + + // 1. "xmlns" can't be bound to any namespace + if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 2. the namespace for "xmlns" can't be bound to any prefix + if (uri == NamespaceContext.XMLNS_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 3. "xml" can't be bound to any other namespace than it's own + if (localpart == XMLSymbols.PREFIX_XML) { + if (uri != NamespaceContext.XML_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + // 4. the namespace for "xml" can't be bound to any other prefix + else { + if (uri ==NamespaceContext.XML_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + + prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING; + + // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix + // We should only report an error if there is a prefix, + // that is, the local part is not "xmlns". -SG + // Since this is an error condition in XML 1.0, + // and should be relatively uncommon in XML 1.1, + // making this test into a method call to reuse code + // should be acceptable. - NG + if(prefixBoundToNullURI(uri, localpart)) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "EmptyPrefixedAttName", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + continue; + } + + // declare prefix in context + fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null); + + } + } + + // bind the element + String prefix = element.prefix != null + ? element.prefix : XMLSymbols.EMPTY_STRING; + element.uri = fNamespaceContext.getURI(prefix); + if (element.prefix == null && element.uri != null) { + element.prefix = XMLSymbols.EMPTY_STRING; + } + if (element.prefix != null && element.uri == null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "ElementPrefixUnbound", + new Object[]{element.prefix, element.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind the attributes + for (int i = 0; i < length; i++) { + attributes.getName(i, fAttributeQName); + String aprefix = fAttributeQName.prefix != null + ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; + String arawname = fAttributeQName.rawname; + if (arawname == XMLSymbols.PREFIX_XMLNS) { + fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS); + attributes.setName(i, fAttributeQName); + } + else if (aprefix != XMLSymbols.EMPTY_STRING) { + fAttributeQName.uri = fNamespaceContext.getURI(aprefix); + if (fAttributeQName.uri == null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributePrefixUnbound", + new Object[]{element.rawname,arawname,aprefix}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + attributes.setName(i, fAttributeQName); + } + } + + // verify that duplicate attributes don't exist + // Example: + int attrCount = attributes.getLength(); + for (int i = 0; i < attrCount - 1; i++) { + String auri = attributes.getURI(i); + if (auri == null || auri == NamespaceContext.XMLNS_URI) { + continue; + } + String alocalpart = attributes.getLocalName(i); + for (int j = i + 1; j < attrCount; j++) { + String blocalpart = attributes.getLocalName(j); + String buri = attributes.getURI(j); + if (alocalpart == blocalpart && auri == buri) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNSNotUnique", + new Object[]{element.rawname,alocalpart, auri}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + } + + // call handler + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + if (isEmpty) { + fDocumentHandler.emptyElement(element, attributes, augs); + } + else { + fDocumentHandler.startElement(element, attributes, augs); + } + } + + + } // handleStartElement(QName,XMLAttributes,boolean) + + /** Handles end element. */ + protected void handleEndElement(QName element, Augmentations augs, boolean isEmpty) + throws XNIException { + + // bind element + String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; + element.uri = fNamespaceContext.getURI(eprefix); + if (element.uri != null) { + element.prefix = eprefix; + } + + // call handlers + if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) { + if (!isEmpty) { + fDocumentHandler.endElement(element, augs); + } + } + + // pop context + fNamespaceContext.popContext(); + + } // handleEndElement(QName,boolean) + + // returns true iff the given prefix is bound to "" *and* + // this is disallowed by the version of XML namespaces in use. + protected boolean prefixBoundToNullURI(String uri, String localpart) { + return (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS); + } // prefixBoundToNullURI(String, String): boolean + +} // class XMLNamespaceBinder diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLScanner.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLScanner.java new file mode 100644 index 0000000..2c4026a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLScanner.java @@ -0,0 +1,1510 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.IOException; + +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLResourceIdentifierImpl; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; + +/** + * This class is responsible for holding scanning methods common to + * scanning the XML document structure and content as well as the DTD + * structure and content. Both XMLDocumentScanner and XMLDTDScanner inherit + * from this base class. + * + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/validation
  • + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://apache.org/xml/features/scanner/notify-char-refs
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-manager
  • + *
+ * + * @xerces.internal + * + * @author Andy Clark, IBM + * @author Arnaud Le Hors, IBM + * @author Eric Ye, IBM + * + * @version $Id$ + */ +public abstract class XMLScanner + implements XMLComponent { + + // + // Constants + // + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: notify character references. */ + protected static final String NOTIFY_CHAR_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE; + + protected static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + // property identifiers + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + // debugging + + /** Debug attribute normalization. */ + protected static final boolean DEBUG_ATTR_NORMALIZATION = false; + + // + // Data + // + + + // features + + /** + * Validation. This feature identifier is: + * http://xml.org/sax/features/validation + */ + protected boolean fValidation = false; + + /** Namespaces. */ + protected boolean fNamespaces; + + /** Character references notification. */ + protected boolean fNotifyCharRefs = false; + + /** Internal parser-settings feature */ + protected boolean fParserSettings = true; + + // properties + + /** Symbol table. */ + protected SymbolTable fSymbolTable; + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + /** Entity manager. */ + protected XMLEntityManager fEntityManager; + + // protected data + + /** Entity scanner. */ + protected XMLEntityScanner fEntityScanner; + + /** Entity depth. */ + protected int fEntityDepth; + + /** Literal value of the last character refence scanned. */ + protected String fCharRefLiteral = null; + + /** Scanning attribute. */ + protected boolean fScanningAttribute; + + /** Report entity boundary. */ + protected boolean fReportEntity; + + // symbols + + /** Symbol: "version". */ + protected final static String fVersionSymbol = "version".intern(); + + /** Symbol: "encoding". */ + protected final static String fEncodingSymbol = "encoding".intern(); + + /** Symbol: "standalone". */ + protected final static String fStandaloneSymbol = "standalone".intern(); + + /** Symbol: "amp". */ + protected final static String fAmpSymbol = "amp".intern(); + + /** Symbol: "lt". */ + protected final static String fLtSymbol = "lt".intern(); + + /** Symbol: "gt". */ + protected final static String fGtSymbol = "gt".intern(); + + /** Symbol: "quot". */ + protected final static String fQuotSymbol = "quot".intern(); + + /** Symbol: "apos". */ + protected final static String fAposSymbol = "apos".intern(); + + // temporary variables + + // NOTE: These objects are private to help prevent accidental modification + // of values by a subclass. If there were protected *and* the sub- + // modified the values, it would be difficult to track down the real + // cause of the bug. By making these private, we avoid this + // possibility. + + /** String. */ + private final XMLString fString = new XMLString(); + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); + + /** String buffer. */ + private final XMLStringBuffer fStringBuffer3 = new XMLStringBuffer(); + + // temporary location for Resource identification information. + protected final XMLResourceIdentifierImpl fResourceIdentifier = new XMLResourceIdentifierImpl(); + + // + // XMLComponent methods + // + + /** + * + * + * @param componentManager The component manager. + * + * @throws SAXException Throws exception if required features and + * properties cannot be found. + */ + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + try { + fParserSettings = componentManager.getFeature(PARSER_SETTINGS); + } catch (XMLConfigurationException e) { + fParserSettings = true; + } + + if (!fParserSettings) { + // parser settings have not been changed + init(); + return; + } + + // Xerces properties + fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE); + fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); + fEntityManager = (XMLEntityManager)componentManager.getProperty(ENTITY_MANAGER); + + // sax features + try { + fValidation = componentManager.getFeature(VALIDATION); + } + catch (XMLConfigurationException e) { + fValidation = false; + } + try { + fNamespaces = componentManager.getFeature(NAMESPACES); + } + catch (XMLConfigurationException e) { + fNamespaces = true; + } + try { + fNotifyCharRefs = componentManager.getFeature(NOTIFY_CHAR_REFS); + } + catch (XMLConfigurationException e) { + fNotifyCharRefs = false; + } + + init(); + + } // reset(XMLComponentManager) + + /** + * Sets the value of a property during parsing. + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // Xerces properties + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SYMBOL_TABLE_PROPERTY.length() && + propertyId.endsWith(Constants.SYMBOL_TABLE_PROPERTY)) { + fSymbolTable = (SymbolTable)value; + } + else if (suffixLength == Constants.ERROR_REPORTER_PROPERTY.length() && + propertyId.endsWith(Constants.ERROR_REPORTER_PROPERTY)) { + fErrorReporter = (XMLErrorReporter)value; + } + else if (suffixLength == Constants.ENTITY_MANAGER_PROPERTY.length() && + propertyId.endsWith(Constants.ENTITY_MANAGER_PROPERTY)) { + fEntityManager = (XMLEntityManager)value; + } + } + + } // setProperty(String,Object) + + /* + * Sets the feature of the scanner. + */ + public void setFeature(String featureId, boolean value) + throws XMLConfigurationException { + + if (VALIDATION.equals(featureId)) { + fValidation = value; + } else if (NOTIFY_CHAR_REFS.equals(featureId)) { + fNotifyCharRefs = value; + } + } + + /* + * Gets the state of the feature of the scanner. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + + if (VALIDATION.equals(featureId)) { + return fValidation; + } else if (NOTIFY_CHAR_REFS.equals(featureId)) { + return fNotifyCharRefs; + } + throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId); + } + + // + // Protected methods + // + + // anybody calling this had better have set Symtoltable! + protected void reset() { + init(); + + // DTD preparsing defaults: + fValidation = true; + fNotifyCharRefs = false; + + } + + // common scanning methods + + /** + * Scans an XML or text declaration. + *

+ *

+     * [23] XMLDecl ::= ''
+     * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
+     * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
+     * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+     * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
+     *                 | ('"' ('yes' | 'no') '"'))
+     *
+     * [77] TextDecl ::= ''
+     * 
+ * + * @param scanningTextDecl True if a text declaration is to + * be scanned instead of an XML + * declaration. + * @param pseudoAttributeValues An array of size 3 to return the version, + * encoding and standalone pseudo attribute values + * (in that order). + * + * Note: This method uses fString, anything in it + * at the time of calling is lost. + */ + protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl, + String[] pseudoAttributeValues) + throws IOException, XNIException { + + // pseudo-attribute values + String version = null; + String encoding = null; + String standalone = null; + + // scan pseudo-attributes + final int STATE_VERSION = 0; + final int STATE_ENCODING = 1; + final int STATE_STANDALONE = 2; + final int STATE_DONE = 3; + int state = STATE_VERSION; + + boolean dataFoundForTarget = false; + boolean sawSpace = fEntityScanner.skipDeclSpaces(); + // since pseudoattributes are *not* attributes, + // their quotes don't need to be preserved in external parameter entities. + // the XMLEntityScanner#scanLiteral method will continue to + // emit -1 in such cases when it finds a quote; this is + // fine for other methods that parse scanned entities, + // but not for the scanning of pseudoattributes. So, + // temporarily, we must mark the current entity as not being "literal" + XMLEntityManager.ScannedEntity currEnt = fEntityManager.getCurrentEntity(); + boolean currLiteral = currEnt.literal; + currEnt.literal = false; + while (fEntityScanner.peekChar() != '?') { + dataFoundForTarget = true; + String name = scanPseudoAttribute(scanningTextDecl, fString); + switch (state) { + case STATE_VERSION: { + if (name == fVersionSymbol) { + if (!sawSpace) { + reportFatalError(scanningTextDecl + ? "SpaceRequiredBeforeVersionInTextDecl" + : "SpaceRequiredBeforeVersionInXMLDecl", + null); + } + version = fString.toString(); + state = STATE_ENCODING; + if (!versionSupported(version)) { + reportFatalError(getVersionNotSupportedKey(), + new Object[]{version}); + } + } + else if (name == fEncodingSymbol) { + if (!scanningTextDecl) { + reportFatalError("VersionInfoRequired", null); + } + if (!sawSpace) { + reportFatalError(scanningTextDecl + ? "SpaceRequiredBeforeEncodingInTextDecl" + : "SpaceRequiredBeforeEncodingInXMLDecl", + null); + } + encoding = fString.toString(); + state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE; + } + else { + if (scanningTextDecl) { + reportFatalError("EncodingDeclRequired", null); + } + else { + reportFatalError("VersionInfoRequired", null); + } + } + break; + } + case STATE_ENCODING: { + if (name == fEncodingSymbol) { + if (!sawSpace) { + reportFatalError(scanningTextDecl + ? "SpaceRequiredBeforeEncodingInTextDecl" + : "SpaceRequiredBeforeEncodingInXMLDecl", + null); + } + encoding = fString.toString(); + state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE; + // TODO: check encoding name; set encoding on + // entity scanner + } + else if (!scanningTextDecl && name == fStandaloneSymbol) { + if (!sawSpace) { + reportFatalError("SpaceRequiredBeforeStandalone", + null); + } + standalone = fString.toString(); + state = STATE_DONE; + if (!standalone.equals("yes") && !standalone.equals("no")) { + reportFatalError("SDDeclInvalid", new Object[] {standalone}); + } + } + else { + reportFatalError("EncodingDeclRequired", null); + } + break; + } + case STATE_STANDALONE: { + if (name == fStandaloneSymbol) { + if (!sawSpace) { + reportFatalError("SpaceRequiredBeforeStandalone", + null); + } + standalone = fString.toString(); + state = STATE_DONE; + if (!standalone.equals("yes") && !standalone.equals("no")) { + reportFatalError("SDDeclInvalid", new Object[] {standalone}); + } + } + else { + reportFatalError("EncodingDeclRequired", null); + } + break; + } + default: { + reportFatalError("NoMorePseudoAttributes", null); + } + } + sawSpace = fEntityScanner.skipDeclSpaces(); + } + // restore original literal value + if(currLiteral) + currEnt.literal = true; + // REVISIT: should we remove this error reporting? + if (scanningTextDecl && state != STATE_DONE) { + reportFatalError("MorePseudoAttributes", null); + } + + // If there is no data in the xml or text decl then we fail to report error + // for version or encoding info above. + if (scanningTextDecl) { + if (!dataFoundForTarget && encoding == null) { + reportFatalError("EncodingDeclRequired", null); + } + } + else { + if (!dataFoundForTarget && version == null) { + reportFatalError("VersionInfoRequired", null); + } + } + + // end + if (!fEntityScanner.skipChar('?')) { + reportFatalError("XMLDeclUnterminated", null); + } + if (!fEntityScanner.skipChar('>')) { + reportFatalError("XMLDeclUnterminated", null); + + } + + // fill in return array + pseudoAttributeValues[0] = version; + pseudoAttributeValues[1] = encoding; + pseudoAttributeValues[2] = standalone; + + } // scanXMLDeclOrTextDecl(boolean) + + /** + * Scans a pseudo attribute. + * + * @param scanningTextDecl True if scanning this pseudo-attribute for a + * TextDecl; false if scanning XMLDecl. This + * flag is needed to report the correct type of + * error. + * @param value The string to fill in with the attribute + * value. + * + * @return The name of the attribute + * + * Note: This method uses fStringBuffer2, anything in it + * at the time of calling is lost. + */ + public String scanPseudoAttribute(boolean scanningTextDecl, + XMLString value) + throws IOException, XNIException { + + // REVISIT: This method is used for generic scanning of + // pseudo attributes, but since there are only three such + // attributes: version, encoding, and standalone there are + // for performant ways of scanning them. Every decl must + // have a version, and in TextDecls this version must + // be followed by an encoding declaration. Also the + // methods we invoke on the scanners allow non-ASCII + // characters to be parsed in the decls, but since + // we don't even know what the actual encoding of the + // document is until we scan the encoding declaration + // you cannot reliably read any characters outside + // of the ASCII range here. -- mrglavas + String name = scanPseudoAttributeName(); + XMLEntityManager.print(fEntityManager.getCurrentEntity()); + if (name == null) { + reportFatalError("PseudoAttrNameExpected", null); + } + fEntityScanner.skipDeclSpaces(); + if (!fEntityScanner.skipChar('=')) { + reportFatalError(scanningTextDecl ? "EqRequiredInTextDecl" + : "EqRequiredInXMLDecl", new Object[]{name}); + } + fEntityScanner.skipDeclSpaces(); + int quote = fEntityScanner.peekChar(); + if (quote != '\'' && quote != '"') { + reportFatalError(scanningTextDecl ? "QuoteRequiredInTextDecl" + : "QuoteRequiredInXMLDecl" , new Object[]{name}); + } + fEntityScanner.scanChar(); + int c = fEntityScanner.scanLiteral(quote, value); + if (c != quote) { + fStringBuffer2.clear(); + do { + fStringBuffer2.append(value); + if (c != -1) { + if (c == '&' || c == '%' || c == '<' || c == ']') { + fStringBuffer2.append((char)fEntityScanner.scanChar()); + } + // REVISIT: Even if you could reliably read non-ASCII chars + // why bother scanning for surrogates here? Only ASCII chars + // match the productions in XMLDecls and TextDecls. -- mrglavas + else if (XMLChar.isHighSurrogate(c)) { + scanSurrogates(fStringBuffer2); + } + else if (isInvalidLiteral(c)) { + String key = scanningTextDecl + ? "InvalidCharInTextDecl" : "InvalidCharInXMLDecl"; + reportFatalError(key, + new Object[] {Integer.toString(c, 16)}); + fEntityScanner.scanChar(); + } + } + c = fEntityScanner.scanLiteral(quote, value); + } while (c != quote); + fStringBuffer2.append(value); + value.setValues(fStringBuffer2); + } + if (!fEntityScanner.skipChar(quote)) { + reportFatalError(scanningTextDecl ? "CloseQuoteMissingInTextDecl" + : "CloseQuoteMissingInXMLDecl", + new Object[]{name}); + } + + // return + return name; + + } // scanPseudoAttribute(XMLString):String + + /** + * Scans the name of a pseudo attribute. The only legal names + * in XML 1.0/1.1 documents are 'version', 'encoding' and 'standalone'. + * + * @return the name of the pseudo attribute or null + * if a legal pseudo attribute name could not be scanned. + */ + private String scanPseudoAttributeName() throws IOException, XNIException { + final int ch = fEntityScanner.peekChar(); + switch (ch) { + case 'v': + if (fEntityScanner.skipString(fVersionSymbol)) { + return fVersionSymbol; + } + break; + case 'e': + if (fEntityScanner.skipString(fEncodingSymbol)) { + return fEncodingSymbol; + } + break; + case 's': + if (fEntityScanner.skipString(fStandaloneSymbol)) { + return fStandaloneSymbol; + } + break; + } + return null; + } // scanPseudoAttributeName() + + /** + * Scans a processing instruction. + *

+ *

+     * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
+     * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
+     * 
+ * Note: This method uses fString, anything in it + * at the time of calling is lost. + */ + protected void scanPI() throws IOException, XNIException { + + // target + fReportEntity = false; + String target = null; + if(fNamespaces) { + target = fEntityScanner.scanNCName(); + } else { + target = fEntityScanner.scanName(); + } + if (target == null) { + reportFatalError("PITargetRequired", null); + } + + // scan data + scanPIData(target, fString); + fReportEntity = true; + + } // scanPI() + + /** + * Scans a processing data. This is needed to handle the situation + * where a document starts with a processing instruction whose + * target name starts with "xml". (e.g. xmlfoo) + * + * Note: This method uses fStringBuffer, anything in it + * at the time of calling is lost. + * + * @param target The PI target + * @param data The string to fill in with the data + */ + protected void scanPIData(String target, XMLString data) + throws IOException, XNIException { + + // check target + if (target.length() == 3) { + char c0 = Character.toLowerCase(target.charAt(0)); + char c1 = Character.toLowerCase(target.charAt(1)); + char c2 = Character.toLowerCase(target.charAt(2)); + if (c0 == 'x' && c1 == 'm' && c2 == 'l') { + reportFatalError("ReservedPITarget", null); + } + } + + // spaces + if (!fEntityScanner.skipSpaces()) { + if (fEntityScanner.skipString("?>")) { + // we found the end, there is no data + data.clear(); + return; + } + else { + if(fNamespaces && fEntityScanner.peekChar() == ':') { + fEntityScanner.scanChar(); + XMLStringBuffer colonName = new XMLStringBuffer(target); + colonName.append(':'); + String str = fEntityScanner.scanName(); + if (str != null) + colonName.append(str); + reportFatalError("ColonNotLegalWithNS", new Object[] {colonName.toString()}); + fEntityScanner.skipSpaces(); + } else { + // if there is data there should be some space + reportFatalError("SpaceRequiredInPI", null); + } + } + } + + fStringBuffer.clear(); + // data + if (fEntityScanner.scanData("?>", fStringBuffer)) { + do { + int c = fEntityScanner.peekChar(); + if (c != -1) { + if (XMLChar.isHighSurrogate(c)) { + scanSurrogates(fStringBuffer); + } + else if (isInvalidLiteral(c)) { + reportFatalError("InvalidCharInPI", + new Object[]{Integer.toHexString(c)}); + fEntityScanner.scanChar(); + } + } + } while (fEntityScanner.scanData("?>", fStringBuffer)); + } + data.setValues(fStringBuffer); + + } // scanPIData(String,XMLString) + + /** + * Scans a comment. + *

+ *

+     * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
+     * 
+ *

+ * Note: Called after scanning past '<!--' + * Note: This method uses fString, anything in it + * at the time of calling is lost. + * + * @param text The buffer to fill in with the text. + */ + protected void scanComment(XMLStringBuffer text) + throws IOException, XNIException { + + // text + // REVISIT: handle invalid character, eof + text.clear(); + while (fEntityScanner.scanData("--", text)) { + int c = fEntityScanner.peekChar(); + if (c != -1) { + if (XMLChar.isHighSurrogate(c)) { + scanSurrogates(text); + } + else if (isInvalidLiteral(c)) { + reportFatalError("InvalidCharInComment", + new Object[] { Integer.toHexString(c) }); + fEntityScanner.scanChar(); + } + } + } + if (!fEntityScanner.skipChar('>')) { + reportFatalError("DashDashInComment", null); + } + + } // scanComment() + + /** + * Scans an attribute value and normalizes whitespace converting all + * whitespace characters to space characters. + * + * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'" + * + * @param value The XMLString to fill in with the value. + * @param nonNormalizedValue The XMLString to fill in with the + * non-normalized value. + * @param atName The name of the attribute being parsed (for error msgs). + * @param checkEntities true if undeclared entities should be reported as VC violation, + * false if undeclared entities should be reported as WFC violation. + * @param eleName The name of element to which this attribute belongs. + * + * @return true if the non-normalized and normalized value are the same + * + * Note: This method uses fStringBuffer2, anything in it + * at the time of calling is lost. + **/ + protected boolean scanAttributeValue(XMLString value, + XMLString nonNormalizedValue, + String atName, + boolean checkEntities,String eleName) + throws IOException, XNIException + { + // quote + int quote = fEntityScanner.peekChar(); + if (quote != '\'' && quote != '"') { + reportFatalError("OpenQuoteExpected", new Object[]{eleName,atName}); + } + + fEntityScanner.scanChar(); + int entityDepth = fEntityDepth; + + int c = fEntityScanner.scanLiteral(quote, value); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** scanLiteral -> \"" + + value.toString() + "\""); + } + + int fromIndex = 0; + if (c == quote && (fromIndex = isUnchangedByNormalization(value)) == -1) { + /** Both the non-normalized and normalized attribute values are equal. **/ + nonNormalizedValue.setValues(value); + int cquote = fEntityScanner.scanChar(); + if (cquote != quote) { + reportFatalError("CloseQuoteExpected", new Object[]{eleName,atName}); + } + return true; + } + fStringBuffer2.clear(); + fStringBuffer2.append(value); + normalizeWhitespace(value, fromIndex); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** normalizeWhitespace -> \"" + + value.toString() + "\""); + } + if (c != quote) { + fScanningAttribute = true; + fStringBuffer.clear(); + do { + fStringBuffer.append(value); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value2: \"" + + fStringBuffer.toString() + "\""); + } + if (c == '&') { + fEntityScanner.skipChar('&'); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append('&'); + } + if (fEntityScanner.skipChar('#')) { + if (entityDepth == fEntityDepth) { + fStringBuffer2.append('#'); + } + int ch = scanCharReferenceValue(fStringBuffer, fStringBuffer2); + if (ch != -1) { + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value3: \"" + + fStringBuffer.toString() + + "\""); + } + } + } + else { + String entityName = fEntityScanner.scanName(); + if (entityName == null) { + reportFatalError("NameRequiredInReference", null); + } + else if (entityDepth == fEntityDepth) { + fStringBuffer2.append(entityName); + } + if (!fEntityScanner.skipChar(';')) { + reportFatalError("SemicolonRequiredInReference", + new Object []{entityName}); + } + else if (entityDepth == fEntityDepth) { + fStringBuffer2.append(';'); + } + if (entityName == fAmpSymbol) { + fStringBuffer.append('&'); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value5: \"" + + fStringBuffer.toString() + + "\""); + } + } + else if (entityName == fAposSymbol) { + fStringBuffer.append('\''); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value7: \"" + + fStringBuffer.toString() + + "\""); + } + } + else if (entityName == fLtSymbol) { + fStringBuffer.append('<'); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** value9: \"" + + fStringBuffer.toString() + + "\""); + } + } + else if (entityName == fGtSymbol) { + fStringBuffer.append('>'); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueB: \"" + + fStringBuffer.toString() + + "\""); + } + } + else if (entityName == fQuotSymbol) { + fStringBuffer.append('"'); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueD: \"" + + fStringBuffer.toString() + + "\""); + } + } + else { + if (fEntityManager.isExternalEntity(entityName)) { + reportFatalError("ReferenceToExternalEntity", + new Object[] { entityName }); + } + else { + if (!fEntityManager.isDeclaredEntity(entityName)) { + //WFC & VC: Entity Declared + if (checkEntities) { + if (fValidation) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "EntityNotDeclared", + new Object[]{entityName}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + else { + reportFatalError("EntityNotDeclared", + new Object[]{entityName}); + } + } + fEntityManager.startEntity(entityName, true); + } + } + } + } + else if (c == '<') { + reportFatalError("LessthanInAttValue", + new Object[] { eleName, atName }); + fEntityScanner.scanChar(); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append((char)c); + } + } + else if (c == '%' || c == ']') { + fEntityScanner.scanChar(); + fStringBuffer.append((char)c); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append((char)c); + } + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueF: \"" + + fStringBuffer.toString() + "\""); + } + } + else if (c == '\n' || c == '\r') { + fEntityScanner.scanChar(); + fStringBuffer.append(' '); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append('\n'); + } + } + else if (c != -1 && XMLChar.isHighSurrogate(c)) { + fStringBuffer3.clear(); + if (scanSurrogates(fStringBuffer3)) { + fStringBuffer.append(fStringBuffer3); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append(fStringBuffer3); + } + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueI: \"" + + fStringBuffer.toString() + + "\""); + } + } + } + else if (c != -1 && isInvalidLiteral(c)) { + reportFatalError("InvalidCharInAttValue", + new Object[] {eleName, atName, Integer.toString(c, 16)}); + fEntityScanner.scanChar(); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append((char)c); + } + } + c = fEntityScanner.scanLiteral(quote, value); + if (entityDepth == fEntityDepth) { + fStringBuffer2.append(value); + } + normalizeWhitespace(value); + } while (c != quote || entityDepth != fEntityDepth); + fStringBuffer.append(value); + if (DEBUG_ATTR_NORMALIZATION) { + System.out.println("** valueN: \"" + + fStringBuffer.toString() + "\""); + } + value.setValues(fStringBuffer); + fScanningAttribute = false; + } + nonNormalizedValue.setValues(fStringBuffer2); + + // quote + int cquote = fEntityScanner.scanChar(); + if (cquote != quote) { + reportFatalError("CloseQuoteExpected", new Object[]{eleName,atName}); + } + return nonNormalizedValue.equals(value.ch, value.offset, value.length); + + } // scanAttributeValue() + + + /** + * Scans External ID and return the public and system IDs. + * + * @param identifiers An array of size 2 to return the system id, + * and public id (in that order). + * @param optionalSystemId Specifies whether the system id is optional. + * + * Note: This method uses fString and fStringBuffer, + * anything in them at the time of calling is lost. + */ + protected void scanExternalID(String[] identifiers, + boolean optionalSystemId) + throws IOException, XNIException { + + String systemId = null; + String publicId = null; + if (fEntityScanner.skipString("PUBLIC")) { + if (!fEntityScanner.skipSpaces()) { + reportFatalError("SpaceRequiredAfterPUBLIC", null); + } + scanPubidLiteral(fString); + publicId = fString.toString(); + + if (!fEntityScanner.skipSpaces() && !optionalSystemId) { + reportFatalError("SpaceRequiredBetweenPublicAndSystem", null); + } + } + + if (publicId != null || fEntityScanner.skipString("SYSTEM")) { + if (publicId == null && !fEntityScanner.skipSpaces()) { + reportFatalError("SpaceRequiredAfterSYSTEM", null); + } + int quote = fEntityScanner.peekChar(); + if (quote != '\'' && quote != '"') { + if (publicId != null && optionalSystemId) { + // looks like we don't have any system id + // simply return the public id + identifiers[0] = null; + identifiers[1] = publicId; + return; + } + reportFatalError("QuoteRequiredInSystemID", null); + } + fEntityScanner.scanChar(); + XMLString ident = fString; + if (fEntityScanner.scanLiteral(quote, ident) != quote) { + fStringBuffer.clear(); + do { + fStringBuffer.append(ident); + int c = fEntityScanner.peekChar(); + if (XMLChar.isMarkup(c) || c == ']') { + fStringBuffer.append((char)fEntityScanner.scanChar()); + } + else if (XMLChar.isHighSurrogate(c)) { + scanSurrogates(fStringBuffer); + } + else if (isInvalidLiteral(c)) { + reportFatalError("InvalidCharInSystemID", + new Object[] { Integer.toHexString(c) }); + fEntityScanner.scanChar(); + } + } while (fEntityScanner.scanLiteral(quote, ident) != quote); + fStringBuffer.append(ident); + ident = fStringBuffer; + } + systemId = ident.toString(); + if (!fEntityScanner.skipChar(quote)) { + reportFatalError("SystemIDUnterminated", null); + } + } + + // store result in array + identifiers[0] = systemId; + identifiers[1] = publicId; + } + + + /** + * Scans public ID literal. + * + * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" + * [13] PubidChar::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] + * + * The returned string is normalized according to the following rule, + * from http://www.w3.org/TR/REC-xml#dt-pubid: + * + * Before a match is attempted, all strings of white space in the public + * identifier must be normalized to single space characters (#x20), and + * leading and trailing white space must be removed. + * + * @param literal The string to fill in with the public ID literal. + * @return True on success. + * + * Note: This method uses fStringBuffer, anything in it at + * the time of calling is lost. + */ + protected boolean scanPubidLiteral(XMLString literal) + throws IOException, XNIException + { + int quote = fEntityScanner.scanChar(); + if (quote != '\'' && quote != '"') { + reportFatalError("QuoteRequiredInPublicID", null); + return false; + } + + fStringBuffer.clear(); + // skip leading whitespace + boolean skipSpace = true; + boolean dataok = true; + while (true) { + int c = fEntityScanner.scanChar(); + if (c == ' ' || c == '\n' || c == '\r') { + if (!skipSpace) { + // take the first whitespace as a space and skip the others + fStringBuffer.append(' '); + skipSpace = true; + } + } + else if (c == quote) { + if (skipSpace) { + // if we finished on a space let's trim it + fStringBuffer.length--; + } + literal.setValues(fStringBuffer); + break; + } + else if (XMLChar.isPubid(c)) { + fStringBuffer.append((char)c); + skipSpace = false; + } + else if (c == -1) { + reportFatalError("PublicIDUnterminated", null); + return false; + } + else { + dataok = false; + reportFatalError("InvalidCharInPublicID", + new Object[]{Integer.toHexString(c)}); + } + } + return dataok; + } + + + /** + * Normalize whitespace in an XMLString converting all whitespace + * characters to space characters. + */ + protected void normalizeWhitespace(XMLString value) { + int end = value.offset + value.length; + for (int i = value.offset; i < end; ++i) { + int c = value.ch[i]; + // Performance: For XML 1.0 documents take advantage of + // the fact that the only legal characters below 0x20 + // are 0x09 (TAB), 0x0A (LF) and 0x0D (CR). Since we've + // already determined the well-formedness of these + // characters it is sufficient (and safe) to check + // against 0x20. -- mrglavas + if (c < 0x20) { + value.ch[i] = ' '; + } + } + } + + /** + * Normalize whitespace in an XMLString converting all whitespace + * characters to space characters. + */ + protected void normalizeWhitespace(XMLString value, int fromIndex) { + int end = value.offset + value.length; + for (int i = value.offset + fromIndex; i < end; ++i) { + int c = value.ch[i]; + // Performance: For XML 1.0 documents take advantage of + // the fact that the only legal characters below 0x20 + // are 0x09 (TAB), 0x0A (LF) and 0x0D (CR). Since we've + // already determined the well-formedness of these + // characters it is sufficient (and safe) to check + // against 0x20. -- mrglavas + if (c < 0x20) { + value.ch[i] = ' '; + } + } + } + + /** + * Checks whether this string would be unchanged by normalization. + * + * @return -1 if the value would be unchanged by normalization, + * otherwise the index of the first whitespace character which + * would be transformed. + */ + protected int isUnchangedByNormalization(XMLString value) { + int end = value.offset + value.length; + for (int i = value.offset; i < end; ++i) { + int c = value.ch[i]; + // Performance: For XML 1.0 documents take advantage of + // the fact that the only legal characters below 0x20 + // are 0x09 (TAB), 0x0A (LF) and 0x0D (CR). Since we've + // already determined the well-formedness of these + // characters it is sufficient (and safe) to check + // against 0x20. -- mrglavas + if (c < 0x20) { + return i - value.offset; + } + } + return -1; + } + + // + // XMLEntityHandler methods + // + + /** + * This method notifies of the start of an entity. The document entity + * has the pseudo-name of "[xml]" the DTD has the pseudo-name of "[dtd]" + * parameter entity names start with '%'; and general entities are just + * specified by their name. + * + * @param name The name of the entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startEntity(String name, + XMLResourceIdentifier identifier, + String encoding, Augmentations augs) throws XNIException { + + // keep track of the entity depth + fEntityDepth++; + // must reset entity scanner + fEntityScanner = fEntityManager.getEntityScanner(); + + } // startEntity(String,XMLResourceIdentifier,String) + + /** + * This method notifies the end of an entity. The document entity has + * the pseudo-name of "[xml]" the DTD has the pseudo-name of "[dtd]" + * parameter entity names start with '%'; and general entities are just + * specified by their name. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endEntity(String name, Augmentations augs) throws XNIException { + + // keep track of the entity depth + fEntityDepth--; + + } // endEntity(String) + + /** + * Scans a character reference and append the corresponding chars to the + * specified buffer. + * + *

+ *

+     * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
+     * 
+ * + * Note: This method uses fStringBuffer, anything in it + * at the time of calling is lost. + * + * @param buf the character buffer to append chars to + * @param buf2 the character buffer to append non-normalized chars to + * + * @return the character value or (-1) on conversion failure + */ + protected int scanCharReferenceValue(XMLStringBuffer buf, XMLStringBuffer buf2) + throws IOException, XNIException { + + // scan hexadecimal value + boolean hex = false; + if (fEntityScanner.skipChar('x')) { + if (buf2 != null) { buf2.append('x'); } + hex = true; + fStringBuffer3.clear(); + boolean digit = true; + + int c = fEntityScanner.peekChar(); + digit = (c >= '0' && c <= '9') || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); + if (digit) { + if (buf2 != null) { buf2.append((char)c); } + fEntityScanner.scanChar(); + fStringBuffer3.append((char)c); + + do { + c = fEntityScanner.peekChar(); + digit = (c >= '0' && c <= '9') || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); + if (digit) { + if (buf2 != null) { buf2.append((char)c); } + fEntityScanner.scanChar(); + fStringBuffer3.append((char)c); + } + } while (digit); + } + else { + reportFatalError("HexdigitRequiredInCharRef", null); + } + } + + // scan decimal value + else { + fStringBuffer3.clear(); + boolean digit = true; + + int c = fEntityScanner.peekChar(); + digit = c >= '0' && c <= '9'; + if (digit) { + if (buf2 != null) { buf2.append((char)c); } + fEntityScanner.scanChar(); + fStringBuffer3.append((char)c); + + do { + c = fEntityScanner.peekChar(); + digit = c >= '0' && c <= '9'; + if (digit) { + if (buf2 != null) { buf2.append((char)c); } + fEntityScanner.scanChar(); + fStringBuffer3.append((char)c); + } + } while (digit); + } + else { + reportFatalError("DigitRequiredInCharRef", null); + } + } + + // end + if (!fEntityScanner.skipChar(';')) { + reportFatalError("SemicolonRequiredInCharRef", null); + } + if (buf2 != null) { buf2.append(';'); } + + // convert string to number + int value = -1; + try { + value = Integer.parseInt(fStringBuffer3.toString(), + hex ? 16 : 10); + + // character reference must be a valid XML character + if (isInvalid(value)) { + StringBuffer errorBuf = new StringBuffer(fStringBuffer3.length + 1); + if (hex) errorBuf.append('x'); + errorBuf.append(fStringBuffer3.ch, fStringBuffer3.offset, fStringBuffer3.length); + reportFatalError("InvalidCharRef", + new Object[]{errorBuf.toString()}); + } + } + catch (NumberFormatException e) { + // Conversion failed, let -1 value drop through. + // If we end up here, the character reference was invalid. + StringBuffer errorBuf = new StringBuffer(fStringBuffer3.length + 1); + if (hex) errorBuf.append('x'); + errorBuf.append(fStringBuffer3.ch, fStringBuffer3.offset, fStringBuffer3.length); + reportFatalError("InvalidCharRef", + new Object[]{errorBuf.toString()}); + } + + // append corresponding chars to the given buffer + if (!XMLChar.isSupplemental(value)) { + buf.append((char) value); + } + else { + // character is supplemental, split it into surrogate chars + buf.append(XMLChar.highSurrogate(value)); + buf.append(XMLChar.lowSurrogate(value)); + } + + // char refs notification code + if (fNotifyCharRefs && value != -1) { + String literal = "#" + (hex ? "x" : "") + fStringBuffer3.toString(); + if (!fScanningAttribute) { + fCharRefLiteral = literal; + } + } + + return value; + } + + // returns true if the given character is not + // valid with respect to the version of + // XML understood by this scanner. + protected boolean isInvalid(int value) { + return (XMLChar.isInvalid(value)); + } // isInvalid(int): boolean + + // returns true if the given character is not + // valid or may not be used outside a character reference + // with respect to the version of XML understood by this scanner. + protected boolean isInvalidLiteral(int value) { + return (XMLChar.isInvalid(value)); + } // isInvalidLiteral(int): boolean + + // returns true if the given character is + // a valid nameChar with respect to the version of + // XML understood by this scanner. + protected boolean isValidNameChar(int value) { + return (XMLChar.isName(value)); + } // isValidNameChar(int): boolean + + // returns true if the given character is + // a valid nameStartChar with respect to the version of + // XML understood by this scanner. + protected boolean isValidNameStartChar(int value) { + return (XMLChar.isNameStart(value)); + } // isValidNameStartChar(int): boolean + + // returns true if the given character is + // a valid NCName character with respect to the version of + // XML understood by this scanner. + protected boolean isValidNCName(int value) { + return (XMLChar.isNCName(value)); + } // isValidNCName(int): boolean + + // returns true if the given character is + // a valid high surrogate for a nameStartChar + // with respect to the version of XML understood + // by this scanner. + protected boolean isValidNameStartHighSurrogate(int value) { + return false; + } // isValidNameStartHighSurrogate(int): boolean + + protected boolean versionSupported(String version ) { + return version.equals("1.0"); + } // version Supported + + // returns the error message key for unsupported + // versions of XML with respect to the version of + // XML understood by this scanner. + protected String getVersionNotSupportedKey () { + return "VersionNotSupported"; + } // getVersionNotSupportedKey: String + + /** + * Scans surrogates and append them to the specified buffer. + *

+ * Note: This assumes the current char has already been + * identified as a high surrogate. + * + * @param buf The StringBuffer to append the read surrogates to. + * @return True if it succeeded. + */ + protected boolean scanSurrogates(XMLStringBuffer buf) + throws IOException, XNIException { + + int high = fEntityScanner.scanChar(); + int low = fEntityScanner.peekChar(); + if (!XMLChar.isLowSurrogate(low)) { + reportFatalError("InvalidCharInContent", + new Object[] {Integer.toString(high, 16)}); + return false; + } + fEntityScanner.scanChar(); + + // convert surrogates to supplemental character + int c = XMLChar.supplemental((char)high, (char)low); + + // supplemental character must be a valid XML character + if (isInvalid(c)) { + reportFatalError("InvalidCharInContent", + new Object[]{Integer.toString(c, 16)}); + return false; + } + + // fill in the buffer + buf.append((char)high); + buf.append((char)low); + + return true; + + } // scanSurrogates():boolean + + + /** + * Convenience function used in all XML scanners. + */ + protected void reportFatalError(String msgId, Object[] args) + throws XNIException { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + msgId, args, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // private methods + private void init() { + fEntityScanner = null; + // initialize vars + fEntityDepth = 0; + fReportEntity = true; + fResourceIdentifier.clear(); + } + +} // class XMLScanner diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/XMLVersionDetector.java b/resources/xerces2-j-src/org/apache/xerces/impl/XMLVersionDetector.java new file mode 100644 index 0000000..e7fd538 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/XMLVersionDetector.java @@ -0,0 +1,242 @@ +/* + * 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. + */ + +package org.apache.xerces.impl; + +import java.io.CharConversionException; +import java.io.EOFException; +import java.io.IOException; + +import org.apache.xerces.impl.io.MalformedByteSequenceException; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * This class scans the version of the document to determine + * which scanner to use: XML 1.1 or XML 1.0. + * The version is scanned using XML 1.1. scanner. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @author Elena Litani, IBM + * @version $Id$ + */ +public class XMLVersionDetector { + + // + // Constants + // + + private static final char[] XML11_VERSION = new char[]{'1', '.', '1'}; + + // property identifiers + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + // + // Data + // + + /** Symbol: "version". */ + protected static final String fVersionSymbol = "version".intern(); + + // symbol: [xml]: + protected static final String fXMLSymbol = "[xml]".intern(); + + /** Symbol table. */ + protected SymbolTable fSymbolTable; + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + /** Entity manager. */ + protected XMLEntityManager fEntityManager; + + protected String fEncoding = null; + + private final char [] fExpectedVersionString = {'<', '?', 'x', 'm', 'l', ' ', 'v', 'e', 'r', 's', + 'i', 'o', 'n', '=', ' ', ' ', ' ', ' ', ' '}; + + /** + * + * + * @param componentManager The component manager. + * + * @throws XNIException Throws exception if required features and + * properties cannot be found. + */ + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + // Xerces properties + fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE); + fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); + fEntityManager = (XMLEntityManager)componentManager.getProperty(ENTITY_MANAGER); + for(int i=14; i currentEntity.ch.length) { + //resize array; this case is hard to imagine... + char[] tempCh = currentEntity.ch; + currentEntity.ch = new char[length+currentEntity.count-currentEntity.position+1]; + System.arraycopy(tempCh, 0, currentEntity.ch, 0, tempCh.length); + } + if(currentEntity.position < length) { + // have to move sensitive stuff out of the way... + System.arraycopy(currentEntity.ch, currentEntity.position, currentEntity.ch, length, currentEntity.count-currentEntity.position); + currentEntity.count += length-currentEntity.position; + } else { + // have to reintroduce some whitespace so this parses: + for(int i=length; iA DTD grammar that produces balanced syntax trees.

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class BalancedDTDGrammar extends DTDGrammar { + + // + // Data + // + + /** Mixed. */ + private boolean fMixed; + + /** Stack depth */ + private int fDepth = 0; + + /** Children content model operation stack. */ + private short [] fOpStack = null; + + /** Holder for choice/sequence/leaf groups at each depth. */ + private int [][] fGroupIndexStack; + + /** Sizes of the allocated portions of each int[] in fGroupIndexStack. */ + private int [] fGroupIndexStackSizes; + + // + // Constructors + // + + /** Default constructor. */ + public BalancedDTDGrammar(SymbolTable symbolTable, XMLDTDDescription desc) { + super(symbolTable, desc); + } // BalancedDTDGrammar(SymbolTable,XMLDTDDescription) + + // + // Public methods + // + + /** + * The start of a content model. Depending on the type of the content + * model, specific methods may be called between the call to the + * startContentModel method and the call to the endContentModel method. + * + * @param elementName The name of the element. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public final void startContentModel(String elementName, Augmentations augs) + throws XNIException { + fDepth = 0; + initializeContentModelStacks(); + super.startContentModel(elementName, augs); + } // startContentModel(String) + + /** + * A start of either a mixed or children content model. A mixed + * content model will immediately be followed by a call to the + * pcdata() method. A children content model will + * contain additional groups and/or elements. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see #any + * @see #empty + */ + public final void startGroup(Augmentations augs) throws XNIException { + ++fDepth; + initializeContentModelStacks(); + fMixed = false; + } // startGroup() + + /** + * The appearance of "#PCDATA" within a group signifying a + * mixed content model. This method will be the first called + * following the content model's startGroup(). + * + *@param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #startGroup + */ + public final void pcdata(Augmentations augs) throws XNIException { + fMixed = true; + } // pcdata() + + /** + * A referenced element in a mixed or children content model. + * + * @param elementName The name of the referenced element. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public final void element(String elementName, Augmentations augs) throws XNIException { + addToCurrentGroup(addUniqueLeafNode(elementName)); + } // element(String) + + /** + * The separator between choices or sequences of a mixed or children + * content model. + * + * @param separator The type of children separator. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_CHOICE + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_SEQUENCE + */ + public final void separator(short separator, Augmentations augs) throws XNIException { + if (separator == XMLDTDContentModelHandler.SEPARATOR_CHOICE) { + fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_CHOICE; + } + else if (separator == XMLDTDContentModelHandler.SEPARATOR_SEQUENCE) { + fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_SEQ; + } + } // separator(short) + + /** + * The occurrence count for a child in a children content model or + * for the mixed content model group. + * + * @param occurrence The occurrence count for the last element + * or group. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_ONE + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_MORE + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ONE_OR_MORE + */ + public final void occurrence(short occurrence, Augmentations augs) throws XNIException { + if (!fMixed) { + int currentIndex = fGroupIndexStackSizes[fDepth] - 1; + if (occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE) { + fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, fGroupIndexStack[fDepth][currentIndex], -1); + } + else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE) { + fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE, fGroupIndexStack[fDepth][currentIndex], -1); + } + else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE) { + fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE, fGroupIndexStack[fDepth][currentIndex], -1); + } + } + } // occurrence(short) + + /** + * The end of a group for mixed or children content models. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public final void endGroup(Augmentations augs) throws XNIException { + final int length = fGroupIndexStackSizes[fDepth]; + final int group = length > 0 ? addContentSpecNodes(0, length - 1) : addUniqueLeafNode(null); + --fDepth; + addToCurrentGroup(group); + } // endGroup() + + /** + * The end of the DTD. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public final void endDTD(Augmentations augs) throws XNIException { + super.endDTD(augs); + fOpStack = null; + fGroupIndexStack = null; + fGroupIndexStackSizes = null; + } // endDTD() + + // + // Protected methods + // + + /** + * Adds the content spec to the given element declaration. + */ + protected final void addContentSpecToElement(XMLElementDecl elementDecl) { + int contentSpec = fGroupIndexStackSizes[0] > 0 ? fGroupIndexStack[0][0] : -1; + setContentSpecIndex(fCurrentElementIndex, contentSpec); + } + + // + // Private methods + // + + /** + * Creates a subtree from the leaf nodes at the current depth. + */ + private int addContentSpecNodes(int begin, int end) { + if (begin == end) { + return fGroupIndexStack[fDepth][begin]; + } + final int middle = (begin + end) >>> 1; + return addContentSpecNode(fOpStack[fDepth], + addContentSpecNodes(begin, middle), + addContentSpecNodes(middle + 1, end)); + } // addContentSpecNodes(int,int) + + /** + * Initialize the stacks which temporarily hold content models. + */ + private void initializeContentModelStacks() { + if (fOpStack == null) { + fOpStack = new short[8]; + fGroupIndexStack = new int [8][]; + fGroupIndexStackSizes = new int [8]; + } + else if (fDepth == fOpStack.length) { + short [] newOpStack = new short[fDepth * 2]; + System.arraycopy(fOpStack, 0, newOpStack, 0, fDepth); + fOpStack = newOpStack; + int [][] newGroupIndexStack = new int[fDepth * 2][]; + System.arraycopy(fGroupIndexStack, 0, newGroupIndexStack, 0, fDepth); + fGroupIndexStack = newGroupIndexStack; + int [] newGroupIndexStackLengths = new int[fDepth * 2]; + System.arraycopy(fGroupIndexStackSizes, 0, newGroupIndexStackLengths, 0, fDepth); + fGroupIndexStackSizes = newGroupIndexStackLengths; + } + fOpStack[fDepth] = -1; + fGroupIndexStackSizes[fDepth] = 0; + } // initializeContentModelStacks() + + /** + * Add XMLContentSpec to the current group. + * + * @param contentSpec handle to the XMLContentSpec to add to the current group + */ + private void addToCurrentGroup(int contentSpec) { + int [] currentGroup = fGroupIndexStack[fDepth]; + int length = fGroupIndexStackSizes[fDepth]++; + if (currentGroup == null) { + currentGroup = new int[8]; + fGroupIndexStack[fDepth] = currentGroup; + } + else if (length == currentGroup.length) { + int [] newGroup = new int[currentGroup.length * 2]; + System.arraycopy(currentGroup, 0, newGroup, 0, currentGroup.length); + currentGroup = newGroup; + fGroupIndexStack[fDepth] = currentGroup; + } + currentGroup[length] = contentSpec; + } // addToCurrentGroup(int) + +} // class BalancedDTDGrammar diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/DTDGrammar.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/DTDGrammar.java new file mode 100644 index 0000000..a06f4d8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/DTDGrammar.java @@ -0,0 +1,2893 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Random; + +import org.apache.xerces.impl.dtd.models.CMAny; +import org.apache.xerces.impl.dtd.models.CMBinOp; +import org.apache.xerces.impl.dtd.models.CMLeaf; +import org.apache.xerces.impl.dtd.models.CMNode; +import org.apache.xerces.impl.dtd.models.CMUniOp; +import org.apache.xerces.impl.dtd.models.ContentModelValidator; +import org.apache.xerces.impl.dtd.models.DFAContentModel; +import org.apache.xerces.impl.dtd.models.MixedContentModel; +import org.apache.xerces.impl.dtd.models.SimpleContentModel; +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.validation.EntityState; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.parser.XMLDTDContentModelSource; +import org.apache.xerces.xni.parser.XMLDTDSource; + +/** + * A DTD grammar. This class implements the XNI handler interfaces + * for DTD information so that it can build the appropriate validation + * structures automatically from the callbacks. + * + * @xerces.internal + * + * @author Eric Ye, IBM + * @author Jeffrey Rodriguez, IBM + * @author Andy Clark, IBM + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class DTDGrammar + implements XMLDTDHandler, XMLDTDContentModelHandler, EntityState, Grammar { + + // + // Constants + // + + /** Top level scope (-1). */ + public static final int TOP_LEVEL_SCOPE = -1; + + // private + + /** Chunk shift (8). */ + private static final int CHUNK_SHIFT = 8; // 2^8 = 256 + + /** Chunk size (1 << CHUNK_SHIFT). */ + private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT); + + /** Chunk mask (CHUNK_SIZE - 1). */ + private static final int CHUNK_MASK = CHUNK_SIZE - 1; + + /** Initial chunk count (1 << (10 - CHUNK_SHIFT)). */ + private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k + + /** List flag (0x80). */ + private static final short LIST_FLAG = 0x80; + + /** List mask (~LIST_FLAG). */ + private static final short LIST_MASK = ~LIST_FLAG; + + // debugging + + /** Debug DTDGrammar. */ + private static final boolean DEBUG = false; + + // + // Data + // + + protected XMLDTDSource fDTDSource = null; + protected XMLDTDContentModelSource fDTDContentModelSource = null; + + /** Current element index. */ + protected int fCurrentElementIndex; + + /** Current attribute index. */ + protected int fCurrentAttributeIndex; + + /** fReadingExternalDTD */ + protected boolean fReadingExternalDTD = false; + + /** Symbol table. */ + private SymbolTable fSymbolTable; + + // The XMLDTDDescription with which this Grammar is associated + protected XMLDTDDescription fGrammarDescription = null; + + // element declarations + + /** Number of element declarations. */ + private int fElementDeclCount = 0; + + /** Element declaration name. */ + private QName fElementDeclName[][] = new QName[INITIAL_CHUNK_COUNT][]; + + /** + * Element declaration type. + * @see XMLElementDecl + */ + private short fElementDeclType[][] = new short[INITIAL_CHUNK_COUNT][]; + + /** + * Element declaration content spec index. This index value is used + * to refer to the content spec information tables. + */ + private int fElementDeclContentSpecIndex[][] = new int[INITIAL_CHUNK_COUNT][]; + + /** + * Element declaration content model validator. This validator is + * constructed from the content spec nodes. + */ + private ContentModelValidator fElementDeclContentModelValidator[][] = new ContentModelValidator[INITIAL_CHUNK_COUNT][]; + + /** First attribute declaration of an element declaration. */ + private int fElementDeclFirstAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][]; + + /** Last attribute declaration of an element declaration. */ + private int fElementDeclLastAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][]; + + // attribute declarations + + /** Number of attribute declarations. */ + private int fAttributeDeclCount = 0 ; + + /** Attribute declaration name. */ + private QName fAttributeDeclName[][] = new QName[INITIAL_CHUNK_COUNT][]; + + // is this grammar immutable? (fully constructed and not changeable) + private boolean fIsImmutable = false; + + /** + * Attribute declaration type. + * @see XMLAttributeDecl + */ + private short fAttributeDeclType[][] = new short[INITIAL_CHUNK_COUNT][]; + + /** Attribute declaration enumeration values. */ + private String[] fAttributeDeclEnumeration[][] = new String[INITIAL_CHUNK_COUNT][][]; + private short fAttributeDeclDefaultType[][] = new short[INITIAL_CHUNK_COUNT][]; + private DatatypeValidator fAttributeDeclDatatypeValidator[][] = new DatatypeValidator[INITIAL_CHUNK_COUNT][]; + private String fAttributeDeclDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][]; + private String fAttributeDeclNonNormalizedDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][]; + private int fAttributeDeclNextAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][]; + + // content specs + + // here saves the content spec binary trees for element decls, + // each element with a content model will hold a pointer which is + // the index of the head node of the content spec tree. + + private int fContentSpecCount = 0; + private short fContentSpecType[][] = new short[INITIAL_CHUNK_COUNT][]; + private Object fContentSpecValue[][] = new Object[INITIAL_CHUNK_COUNT][]; + private Object fContentSpecOtherValue[][] = new Object[INITIAL_CHUNK_COUNT][]; + + // entities + + private int fEntityCount = 0; + private String fEntityName[][] = new String[INITIAL_CHUNK_COUNT][]; + private String[][] fEntityValue = new String[INITIAL_CHUNK_COUNT][]; + private String[][] fEntityPublicId = new String[INITIAL_CHUNK_COUNT][]; + private String[][] fEntitySystemId = new String[INITIAL_CHUNK_COUNT][]; + private String[][] fEntityBaseSystemId = new String[INITIAL_CHUNK_COUNT][]; + private String[][] fEntityNotation = new String[INITIAL_CHUNK_COUNT][]; + private byte[][] fEntityIsPE = new byte[INITIAL_CHUNK_COUNT][]; + private byte[][] fEntityInExternal = new byte[INITIAL_CHUNK_COUNT][]; + + // notations + + private int fNotationCount = 0; + private String fNotationName[][] = new String[INITIAL_CHUNK_COUNT][]; + private String[][] fNotationPublicId = new String[INITIAL_CHUNK_COUNT][]; + private String[][] fNotationSystemId = new String[INITIAL_CHUNK_COUNT][]; + private String[][] fNotationBaseSystemId = new String[INITIAL_CHUNK_COUNT][]; + + // other information + + /** Element index mapping table. */ + private QNameHashtable fElementIndexMap = new QNameHashtable(); + + /** Entity index mapping table. */ + private QNameHashtable fEntityIndexMap = new QNameHashtable(); + + /** Notation index mapping table. */ + private QNameHashtable fNotationIndexMap = new QNameHashtable(); + + // temp variables + + /** Mixed. */ + private boolean fMixed; + + /** Temporary qualified name. */ + private final QName fQName = new QName(); + + /** Temporary qualified name. */ + private final QName fQName2 = new QName(); + + /** Temporary Attribute decl. */ + protected final XMLAttributeDecl fAttributeDecl = new XMLAttributeDecl(); + + // for buildSyntaxTree method + + private int fLeafCount = 0; + private int fEpsilonIndex = -1; + + /** Element declaration. */ + private XMLElementDecl fElementDecl = new XMLElementDecl(); + + /** Entity declaration. */ + private XMLEntityDecl fEntityDecl = new XMLEntityDecl(); + + /** Simple type. */ + private XMLSimpleType fSimpleType = new XMLSimpleType(); + + /** Content spec node. */ + private XMLContentSpec fContentSpec = new XMLContentSpec(); + + /** table of XMLElementDecl */ + Hashtable fElementDeclTab = new Hashtable(); + + /** Children content model operation stack. */ + private short[] fOpStack = null; + + /** Children content model index stack. */ + private int[] fNodeIndexStack = null; + + /** Children content model previous node index stack. */ + private int[] fPrevNodeIndexStack = null; + + /** Stack depth */ + private int fDepth = 0; + + /** Entity stack. */ + private boolean[] fPEntityStack = new boolean[4]; + private int fPEDepth = 0; + + // additional fields(columns) for the element Decl pool in the Grammar + + /** flag if the elementDecl is External. */ + private int fElementDeclIsExternal[][] = new int[INITIAL_CHUNK_COUNT][]; + + + // additional fields(columns) for the attribute Decl pool in the Grammar + + /** flag if the AttributeDecl is External. */ + private int fAttributeDeclIsExternal[][] = new int[INITIAL_CHUNK_COUNT][]; + + // for mixedElement method + + int valueIndex = -1; + int prevNodeIndex = -1; + int nodeIndex = -1; + + // + // Constructors + // + + /** Default constructor. */ + public DTDGrammar(SymbolTable symbolTable, XMLDTDDescription desc) { + fSymbolTable = symbolTable; + fGrammarDescription = desc; + } // (SymbolTable) + + // Grammar methods + + // return the XMLDTDDescription object with which this is associated + public XMLGrammarDescription getGrammarDescription() { + return fGrammarDescription; + } // getGrammarDescription(): XMLGrammarDescription + + // + // Public methods + // + + /** + * Returns true if the specified element declaration is external. + * + * @param elementDeclIndex The element declaration index. + */ + public boolean getElementDeclIsExternal(int elementDeclIndex) { + + if (elementDeclIndex < 0) { + return false; + } + + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + return (fElementDeclIsExternal[chunk][index] != 0); + + } // getElementDeclIsExternal(int):boolean + + /** + * Returns true if the specified attribute declaration is external. + * + * @param attributeDeclIndex Attribute declaration index. + */ + public boolean getAttributeDeclIsExternal(int attributeDeclIndex) { + + if (attributeDeclIndex < 0) { + return false; + } + + int chunk = attributeDeclIndex >> CHUNK_SHIFT; + int index = attributeDeclIndex & CHUNK_MASK; + return (fAttributeDeclIsExternal[chunk][index] != 0); + } + + public int getAttributeDeclIndex(int elementDeclIndex, String attributeDeclName) { + if (elementDeclIndex == -1) { + return -1; + } + int attDefIndex = getFirstAttributeDeclIndex(elementDeclIndex); + while (attDefIndex != -1) { + getAttributeDecl(attDefIndex, fAttributeDecl); + + if (fAttributeDecl.name.rawname == attributeDeclName + || attributeDeclName.equals(fAttributeDecl.name.rawname) ) { + return attDefIndex; + } + attDefIndex = getNextAttributeDeclIndex(attDefIndex); + } + return -1; + } // getAttributeDeclIndex (int,QName) + + // + // XMLDTDHandler methods + // + + /** + * The start of the DTD. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing of + * the document DTD. However, it is strongly + * recommended that a locator be supplied that can + * at least report the base system identifier of the + * DTD. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException { + //Initialize stack + fOpStack = null; + fNodeIndexStack = null; + fPrevNodeIndexStack = null; + } // startDTD(XMLLocator) + + /** + * This method notifies of the start of an entity. The DTD has the + * pseudo-name of "[dtd]" and parameter entity names start with '%'. + *

+ * Note: Since the DTD is an entity, the handler + * will be notified of the start of the DTD entity by calling the + * startParameterEntity method with the entity name "[dtd]" before calling + * the startDTD method. + * + * @param name The name of the parameter entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal parameter entities). + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startParameterEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException { + + // keep track of this entity before fEntityDepth is increased + if (fPEDepth == fPEntityStack.length) { + boolean[] entityarray = new boolean[fPEntityStack.length * 2]; + System.arraycopy(fPEntityStack, 0, entityarray, 0, fPEntityStack.length); + fPEntityStack = entityarray; + } + fPEntityStack[fPEDepth] = fReadingExternalDTD; + fPEDepth++; + + } // startParameterEntity(String,XMLResourceIdentifier,String,Augmentations) + + /** + * The start of the DTD external subset. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startExternalSubset(XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + fReadingExternalDTD = true; + } // startExternalSubset(Augmentations) + + /** + * This method notifies the end of an entity. The DTD has the pseudo-name + * of "[dtd]" and parameter entity names start with '%'. + *

+ * Note: Since the DTD is an entity, the handler + * will be notified of the end of the DTD entity by calling the + * endEntity method with the entity name "[dtd]" after calling + * the endDTD method. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void endParameterEntity(String name, Augmentations augs) throws XNIException { + + fPEDepth--; + fReadingExternalDTD = fPEntityStack[fPEDepth]; + + } // endParameterEntity(String,Augmentations) + + /** + * The end of the DTD external subset. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endExternalSubset(Augmentations augs) throws XNIException { + fReadingExternalDTD = false; + } // endExternalSubset(Augmentations) + + /** + * An element declaration. + * + * @param name The name of the element. + * @param contentModel The element content model. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void elementDecl(String name, String contentModel, Augmentations augs) + throws XNIException { + + XMLElementDecl tmpElementDecl = (XMLElementDecl) fElementDeclTab.get(name) ; + + // check if it is already defined + if ( tmpElementDecl != null ) { + if (tmpElementDecl.type == -1) { + fCurrentElementIndex = getElementDeclIndex(name); + } + else { + // duplicate element, ignored. + return; + } + } + else { + fCurrentElementIndex = createElementDecl();//create element decl + } + + XMLElementDecl elementDecl = new XMLElementDecl(); + + fQName.setValues(null, name, name, null); + + elementDecl.name.setValues(fQName); + + elementDecl.contentModelValidator = null; + elementDecl.scope= -1; + if (contentModel.equals("EMPTY")) { + elementDecl.type = XMLElementDecl.TYPE_EMPTY; + } + else if (contentModel.equals("ANY")) { + elementDecl.type = XMLElementDecl.TYPE_ANY; + } + else if (contentModel.startsWith("(") ) { + if (contentModel.indexOf("#PCDATA") > 0 ) { + elementDecl.type = XMLElementDecl.TYPE_MIXED; + } + else { + elementDecl.type = XMLElementDecl.TYPE_CHILDREN; + } + } + + + //add(or set) this elementDecl to the local cache + this.fElementDeclTab.put(name, elementDecl ); + + fElementDecl = elementDecl; + addContentSpecToElement(elementDecl); + + if ( DEBUG ) { + System.out.println( "name = " + fElementDecl.name.localpart ); + System.out.println( "Type = " + fElementDecl.type ); + } + + setElementDecl(fCurrentElementIndex, fElementDecl );//set internal structure + + int chunk = fCurrentElementIndex >> CHUNK_SHIFT; + int index = fCurrentElementIndex & CHUNK_MASK; + ensureElementDeclCapacity(chunk); + fElementDeclIsExternal[chunk][index] = (fReadingExternalDTD || fPEDepth > 0) ? 1 : 0; + + } // elementDecl(String,String) + + /** + * An attribute declaration. + * + * @param elementName The name of the element that this attribute + * is associated with. + * @param attributeName The name of the attribute. + * @param type The attribute type. This value will be one of + * the following: "CDATA", "ENTITY", "ENTITIES", + * "ENUMERATION", "ID", "IDREF", "IDREFS", + * "NMTOKEN", "NMTOKENS", or "NOTATION". + * @param enumeration If the type has the value "ENUMERATION", this + * array holds the allowed attribute values; + * otherwise, this array is null. + * @param defaultType The attribute default type. This value will be + * one of the following: "#FIXED", "#IMPLIED", + * "#REQUIRED", or null. + * @param defaultValue The attribute default value, or null if no + * default value is specified. + * @param nonNormalizedDefaultValue The attribute default value with no normalization + * performed, or null if no default value is specified. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, + String defaultType, XMLString defaultValue, + XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException { + + if ( this.fElementDeclTab.containsKey( (String) elementName) ) { + //if ElementDecl has already being created in the Grammar then remove from table, + //this.fElementDeclTab.remove( (String) elementName ); + } + // then it is forward reference to a element decl, create the elementDecl first. + else { + fCurrentElementIndex = createElementDecl();//create element decl + + XMLElementDecl elementDecl = new XMLElementDecl(); + elementDecl.name.setValues(null, elementName, elementName, null); + + elementDecl.scope= -1; + + //add(or set) this elementDecl to the local cache + this.fElementDeclTab.put(elementName, elementDecl ); + + //set internal structure + setElementDecl(fCurrentElementIndex, elementDecl ); + } + + //Get Grammar index to grammar array + int elementIndex = getElementDeclIndex(elementName); + + //return, when more than one definition is provided for the same attribute of given element type + //only the first declaration is binding and later declarations are ignored + if (getAttributeDeclIndex(elementIndex, attributeName) != -1) { + return; + } + + fCurrentAttributeIndex = createAttributeDecl();// Create current Attribute Decl + + fSimpleType.clear(); + if ( defaultType != null ) { + if ( defaultType.equals( "#FIXED") ) { + fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_FIXED; + } else if ( defaultType.equals( "#IMPLIED") ) { + fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_IMPLIED; + } else if ( defaultType.equals( "#REQUIRED") ) { + fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_REQUIRED; + } + } + if ( DEBUG ) { + System.out.println("defaultvalue = " + defaultValue.toString() ); + } + fSimpleType.defaultValue = defaultValue!=null ? defaultValue.toString() : null; + fSimpleType.nonNormalizedDefaultValue = nonNormalizedDefaultValue!=null ? nonNormalizedDefaultValue.toString() : null; + fSimpleType.enumeration = enumeration; + + if (type.equals("CDATA")) { + fSimpleType.type = XMLSimpleType.TYPE_CDATA; + } + else if ( type.equals("ID") ) { + fSimpleType.type = XMLSimpleType.TYPE_ID; + } + else if ( type.startsWith("IDREF") ) { + fSimpleType.type = XMLSimpleType.TYPE_IDREF; + if (type.indexOf("S") > 0) { + fSimpleType.list = true; + } + } + else if (type.equals("ENTITIES")) { + fSimpleType.type = XMLSimpleType.TYPE_ENTITY; + fSimpleType.list = true; + } + else if (type.equals("ENTITY")) { + fSimpleType.type = XMLSimpleType.TYPE_ENTITY; + } + else if (type.equals("NMTOKENS")) { + fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN; + fSimpleType.list = true; + } + else if (type.equals("NMTOKEN")) { + fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN; + } + else if (type.startsWith("NOTATION") ) { + fSimpleType.type = XMLSimpleType.TYPE_NOTATION; + } + else if (type.startsWith("ENUMERATION") ) { + fSimpleType.type = XMLSimpleType.TYPE_ENUMERATION; + } + else { + // REVISIT: Report error message. -Ac + System.err.println("!!! unknown attribute type "+type); + } + // REVISIT: The datatype should be stored with the attribute value + // and not special-cased in the XMLValidator. -Ac + //fSimpleType.datatypeValidator = fDatatypeValidatorFactory.createDatatypeValidator(type, null, facets, fSimpleType.list); + + fQName.setValues(null, attributeName, attributeName, null); + fAttributeDecl.setValues( fQName, fSimpleType, false ); + + setAttributeDecl(elementIndex, fCurrentAttributeIndex, fAttributeDecl); + + int chunk = fCurrentAttributeIndex >> CHUNK_SHIFT; + int index = fCurrentAttributeIndex & CHUNK_MASK; + ensureAttributeDeclCapacity(chunk); + fAttributeDeclIsExternal[chunk][index] = (fReadingExternalDTD || fPEDepth > 0) ? 1 : 0; + + } // attributeDecl(String,String,String,String[],String,XMLString,XMLString, Augmentations) + + /** + * An internal entity declaration. + * + * @param name The name of the entity. Parameter entity names start with + * '%', whereas the name of a general entity is just the + * entity name. + * @param text The value of the entity. + * @param nonNormalizedText The non-normalized value of the entity. This + * value contains the same sequence of characters that was in + * the internal entity declaration, without any entity + * references expanded. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void internalEntityDecl(String name, XMLString text, + XMLString nonNormalizedText, + Augmentations augs) throws XNIException { + + int entityIndex = getEntityDeclIndex(name); + if( entityIndex == -1){ + entityIndex = createEntityDecl(); + boolean isPE = name.startsWith("%"); + boolean inExternal = (fReadingExternalDTD || fPEDepth > 0); + XMLEntityDecl entityDecl = new XMLEntityDecl(); + entityDecl.setValues(name,null,null, null, null, + text.toString(), isPE, inExternal); + + setEntityDecl(entityIndex, entityDecl); + } + + } // internalEntityDecl(String,XMLString,XMLString) + + /** + * An external entity declaration. + * + * @param name The name of the entity. Parameter entity names start + * with '%', whereas the name of a general entity is just + * the entity name. + * @param identifier An object containing all location information + * pertinent to this external entity declaration. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void externalEntityDecl(String name, + XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + + int entityIndex = getEntityDeclIndex(name); + if( entityIndex == -1){ + entityIndex = createEntityDecl(); + boolean isPE = name.startsWith("%"); + boolean inExternal = (fReadingExternalDTD || fPEDepth > 0); + + XMLEntityDecl entityDecl = new XMLEntityDecl(); + entityDecl.setValues(name, identifier.getPublicId(), identifier.getLiteralSystemId(), + identifier.getBaseSystemId(), + null, null, isPE, inExternal); + + setEntityDecl(entityIndex, entityDecl); + } + } // externalEntityDecl(String, XMLResourceIdentifier, Augmentations) + + /** + * An unparsed entity declaration. + * + * @param name The name of the entity. + * @param identifier An object containing all location information + * pertinent to this entity. + * @param notation The name of the notation. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier, + String notation, + Augmentations augs) throws XNIException { + + XMLEntityDecl entityDecl = new XMLEntityDecl(); + boolean isPE = name.startsWith("%"); + boolean inExternal = (fReadingExternalDTD || fPEDepth > 0); + + entityDecl.setValues(name,identifier.getPublicId(),identifier.getLiteralSystemId(), + identifier.getBaseSystemId(), notation, + null, isPE, inExternal); + int entityIndex = getEntityDeclIndex(name); + if (entityIndex == -1) { + entityIndex = createEntityDecl(); + setEntityDecl(entityIndex, entityDecl); + } + + } // unparsedEntityDecl(String,StringXMLResourceIdentifier,Augmentations) + + /** + * A notation declaration + * + * @param name The name of the notation. + * @param identifier An object containing all location information + * pertinent to this notation. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void notationDecl(String name, XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + + XMLNotationDecl notationDecl = new XMLNotationDecl(); + notationDecl.setValues(name,identifier.getPublicId(),identifier.getLiteralSystemId(), + identifier.getBaseSystemId()); + int notationIndex = getNotationDeclIndex(name); + if (notationIndex == -1) { + notationIndex = createNotationDecl(); + setNotationDecl(notationIndex, notationDecl); + } + + } // notationDecl(String,XMLResourceIdentifier,Augmentations) + + /** + * The end of the DTD. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDTD(Augmentations augs) throws XNIException { + fIsImmutable = true; + // make sure our description contains useful stuff... + if (fGrammarDescription.getRootName() == null) { + // we don't know what the root is; so use possibleRoots... + int chunk, index = 0; + String currName = null; + final int size = fElementDeclCount; + ArrayList elements = new ArrayList(size); + for (int i = 0; i < size; ++i) { + chunk = i >> CHUNK_SHIFT; + index = i & CHUNK_MASK; + currName = fElementDeclName[chunk][index].rawname; + elements.add(currName); + } + fGrammarDescription.setPossibleRoots(elements); + } + } // endDTD() + + // sets the source of this handler + public void setDTDSource(XMLDTDSource source) { + fDTDSource = source; + } // setDTDSource(XMLDTDSource) + + // returns the source of this handler + public XMLDTDSource getDTDSource() { + return fDTDSource; + } // getDTDSource(): XMLDTDSource + + // no-op methods + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

+ * Note: This method is only called for external + * parameter entities referenced in the DTD. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) + throws XNIException {} + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException {} + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, + Augmentations augs) throws XNIException {} + + /** + * The start of an attribute list. + * + * @param elementName The name of the element that this attribute + * list is associated with. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void startAttlist(String elementName, Augmentations augs) + throws XNIException {} + + /** + * The end of an attribute list. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void endAttlist(Augmentations augs) throws XNIException {} + + /** + * The start of a conditional section. + * + * @param type The type of the conditional section. This value will + * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see XMLDTDHandler#CONDITIONAL_INCLUDE + * @see XMLDTDHandler#CONDITIONAL_IGNORE + */ + public void startConditional(short type, Augmentations augs) + throws XNIException {} + + /** + * Characters within an IGNORE conditional section. + * + * @param text The ignored text. + * @param augs Additional information that may include infoset + * augmentations. + */ + public void ignoredCharacters(XMLString text, Augmentations augs) + throws XNIException {} + + /** + * The end of a conditional section. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void endConditional(Augmentations augs) throws XNIException {} + + // + // XMLDTDContentModelHandler methods + // + + // set content model source + public void setDTDContentModelSource(XMLDTDContentModelSource source) { + fDTDContentModelSource = source; + } + + // get content model source + public XMLDTDContentModelSource getDTDContentModelSource() { + return fDTDContentModelSource; + } + + /** + * The start of a content model. Depending on the type of the content + * model, specific methods may be called between the call to the + * startContentModel method and the call to the endContentModel method. + * + * @param elementName The name of the element. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void startContentModel(String elementName, Augmentations augs) + throws XNIException { + + XMLElementDecl elementDecl = (XMLElementDecl) this.fElementDeclTab.get( elementName); + if ( elementDecl != null ) { + fElementDecl = elementDecl; + } + fDepth = 0; + initializeContentModelStack(); + + } // startContentModel(String) + + /** + * A start of either a mixed or children content model. A mixed + * content model will immediately be followed by a call to the + * pcdata() method. A children content model will + * contain additional groups and/or elements. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see #any + * @see #empty + */ + public void startGroup(Augmentations augs) throws XNIException { + fDepth++; + initializeContentModelStack(); + fMixed = false; + } // startGroup() + + /** + * The appearance of "#PCDATA" within a group signifying a + * mixed content model. This method will be the first called + * following the content model's startGroup(). + * + *@param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #startGroup + */ + public void pcdata(Augmentations augs) throws XNIException { + fMixed = true; + } // pcdata() + + /** + * A referenced element in a mixed or children content model. + * + * @param elementName The name of the referenced element. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void element(String elementName, Augmentations augs) throws XNIException { + if (fMixed) { + if (fNodeIndexStack[fDepth] == -1 ) { + fNodeIndexStack[fDepth] = addUniqueLeafNode(elementName); + } + else { + fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_CHOICE, + fNodeIndexStack[fDepth], + addUniqueLeafNode(elementName)); + } + } + else { + fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF, elementName); + } + } // element(String) + + /** + * The separator between choices or sequences of a mixed or children + * content model. + * + * @param separator The type of children separator. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_CHOICE + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_SEQUENCE + */ + public void separator(short separator, Augmentations augs) throws XNIException { + + if (!fMixed) { + if (fOpStack[fDepth] != XMLContentSpec.CONTENTSPECNODE_SEQ && separator == XMLDTDContentModelHandler.SEPARATOR_CHOICE ) { + if (fPrevNodeIndexStack[fDepth] != -1) { + fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]); + } + fPrevNodeIndexStack[fDepth] = fNodeIndexStack[fDepth]; + fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_CHOICE; + } else if (fOpStack[fDepth] != XMLContentSpec.CONTENTSPECNODE_CHOICE && separator == XMLDTDContentModelHandler.SEPARATOR_SEQUENCE) { + if (fPrevNodeIndexStack[fDepth] != -1) { + fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]); + } + fPrevNodeIndexStack[fDepth] = fNodeIndexStack[fDepth]; + fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_SEQ; + } + } + + } // separator(short) + + /** + * The occurrence count for a child in a children content model or + * for the mixed content model group. + * + * @param occurrence The occurrence count for the last element + * or group. + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_ONE + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_MORE + * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ONE_OR_MORE + */ + public void occurrence(short occurrence, Augmentations augs) throws XNIException { + + if (!fMixed) { + if (occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE ) { + fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, fNodeIndexStack[fDepth], -1); + } else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE ) { + fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE, fNodeIndexStack[fDepth], -1 ); + } else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE) { + fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE, fNodeIndexStack[fDepth], -1 ); + } + } + + } // occurrence(short) + + /** + * The end of a group for mixed or children content models. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + */ + public void endGroup(Augmentations augs) throws XNIException { + + if (!fMixed) { + if (fPrevNodeIndexStack[fDepth] != -1) { + fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]); + } + int nodeIndex = fNodeIndexStack[fDepth--]; + fNodeIndexStack[fDepth] = nodeIndex; + } + + } // endGroup() + + // no-op methods + + /** + * A content model of ANY. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see #empty + * @see #startGroup + */ + public void any(Augmentations augs) throws XNIException {} + + /** + * A content model of EMPTY. + * + * @param augs Additional information that may include infoset + * augmentations. + * @throws XNIException Thrown by handler to signal an error. + * + * @see #any + * @see #startGroup + */ + public void empty(Augmentations augs) throws XNIException {} + + /** + * The end of a content model. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endContentModel(Augmentations augs) throws XNIException {} + + // + // Grammar methods + // + + /** Returns true if this grammar is namespace aware. */ + public boolean isNamespaceAware() { + return false; + } // isNamespaceAware():boolean + + /** Returns the symbol table. */ + public SymbolTable getSymbolTable() { + return fSymbolTable; + } // getSymbolTable():SymbolTable + + /** + * Returns the index of the first element declaration. This index + * is then used to query more information about the element declaration. + * + * @see #getNextElementDeclIndex + * @see #getElementDecl + */ + public int getFirstElementDeclIndex() { + return fElementDeclCount >= 0 ? 0 : -1; + } // getFirstElementDeclIndex():int + + /** + * Returns the next index of the element declaration following the + * specified element declaration. + * + * @param elementDeclIndex The element declaration index. + */ + public int getNextElementDeclIndex(int elementDeclIndex) { + return elementDeclIndex < fElementDeclCount - 1 + ? elementDeclIndex + 1 : -1; + } // getNextElementDeclIndex(int):int + + /** + * getElementDeclIndex + * + * @param elementDeclName + * + * @return index of the elementDeclName in scope + */ + public int getElementDeclIndex(String elementDeclName) { + int mapping = fElementIndexMap.get(elementDeclName); + //System.out.println("getElementDeclIndex("+elementDeclName+") -> "+mapping); + return mapping; + } // getElementDeclIndex(String):int + + /** Returns the element decl index. + * @param elementDeclQName qualilfied name of the element + */ + public int getElementDeclIndex(QName elementDeclQName) { + return getElementDeclIndex(elementDeclQName.rawname); + } // getElementDeclIndex(QName):int + + /** make separate function for getting contentSpecType of element. + * we can avoid setting of the element values. + */ + + public short getContentSpecType(int elementIndex){ + if (elementIndex < 0 || elementIndex >= fElementDeclCount) { + return -1 ; + } + + int chunk = elementIndex >> CHUNK_SHIFT; + int index = elementIndex & CHUNK_MASK; + + if(fElementDeclType[chunk][index] == -1){ + return -1 ; + } + else{ + return (short) (fElementDeclType[chunk][index] & LIST_MASK); + } + + }//getContentSpecType + + /** + * getElementDecl + * + * @param elementDeclIndex + * @param elementDecl The values of this structure are set by this call. + * + * @return True if find the element, False otherwise. + */ + public boolean getElementDecl(int elementDeclIndex, + XMLElementDecl elementDecl) { + + if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { + return false; + } + + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + + elementDecl.name.setValues(fElementDeclName[chunk][index]); + + if (fElementDeclType[chunk][index] == -1) { + elementDecl.type = -1; + elementDecl.simpleType.list = false; + } else { + elementDecl.type = (short) (fElementDeclType[chunk][index] & LIST_MASK); + elementDecl.simpleType.list = (fElementDeclType[chunk][index] & LIST_FLAG) != 0; + } + + /* Validators are null until we add that code */ + if (elementDecl.type == XMLElementDecl.TYPE_CHILDREN || elementDecl.type == XMLElementDecl.TYPE_MIXED) { + elementDecl.contentModelValidator = getElementContentModelValidator(elementDeclIndex); + } + + elementDecl.simpleType.datatypeValidator = null; + elementDecl.simpleType.defaultType = -1; + elementDecl.simpleType.defaultValue = null; + + return true; + + } // getElementDecl(int,XMLElementDecl):boolean + + QName getElementDeclName(int elementDeclIndex) { + if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { + return null; + } + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + return fElementDeclName[chunk][index]; + } + + // REVISIT: Make this getAttributeDeclCount/getAttributeDeclAt. -Ac + + /** + * getFirstAttributeDeclIndex + * + * @param elementDeclIndex + * + * @return index of the first attribute for element declaration elementDeclIndex + */ + public int getFirstAttributeDeclIndex(int elementDeclIndex) { + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + + return fElementDeclFirstAttributeDeclIndex[chunk][index]; + } // getFirstAttributeDeclIndex + + /** + * getNextAttributeDeclIndex + * + * @param attributeDeclIndex + * + * @return index of the next attribute of the attribute at attributeDeclIndex + */ + public int getNextAttributeDeclIndex(int attributeDeclIndex) { + int chunk = attributeDeclIndex >> CHUNK_SHIFT; + int index = attributeDeclIndex & CHUNK_MASK; + + return fAttributeDeclNextAttributeDeclIndex[chunk][index]; + } // getNextAttributeDeclIndex + + /** + * getAttributeDecl + * + * @param attributeDeclIndex + * @param attributeDecl The values of this structure are set by this call. + * + * @return true if getAttributeDecl was able to fill in the value of attributeDecl + */ + public boolean getAttributeDecl(int attributeDeclIndex, XMLAttributeDecl attributeDecl) { + if (attributeDeclIndex < 0 || attributeDeclIndex >= fAttributeDeclCount) { + return false; + } + int chunk = attributeDeclIndex >> CHUNK_SHIFT; + int index = attributeDeclIndex & CHUNK_MASK; + + attributeDecl.name.setValues(fAttributeDeclName[chunk][index]); + + short attributeType; + boolean isList; + + if (fAttributeDeclType[chunk][index] == -1) { + + attributeType = -1; + isList = false; + } else { + attributeType = (short) (fAttributeDeclType[chunk][index] & LIST_MASK); + isList = (fAttributeDeclType[chunk][index] & LIST_FLAG) != 0; + } + attributeDecl.simpleType.setValues(attributeType,fAttributeDeclName[chunk][index].localpart, + fAttributeDeclEnumeration[chunk][index], + isList, fAttributeDeclDefaultType[chunk][index], + fAttributeDeclDefaultValue[chunk][index], + fAttributeDeclNonNormalizedDefaultValue[chunk][index], + fAttributeDeclDatatypeValidator[chunk][index]); + return true; + + } // getAttributeDecl + + + /** + * Returns whether the given attribute is of type CDATA or not + * + * @param elName The element name. + * @param atName The attribute name. + * + * @return true if the attribute is of type CDATA + */ + public boolean isCDATAAttribute(QName elName, QName atName) { + int elDeclIdx = getElementDeclIndex(elName); + if (getAttributeDecl(elDeclIdx, fAttributeDecl) + && fAttributeDecl.simpleType.type != XMLSimpleType.TYPE_CDATA){ + return false; + } + return true; + } + + /** + * getEntityDeclIndex + * + * @param entityDeclName + * + * @return the index of the EntityDecl + */ + public int getEntityDeclIndex(String entityDeclName) { + if (entityDeclName == null) { + return -1; + } + + return fEntityIndexMap.get(entityDeclName); + } // getEntityDeclIndex + + /** + * getEntityDecl + * + * @param entityDeclIndex + * @param entityDecl + * + * @return true if getEntityDecl was able to fill entityDecl with the contents of the entity + * with index entityDeclIndex + */ + public boolean getEntityDecl(int entityDeclIndex, XMLEntityDecl entityDecl) { + if (entityDeclIndex < 0 || entityDeclIndex >= fEntityCount) { + return false; + } + int chunk = entityDeclIndex >> CHUNK_SHIFT; + int index = entityDeclIndex & CHUNK_MASK; + + entityDecl.setValues(fEntityName[chunk][index], + fEntityPublicId[chunk][index], + fEntitySystemId[chunk][index], + fEntityBaseSystemId[chunk][index], + fEntityNotation[chunk][index], + fEntityValue[chunk][index], + fEntityIsPE[chunk][index] == 0 ? false : true , + fEntityInExternal[chunk][index] == 0 ? false : true ); + + return true; + } // getEntityDecl + + /** + * getNotationDeclIndex + * + * @param notationDeclName + * + * @return the index if found a notation with the name, otherwise -1. + */ + public int getNotationDeclIndex(String notationDeclName) { + if (notationDeclName == null) { + return -1; + } + + return fNotationIndexMap.get(notationDeclName); + } // getNotationDeclIndex + + /** + * getNotationDecl + * + * @param notationDeclIndex + * @param notationDecl + * + * @return return true of getNotationDecl can fill notationDecl with information about + * the notation at notationDeclIndex. + */ + public boolean getNotationDecl(int notationDeclIndex, XMLNotationDecl notationDecl) { + if (notationDeclIndex < 0 || notationDeclIndex >= fNotationCount) { + return false; + } + int chunk = notationDeclIndex >> CHUNK_SHIFT; + int index = notationDeclIndex & CHUNK_MASK; + + notationDecl.setValues(fNotationName[chunk][index], + fNotationPublicId[chunk][index], + fNotationSystemId[chunk][index], + fNotationBaseSystemId[chunk][index]); + + return true; + + } // getNotationDecl + + /** + * getContentSpec + * + * @param contentSpecIndex + * @param contentSpec + * + * @return true if find the requested contentSpec node, false otherwise + */ + public boolean getContentSpec(int contentSpecIndex, XMLContentSpec contentSpec) { + if (contentSpecIndex < 0 || contentSpecIndex >= fContentSpecCount ) + return false; + + int chunk = contentSpecIndex >> CHUNK_SHIFT; + int index = contentSpecIndex & CHUNK_MASK; + + contentSpec.type = fContentSpecType[chunk][index]; + contentSpec.value = fContentSpecValue[chunk][index]; + contentSpec.otherValue = fContentSpecOtherValue[chunk][index]; + return true; + } + + /** + * Returns the index to the content spec for the given element + * declaration, or -1 if the element declaration + * index was invalid. + */ + public int getContentSpecIndex(int elementDeclIndex) { + if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { + return -1; + } + final int chunk = elementDeclIndex >> CHUNK_SHIFT; + final int index = elementDeclIndex & CHUNK_MASK; + return fElementDeclContentSpecIndex[chunk][index]; + } + + /** + * getContentSpecAsString + * + * @param elementDeclIndex + * + * @return String + */ + public String getContentSpecAsString(int elementDeclIndex){ + + if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { + return null; + } + + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + + int contentSpecIndex = fElementDeclContentSpecIndex[chunk][index]; + + // lookup content spec node + XMLContentSpec contentSpec = new XMLContentSpec(); + + if (getContentSpec(contentSpecIndex, contentSpec)) { + + // build string + StringBuffer str = new StringBuffer(); + int parentContentSpecType = contentSpec.type & 0x0f; + int nextContentSpec; + switch (parentContentSpecType) { + case XMLContentSpec.CONTENTSPECNODE_LEAF: { + str.append('('); + if (contentSpec.value == null && contentSpec.otherValue == null) { + str.append("#PCDATA"); + } + else { + str.append(contentSpec.value); + } + str.append(')'); + break; + } + case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: { + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + nextContentSpec = contentSpec.type; + + if (nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) { + str.append('('); + str.append(contentSpec.value); + str.append(')'); + } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE || + nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE || + nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) { + str.append('(' ); + appendContentSpec(contentSpec, str, + true, parentContentSpecType ); + str.append(')'); + } else { + appendContentSpec(contentSpec, str, + true, parentContentSpecType ); + } + str.append('?'); + break; + } + case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: { + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + nextContentSpec = contentSpec.type; + + if ( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) { + str.append('('); + if (contentSpec.value == null && contentSpec.otherValue == null) { + str.append("#PCDATA"); + } + else if (contentSpec.otherValue != null) { + str.append("##any:uri=").append(contentSpec.otherValue); + } + else if (contentSpec.value == null) { + str.append("##any"); + } + else { + appendContentSpec(contentSpec, str, + true, parentContentSpecType ); + } + str.append(')'); + } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE || + nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE || + nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) { + str.append('(' ); + appendContentSpec(contentSpec, str, + true, parentContentSpecType ); + str.append(')'); + } else { + appendContentSpec(contentSpec, str, + true, parentContentSpecType ); + } + str.append('*'); + break; + } + case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: { + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + nextContentSpec = contentSpec.type; + + if ( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) { + str.append('('); + if (contentSpec.value == null && contentSpec.otherValue == null) { + str.append("#PCDATA"); + } + else if (contentSpec.otherValue != null) { + str.append("##any:uri=").append(contentSpec.otherValue); + } + else if (contentSpec.value == null) { + str.append("##any"); + } + else { + str.append(contentSpec.value); + } + str.append(')'); + } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE || + nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE || + nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) { + str.append('(' ); + appendContentSpec(contentSpec, str, + true, parentContentSpecType ); + str.append(')'); + } else { + appendContentSpec(contentSpec, str, + true, parentContentSpecType); + } + str.append('+'); + break; + } + case XMLContentSpec.CONTENTSPECNODE_CHOICE: + case XMLContentSpec.CONTENTSPECNODE_SEQ: { + appendContentSpec(contentSpec, str, + true, parentContentSpecType ); + break; + } + case XMLContentSpec.CONTENTSPECNODE_ANY: { + str.append("##any"); + if (contentSpec.otherValue != null) { + str.append(":uri="); + str.append(contentSpec.otherValue); + } + break; + } + case XMLContentSpec.CONTENTSPECNODE_ANY_OTHER: { + str.append("##other:uri="); + str.append(contentSpec.otherValue); + break; + } + case XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL: { + str.append("##local"); + break; + } + default: { + str.append("???"); + } + + } // switch type + + // return string + return str.toString(); + } + + // not found + return null; + + } // getContentSpecAsString(int):String + + // debugging + + public void printElements( ) { + int elementDeclIndex = 0; + XMLElementDecl elementDecl = new XMLElementDecl(); + while (getElementDecl(elementDeclIndex++, elementDecl)) { + + System.out.println("element decl: "+elementDecl.name+ + ", "+ elementDecl.name.rawname ); + + // ", "+ elementDecl.contentModelValidator.toString()); + } + } + + public void printAttributes(int elementDeclIndex) { + int attributeDeclIndex = getFirstAttributeDeclIndex(elementDeclIndex); + System.out.print(elementDeclIndex); + System.out.print(" ["); + while (attributeDeclIndex != -1) { + System.out.print(' '); + System.out.print(attributeDeclIndex); + printAttribute(attributeDeclIndex); + attributeDeclIndex = getNextAttributeDeclIndex(attributeDeclIndex); + if (attributeDeclIndex != -1) { + System.out.print(","); + } + } + System.out.println(" ]"); + } + + // + // Protected methods + // + + /** + * Adds the content spec to the given element declaration. + */ + protected void addContentSpecToElement(XMLElementDecl elementDecl) { + if ((fDepth == 0 || (fDepth == 1 && elementDecl.type == XMLElementDecl.TYPE_MIXED)) && + fNodeIndexStack != null) { + if (elementDecl.type == XMLElementDecl.TYPE_MIXED) { + int pcdata = addUniqueLeafNode(null); + if (fNodeIndexStack[0] == -1) { + fNodeIndexStack[0] = pcdata; + } + else { + fNodeIndexStack[0] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_CHOICE, + pcdata, fNodeIndexStack[0]); + } + } + setContentSpecIndex(fCurrentElementIndex, fNodeIndexStack[fDepth]); + } + } + + /** + * getElementContentModelValidator + * + * @param elementDeclIndex + * + * @return its ContentModelValidator if any. + */ + protected ContentModelValidator getElementContentModelValidator(int elementDeclIndex) { + + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + + ContentModelValidator contentModel = fElementDeclContentModelValidator[chunk][index]; + + // If we have one, just return that. Otherwise, gotta create one + if (contentModel != null) { + return contentModel; + } + + int contentType = fElementDeclType[chunk][index]; + if (contentType == XMLElementDecl.TYPE_SIMPLE) { + return null; + } + + // Get the type of content this element has + int contentSpecIndex = fElementDeclContentSpecIndex[chunk][index]; + + /*** + if ( contentSpecIndex == -1 ) + return null; + /***/ + + XMLContentSpec contentSpec = new XMLContentSpec(); + getContentSpec( contentSpecIndex, contentSpec ); + + // And create the content model according to the spec type + if ( contentType == XMLElementDecl.TYPE_MIXED ) { + // + // Just create a mixel content model object. This type of + // content model is optimized for mixed content validation. + // + ChildrenList children = new ChildrenList(); + contentSpecTree(contentSpecIndex, contentSpec, children); + contentModel = new MixedContentModel(children.qname, + children.type, + 0, children.length, + false); + } else if (contentType == XMLElementDecl.TYPE_CHILDREN) { + // This method will create an optimal model for the complexity + // of the element's defined model. If its simple, it will create + // a SimpleContentModel object. If its a simple list, it will + // create a SimpleListContentModel object. If its complex, it + // will create a DFAContentModel object. + // + contentModel = createChildModel(contentSpecIndex); + } else { + throw new RuntimeException("Unknown content type for a element decl " + + "in getElementContentModelValidator() in AbstractDTDGrammar class"); + } + + // Add the new model to the content model for this element + fElementDeclContentModelValidator[chunk][index] = contentModel; + + return contentModel; + + } // getElementContentModelValidator(int):ContentModelValidator + + protected int createElementDecl() { + int chunk = fElementDeclCount >> CHUNK_SHIFT; + int index = fElementDeclCount & CHUNK_MASK; + ensureElementDeclCapacity(chunk); + fElementDeclName[chunk][index] = new QName(); + fElementDeclType[chunk][index] = -1; + fElementDeclContentModelValidator[chunk][index] = null; + fElementDeclFirstAttributeDeclIndex[chunk][index] = -1; + fElementDeclLastAttributeDeclIndex[chunk][index] = -1; + return fElementDeclCount++; + } + + protected void setElementDecl(int elementDeclIndex, XMLElementDecl elementDecl) { + if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { + return; + } + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + + fElementDeclName[chunk][index].setValues(elementDecl.name); + fElementDeclType[chunk][index] = elementDecl.type; + + fElementDeclContentModelValidator[chunk][index] = elementDecl.contentModelValidator; + + if (elementDecl.simpleType.list == true ) { + fElementDeclType[chunk][index] |= LIST_FLAG; + } + + fElementIndexMap.put(elementDecl.name.rawname, elementDeclIndex); + } + + + + + protected void putElementNameMapping(QName name, int scope, + int elementDeclIndex) { + } + + protected void setFirstAttributeDeclIndex(int elementDeclIndex, int newFirstAttrIndex){ + + if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { + return; + } + + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + + fElementDeclFirstAttributeDeclIndex[chunk][index] = newFirstAttrIndex; + } + + protected void setContentSpecIndex(int elementDeclIndex, int contentSpecIndex){ + + if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { + return; + } + + int chunk = elementDeclIndex >> CHUNK_SHIFT; + int index = elementDeclIndex & CHUNK_MASK; + + fElementDeclContentSpecIndex[chunk][index] = contentSpecIndex; + } + + + protected int createAttributeDecl() { + int chunk = fAttributeDeclCount >> CHUNK_SHIFT; + int index = fAttributeDeclCount & CHUNK_MASK; + + ensureAttributeDeclCapacity(chunk); + fAttributeDeclName[chunk][index] = new QName(); + fAttributeDeclType[chunk][index] = -1; + fAttributeDeclDatatypeValidator[chunk][index] = null; + fAttributeDeclEnumeration[chunk][index] = null; + fAttributeDeclDefaultType[chunk][index] = XMLSimpleType.DEFAULT_TYPE_IMPLIED; + fAttributeDeclDefaultValue[chunk][index] = null; + fAttributeDeclNonNormalizedDefaultValue[chunk][index] = null; + fAttributeDeclNextAttributeDeclIndex[chunk][index] = -1; + return fAttributeDeclCount++; + } + + + protected void setAttributeDecl(int elementDeclIndex, int attributeDeclIndex, + XMLAttributeDecl attributeDecl) { + int attrChunk = attributeDeclIndex >> CHUNK_SHIFT; + int attrIndex = attributeDeclIndex & CHUNK_MASK; + fAttributeDeclName[attrChunk][attrIndex].setValues(attributeDecl.name); + fAttributeDeclType[attrChunk][attrIndex] = attributeDecl.simpleType.type; + + if (attributeDecl.simpleType.list) { + fAttributeDeclType[attrChunk][attrIndex] |= LIST_FLAG; + } + fAttributeDeclEnumeration[attrChunk][attrIndex] = attributeDecl.simpleType.enumeration; + fAttributeDeclDefaultType[attrChunk][attrIndex] = attributeDecl.simpleType.defaultType; + fAttributeDeclDatatypeValidator[attrChunk][attrIndex] = attributeDecl.simpleType.datatypeValidator; + + fAttributeDeclDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.defaultValue; + fAttributeDeclNonNormalizedDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.nonNormalizedDefaultValue; + + int elemChunk = elementDeclIndex >> CHUNK_SHIFT; + int elemIndex = elementDeclIndex & CHUNK_MASK; + int index = fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex]; + while (index != -1) { + if (index == attributeDeclIndex) { + break; + } + attrChunk = index >> CHUNK_SHIFT; + attrIndex = index & CHUNK_MASK; + index = fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex]; + } + if (index == -1) { + if (fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] == -1) { + fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex; + } else { + index = fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex]; + attrChunk = index >> CHUNK_SHIFT; + attrIndex = index & CHUNK_MASK; + fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex] = attributeDeclIndex; + } + fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex; + } + } + + protected int createContentSpec() { + int chunk = fContentSpecCount >> CHUNK_SHIFT; + int index = fContentSpecCount & CHUNK_MASK; + + ensureContentSpecCapacity(chunk); + fContentSpecType[chunk][index] = -1; + fContentSpecValue[chunk][index] = null; + fContentSpecOtherValue[chunk][index] = null; + + return fContentSpecCount++; + } + + protected void setContentSpec(int contentSpecIndex, XMLContentSpec contentSpec) { + int chunk = contentSpecIndex >> CHUNK_SHIFT; + int index = contentSpecIndex & CHUNK_MASK; + + fContentSpecType[chunk][index] = contentSpec.type; + fContentSpecValue[chunk][index] = contentSpec.value; + fContentSpecOtherValue[chunk][index] = contentSpec.otherValue; + } + + + protected int createEntityDecl() { + int chunk = fEntityCount >> CHUNK_SHIFT; + int index = fEntityCount & CHUNK_MASK; + + ensureEntityDeclCapacity(chunk); + fEntityIsPE[chunk][index] = 0; + fEntityInExternal[chunk][index] = 0; + + return fEntityCount++; + } + + protected void setEntityDecl(int entityDeclIndex, XMLEntityDecl entityDecl) { + int chunk = entityDeclIndex >> CHUNK_SHIFT; + int index = entityDeclIndex & CHUNK_MASK; + + fEntityName[chunk][index] = entityDecl.name; + fEntityValue[chunk][index] = entityDecl.value; + fEntityPublicId[chunk][index] = entityDecl.publicId; + fEntitySystemId[chunk][index] = entityDecl.systemId; + fEntityBaseSystemId[chunk][index] = entityDecl.baseSystemId; + fEntityNotation[chunk][index] = entityDecl.notation; + fEntityIsPE[chunk][index] = entityDecl.isPE ? (byte)1 : (byte)0; + fEntityInExternal[chunk][index] = entityDecl.inExternal ? (byte)1 : (byte)0; + + fEntityIndexMap.put(entityDecl.name, entityDeclIndex); + } + + protected int createNotationDecl() { + int chunk = fNotationCount >> CHUNK_SHIFT; + ensureNotationDeclCapacity(chunk); + return fNotationCount++; + } + + protected void setNotationDecl(int notationDeclIndex, XMLNotationDecl notationDecl) { + int chunk = notationDeclIndex >> CHUNK_SHIFT; + int index = notationDeclIndex & CHUNK_MASK; + + fNotationName[chunk][index] = notationDecl.name; + fNotationPublicId[chunk][index] = notationDecl.publicId; + fNotationSystemId[chunk][index] = notationDecl.systemId; + fNotationBaseSystemId[chunk][index] = notationDecl.baseSystemId; + + fNotationIndexMap.put(notationDecl.name, notationDeclIndex); + } + + /** + * Create an XMLContentSpec for a single non-leaf + * + * @param nodeType the type of XMLContentSpec to create - from XMLContentSpec.CONTENTSPECNODE_* + * @param nodeValue handle to an XMLContentSpec + * @return handle to the newly create XMLContentSpec + */ + protected int addContentSpecNode(short nodeType, String nodeValue) { + + // create content spec node + int contentSpecIndex = createContentSpec(); + + // set content spec node values + fContentSpec.setValues(nodeType, nodeValue, null); + setContentSpec(contentSpecIndex, fContentSpec); + + // return index + return contentSpecIndex; + + } // addContentSpecNode(short,String):int + + /** + * create an XMLContentSpec for a leaf + * + * @param elementName the name (Element) for the node + * @return handle to the newly create XMLContentSpec + */ + protected int addUniqueLeafNode(String elementName) { + + // create content spec node + int contentSpecIndex = createContentSpec(); + + // set content spec node values + fContentSpec.setValues( XMLContentSpec.CONTENTSPECNODE_LEAF, + elementName, null); + setContentSpec(contentSpecIndex, fContentSpec); + + // return index + return contentSpecIndex; + + } // addUniqueLeafNode(String):int + + /** + * Create an XMLContentSpec for a two child leaf + * + * @param nodeType the type of XMLContentSpec to create - from XMLContentSpec.CONTENTSPECNODE_* + * @param leftNodeIndex handle to an XMLContentSpec + * @param rightNodeIndex handle to an XMLContentSpec + * @return handle to the newly create XMLContentSpec + */ + protected int addContentSpecNode(short nodeType, + int leftNodeIndex, int rightNodeIndex) { + + // create content spec node + int contentSpecIndex = createContentSpec(); + + // set content spec node values + int[] leftIntArray = new int[1]; + int[] rightIntArray = new int[1]; + + leftIntArray[0] = leftNodeIndex; + rightIntArray[0] = rightNodeIndex; + fContentSpec.setValues(nodeType, leftIntArray, rightIntArray); + setContentSpec(contentSpecIndex, fContentSpec); + + // return index + return contentSpecIndex; + + } // addContentSpecNode(short,int,int):int + + /** Initialize content model stack. */ + protected void initializeContentModelStack() { + + if (fOpStack == null) { + fOpStack = new short[8]; + fNodeIndexStack = new int[8]; + fPrevNodeIndexStack = new int[8]; + } else if (fDepth == fOpStack.length) { + short[] newStack = new short[fDepth * 2]; + System.arraycopy(fOpStack, 0, newStack, 0, fDepth); + fOpStack = newStack; + int[] newIntStack = new int[fDepth * 2]; + System.arraycopy(fNodeIndexStack, 0, newIntStack, 0, fDepth); + fNodeIndexStack = newIntStack; + newIntStack = new int[fDepth * 2]; + System.arraycopy(fPrevNodeIndexStack, 0, newIntStack, 0, fDepth); + fPrevNodeIndexStack = newIntStack; + } + fOpStack[fDepth] = -1; + fNodeIndexStack[fDepth] = -1; + fPrevNodeIndexStack[fDepth] = -1; + + } // initializeContentModelStack() + + boolean isImmutable() { + return fIsImmutable; + } + + // + // Private methods + // + + private void appendContentSpec(XMLContentSpec contentSpec, + StringBuffer str, boolean parens, + int parentContentSpecType ) { + + int thisContentSpec = contentSpec.type & 0x0f; + switch (thisContentSpec) { + case XMLContentSpec.CONTENTSPECNODE_LEAF: { + if (contentSpec.value == null && contentSpec.otherValue == null) { + str.append("#PCDATA"); + } + else if (contentSpec.value == null && contentSpec.otherValue != null) { + str.append("##any:uri=").append(contentSpec.otherValue); + } + else if (contentSpec.value == null) { + str.append("##any"); + } + else { + str.append(contentSpec.value); + } + break; + } + case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: { + if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE || + parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE || + parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) { + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + str.append('('); + appendContentSpec(contentSpec, str, true, thisContentSpec ); + str.append(')'); + } + else { + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + appendContentSpec( contentSpec, str, true, thisContentSpec ); + } + str.append('?'); + break; + } + case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: { + if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE || + parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE || + parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) { + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + str.append('('); + appendContentSpec(contentSpec, str, true, thisContentSpec); + str.append(')' ); + } + else { + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + appendContentSpec(contentSpec, str, true, thisContentSpec); + } + str.append('*'); + break; + } + case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: { + if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE || + parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE || + parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) { + + str.append('('); + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + appendContentSpec(contentSpec, str, true, thisContentSpec); + str.append(')' ); + } + else { + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + appendContentSpec(contentSpec, str, true, thisContentSpec); + } + str.append('+'); + break; + } + case XMLContentSpec.CONTENTSPECNODE_CHOICE: + case XMLContentSpec.CONTENTSPECNODE_SEQ: { + if (parens) { + str.append('('); + } + int type = contentSpec.type; + int otherValue = ((int[])contentSpec.otherValue)[0]; + getContentSpec(((int[])contentSpec.value)[0], contentSpec); + appendContentSpec(contentSpec, str, contentSpec.type != type, thisContentSpec); + if (type == XMLContentSpec.CONTENTSPECNODE_CHOICE) { + str.append('|'); + } + else { + str.append(','); + } + getContentSpec(otherValue, contentSpec); + appendContentSpec(contentSpec, str, true, thisContentSpec); + if (parens) { + str.append(')'); + } + break; + } + case XMLContentSpec.CONTENTSPECNODE_ANY: { + str.append("##any"); + if (contentSpec.otherValue != null) { + str.append(":uri="); + str.append(contentSpec.otherValue); + } + break; + } + case XMLContentSpec.CONTENTSPECNODE_ANY_OTHER: { + str.append("##other:uri="); + str.append(contentSpec.otherValue); + break; + } + case XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL: { + str.append("##local"); + break; + } + default: { + str.append("???"); + break; + } + + } // switch type + + } // appendContentSpec(XMLContentSpec.Provider,StringPool,XMLContentSpec,StringBuffer,boolean) + + // debugging + + private void printAttribute(int attributeDeclIndex) { + + XMLAttributeDecl attributeDecl = new XMLAttributeDecl(); + if (getAttributeDecl(attributeDeclIndex, attributeDecl)) { + System.out.print(" { "); + System.out.print(attributeDecl.name.localpart); + System.out.print(" }"); + } + + } // printAttribute(int) + + // content models + + /** + * When the element has a 'CHILDREN' model, this method is called to + * create the content model object. It looks for some special case simple + * models and creates SimpleContentModel objects for those. For the rest + * it creates the standard DFA style model. + */ + private synchronized ContentModelValidator createChildModel(int contentSpecIndex) { + + // + // Get the content spec node for the element we are working on. + // This will tell us what kind of node it is, which tells us what + // kind of model we will try to create. + // + XMLContentSpec contentSpec = new XMLContentSpec(); + getContentSpec(contentSpecIndex, contentSpec); + + if ((contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY || + (contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER || + (contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) { + // let fall through to build a DFAContentModel + } + + else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) { + // + // Check that the left value is not -1, since any content model + // with PCDATA should be MIXED, so we should not have gotten here. + // + if (contentSpec.value == null && contentSpec.otherValue == null) + throw new RuntimeException("ImplementationMessages.VAL_NPCD"); + + // + // Its a single leaf, so its an 'a' type of content model, i.e. + // just one instance of one element. That one is definitely a + // simple content model. + // + + fQName.setValues(null, (String)contentSpec.value, + (String)contentSpec.value, (String)contentSpec.otherValue); + return new SimpleContentModel(contentSpec.type, fQName, null); + } else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE) + || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) { + // + // Lets see if both of the children are leafs. If so, then it + // it has to be a simple content model + // + XMLContentSpec contentSpecLeft = new XMLContentSpec(); + XMLContentSpec contentSpecRight = new XMLContentSpec(); + + getContentSpec( ((int[])contentSpec.value)[0], contentSpecLeft); + getContentSpec( ((int[])contentSpec.otherValue)[0], contentSpecRight); + + if ((contentSpecLeft.type == XMLContentSpec.CONTENTSPECNODE_LEAF) + && (contentSpecRight.type == XMLContentSpec.CONTENTSPECNODE_LEAF)) { + // + // Its a simple choice or sequence, so we can do a simple + // content model for it. + // + fQName.setValues(null, (String)contentSpecLeft.value, + (String)contentSpecLeft.value, (String)contentSpecLeft.otherValue); + fQName2.setValues(null, (String)contentSpecRight.value, + (String)contentSpecRight.value, (String)contentSpecRight.otherValue); + return new SimpleContentModel(contentSpec.type, fQName, fQName2); + } + } else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE) + || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE) + || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE)) { + // + // Its a repetition, so see if its one child is a leaf. If so + // its a repetition of a single element, so we can do a simple + // content model for that. + // + XMLContentSpec contentSpecLeft = new XMLContentSpec(); + getContentSpec(((int[])contentSpec.value)[0], contentSpecLeft); + + if (contentSpecLeft.type == XMLContentSpec.CONTENTSPECNODE_LEAF) { + // + // It is, so we can create a simple content model here that + // will check for this repetition. We pass -1 for the unused + // right node. + // + fQName.setValues(null, (String)contentSpecLeft.value, + (String)contentSpecLeft.value, (String)contentSpecLeft.otherValue); + return new SimpleContentModel(contentSpec.type, fQName, null); + } + } else { + throw new RuntimeException("ImplementationMessages.VAL_CST"); + } + + // + // Its not a simple content model, so here we have to create a DFA + // for this element. So we create a DFAContentModel object. He + // encapsulates all of the work to create the DFA. + // + + fLeafCount = 0; + //int leafCount = countLeaves(contentSpecIndex); + fLeafCount = 0; + CMNode cmn = buildSyntaxTree(contentSpecIndex, contentSpec); + + // REVISIT: has to be fLeafCount because we convert x+ to x,x*, one more leaf + return new DFAContentModel( cmn, fLeafCount, false); + + } // createChildModel(int):ContentModelValidator + + private final CMNode buildSyntaxTree(int startNode, + XMLContentSpec contentSpec) { + + // We will build a node at this level for the new tree + CMNode nodeRet = null; + getContentSpec(startNode, contentSpec); + if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY) { + //nodeRet = new CMAny(contentSpec.type, -1, fLeafCount++); + nodeRet = new CMAny(contentSpec.type, (String)contentSpec.otherValue, fLeafCount++); + } + else if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) { + nodeRet = new CMAny(contentSpec.type, (String)contentSpec.otherValue, fLeafCount++); + } + else if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) { + nodeRet = new CMAny(contentSpec.type, null, fLeafCount++); + } + // + // If this node is a leaf, then its an easy one. We just add it + // to the tree. + // + else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) { + // + // Create a new leaf node, and pass it the current leaf count, + // which is its DFA state position. Bump the leaf count after + // storing it. This makes the positions zero based since we + // store first and then increment. + // + fQName.setValues(null, (String)contentSpec.value, + (String)contentSpec.value, (String)contentSpec.otherValue); + nodeRet = new CMLeaf(fQName, fLeafCount++); + } + else { + // + // Its not a leaf, so we have to recurse its left and maybe right + // nodes. Save both values before we recurse and trash the node. + final int leftNode = ((int[])contentSpec.value)[0]; + final int rightNode = ((int[])contentSpec.otherValue)[0]; + + if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE) + || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) { + // + // Recurse on both children, and return a binary op node + // with the two created sub nodes as its children. The node + // type is the same type as the source. + // + + nodeRet = new CMBinOp( contentSpec.type, buildSyntaxTree(leftNode, contentSpec) + , buildSyntaxTree(rightNode, contentSpec)); + } + else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE) { + nodeRet = new CMUniOp( contentSpec.type, buildSyntaxTree(leftNode, contentSpec)); + } + else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE + || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE + || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) { + nodeRet = new CMUniOp(contentSpec.type, buildSyntaxTree(leftNode, contentSpec)); + } + else { + throw new RuntimeException("ImplementationMessages.VAL_CST"); + } + } + // And return our new node for this level + return nodeRet; + } + + /** + * Build a vector of valid QNames from Content Spec + * table. + * + * @param contentSpecIndex + * Content Spec index + * @param vectorQName + * Array of QName + * @exception RuntimeException + */ + private void contentSpecTree(int contentSpecIndex, + XMLContentSpec contentSpec, + ChildrenList children) { + + // Handle any and leaf nodes + getContentSpec( contentSpecIndex, contentSpec); + if ( contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF || + (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY || + (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL || + (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) { + + // resize arrays, if needed + if (children.length == children.qname.length) { + QName[] newQName = new QName[children.length * 2]; + System.arraycopy(children.qname, 0, newQName, 0, children.length); + children.qname = newQName; + int[] newType = new int[children.length * 2]; + System.arraycopy(children.type, 0, newType, 0, children.length); + children.type = newType; + } + + // save values and return length + children.qname[children.length] = new QName(null, (String)contentSpec.value, + (String) contentSpec.value, + (String) contentSpec.otherValue); + children.type[children.length] = contentSpec.type; + children.length++; + return; + } + + // + // Its not a leaf, so we have to recurse its left and maybe right + // nodes. Save both values before we recurse and trash the node. + // + final int leftNode = contentSpec.value != null + ? ((int[])(contentSpec.value))[0] : -1; + int rightNode = -1 ; + if (contentSpec.otherValue != null ) + rightNode = ((int[])(contentSpec.otherValue))[0]; + else + return; + + if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE || + contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ) { + contentSpecTree(leftNode, contentSpec, children); + contentSpecTree(rightNode, contentSpec, children); + return; + } + + if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE || + contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE || + contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) { + contentSpecTree(leftNode, contentSpec, children); + return; + } + + // error + throw new RuntimeException("Invalid content spec type seen in contentSpecTree() method of AbstractDTDGrammar class : "+contentSpec.type); + + } // contentSpecTree(int,XMLContentSpec,ChildrenList) + + // ensure capacity + + private void ensureElementDeclCapacity(int chunk) { + if (chunk >= fElementDeclName.length) { + fElementDeclIsExternal = resize(fElementDeclIsExternal, + fElementDeclIsExternal.length * 2); + + fElementDeclName = resize(fElementDeclName, fElementDeclName.length * 2); + fElementDeclType = resize(fElementDeclType, fElementDeclType.length * 2); + fElementDeclContentModelValidator = resize(fElementDeclContentModelValidator, fElementDeclContentModelValidator.length * 2); + fElementDeclContentSpecIndex = resize(fElementDeclContentSpecIndex,fElementDeclContentSpecIndex.length * 2); + fElementDeclFirstAttributeDeclIndex = resize(fElementDeclFirstAttributeDeclIndex, fElementDeclFirstAttributeDeclIndex.length * 2); + fElementDeclLastAttributeDeclIndex = resize(fElementDeclLastAttributeDeclIndex, fElementDeclLastAttributeDeclIndex.length * 2); + } + else if (fElementDeclName[chunk] != null) { + return; + } + + fElementDeclIsExternal[chunk] = new int[CHUNK_SIZE]; + fElementDeclName[chunk] = new QName[CHUNK_SIZE]; + fElementDeclType[chunk] = new short[CHUNK_SIZE]; + fElementDeclContentModelValidator[chunk] = new ContentModelValidator[CHUNK_SIZE]; + fElementDeclContentSpecIndex[chunk] = new int[CHUNK_SIZE]; + fElementDeclFirstAttributeDeclIndex[chunk] = new int[CHUNK_SIZE]; + fElementDeclLastAttributeDeclIndex[chunk] = new int[CHUNK_SIZE]; + return; + } + + private void ensureAttributeDeclCapacity(int chunk) { + + if (chunk >= fAttributeDeclName.length) { + fAttributeDeclIsExternal = resize(fAttributeDeclIsExternal, + fAttributeDeclIsExternal.length * 2); + fAttributeDeclName = resize(fAttributeDeclName, fAttributeDeclName.length * 2); + fAttributeDeclType = resize(fAttributeDeclType, fAttributeDeclType.length * 2); + fAttributeDeclEnumeration = resize(fAttributeDeclEnumeration, fAttributeDeclEnumeration.length * 2); + fAttributeDeclDefaultType = resize(fAttributeDeclDefaultType, fAttributeDeclDefaultType.length * 2); + fAttributeDeclDatatypeValidator = resize(fAttributeDeclDatatypeValidator, fAttributeDeclDatatypeValidator.length * 2); + fAttributeDeclDefaultValue = resize(fAttributeDeclDefaultValue, fAttributeDeclDefaultValue.length * 2); + fAttributeDeclNonNormalizedDefaultValue = resize(fAttributeDeclNonNormalizedDefaultValue, fAttributeDeclNonNormalizedDefaultValue.length * 2); + fAttributeDeclNextAttributeDeclIndex = resize(fAttributeDeclNextAttributeDeclIndex, fAttributeDeclNextAttributeDeclIndex.length * 2); + } + else if (fAttributeDeclName[chunk] != null) { + return; + } + + fAttributeDeclIsExternal[chunk] = new int[CHUNK_SIZE]; + fAttributeDeclName[chunk] = new QName[CHUNK_SIZE]; + fAttributeDeclType[chunk] = new short[CHUNK_SIZE]; + fAttributeDeclEnumeration[chunk] = new String[CHUNK_SIZE][]; + fAttributeDeclDefaultType[chunk] = new short[CHUNK_SIZE]; + fAttributeDeclDatatypeValidator[chunk] = new DatatypeValidator[CHUNK_SIZE]; + fAttributeDeclDefaultValue[chunk] = new String[CHUNK_SIZE]; + fAttributeDeclNonNormalizedDefaultValue[chunk] = new String[CHUNK_SIZE]; + fAttributeDeclNextAttributeDeclIndex[chunk] = new int[CHUNK_SIZE]; + return; + } + + private void ensureEntityDeclCapacity(int chunk) { + if (chunk >= fEntityName.length) { + fEntityName = resize(fEntityName, fEntityName.length * 2); + fEntityValue = resize(fEntityValue, fEntityValue.length * 2); + fEntityPublicId = resize(fEntityPublicId, fEntityPublicId.length * 2); + fEntitySystemId = resize(fEntitySystemId, fEntitySystemId.length * 2); + fEntityBaseSystemId = resize(fEntityBaseSystemId, fEntityBaseSystemId.length * 2); + fEntityNotation = resize(fEntityNotation, fEntityNotation.length * 2); + fEntityIsPE = resize(fEntityIsPE, fEntityIsPE.length * 2); + fEntityInExternal = resize(fEntityInExternal, fEntityInExternal.length * 2); + } + else if (fEntityName[chunk] != null) { + return; + } + + fEntityName[chunk] = new String[CHUNK_SIZE]; + fEntityValue[chunk] = new String[CHUNK_SIZE]; + fEntityPublicId[chunk] = new String[CHUNK_SIZE]; + fEntitySystemId[chunk] = new String[CHUNK_SIZE]; + fEntityBaseSystemId[chunk] = new String[CHUNK_SIZE]; + fEntityNotation[chunk] = new String[CHUNK_SIZE]; + fEntityIsPE[chunk] = new byte[CHUNK_SIZE]; + fEntityInExternal[chunk] = new byte[CHUNK_SIZE]; + return; + } + + private void ensureNotationDeclCapacity(int chunk) { + if (chunk >= fNotationName.length) { + fNotationName = resize(fNotationName, fNotationName.length * 2); + fNotationPublicId = resize(fNotationPublicId, fNotationPublicId.length * 2); + fNotationSystemId = resize(fNotationSystemId, fNotationSystemId.length * 2); + fNotationBaseSystemId = resize(fNotationBaseSystemId, fNotationBaseSystemId.length * 2); + } + else if (fNotationName[chunk] != null) { + return; + } + + fNotationName[chunk] = new String[CHUNK_SIZE]; + fNotationPublicId[chunk] = new String[CHUNK_SIZE]; + fNotationSystemId[chunk] = new String[CHUNK_SIZE]; + fNotationBaseSystemId[chunk] = new String[CHUNK_SIZE]; + return; + } + + private void ensureContentSpecCapacity(int chunk) { + if (chunk >= fContentSpecType.length) { + fContentSpecType = resize(fContentSpecType, fContentSpecType.length * 2); + fContentSpecValue = resize(fContentSpecValue, fContentSpecValue.length * 2); + fContentSpecOtherValue = resize(fContentSpecOtherValue, fContentSpecOtherValue.length * 2); + } + else if (fContentSpecType[chunk] != null) { + return; + } + + fContentSpecType[chunk] = new short[CHUNK_SIZE]; + fContentSpecValue[chunk] = new Object[CHUNK_SIZE]; + fContentSpecOtherValue[chunk] = new Object[CHUNK_SIZE]; + return; + } + + // + // Private static methods + // + + // resize chunks + + private static byte[][] resize(byte array[][], int newsize) { + byte newarray[][] = new byte[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static short[][] resize(short array[][], int newsize) { + short newarray[][] = new short[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static int[][] resize(int array[][], int newsize) { + int newarray[][] = new int[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static DatatypeValidator[][] resize(DatatypeValidator array[][], int newsize) { + DatatypeValidator newarray[][] = new DatatypeValidator[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static ContentModelValidator[][] resize(ContentModelValidator array[][], int newsize) { + ContentModelValidator newarray[][] = new ContentModelValidator[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static Object[][] resize(Object array[][], int newsize) { + Object newarray[][] = new Object[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static QName[][] resize(QName array[][], int newsize) { + QName newarray[][] = new QName[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static String[][] resize(String array[][], int newsize) { + String newarray[][] = new String[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static String[][][] resize(String array[][][], int newsize) { + String newarray[][][] = new String[newsize] [][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + // + // Classes + // + + /** + * Children list for contentSpecTree method. + * + * @xerces.internal + * + * @author Eric Ye, IBM + */ + private static class ChildrenList { + + // + // Data + // + + /** Length. */ + public int length = 0; + + // NOTE: The following set of data is mutually exclusive. It is + // written this way because Java doesn't have a native + // union data structure. -Ac + + /** Left and right children names. */ + public QName[] qname = new QName[2]; + + /** Left and right children types. */ + public int[] type = new int[2]; + + // + // Constructors + // + + public ChildrenList () {} + + } // class ChildrenList + + // + // Classes + // + + /** + * A simple Hashtable implementation that takes a tuple (String, String) + * as the key and a int as value. + * + * @xerces.internal + * + * @author Eric Ye, IBM + * @author Andy Clark, IBM + */ + protected static final class QNameHashtable { + + /** + * Fills an array with a random sequence of prime numbers. + * + * @xerces.internal + */ + private static final class PrimeNumberSequenceGenerator { + + private static int [] PRIMES = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727}; + + static void generateSequence(int[] arrayToFill) { + Random r = new Random(); + for (int i = 0; i < arrayToFill.length; ++i) { + arrayToFill[i] = PRIMES[r.nextInt(PRIMES.length)]; + } + } + } + + // + // Constants + // + + /** Initial bucket size (4). */ + private static final int INITIAL_BUCKET_SIZE = 4; + + // NOTE: Changed previous hashtable size from 512 to 101 so + // that we get a better distribution for hashing. -Ac + /** Hashtable size (101). */ + private static final int HASHTABLE_SIZE = 101; + + /** Maximum hash collisions per bucket for a table with load factor == 1. */ + private static final int MAX_HASH_COLLISIONS = 40; + + private static final int MULTIPLIERS_SIZE = 1 << 5; + private static final int MULTIPLIERS_MASK = MULTIPLIERS_SIZE - 1; + + // + // Data + // + private Object[][] fHashTable = new Object[HASHTABLE_SIZE][]; + + /** actual table size **/ + private int fTableSize = HASHTABLE_SIZE; + + /** The total number of entries in the hash table. */ + private int fCount = 0; + + /** + * Array of randomly selected hash function multipliers or null + * if the default String.hashCode() function should be used. + */ + private int[] fHashMultipliers; + + // + // Public methods + // + /** Associates the given value with the specified key tuple. */ + public void put(String key, int value) { + + int hash = (hash(key) & 0x7FFFFFFF) % fTableSize; + Object[] bucket = fHashTable[hash]; + + if (bucket == null) { + bucket = new Object[1 + 2*INITIAL_BUCKET_SIZE]; + bucket[0] = new int[]{1}; + bucket[1] = key; + bucket[2] = new int[]{value}; + fHashTable[hash] = bucket; + if (++fCount > fTableSize) { + // Rehash the table if the number of entries + // would exceed the number of buckets. + rehash(); + } + } else { + int count = ((int[])bucket[0])[0]; + int offset = 1 + 2*count; + if (offset == bucket.length) { + int newSize = count + INITIAL_BUCKET_SIZE; + Object[] newBucket = new Object[1 + 2*newSize]; + System.arraycopy(bucket, 0, newBucket, 0, offset); + bucket = newBucket; + fHashTable[hash] = bucket; + } + boolean found = false; + int j=1; + for (int i=0; i fTableSize) { + // Rehash the table if the number of entries + // would exceed the number of buckets. + rehash(); + } + else if (count > MAX_HASH_COLLISIONS) { + // Select a new hash function and rehash the table if + // MAX_HASH_COLLISIONS is exceeded. + rebalance(); + } + } + + } + //System.out.println("put("+key+" -> "+value+')'); + //System.out.println("get("+key+") -> "+get(key)); + + } // put(int,String,String,int) + + /** Returns the value associated with the specified key tuple. */ + public int get(String key) { + int hash = (hash(key) & 0x7FFFFFFF) % fTableSize; + Object[] bucket = fHashTable[hash]; + + if (bucket == null) { + return -1; + } + int count = ((int[])bucket[0])[0]; + + int j=1; + for (int i=0; i-1) { + int chunk = entityIndex >> CHUNK_SHIFT; + int index = entityIndex & CHUNK_MASK; + //for unparsed entity notation!=null + return (fEntityNotation[chunk][index]!=null)?true:false; + } + return false; + } +} // class DTDGrammar diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/DTDGrammarBucket.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/DTDGrammarBucket.java new file mode 100644 index 0000000..e7b6f1c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/DTDGrammarBucket.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import java.util.Hashtable; + +import org.apache.xerces.xni.grammars.XMLGrammarDescription; + +/** + * This very simple class is the skeleton of what the DTDValidator could use + * to store various grammars that it gets from the GrammarPool. As in the + * case of XSGrammarBucket, one thinks of this object as being closely + * associated with its validator; when fully mature, this class will be + * filled from the GrammarPool when the DTDValidator is invoked on a + * document, and, if a new DTD grammar is parsed, the new set will be + * offered back to the GrammarPool for possible inclusion. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class DTDGrammarBucket { + + // REVISIT: make this class smarter and *way* more complete! + + // + // Data + // + + /** Grammars associated with element root name. */ + protected final Hashtable fGrammars; + + // the unique grammar from fGrammars (or that we're + // building) that is used in validation. + protected DTDGrammar fActiveGrammar; + + // is the "active" grammar standalone? + protected boolean fIsStandalone; + + // + // Constructors + // + + /** Default constructor. */ + public DTDGrammarBucket() { + fGrammars = new Hashtable(); + } // () + + // + // Public methods + // + + /** + * Puts the specified grammar into the grammar pool and associate it to + * a root element name (this being internal, the lack of generality is irrelevant). + * + * @param grammar The grammar. + */ + public void putGrammar(DTDGrammar grammar) { + XMLDTDDescription desc = (XMLDTDDescription)grammar.getGrammarDescription(); + fGrammars.put(desc, grammar); + } // putGrammar(DTDGrammar) + + // retrieve a DTDGrammar given an XMLDTDDescription + public DTDGrammar getGrammar(XMLGrammarDescription desc) { + return (DTDGrammar)(fGrammars.get((XMLDTDDescription)desc)); + } // putGrammar(DTDGrammar) + + public void clear() { + fGrammars.clear(); + fActiveGrammar = null; + fIsStandalone = false; + } // clear() + + // is the active grammar standalone? This must live here because + // at the time the validator discovers this we don't yet know + // what the active grammar should be (no info about root) + void setStandalone(boolean standalone) { + fIsStandalone = standalone; + } + + boolean getStandalone() { + return fIsStandalone; + } + + // set the "active" grammar: + void setActiveGrammar (DTDGrammar grammar) { + fActiveGrammar = grammar; + } + DTDGrammar getActiveGrammar () { + return fActiveGrammar; + } +} // class DTDGrammarBucket diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11DTDProcessor.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11DTDProcessor.java new file mode 100644 index 0000000..2524b71 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11DTDProcessor.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XML11DTDScannerImpl; +import org.apache.xerces.impl.XMLDTDScannerImpl; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLEntityResolver; + +/** + * This class extends XMLDTDProcessor by giving it + * the ability to parse XML 1.1 documents correctly. It can also be used + * as a DTD loader, so that XML 1.1 external subsets can + * be processed correctly (hence it's rather anomalous-appearing + * derivation from XMLDTDLoader). + * + * @xerces.internal + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XML11DTDProcessor extends XMLDTDLoader{ + + // constructors + + public XML11DTDProcessor() { + super(); + } // () + + public XML11DTDProcessor(SymbolTable symbolTable) { + super(symbolTable); + } // init(SymbolTable) + + public XML11DTDProcessor(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + super(symbolTable, grammarPool); + } // init(SymbolTable, XMLGrammarPool) + + XML11DTDProcessor(SymbolTable symbolTable, + XMLGrammarPool grammarPool, XMLErrorReporter errorReporter, + XMLEntityResolver entityResolver) { + super(symbolTable, grammarPool, errorReporter, entityResolver); + } // init(SymbolTable, XMLGrammarPool, XMLErrorReporter, XMLEntityResolver) + + // overridden methods + + protected boolean isValidNmtoken(String nmtoken) { + return XML11Char.isXML11ValidNmtoken(nmtoken); + } // isValidNmtoken(String): boolean + + protected boolean isValidName(String name) { + return XML11Char.isXML11ValidName(name); + } // isValidNmtoken(String): boolean + + protected XMLDTDScannerImpl createDTDScanner(SymbolTable symbolTable, + XMLErrorReporter errorReporter, XMLEntityManager entityManager) { + return new XML11DTDScannerImpl(symbolTable, errorReporter, entityManager); + } // createDTDScanner(SymbolTable, XMLErrorReporter, XMLEntityManager) : XMLDTDScannerImpl + + protected short getScannerVersion() { + return Constants.XML_VERSION_1_1; + } // getScannerVersion() : short + +} // class XML11DTDProcessor diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11DTDValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11DTDValidator.java new file mode 100644 index 0000000..dc27740 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11DTDValidator.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.xni.parser.XMLComponentManager; + +/** + * This allows the validator to correctlyhandle XML 1.1 + * documents. + * + * @xerces.internal + * + * @author Neil Graham + * @version $Id$ + */ +public class XML11DTDValidator extends XMLDTDValidator { + + // + // Constants + // + + protected final static String DTD_VALIDATOR_PROPERTY = + Constants.XERCES_PROPERTY_PREFIX+Constants.DTD_VALIDATOR_PROPERTY; + + // + // Constructors + // + + /** Default constructor. */ + public XML11DTDValidator() { + + super(); + } // () + + // overridden so that this class has access to the same + // grammarBucket as the corresponding DTDProcessor + // will try and use... + public void reset(XMLComponentManager manager) { + XMLDTDValidator curr = null; + if((curr = (XMLDTDValidator)manager.getProperty(DTD_VALIDATOR_PROPERTY)) != null && + curr != this) { + fGrammarBucket = curr.getGrammarBucket(); + } + super.reset(manager); + } //reset(XMLComponentManager) + + protected void init() { + if(fValidation || fDynamicValidation) { + super.init(); + // now overwrite some entries in parent: + + try { + fValID = fDatatypeValidatorFactory.getBuiltInDV("XML11ID"); + fValIDRef = fDatatypeValidatorFactory.getBuiltInDV("XML11IDREF"); + fValIDRefs = fDatatypeValidatorFactory.getBuiltInDV("XML11IDREFS"); + fValNMTOKEN = fDatatypeValidatorFactory.getBuiltInDV("XML11NMTOKEN"); + fValNMTOKENS = fDatatypeValidatorFactory.getBuiltInDV("XML11NMTOKENS"); + + } + catch (Exception e) { + // should never happen + e.printStackTrace(System.err); + } + } + } // init() + +} // class XML11DTDValidator diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11NSDTDValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11NSDTDValidator.java new file mode 100644 index 0000000..a9f2fe2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XML11NSDTDValidator.java @@ -0,0 +1,222 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XNIException; + +/** + * The DTD validator. The validator implements a document + * filter: receiving document events from the scanner; validating + * the content and structure; augmenting the InfoSet, if applicable; + * and notifying the parser of the information resulting from the + * validation process. + *

Formerly, this component also handled DTD events and grammar construction. + * To facilitate the development of a meaningful DTD grammar caching/preparsing + * framework, this functionality has been moved into the XMLDTDLoader + * class. Therefore, this class no longer implements the DTDFilter + * or DTDContentModelFilter interfaces. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/validation/dynamic
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/grammar-pool
  • + *
  • http://apache.org/xml/properties/internal/datatype-validator-factory
  • + *
+ * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XML11NSDTDValidator extends XML11DTDValidator { + + /** Attribute QName. */ + private final QName fAttributeQName = new QName(); + + /** Bind namespaces */ + protected final void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + // add new namespace context + fNamespaceContext.pushContext(); + + if (element.prefix == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "ElementXMLNSPrefix", + new Object[] { element.rawname }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // search for new namespace bindings + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + String localpart = attributes.getLocalName(i); + String prefix = attributes.getPrefix(i); + // when it's of form xmlns="..." or xmlns:prefix="...", + // it's a namespace declaration. but prefix:xmlns="..." isn't. + if (prefix == XMLSymbols.PREFIX_XMLNS || prefix == XMLSymbols.EMPTY_STRING + && localpart == XMLSymbols.PREFIX_XMLNS) { + + // get the internalized value of this attribute + String uri = fSymbolTable.addSymbol(attributes.getValue(i)); + + // 1. "xmlns" can't be bound to any namespace + if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[] { attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 2. the namespace for "xmlns" can't be bound to any prefix + if (uri == NamespaceContext.XMLNS_URI) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[] { attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 3. "xml" can't be bound to any other namespace than it's own + if (localpart == XMLSymbols.PREFIX_XML) { + if (uri != NamespaceContext.XML_URI) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[] { attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + // 4. the namespace for "xml" can't be bound to any other prefix + else { + if (uri == NamespaceContext.XML_URI) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[] { attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + + prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING; + + // Declare prefix in context. Removing the association between a prefix and a + // namespace name is permitted in XML 1.1, so if the uri value is the empty string, + // the prefix is being unbound. -- mrglavas + fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null); + } + } + + // bind the element + String prefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; + element.uri = fNamespaceContext.getURI(prefix); + if (element.prefix == null && element.uri != null) { + element.prefix = XMLSymbols.EMPTY_STRING; + } + if (element.prefix != null && element.uri == null) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "ElementPrefixUnbound", + new Object[] { element.prefix, element.rawname }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind the attributes + for (int i = 0; i < length; i++) { + attributes.getName(i, fAttributeQName); + String aprefix = fAttributeQName.prefix != null ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; + String arawname = fAttributeQName.rawname; + if (arawname == XMLSymbols.PREFIX_XMLNS) { + fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS); + attributes.setName(i, fAttributeQName); + } else if (aprefix != XMLSymbols.EMPTY_STRING) { + fAttributeQName.uri = fNamespaceContext.getURI(aprefix); + if (fAttributeQName.uri == null) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "AttributePrefixUnbound", + new Object[] { element.rawname, arawname, aprefix }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + attributes.setName(i, fAttributeQName); + } + } + + // verify that duplicate attributes don't exist + // Example: + int attrCount = attributes.getLength(); + for (int i = 0; i < attrCount - 1; i++) { + String auri = attributes.getURI(i); + if (auri == null || auri == NamespaceContext.XMLNS_URI) { + continue; + } + String alocalpart = attributes.getLocalName(i); + for (int j = i + 1; j < attrCount; j++) { + String blocalpart = attributes.getLocalName(j); + String buri = attributes.getURI(j); + if (alocalpart == blocalpart && auri == buri) { + fErrorReporter.reportError( + XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNSNotUnique", + new Object[] { element.rawname, alocalpart, auri }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + } + + } // startNamespaceScope(QName,XMLAttributes) + + /** Handles end element. */ + protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty) + throws XNIException { + + // bind element + String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; + element.uri = fNamespaceContext.getURI(eprefix); + if (element.uri != null) { + element.prefix = eprefix; + } + + // call handlers + if (fDocumentHandler != null) { + if (!isEmpty) { + fDocumentHandler.endElement(element, augs); + } + } + + // pop context + fNamespaceContext.popContext(); + + } // endNamespaceScope(QName,boolean) +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLAttributeDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLAttributeDecl.java new file mode 100644 index 0000000..c695902 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLAttributeDecl.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import org.apache.xerces.xni.QName; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public class XMLAttributeDecl { + + // + // Data + // + + /** name */ + public final QName name = new QName(); + + /** simpleType */ + public final XMLSimpleType simpleType = new XMLSimpleType(); + + /** optional */ + public boolean optional; + + // + // Methods + // + + /** + * setValues + * + * @param name + * @param simpleType + * @param optional + */ + public void setValues(QName name, XMLSimpleType simpleType, boolean optional) { + this.name.setValues(name); + this.simpleType.setValues(simpleType); + this.optional = optional; + } // setValues + + /** + * clear + */ + public void clear() { + this.name.clear(); + this.simpleType.clear(); + this.optional = false; + } // clear + +} // class XMLAttributeDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLContentSpec.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLContentSpec.java new file mode 100644 index 0000000..6d4060b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLContentSpec.java @@ -0,0 +1,294 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +/** + * ContentSpec really exists to aid the parser classes in implementing + * access to the grammar. + *

+ * This class is used by the DTD scanner and the validator classes, + * allowing them to be used separately or together. This "struct" + * class is used to build content models for validation, where it + * is more efficient to fetch all of the information for each of + * these content model "fragments" than to fetch each field one at + * a time. Since configurations are allowed to have validators + * without a DTD scanner (i.e. a schema validator) and a DTD scanner + * without a validator (non-validating processor), this class can be + * used by each without requiring the presence of the other. + *

+ * When processing element declarations, the DTD scanner will build + * up a representation of the content model using the node types that + * are defined here. Since a non-validating processor only needs to + * remember the type of content model declared (i.e. ANY, EMPTY, MIXED, + * or CHILDREN), it is free to discard the specific details of the + * MIXED and CHILDREN content models described using this class. + *

+ * In the typical case of a validating processor reading the grammar + * of the document from a DTD, the information about the content model + * declared will be preserved and later "compiled" into an efficient + * form for use during element validation. Each content spec node + * that is saved is assigned a unique index that is used as a handle + * for the "value" or "otherValue" fields of other content spec nodes. + * A leaf node has a "value" that is either an index in the string + * pool of the element type of that leaf, or a value of -1 to indicate + * the special "#PCDATA" leaf type used in a mixed content model. + *

+ * For a mixed content model, the content spec will be made up of + * leaf and choice content spec nodes, with an optional "zero or more" + * node. For example, the mixed content declaration "(#PCDATA)" would + * contain a single leaf node with a node value of -1. A mixed content + * declaration of "(#PCDATA|foo)*" would have a content spec consisting + * of two leaf nodes, for the "#PCDATA" and "foo" choices, a choice node + * with the "value" set to the index of the "#PCDATA" leaf node and the + * "otherValue" set to the index of the "foo" leaf node, and a "zero or + * more" node with the "value" set to the index of the choice node. If + * the content model has more choices, for example "(#PCDATA|a|b)*", then + * there will be more corresponding choice and leaf nodes, the choice + * nodes will be chained together through the "value" field with each + * leaf node referenced by the "otherValue" field. + *

+ * For element content models, there are sequence nodes and also "zero or + * one" and "one or more" nodes. The leaf nodes would always have a valid + * string pool index, as the "#PCDATA" leaf is not used in the declarations + * for element content models. + * + * @xerces.internal + * + * @version $Id$ + */ +public class XMLContentSpec { + + // + // Constants + // + + /** + * Name or #PCDATA. Leaf nodes that represent parsed character + * data (#PCDATA) have values of -1. + */ + public static final short CONTENTSPECNODE_LEAF = 0; + + /** Represents a zero or one occurence count, '?'. */ + public static final short CONTENTSPECNODE_ZERO_OR_ONE = 1; + + /** Represents a zero or more occurence count, '*'. */ + public static final short CONTENTSPECNODE_ZERO_OR_MORE = 2; + + /** Represents a one or more occurence count, '+'. */ + public static final short CONTENTSPECNODE_ONE_OR_MORE = 3; + + /** Represents choice, '|'. */ + public static final short CONTENTSPECNODE_CHOICE = 4; + + /** Represents sequence, ','. */ + public static final short CONTENTSPECNODE_SEQ = 5; + + /** + * Represents any namespace specified namespace. When the element + * found in the document must belong to a specific namespace, + * otherValue will contain the name of the namespace. + * If otherValue is -1 then the element + * can be from any namespace. + *

+ * Lists of valid namespaces are created from choice content spec + * nodes that have any content spec nodes as children. + */ + public static final short CONTENTSPECNODE_ANY = 6; + + /** + * Represents any other namespace (XML Schema: ##other). + *

+ * When the content spec node type is set to CONTENTSPECNODE_ANY_OTHER, + * value will contain the namespace that cannot + * occur. + */ + public static final short CONTENTSPECNODE_ANY_OTHER = 7; + + /** Represents any local element (XML Schema: ##local). */ + public static final short CONTENTSPECNODE_ANY_LOCAL = 8; + + /** prcessContent is 'lax' **/ + public static final short CONTENTSPECNODE_ANY_LAX = 22; + + public static final short CONTENTSPECNODE_ANY_OTHER_LAX = 23; + + public static final short CONTENTSPECNODE_ANY_LOCAL_LAX = 24; + + /** processContent is 'skip' **/ + + public static final short CONTENTSPECNODE_ANY_SKIP = 38; + + public static final short CONTENTSPECNODE_ANY_OTHER_SKIP = 39; + + public static final short CONTENTSPECNODE_ANY_LOCAL_SKIP = 40; + // + // Data + // + + /** + * The content spec node type. + * + * @see #CONTENTSPECNODE_LEAF + * @see #CONTENTSPECNODE_ZERO_OR_ONE + * @see #CONTENTSPECNODE_ZERO_OR_MORE + * @see #CONTENTSPECNODE_ONE_OR_MORE + * @see #CONTENTSPECNODE_CHOICE + * @see #CONTENTSPECNODE_SEQ + */ + public short type; + + /** + * The "left hand" value object of the content spec node. + * leaf name.localpart, single child for unary ops, left child for binary ops. + */ + public Object value; + + /** + * The "right hand" value of the content spec node. + * leaf name.uri, right child for binary ops + */ + public Object otherValue; + + // + // Constructors + // + + /** Default constructor. */ + public XMLContentSpec() { + clear(); + } + + /** Constructs a content spec with the specified values. */ + public XMLContentSpec(short type, Object value, Object otherValue) { + setValues(type, value, otherValue); + } + + /** + * Constructs a content spec from the values in the specified content spec. + */ + public XMLContentSpec(XMLContentSpec contentSpec) { + setValues(contentSpec); + } + + /** + * Constructs a content spec from the values specified by the given + * content spec provider and identifier. + */ + public XMLContentSpec(XMLContentSpec.Provider provider, + int contentSpecIndex) { + setValues(provider, contentSpecIndex); + } + + // + // Public methods + // + + /** Clears the values. */ + public void clear() { + type = -1; + value = null; + otherValue = null; + } + + /** Sets the values. */ + public void setValues(short type, Object value, Object otherValue) { + this.type = type; + this.value = value; + this.otherValue = otherValue; + } + + /** Sets the values of the specified content spec. */ + public void setValues(XMLContentSpec contentSpec) { + type = contentSpec.type; + value = contentSpec.value; + otherValue = contentSpec.otherValue; + } + + /** + * Sets the values from the values specified by the given content spec + * provider and identifier. If the specified content spec cannot be + * provided, the values of this content spec are cleared. + */ + public void setValues(XMLContentSpec.Provider provider, + int contentSpecIndex) { + if (!provider.getContentSpec(contentSpecIndex, this)) { + clear(); + } + } + + + // + // Object methods + // + + /** Returns a hash code for this node. */ + public int hashCode() { + return type << 16 | + value.hashCode() << 8 | + otherValue.hashCode(); + } + + /** Returns true if the two objects are equal. */ + public boolean equals(Object object) { + if (object != null && object instanceof XMLContentSpec) { + XMLContentSpec contentSpec = (XMLContentSpec)object; + return type == contentSpec.type && + value == contentSpec.value && + otherValue == contentSpec.otherValue; + } + return false; + } + + + // + // Interfaces + // + + /** + * Provides a means for walking the structure built out of + * content spec "nodes". The user of this provider interface is + * responsible for knowing what the content spec node values + * "mean". If those values refer to content spec identifiers, + * then the user can call back into the provider to get the + * next content spec node in the structure. + * + * @xerces.internal + */ + public interface Provider { + + // + // XMLContentSpec.Provider methods + // + + /** + * Fills in the provided content spec structure with content spec + * information for a unique identifier. + * + * @param contentSpecIndex The content spec identifier. All content + * spec "nodes" have a unique identifier. + * @param contentSpec The content spec struct to fill in with + * the information. + * + * @return Returns true if the contentSpecIndex was found. + */ + public boolean getContentSpec(int contentSpecIndex, XMLContentSpec contentSpec); + + } // interface Provider + +} // class XMLContentSpec + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDDescription.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDDescription.java new file mode 100644 index 0000000..0bb366c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDDescription.java @@ -0,0 +1,186 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import java.util.ArrayList; +import java.util.Vector; + +import org.apache.xerces.util.XMLResourceIdentifierImpl; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * All information specific to DTD grammars. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +public class XMLDTDDescription extends XMLResourceIdentifierImpl + implements org.apache.xerces.xni.grammars.XMLDTDDescription { + + // Data + + // pieces of information needed to make this usable as a Grammar key + // if we know the root of this grammar, here's its name: + protected String fRootName = null; + + // if we don't know the root name, this stores all elements that + // could serve; fPossibleRoots and fRootName cannot both be non-null + protected ArrayList fPossibleRoots = null; + + // Constructors: + public XMLDTDDescription(XMLResourceIdentifier id, String rootName) { + this.setValues(id.getPublicId(), id.getLiteralSystemId(), + id.getBaseSystemId(), id.getExpandedSystemId()); + this.fRootName = rootName; + this.fPossibleRoots = null; + } // init(XMLResourceIdentifier, String) + + public XMLDTDDescription(String publicId, String literalId, + String baseId, String expandedId, String rootName) { + this.setValues(publicId, literalId, baseId, expandedId); + this.fRootName = rootName; + this.fPossibleRoots = null; + } // init(String, String, String, String, String) + + public XMLDTDDescription(XMLInputSource source) { + this.setValues(source.getPublicId(), null, + source.getBaseSystemId(), source.getSystemId()); + this.fRootName = null; + this.fPossibleRoots = null; + } // init(XMLInputSource) + + // XMLGrammarDescription methods + + public String getGrammarType () { + return XMLGrammarDescription.XML_DTD; + } // getGrammarType(): String + + /** + * @return the root name of this DTD or null if root name is unknown + */ + public String getRootName() { + return fRootName; + } // getRootName(): String + + /** Set the root name **/ + public void setRootName(String rootName) { + fRootName = rootName; + fPossibleRoots = null; + } + + /** Set possible roots **/ + public void setPossibleRoots(ArrayList possibleRoots) { + fPossibleRoots = possibleRoots; + } + + /** Set possible roots **/ + public void setPossibleRoots(Vector possibleRoots) { + fPossibleRoots = (possibleRoots != null) ? new ArrayList(possibleRoots) : null; + } + + /** + * Compares this grammar with the given grammar. Currently, we compare + * as follows: + * - if grammar type not equal return false immediately + * - try and find a common root name: + * - if both have roots, use them + * - else if one has a root, examine other's possible root's for a match; + * - else try all combinations + * - test fExpandedSystemId and fPublicId as above + * + * @param desc The description of the grammar to be compared with + * @return True if they are equal, else false + */ + public boolean equals(Object desc) { + if (!(desc instanceof XMLGrammarDescription)) return false; + if (!getGrammarType().equals(((XMLGrammarDescription)desc).getGrammarType())) { + return false; + } + // assume it's a DTDDescription + XMLDTDDescription dtdDesc = (XMLDTDDescription)desc; + if (fRootName != null) { + if ((dtdDesc.fRootName) != null && !dtdDesc.fRootName.equals(fRootName)) { + return false; + } + else if (dtdDesc.fPossibleRoots != null && !dtdDesc.fPossibleRoots.contains(fRootName)) { + return false; + } + } + else if (fPossibleRoots != null) { + if (dtdDesc.fRootName != null) { + if (!fPossibleRoots.contains(dtdDesc.fRootName)) { + return false; + } + } + else if (dtdDesc.fPossibleRoots == null) { + return false; + } + else { + boolean found = false; + final int size = fPossibleRoots.size(); + for (int i = 0; i < size; ++i) { + String root = (String) fPossibleRoots.get(i); + found = dtdDesc.fPossibleRoots.contains(root); + if (found) break; + } + if (!found) return false; + } + } + // if we got this far we've got a root match... try other two fields, + // since so many different DTD's have roots in common: + if (fExpandedSystemId != null) { + if (!fExpandedSystemId.equals(dtdDesc.fExpandedSystemId)) { + return false; + } + } + else if (dtdDesc.fExpandedSystemId != null) { + return false; + } + if (fPublicId != null) { + if (!fPublicId.equals(dtdDesc.fPublicId)) { + return false; + } + } + else if (dtdDesc.fPublicId != null) { + return false; + } + return true; + } + + /** + * Returns the hash code of this grammar + * Because our .equals method is so complex, we just return a very + * simple hash that might avoid calls to the equals method a bit... + * @return The hash code + */ + public int hashCode() { + if (fExpandedSystemId != null) { + return fExpandedSystemId.hashCode(); + } + if (fPublicId != null) { + return fPublicId.hashCode(); + } + // give up; hope .equals can handle it: + return 0; + } +} // class XMLDTDDescription + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDLoader.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDLoader.java new file mode 100644 index 0000000..d547d4a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDLoader.java @@ -0,0 +1,511 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import java.io.EOFException; +import java.io.IOException; +import java.io.StringReader; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLDTDScannerImpl; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.DefaultErrorHandler; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarLoader; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * The DTD loader. The loader knows how to build grammars from XMLInputSources. + * It extends the DTD processor in order to do this; it's + * a separate class because DTD processors don't need to know how + * to talk to the outside world in their role as instance-document + * helpers. + *

+ * This component requires the following features and properties. It + * know ho to set them if no one else does:from the + *

    + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/grammar-pool
  • + *
  • http://apache.org/xml/properties/internal/datatype-validator-factory
  • + *
+ * + * @xerces.internal + * + * @author Neil Graham, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XMLDTDLoader + extends XMLDTDProcessor + implements XMLGrammarLoader { + + // + // Constants + // + + // feature identifiers + + /** Feature identifier: standard uri conformant feature. */ + protected static final String STANDARD_URI_CONFORMANT_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE; + + /** Feature identifier: balance syntax trees. */ + protected static final String BALANCE_SYNTAX_TREES = + Constants.XERCES_FEATURE_PREFIX + Constants.BALANCE_SYNTAX_TREES; + + // recognized features: + private static final String[] LOADER_RECOGNIZED_FEATURES = { + VALIDATION, + WARN_ON_DUPLICATE_ATTDEF, + WARN_ON_UNDECLARED_ELEMDEF, + NOTIFY_CHAR_REFS, + STANDARD_URI_CONFORMANT_FEATURE, + BALANCE_SYNTAX_TREES + }; + + // property identifiers + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: locale. */ + protected static final String LOCALE = + Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + + /** Recognized properties. */ + private static final String[] LOADER_RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + ERROR_REPORTER, + ERROR_HANDLER, + ENTITY_RESOLVER, + GRAMMAR_POOL, + DTD_VALIDATOR, + LOCALE + }; + + // enforcing strict uri? + private boolean fStrictURI = false; + + /** Controls whether the DTD grammar produces balanced syntax trees. */ + private boolean fBalanceSyntaxTrees = false; + + /** Entity resolver . */ + protected XMLEntityResolver fEntityResolver; + + // the scanner we use to actually read the DTD + protected XMLDTDScannerImpl fDTDScanner; + + // the entity manager the scanner needs. + protected XMLEntityManager fEntityManager; + + // what's our Locale? + protected Locale fLocale; + + // + // Constructors + // + + /** Deny default construction; we need a SymtolTable! */ + public XMLDTDLoader() { + this(new SymbolTable()); + } // () + + public XMLDTDLoader(SymbolTable symbolTable) { + this(symbolTable, null); + } // init(SymbolTable) + + public XMLDTDLoader(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null, new XMLEntityManager()); + } // init(SymbolTable, XMLGrammarPool) + + XMLDTDLoader(SymbolTable symbolTable, + XMLGrammarPool grammarPool, XMLErrorReporter errorReporter, + XMLEntityResolver entityResolver) { + fSymbolTable = symbolTable; + fGrammarPool = grammarPool; + if(errorReporter == null) { + errorReporter = new XMLErrorReporter(); + errorReporter.setProperty(ERROR_HANDLER, new DefaultErrorHandler()); + } + fErrorReporter = errorReporter; + // Add XML message formatter if there isn't one. + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + fEntityResolver = entityResolver; + if(fEntityResolver instanceof XMLEntityManager) { + fEntityManager = (XMLEntityManager)fEntityResolver; + } else { + fEntityManager = new XMLEntityManager(); + } + fEntityManager.setProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY, errorReporter); + fDTDScanner = createDTDScanner(fSymbolTable, fErrorReporter, fEntityManager); + fDTDScanner.setDTDHandler(this); + fDTDScanner.setDTDContentModelHandler(this); + reset(); + } // init(SymbolTable, XMLGrammarPool, XMLErrorReporter, XMLEntityResolver) + + // XMLGrammarLoader methods + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(LOADER_RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + if (featureId.equals(VALIDATION)) { + fValidation = state; + } + else if (featureId.equals(WARN_ON_DUPLICATE_ATTDEF)) { + fWarnDuplicateAttdef = state; + } + else if (featureId.equals(WARN_ON_UNDECLARED_ELEMDEF)) { + fWarnOnUndeclaredElemdef = state; + } + else if (featureId.equals(NOTIFY_CHAR_REFS)) { + fDTDScanner.setFeature(featureId, state); + } + else if (featureId.equals(STANDARD_URI_CONFORMANT_FEATURE)) { + fStrictURI = state; + } + else if (featureId.equals(BALANCE_SYNTAX_TREES)) { + fBalanceSyntaxTrees = state; + } + else { + throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId); + } + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(LOADER_RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Returns the state of a property. + * + * @param propertyId The property identifier. + * + * @throws XMLConfigurationException Thrown on configuration error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException { + if (propertyId.equals(SYMBOL_TABLE)) { + return fSymbolTable; + } + else if (propertyId.equals(ERROR_REPORTER)) { + return fErrorReporter; + } + else if (propertyId.equals(ERROR_HANDLER)) { + return fErrorReporter.getErrorHandler(); + } + else if (propertyId.equals(ENTITY_RESOLVER)) { + return fEntityResolver; + } + else if (propertyId.equals(LOCALE)) { + return getLocale(); + } + else if (propertyId.equals(GRAMMAR_POOL)) { + return fGrammarPool; + } + else if (propertyId.equals(DTD_VALIDATOR)) { + return fValidator; + } + throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, propertyId); + } // getProperty(String): Object + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + if (propertyId.equals(SYMBOL_TABLE)) { + fSymbolTable = (SymbolTable)value; + fDTDScanner.setProperty(propertyId, value); + fEntityManager.setProperty(propertyId, value); + } + else if(propertyId.equals(ERROR_REPORTER)) { + fErrorReporter = (XMLErrorReporter)value; + // Add XML message formatter if there isn't one. + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + fDTDScanner.setProperty(propertyId, value); + fEntityManager.setProperty(propertyId, value); + } + else if (propertyId.equals(ERROR_HANDLER)) { + fErrorReporter.setProperty(propertyId, value); + } + else if (propertyId.equals(ENTITY_RESOLVER)) { + fEntityResolver = (XMLEntityResolver)value; + fEntityManager.setProperty(propertyId, value); + } + else if (propertyId.equals(LOCALE)) { + setLocale((Locale) value); + } + else if(propertyId.equals(GRAMMAR_POOL)) { + fGrammarPool = (XMLGrammarPool)value; + } + else { + throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, propertyId); + } + } // setProperty(String,Object) + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * + * @throws XMLConfigurationException Thrown on configuration error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + if (featureId.equals(VALIDATION)) { + return fValidation; + } + else if (featureId.equals(WARN_ON_DUPLICATE_ATTDEF)) { + return fWarnDuplicateAttdef; + } + else if (featureId.equals(WARN_ON_UNDECLARED_ELEMDEF)) { + return fWarnOnUndeclaredElemdef; + } + else if (featureId.equals(NOTIFY_CHAR_REFS)) { + return fDTDScanner.getFeature(featureId); + } + else if (featureId.equals(STANDARD_URI_CONFORMANT_FEATURE)) { + return fStrictURI; + } + else if (featureId.equals(BALANCE_SYNTAX_TREES)) { + return fBalanceSyntaxTrees; + } + throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId); + } //getFeature(String): boolean + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) { + fLocale = locale; + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + + /** Return the Locale the XMLGrammarLoader is using. */ + public Locale getLocale() { + return fLocale; + } // getLocale(): Locale + + + /** + * Sets the error handler. + * + * @param errorHandler The error handler. + */ + public void setErrorHandler(XMLErrorHandler errorHandler) { + fErrorReporter.setProperty(ERROR_HANDLER, errorHandler); + } // setErrorHandler(XMLErrorHandler) + + /** Returns the registered error handler. */ + public XMLErrorHandler getErrorHandler() { + return fErrorReporter.getErrorHandler(); + } // getErrorHandler(): XMLErrorHandler + + /** + * Sets the entity resolver. + * + * @param entityResolver The new entity resolver. + */ + public void setEntityResolver(XMLEntityResolver entityResolver) { + fEntityResolver = entityResolver; + fEntityManager.setProperty(ENTITY_RESOLVER, entityResolver); + } // setEntityResolver(XMLEntityResolver) + + /** Returns the registered entity resolver. */ + public XMLEntityResolver getEntityResolver() { + return fEntityResolver; + } // getEntityResolver(): XMLEntityResolver + + /** + * Returns a Grammar object by parsing the contents of the + * entity pointed to by source. + * + * @param source the location of the entity which forms + * the starting point of the grammar to be constructed. + * @throws IOException When a problem is encountered reading the entity + * XNIException When a condition arises (such as a FatalError) that requires parsing + * of the entity be terminated. + */ + public Grammar loadGrammar(XMLInputSource source) + throws IOException, XNIException { + reset(); + // First chance checking strict URI + String eid = XMLEntityManager.expandSystemId(source.getSystemId(), source.getBaseSystemId(), fStrictURI); + XMLDTDDescription desc = new XMLDTDDescription(source.getPublicId(), source.getSystemId(), source.getBaseSystemId(), eid, null); + if (!fBalanceSyntaxTrees) { + fDTDGrammar = new DTDGrammar(fSymbolTable, desc); + } + else { + fDTDGrammar = new BalancedDTDGrammar(fSymbolTable, desc); + } + fGrammarBucket = new DTDGrammarBucket(); + fGrammarBucket.setStandalone(false); + fGrammarBucket.setActiveGrammar(fDTDGrammar); + // no reason to use grammar bucket's "put" method--we + // know which grammar it is, and we don't know the root name anyway... + + // actually start the parsing! + try { + fDTDScanner.setInputSource(source); + fDTDScanner.scanDTDExternalSubset(true); + } catch (EOFException e) { + // expected behaviour... + } + finally { + // Close all streams opened by the parser. + fEntityManager.closeReaders(); + } + if(fDTDGrammar != null && fGrammarPool != null) { + fGrammarPool.cacheGrammars(XMLDTDDescription.XML_DTD, new Grammar[] {fDTDGrammar}); + } + return fDTDGrammar; + } // loadGrammar(XMLInputSource): Grammar + + /** + * Parse a DTD internal and/or external subset and insert the content + * into the existing DTD grammar owned by the given DTDValidator. + */ + public void loadGrammarWithContext(XMLDTDValidator validator, String rootName, + String publicId, String systemId, String baseSystemId, String internalSubset) + throws IOException, XNIException { + final DTDGrammarBucket grammarBucket = validator.getGrammarBucket(); + final DTDGrammar activeGrammar = grammarBucket.getActiveGrammar(); + if (activeGrammar != null && !activeGrammar.isImmutable()) { + fGrammarBucket = grammarBucket; + fEntityManager.setScannerVersion(getScannerVersion()); + reset(); + try { + // process internal subset + if (internalSubset != null) { + // To get the DTD scanner to end at the right place we have to fool + // it into thinking that it reached the end of the internal subset + // in a real document. + StringBuffer buffer = new StringBuffer(internalSubset.length() + 2); + buffer.append(internalSubset).append("]>"); + XMLInputSource is = new XMLInputSource(null, baseSystemId, + null, new StringReader(buffer.toString()), null); + fEntityManager.startDocumentEntity(is); + fDTDScanner.scanDTDInternalSubset(true, false, systemId != null); + } + // process external subset + if (systemId != null) { + XMLDTDDescription desc = new XMLDTDDescription(publicId, systemId, baseSystemId, null, rootName); + XMLInputSource source = fEntityManager.resolveEntity(desc); + fDTDScanner.setInputSource(source); + fDTDScanner.scanDTDExternalSubset(true); + } + } + catch (EOFException e) { + // expected behaviour... + } + finally { + // Close all streams opened by the parser. + fEntityManager.closeReaders(); + } + } + } // loadGrammarWithContext(XMLDTDValidator, String, String, String, String, String) + + // reset all the components that we rely upon + protected void reset() { + super.reset(); + fDTDScanner.reset(); + fEntityManager.reset(); + fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner()); + } + + protected XMLDTDScannerImpl createDTDScanner(SymbolTable symbolTable, + XMLErrorReporter errorReporter, XMLEntityManager entityManager) { + return new XMLDTDScannerImpl(symbolTable, errorReporter, entityManager); + } // createDTDScanner(SymbolTable, XMLErrorReporter, XMLEntityManager) : XMLDTDScannerImpl + + protected short getScannerVersion() { + return Constants.XML_VERSION_1_0; + } // getScannerVersion() : short + +} // class XMLDTDLoader diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDProcessor.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDProcessor.java new file mode 100644 index 0000000..e452983 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDProcessor.java @@ -0,0 +1,1735 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDContentModelFilter; +import org.apache.xerces.xni.parser.XMLDTDContentModelSource; +import org.apache.xerces.xni.parser.XMLDTDFilter; +import org.apache.xerces.xni.parser.XMLDTDSource; + +/** + * The DTD processor. The processor implements a DTD + * filter: receiving DTD events from the DTD scanner; validating + * the content and structure; building a grammar, if applicable; + * and notifying the DTDHandler of the information resulting from the + * process. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/grammar-pool
  • + *
  • http://apache.org/xml/properties/internal/datatype-validator-factory
  • + *
+ * + * @xerces.internal + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XMLDTDProcessor + implements XMLComponent, XMLDTDFilter, XMLDTDContentModelFilter { + + // + // Constants + // + + /** Top level scope (-1). */ + private static final int TOP_LEVEL_SCOPE = -1; + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: notify character references. */ + protected static final String NOTIFY_CHAR_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE; + + /** Feature identifier: warn on duplicate attdef */ + protected static final String WARN_ON_DUPLICATE_ATTDEF = + Constants.XERCES_FEATURE_PREFIX +Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; + + /** Feature identifier: warn on undeclared element referenced in content model. */ + protected static final String WARN_ON_UNDECLARED_ELEMDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE; + + protected static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + // property identifiers + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: grammar pool. */ + protected static final String GRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: validator . */ + protected static final String DTD_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + VALIDATION, + WARN_ON_DUPLICATE_ATTDEF, + WARN_ON_UNDECLARED_ELEMDEF, + NOTIFY_CHAR_REFS, + }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { + null, + Boolean.FALSE, + Boolean.FALSE, + null, + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + ERROR_REPORTER, + GRAMMAR_POOL, + DTD_VALIDATOR, + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { + null, + null, + null, + null, + }; + + // debugging + + // + // Data + // + + // features + + /** Validation. */ + protected boolean fValidation; + + /** Validation against only DTD */ + protected boolean fDTDValidation; + + /** warn on duplicate attribute definition, this feature works only when validation is true */ + protected boolean fWarnDuplicateAttdef; + + /** warn on undeclared element referenced in content model, this feature only works when valiation is true */ + protected boolean fWarnOnUndeclaredElemdef; + + // properties + + /** Symbol table. */ + protected SymbolTable fSymbolTable; + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + /** Grammar bucket. */ + protected DTDGrammarBucket fGrammarBucket; + + // the validator to which we look for our grammar bucket (the + // validator needs to hold the bucket so that it can initialize + // the grammar with details like whether it's for a standalone document... + protected XMLDTDValidator fValidator; + + // the grammar pool we'll try to add the grammar to: + protected XMLGrammarPool fGrammarPool; + + // what's our Locale? + protected Locale fLocale; + + // handlers + + /** DTD handler. */ + protected XMLDTDHandler fDTDHandler; + + /** DTD source. */ + protected XMLDTDSource fDTDSource; + + /** DTD content model handler. */ + protected XMLDTDContentModelHandler fDTDContentModelHandler; + + /** DTD content model source. */ + protected XMLDTDContentModelSource fDTDContentModelSource; + + // grammars + + /** DTD Grammar. */ + protected DTDGrammar fDTDGrammar; + + // state + + /** Perform validation. */ + private boolean fPerformValidation; + + /** True if in an ignore conditional section of the DTD. */ + protected boolean fInDTDIgnore; + + // information regarding the current element + + // validation states + + /** Mixed. */ + private boolean fMixed; + + // temporary variables + + /** Temporary entity declaration. */ + private final XMLEntityDecl fEntityDecl = new XMLEntityDecl(); + + /** Notation declaration hash. */ + private final HashMap fNDataDeclNotations = new HashMap(); + + /** DTD element declaration name. */ + private String fDTDElementDeclName = null; + + /** Mixed element type "hash". */ + private final ArrayList fMixedElementTypes = new ArrayList(); + + /** Element declarations in DTD. */ + private final ArrayList fDTDElementDecls = new ArrayList(); + + // to check for duplicate ID or ANNOTATION attribute declare in + // ATTLIST, and misc VCs + + /** ID attribute names. */ + private HashMap fTableOfIDAttributeNames; + + /** NOTATION attribute names. */ + private HashMap fTableOfNOTATIONAttributeNames; + + /** NOTATION enumeration values. */ + private HashMap fNotationEnumVals; + + // + // Constructors + // + + /** Default constructor. */ + public XMLDTDProcessor() { + + // initialize data + + } // () + + // + // XMLComponent methods + // + + /* + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws SAXException Thrown by component on finitialization error. + * For example, if a feature or property is + * required for the operation of the component, the + * component manager may throw a + * SAXNotRecognizedException or a + * SAXNotSupportedException. + */ + public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { + + boolean parser_settings; + try { + parser_settings = componentManager.getFeature(PARSER_SETTINGS); + } catch (XMLConfigurationException e) { + parser_settings = true; + } + + if (!parser_settings) { + // parser settings have not been changed + reset(); + return; + } + + // sax features + try { + fValidation = componentManager.getFeature(VALIDATION); + } catch (XMLConfigurationException e) { + fValidation = false; + } + try { + fDTDValidation = + !(componentManager + .getFeature( + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE)); + } catch (XMLConfigurationException e) { + // must be in a schema-less configuration! + fDTDValidation = true; + } + + // Xerces features + + try { + fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF); + } + catch (XMLConfigurationException e) { + fWarnDuplicateAttdef = false; + } + try { + fWarnOnUndeclaredElemdef = componentManager.getFeature(WARN_ON_UNDECLARED_ELEMDEF); + } + catch (XMLConfigurationException e) { + fWarnOnUndeclaredElemdef = false; + } + + // get needed components + fErrorReporter = + (XMLErrorReporter) componentManager.getProperty( + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY); + fSymbolTable = + (SymbolTable) componentManager.getProperty( + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY); + try { + fGrammarPool = (XMLGrammarPool) componentManager.getProperty(GRAMMAR_POOL); + } catch (XMLConfigurationException e) { + fGrammarPool = null; + } + try { + fValidator = (XMLDTDValidator) componentManager.getProperty(DTD_VALIDATOR); + } catch (XMLConfigurationException e) { + fValidator = null; + } catch (ClassCastException e) { + fValidator = null; + } + // we get our grammarBucket from the validator... + if (fValidator != null) { + fGrammarBucket = fValidator.getGrammarBucket(); + } else { + fGrammarBucket = null; + } + reset(); + + } // reset(XMLComponentManager) + + protected void reset() { + // clear grammars + fDTDGrammar = null; + // initialize state + fInDTDIgnore = false; + + fNDataDeclNotations.clear(); + + // datatype validators + if (fValidation) { + + if (fNotationEnumVals == null) { + fNotationEnumVals = new HashMap(); + } + fNotationEnumVals.clear(); + + fTableOfIDAttributeNames = new HashMap(); + fTableOfNOTATIONAttributeNames = new HashMap(); + } + + } + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + // + // XMLDTDSource methods + // + + /** + * Sets the DTD handler. + * + * @param dtdHandler The DTD handler. + */ + public void setDTDHandler(XMLDTDHandler dtdHandler) { + fDTDHandler = dtdHandler; + } // setDTDHandler(XMLDTDHandler) + + /** + * Returns the DTD handler. + * + * @return The DTD handler. + */ + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } // getDTDHandler(): XMLDTDHandler + + // + // XMLDTDContentModelSource methods + // + + /** + * Sets the DTD content model handler. + * + * @param dtdContentModelHandler The DTD content model handler. + */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler dtdContentModelHandler) { + fDTDContentModelHandler = dtdContentModelHandler; + } // setDTDContentModelHandler(XMLDTDContentModelHandler) + + /** + * Gets the DTD content model handler. + * + * @return dtdContentModelHandler The DTD content model handler. + */ + public XMLDTDContentModelHandler getDTDContentModelHandler() { + return fDTDContentModelHandler; + } // getDTDContentModelHandler(): XMLDTDContentModelHandler + + // + // XMLDTDContentModelHandler and XMLDTDHandler methods + // + + /** + * The start of the DTD external subset. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startExternalSubset(XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + if(fDTDGrammar != null) + fDTDGrammar.startExternalSubset(identifier, augs); + if(fDTDHandler != null){ + fDTDHandler.startExternalSubset(identifier, augs); + } + } + + /** + * The end of the DTD external subset. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endExternalSubset(Augmentations augs) throws XNIException { + if(fDTDGrammar != null) + fDTDGrammar.endExternalSubset(augs); + if(fDTDHandler != null){ + fDTDHandler.endExternalSubset(augs); + } + } + + /** + * Check standalone entity reference. + * Made static to make common between the validator and loader. + * + * @param name + *@param grammar grammar to which entity belongs + * @param tempEntityDecl empty entity declaration to put results in + * @param errorReporter error reporter to send errors to + * + * @throws XNIException Thrown by application to signal an error. + */ + protected static void checkStandaloneEntityRef(String name, DTDGrammar grammar, + XMLEntityDecl tempEntityDecl, XMLErrorReporter errorReporter) throws XNIException { + // check VC: Standalone Document Declartion, entities references appear in the document. + int entIndex = grammar.getEntityDeclIndex(name); + if (entIndex > -1) { + grammar.getEntityDecl(entIndex, tempEntityDecl); + if (tempEntityDecl.inExternal) { + errorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, + "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", + new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); + } + } + } + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException { + + // call handlers + if(fDTDGrammar != null) + fDTDGrammar.comment(text, augs); + if (fDTDHandler != null) { + fDTDHandler.comment(text, augs); + } + + } // comment(XMLString) + + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException { + + // call handlers + if(fDTDGrammar != null) + fDTDGrammar.processingInstruction(target, data, augs); + if (fDTDHandler != null) { + fDTDHandler.processingInstruction(target, data, augs); + } + } // processingInstruction(String,XMLString) + + // + // XMLDTDHandler methods + // + + /** + * The start of the DTD. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing of + * the document DTD. However, it is strongly + * recommended that a locator be supplied that can + * at least report the base system identifier of the + * DTD. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException { + + + // initialize state + fNDataDeclNotations.clear(); + fDTDElementDecls.clear(); + + // the grammar bucket's DTDGrammar will now be the + // one we want, whether we're constructing it or not. + // if we're not constructing it, then we should not have a reference + // to it! + if( !fGrammarBucket.getActiveGrammar().isImmutable()) { + fDTDGrammar = fGrammarBucket.getActiveGrammar(); + } + + // call handlers + if(fDTDGrammar != null ) + fDTDGrammar.startDTD(locator, augs); + if (fDTDHandler != null) { + fDTDHandler.startDTD(locator, augs); + } + + } // startDTD(XMLLocator) + + /** + * Characters within an IGNORE conditional section. + * + * @param text The ignored text. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignoredCharacters(XMLString text, Augmentations augs) throws XNIException { + + // ignored characters in DTD + if(fDTDGrammar != null ) + fDTDGrammar.ignoredCharacters(text, augs); + if (fDTDHandler != null) { + fDTDHandler.ignoredCharacters(text, augs); + } + } + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startParameterEntity call. + *

+ * Note: This method is only called for external + * parameter entities referenced in the DTD. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { + + // call handlers + if(fDTDGrammar != null ) + fDTDGrammar.textDecl(version, encoding, augs); + if (fDTDHandler != null) { + fDTDHandler.textDecl(version, encoding, augs); + } + } + + /** + * This method notifies of the start of a parameter entity. The parameter + * entity name start with a '%' character. + * + * @param name The name of the parameter entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal parameter entities). + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startParameterEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException { + + if (fPerformValidation && fDTDGrammar != null && + fGrammarBucket.getStandalone()) { + checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter); + } + // call handlers + if(fDTDGrammar != null ) + fDTDGrammar.startParameterEntity(name, identifier, encoding, augs); + if (fDTDHandler != null) { + fDTDHandler.startParameterEntity(name, identifier, encoding, augs); + } + } + + /** + * This method notifies the end of a parameter entity. Parameter entity + * names begin with a '%' character. + * + * @param name The name of the parameter entity. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endParameterEntity(String name, Augmentations augs) throws XNIException { + + // call handlers + if(fDTDGrammar != null ) + fDTDGrammar.endParameterEntity(name, augs); + if (fDTDHandler != null) { + fDTDHandler.endParameterEntity(name, augs); + } + } + + /** + * An element declaration. + * + * @param name The name of the element. + * @param contentModel The element content model. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void elementDecl(String name, String contentModel, Augmentations augs) + throws XNIException { + + //check VC: Unique Element Declaration + if (fValidation) { + if (fDTDElementDecls.contains(name)) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_ELEMENT_ALREADY_DECLARED", + new Object[]{ name}, + XMLErrorReporter.SEVERITY_ERROR); + } + else { + fDTDElementDecls.add(name); + } + } + + // call handlers + if(fDTDGrammar != null ) + fDTDGrammar.elementDecl(name, contentModel, augs); + if (fDTDHandler != null) { + fDTDHandler.elementDecl(name, contentModel, augs); + } + + } // elementDecl(String,String) + + /** + * The start of an attribute list. + * + * @param elementName The name of the element that this attribute + * list is associated with. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startAttlist(String elementName, Augmentations augs) + throws XNIException { + + // call handlers + if(fDTDGrammar != null ) + fDTDGrammar.startAttlist(elementName, augs); + if (fDTDHandler != null) { + fDTDHandler.startAttlist(elementName, augs); + } + + } // startAttlist(String) + + /** + * An attribute declaration. + * + * @param elementName The name of the element that this attribute + * is associated with. + * @param attributeName The name of the attribute. + * @param type The attribute type. This value will be one of + * the following: "CDATA", "ENTITY", "ENTITIES", + * "ENUMERATION", "ID", "IDREF", "IDREFS", + * "NMTOKEN", "NMTOKENS", or "NOTATION". + * @param enumeration If the type has the value "ENUMERATION" or + * "NOTATION", this array holds the allowed attribute + * values; otherwise, this array is null. + * @param defaultType The attribute default type. This value will be + * one of the following: "#FIXED", "#IMPLIED", + * "#REQUIRED", or null. + * @param defaultValue The attribute default value, or null if no + * default value is specified. + * @param nonNormalizedDefaultValue The attribute default value with no normalization + * performed, or null if no default value is specified. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, + String defaultType, XMLString defaultValue, + XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException { + + if (type != XMLSymbols.fCDATASymbol && defaultValue != null) { + normalizeDefaultAttrValue(defaultValue); + } + + if (fValidation) { + + boolean duplicateAttributeDef = false ; + + //Get Grammar index to grammar array + DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar:fGrammarBucket.getActiveGrammar()); + int elementIndex = grammar.getElementDeclIndex( elementName); + if (grammar.getAttributeDeclIndex(elementIndex, attributeName) != -1) { + //more than one attribute definition is provided for the same attribute of a given element type. + duplicateAttributeDef = true ; + + //this feature works only when validation is true. + if(fWarnDuplicateAttdef){ + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_DUPLICATE_ATTRIBUTE_DEFINITION", + new Object[]{ elementName, attributeName }, + XMLErrorReporter.SEVERITY_WARNING ); + } + } + + + // + // a) VC: One ID per Element Type, If duplicate ID attribute + // b) VC: ID attribute Default. if there is a declareared attribute + // default for ID it should be of type #IMPLIED or #REQUIRED + if (type == XMLSymbols.fIDSymbol) { + if (defaultValue != null && defaultValue.length != 0) { + if (defaultType == null || + !(defaultType == XMLSymbols.fIMPLIEDSymbol || + defaultType == XMLSymbols.fREQUIREDSymbol)) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "IDDefaultTypeInvalid", + new Object[]{ attributeName}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + + if (!fTableOfIDAttributeNames.containsKey(elementName)) { + fTableOfIDAttributeNames.put(elementName, attributeName); + } + else { + //we should not report an error, when there is duplicate attribute definition for given element type + //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given + //element type, the first declaration is binding and later declaration are *ignored*. So processor should + //ignore the second declarations, however an application would be warned of the duplicate attribute defintion + // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true, + // one typical case where this could be a problem, when any XML file + // provide the ID type information through internal subset so that it is available to the parser which read + //only internal subset. Now that attribute declaration(ID Type) can again be part of external parsed entity + //referenced. At that time if parser doesn't make this distinction it will throw an error for VC One ID per + //Element Type, which (second defintion) actually should be ignored. Application behavior may differ on the + //basis of error or warning thrown. - nb. + + if(!duplicateAttributeDef){ + String previousIDAttributeName = (String)fTableOfIDAttributeNames.get( elementName );//rule a) + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_MORE_THAN_ONE_ID_ATTRIBUTE", + new Object[]{ elementName, previousIDAttributeName, attributeName}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + } + + // + // VC: One Notation Per Element Type, should check if there is a + // duplicate NOTATION attribute + + if (type == XMLSymbols.fNOTATIONSymbol) { + // VC: Notation Attributes: all notation names in the + // (attribute) declaration must be declared. + for (int i=0; ipcdata() method. A children content model will + * contain additional groups and/or elements. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #any + * @see #empty + */ + public void startGroup(Augmentations augs) throws XNIException { + + fMixed = false; + // call handlers + if(fDTDGrammar != null) + fDTDGrammar.startGroup(augs); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.startGroup(augs); + } + + } // startGroup() + + /** + * The appearance of "#PCDATA" within a group signifying a + * mixed content model. This method will be the first called + * following the content model's startGroup(). + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #startGroup + */ + public void pcdata(Augmentations augs) { + fMixed = true; + if(fDTDGrammar != null) + fDTDGrammar.pcdata(augs); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.pcdata(augs); + } + } // pcdata() + + /** + * A referenced element in a mixed or children content model. + * + * @param elementName The name of the referenced element. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void element(String elementName, Augmentations augs) throws XNIException { + + // check VC: No duplicate Types, in a single mixed-content declaration + if (fMixed && fValidation) { + if (fMixedElementTypes.contains(elementName)) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "DuplicateTypeInMixedContent", + new Object[]{fDTDElementDeclName, elementName}, + XMLErrorReporter.SEVERITY_ERROR); + } + else { + fMixedElementTypes.add(elementName); + } + } + + // call handlers + if(fDTDGrammar != null) + fDTDGrammar.element(elementName, augs); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.element(elementName, augs); + } + + } // childrenElement(String) + + /** + * The separator between choices or sequences of a mixed or children + * content model. + * + * @param separator The type of children separator. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #SEPARATOR_CHOICE + * @see #SEPARATOR_SEQUENCE + */ + public void separator(short separator, Augmentations augs) + throws XNIException { + + // call handlers + if(fDTDGrammar != null) + fDTDGrammar.separator(separator, augs); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.separator(separator, augs); + } + + } // separator(short) + + /** + * The occurrence count for a child in a children content model or + * for the mixed content model group. + * + * @param occurrence The occurrence count for the last element + * or group. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #OCCURS_ZERO_OR_ONE + * @see #OCCURS_ZERO_OR_MORE + * @see #OCCURS_ONE_OR_MORE + */ + public void occurrence(short occurrence, Augmentations augs) + throws XNIException { + + // call handlers + if(fDTDGrammar != null) + fDTDGrammar.occurrence(occurrence, augs); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.occurrence(occurrence, augs); + } + + } // occurrence(short) + + /** + * The end of a group for mixed or children content models. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endGroup(Augmentations augs) throws XNIException { + + // call handlers + if(fDTDGrammar != null) + fDTDGrammar.endGroup(augs); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.endGroup(augs); + } + + } // endGroup() + + /** + * The end of a content model. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endContentModel(Augmentations augs) throws XNIException { + + // call handlers + if(fDTDGrammar != null) + fDTDGrammar.endContentModel(augs); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.endContentModel(augs); + } + + } // endContentModel() + + // + // Private methods + // + + /** + * Normalize the attribute value of a non CDATA default attribute + * collapsing sequences of space characters (x20) + * + * @param value The value to normalize + * @return Whether the value was changed or not. + */ + private boolean normalizeDefaultAttrValue(XMLString value) { + + boolean skipSpace = true; // skip leading spaces + int current = value.offset; + int end = value.offset + value.length; + for (int i = value.offset; i < end; i++) { + if (value.ch[i] == ' ') { + if (!skipSpace) { + // take the first whitespace as a space and skip the others + value.ch[current++] = ' '; + skipSpace = true; + } + else { + // just skip it. + } + } + else { + // simply shift non space chars if needed + if (current != i) { + value.ch[current] = value.ch[i]; + } + current++; + skipSpace = false; + } + } + if (current != end) { + if (skipSpace) { + // if we finished on a space trim it + current--; + } + // set the new value length + value.length = current - value.offset; + return true; + } + return false; + } + + protected boolean isValidNmtoken(String nmtoken) { + return XMLChar.isValidNmtoken(nmtoken); + } // isValidNmtoken(String): boolean + + protected boolean isValidName(String name) { + return XMLChar.isValidName(name); + } // isValidName(String): boolean + + /** + * Checks that all elements referenced in content models have + * been declared. This method calls out to the error handler + * to indicate warnings. + */ + private void checkDeclaredElements(DTDGrammar grammar) { + int elementIndex = grammar.getFirstElementDeclIndex(); + XMLContentSpec contentSpec = new XMLContentSpec(); + while (elementIndex >= 0) { + int type = grammar.getContentSpecType(elementIndex); + if (type == XMLElementDecl.TYPE_CHILDREN || type == XMLElementDecl.TYPE_MIXED) { + checkDeclaredElements(grammar, + elementIndex, + grammar.getContentSpecIndex(elementIndex), + contentSpec); + } + elementIndex = grammar.getNextElementDeclIndex(elementIndex); + } + } + + /** + * Does a recursive (if necessary) check on the specified element's + * content spec to make sure that all children refer to declared + * elements. + */ + private void checkDeclaredElements(DTDGrammar grammar, int elementIndex, + int contentSpecIndex, XMLContentSpec contentSpec) { + grammar.getContentSpec(contentSpecIndex, contentSpec); + if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) { + String value = (String) contentSpec.value; + if (value != null && grammar.getElementDeclIndex(value) == -1) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "UndeclaredElementInContentSpec", + new Object[]{grammar.getElementDeclName(elementIndex).rawname, value}, + XMLErrorReporter.SEVERITY_WARNING); + } + } + // It's not a leaf, so we have to recurse its left and maybe right + // nodes. Save both values before we recurse and trash the node. + else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE) + || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) { + final int leftNode = ((int[])contentSpec.value)[0]; + final int rightNode = ((int[])contentSpec.otherValue)[0]; + // Recurse on both children. + checkDeclaredElements(grammar, elementIndex, leftNode, contentSpec); + checkDeclaredElements(grammar, elementIndex, rightNode, contentSpec); + } + else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE + || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE + || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) { + final int leftNode = ((int[])contentSpec.value)[0]; + checkDeclaredElements(grammar, elementIndex, leftNode, contentSpec); + } + } + +} // class XMLDTDProcessor diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDValidator.java new file mode 100644 index 0000000..5b2de56 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDValidator.java @@ -0,0 +1,2118 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import java.util.Iterator; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.RevalidationHandler; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dtd.models.ContentModelValidator; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.validation.ValidationState; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentFilter; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + * The DTD validator. The validator implements a document + * filter: receiving document events from the scanner; validating + * the content and structure; augmenting the InfoSet, if applicable; + * and notifying the parser of the information resulting from the + * validation process. + *

Formerly, this component also handled DTD events and grammar construction. + * To facilitate the development of a meaningful DTD grammar caching/preparsing + * framework, this functionality has been moved into the XMLDTDLoader + * class. Therefore, this class no longer implements the DTDFilter + * or DTDContentModelFilter interfaces. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/validation/dynamic
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/grammar-pool
  • + *
  • http://apache.org/xml/properties/internal/datatype-validator-factory
  • + *
+ * + * @xerces.internal + * + * @author Eric Ye, IBM + * @author Andy Clark, IBM + * @author Jeffrey Rodriguez IBM + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XMLDTDValidator + implements XMLComponent, XMLDocumentFilter, XMLDTDValidatorFilter, RevalidationHandler { + + // + // Constants + // + + /** Symbol: "<<datatypes>>". */ + + /** Top level scope (-1). */ + private static final int TOP_LEVEL_SCOPE = -1; + + // feature identifiers + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: dynamic validation. */ + protected static final String DYNAMIC_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; + + /** Feature identifier: balance syntax trees. */ + protected static final String BALANCE_SYNTAX_TREES = + Constants.XERCES_FEATURE_PREFIX + Constants.BALANCE_SYNTAX_TREES; + + /** Feature identifier: warn on duplicate attdef */ + protected static final String WARN_ON_DUPLICATE_ATTDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; + + protected static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + + + // property identifiers + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: grammar pool. */ + protected static final String GRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: datatype validator factory. */ + protected static final String DATATYPE_VALIDATOR_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; + + // property identifier: ValidationManager + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + NAMESPACES, + VALIDATION, + DYNAMIC_VALIDATION, + BALANCE_SYNTAX_TREES + }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { + null, + null, + Boolean.FALSE, + Boolean.FALSE, + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + ERROR_REPORTER, + GRAMMAR_POOL, + DATATYPE_VALIDATOR_FACTORY, + VALIDATION_MANAGER + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { + null, + null, + null, + null, + null, + }; + + // debugging + + /** Compile to true to debug attributes. */ + private static final boolean DEBUG_ATTRIBUTES = false; + + /** Compile to true to debug element children. */ + private static final boolean DEBUG_ELEMENT_CHILDREN = false; + + // + // Data + // + + // updated during reset + protected ValidationManager fValidationManager = null; + + // validation state + protected final ValidationState fValidationState = new ValidationState(); + + // features + + /** Namespaces. */ + protected boolean fNamespaces; + + /** Validation. */ + protected boolean fValidation; + + /** Validation against only DTD */ + protected boolean fDTDValidation; + + /** + * Dynamic validation. This state of this feature is only useful when + * the validation feature is set to true. + */ + protected boolean fDynamicValidation; + + /** Controls whether the DTD grammar produces balanced syntax trees. */ + protected boolean fBalanceSyntaxTrees; + + /** warn on duplicate attribute definition, this feature works only when validation is true */ + protected boolean fWarnDuplicateAttdef; + + // properties + + /** Symbol table. */ + protected SymbolTable fSymbolTable; + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + // the grammar pool + protected XMLGrammarPool fGrammarPool; + + /** Grammar bucket. */ + protected DTDGrammarBucket fGrammarBucket; + + /* location of the document as passed in from startDocument call */ + protected XMLLocator fDocLocation; + + /** Namespace support. */ + protected NamespaceContext fNamespaceContext = null; + + /** Datatype validator factory. */ + protected DTDDVFactory fDatatypeValidatorFactory; + + // handlers + + /** Document handler. */ + protected XMLDocumentHandler fDocumentHandler; + + protected XMLDocumentSource fDocumentSource; + // grammars + + /** DTD Grammar. */ + protected DTDGrammar fDTDGrammar; + + // state + + /** True if seen DOCTYPE declaration. */ + protected boolean fSeenDoctypeDecl = false; + + /** Perform validation. */ + private boolean fPerformValidation; + + /** Schema type: None, DTD, Schema */ + private String fSchemaType; + + // information regarding the current element + + /** Current element name. */ + private final QName fCurrentElement = new QName(); + + /** Current element index. */ + private int fCurrentElementIndex = -1; + + /** Current content spec type. */ + private int fCurrentContentSpecType = -1; + + /** The root element name. */ + private final QName fRootElement = new QName(); + + private boolean fInCDATASection = false; + // element stack + + /** Element index stack. */ + private int[] fElementIndexStack = new int[8]; + + /** Content spec type stack. */ + private int[] fContentSpecTypeStack = new int[8]; + + /** Element name stack. */ + private QName[] fElementQNamePartsStack = new QName[8]; + + // children list and offset stack + + /** + * Element children. This data structure is a growing stack that + * holds the children of elements from the root to the current + * element depth. This structure never gets "deeper" than the + * deepest element. Space is re-used once each element is closed. + *

+ * Note: This is much more efficient use of memory + * than creating new arrays for each element depth. + *

+ * Note: The use of this data structure is for + * validation "on the way out". If the validation model changes to + * "on the way in", then this data structure is not needed. + */ + private QName[] fElementChildren = new QName[32]; + + /** Element children count. */ + private int fElementChildrenLength = 0; + + /** + * Element children offset stack. This stack refers to offsets + * into the fElementChildren array. + * @see #fElementChildren + */ + private int[] fElementChildrenOffsetStack = new int[32]; + + /** Element depth. */ + private int fElementDepth = -1; + + // validation states + + /** True if seen the root element. */ + private boolean fSeenRootElement = false; + + /** True if inside of element content. */ + private boolean fInElementContent = false; + + // temporary variables + + /** Temporary element declaration. */ + private final XMLElementDecl fTempElementDecl = new XMLElementDecl(); + + /** Temporary atribute declaration. */ + private final XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl(); + + /** Temporary entity declaration. */ + private final XMLEntityDecl fEntityDecl = new XMLEntityDecl(); + + /** Temporary qualified name. */ + private final QName fTempQName = new QName(); + + /** Temporary string buffers. */ + private final StringBuffer fBuffer = new StringBuffer(); + + // symbols: general + + // attribute validators + + /** Datatype validator: ID. */ + protected DatatypeValidator fValID; + + /** Datatype validator: IDREF. */ + protected DatatypeValidator fValIDRef; + + /** Datatype validator: IDREFS. */ + protected DatatypeValidator fValIDRefs; + + /** Datatype validator: ENTITY. */ + protected DatatypeValidator fValENTITY; + + /** Datatype validator: ENTITIES. */ + protected DatatypeValidator fValENTITIES; + + /** Datatype validator: NMTOKEN. */ + protected DatatypeValidator fValNMTOKEN; + + /** Datatype validator: NMTOKENS. */ + protected DatatypeValidator fValNMTOKENS; + + /** Datatype validator: NOTATION. */ + protected DatatypeValidator fValNOTATION; + + // to check for duplicate ID or ANNOTATION attribute declare in + // ATTLIST, and misc VCs + + // + // Constructors + // + + /** Default constructor. */ + public XMLDTDValidator() { + + // initialize data + for (int i = 0; i < fElementQNamePartsStack.length; i++) { + fElementQNamePartsStack[i] = new QName(); + } + fGrammarBucket = new DTDGrammarBucket(); + + } // () + + DTDGrammarBucket getGrammarBucket() { + return fGrammarBucket; + } // getGrammarBucket(): DTDGrammarBucket + + // + // XMLComponent methods + // + + /* + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws SAXException Thrown by component on finitialization error. + * For example, if a feature or property is + * required for the operation of the component, the + * component manager may throw a + * SAXNotRecognizedException or a + * SAXNotSupportedException. + */ + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException { + + // clear grammars + fDTDGrammar = null; + fSeenDoctypeDecl = false; + fInCDATASection = false; + // initialize state + fSeenRootElement = false; + fInElementContent = false; + fCurrentElementIndex = -1; + fCurrentContentSpecType = -1; + + fRootElement.clear(); + + fValidationState.resetIDTables(); + + fGrammarBucket.clear(); + fElementDepth = -1; + fElementChildrenLength = 0; + + boolean parser_settings; + try { + parser_settings = componentManager.getFeature(PARSER_SETTINGS); + } + catch (XMLConfigurationException e){ + parser_settings = true; + } + + if (!parser_settings){ + // parser settings have not been changed + fValidationManager.addValidationState(fValidationState); + return; + } + + // sax features + try { + fNamespaces = componentManager.getFeature(NAMESPACES); + } + catch (XMLConfigurationException e) { + fNamespaces = true; + } + try { + fValidation = componentManager.getFeature(VALIDATION); + } + catch (XMLConfigurationException e) { + fValidation = false; + } + try { + fDTDValidation = !(componentManager.getFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE)); + } + catch (XMLConfigurationException e) { + // must be in a schema-less configuration! + fDTDValidation = true; + } + + // Xerces features + try { + fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION); + } + catch (XMLConfigurationException e) { + fDynamicValidation = false; + } + + try { + fBalanceSyntaxTrees = componentManager.getFeature(BALANCE_SYNTAX_TREES); + } + catch (XMLConfigurationException e) { + fBalanceSyntaxTrees = false; + } + + try { + fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF); + } + catch (XMLConfigurationException e) { + fWarnDuplicateAttdef = false; + } + + try { + fSchemaType = (String)componentManager.getProperty (Constants.JAXP_PROPERTY_PREFIX + + Constants.SCHEMA_LANGUAGE); + } + catch (XMLConfigurationException e){ + fSchemaType = null; + } + + fValidationManager= (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER); + fValidationManager.addValidationState(fValidationState); + fValidationState.setUsingNamespaces(fNamespaces); + + // get needed components + fErrorReporter = (XMLErrorReporter)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.ERROR_REPORTER_PROPERTY); + fSymbolTable = (SymbolTable)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY); + try { + fGrammarPool= (XMLGrammarPool)componentManager.getProperty(GRAMMAR_POOL); + } catch (XMLConfigurationException e) { + fGrammarPool = null; + } + + fDatatypeValidatorFactory = (DTDDVFactory)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY); + init(); + + } // reset(XMLComponentManager) + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + // + // XMLDocumentSource methods + // + + /** Sets the document handler to receive information about the document. */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + } // setDocumentHandler(XMLDocumentHandler) + + /** Returns the document handler */ + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } // getDocumentHandler(): XMLDocumentHandler + + + // + // XMLDocumentHandler methods + // + + /** Sets the document source */ + public void setDocumentSource(XMLDocumentSource source){ + fDocumentSource = source; + } // setDocumentSource + + /** Returns the document source */ + public XMLDocumentSource getDocumentSource (){ + return fDocumentSource; + } // getDocumentSource + + /** + * The start of the document. + * + * @param locator The system identifier of the entity if the entity + * is external, null otherwise. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param namespaceContext + * The namespace context in effect at the + * start of this document. + * This object represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException { + + // call handlers + // get initial grammars + if (fGrammarPool != null) { + Grammar [] grammars = fGrammarPool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_DTD); + final int length = (grammars != null) ? grammars.length : 0; + for (int i = 0; i < length; ++i) { + fGrammarBucket.putGrammar((DTDGrammar)grammars[i]); + } + } + fDocLocation = locator; + fNamespaceContext = namespaceContext; + + if (fDocumentHandler != null) { + fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); + } + + } // startDocument(XMLLocator,String) + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) + throws XNIException { + + // save standalone state + fGrammarBucket.setStandalone(standalone != null && standalone.equals("yes")); + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.xmlDecl(version, encoding, standalone, augs); + } + + } // xmlDecl(String,String,String) + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * otherwise. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void doctypeDecl(String rootElement, String publicId, String systemId, + Augmentations augs) + throws XNIException { + + // save root element state + fSeenDoctypeDecl = true; + fRootElement.setValues(null, rootElement, rootElement, null); + // find or create grammar: + String eid = null; + try { + eid = XMLEntityManager.expandSystemId(systemId, fDocLocation.getExpandedSystemId(), false); + } catch (java.io.IOException e) { + } + XMLDTDDescription grammarDesc = new XMLDTDDescription(publicId, systemId, fDocLocation.getExpandedSystemId(), eid, rootElement); + fDTDGrammar = fGrammarBucket.getGrammar(grammarDesc); + if(fDTDGrammar == null) { + // give grammar pool a chance... + // + // Do not bother checking the pool if no public or system identifier was provided. + // Since so many different DTDs have roots in common, using only a root name as the + // key may cause an unexpected grammar to be retrieved from the grammar pool. This scenario + // would occur when an ExternalSubsetResolver has been queried and the + // XMLInputSource returned contains an input stream but no external identifier. + // This can never happen when the instance document specified a DOCTYPE. -- mrglavas + if (fGrammarPool != null && (systemId != null || publicId != null)) { + fDTDGrammar = (DTDGrammar)fGrammarPool.retrieveGrammar(grammarDesc); + } + } + if(fDTDGrammar == null) { + // we'll have to create it... + if (!fBalanceSyntaxTrees) { + fDTDGrammar = new DTDGrammar(fSymbolTable, grammarDesc); + } + else { + fDTDGrammar = new BalancedDTDGrammar(fSymbolTable, grammarDesc); + } + } else { + // we've found a cached one;so let's make sure not to read + // any external subset! + fValidationManager.setCachedDTD(true); + } + fGrammarBucket.setActiveGrammar(fDTDGrammar); + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); + } + + } // doctypeDecl(String,String,String, Augmentations) + + + /** + * The start of an element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + handleStartElement(element, attributes, augs); + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.startElement(element, attributes, augs); + + } + + } // startElement(QName,XMLAttributes) + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + boolean removed = handleStartElement(element, attributes, augs); + + if (fDocumentHandler !=null) { + fDocumentHandler.emptyElement(element, attributes, augs); + } + if (!removed) { + handleEndElement(element, augs, true); + } + + + } // emptyElement(QName,XMLAttributes) + + /** + * Character content. + * + * @param text The content. + * + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException { + + boolean callNextCharacters = true; + + // REVISIT: [Q] Is there a more efficient way of doing this? + // Perhaps if the scanner told us so we don't have to + // look at the characters again. -Ac + boolean allWhiteSpace = true; + for (int i=text.offset; i< text.offset+text.length; i++) { + if (!isSpace(text.ch[i])) { + allWhiteSpace = false; + break; + } + } + // call the ignoreableWhiteSpace callback + // never call ignorableWhitespace if we are in cdata section + if (fInElementContent && allWhiteSpace && !fInCDATASection) { + if (fDocumentHandler != null) { + fDocumentHandler.ignorableWhitespace(text, augs); + callNextCharacters = false; + } + } + + // validate + if (fPerformValidation) { + if (fInElementContent) { + if (fGrammarBucket.getStandalone() && + fDTDGrammar.getElementDeclIsExternal(fCurrentElementIndex)) { + if (allWhiteSpace) { + fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, + "MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE", + null, XMLErrorReporter.SEVERITY_ERROR); + } + } + if (!allWhiteSpace) { + charDataInContent(); + } + + // For E15.2 + if (augs != null && augs.getItem(Constants.CHAR_REF_PROBABLE_WS) == Boolean.TRUE) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_CONTENT_INVALID_SPECIFIED", + new Object[]{ fCurrentElement.rawname, + fDTDGrammar.getContentSpecAsString(fElementDepth), + "character reference"}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + + if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) { + charDataInContent(); + } + } + + // call handlers + if (callNextCharacters && fDocumentHandler != null) { + fDocumentHandler.characters(text, augs); + } + + } // characters(XMLString) + + + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.ignorableWhitespace(text, augs); + } + + } // ignorableWhitespace(XMLString) + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException { + + handleEndElement(element, augs, false); + + } // endElement(QName) + + /** + * The start of a CDATA section. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException { + + if (fPerformValidation && fInElementContent) { + charDataInContent(); + } + fInCDATASection = true; + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.startCDATA(augs); + } + + } // startCDATA() + + /** + * The end of a CDATA section. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException { + + fInCDATASection = false; + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.endCDATA(augs); + } + + } // endCDATA() + + /** + * The end of the document. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDocument(Augmentations augs) throws XNIException { + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.endDocument(augs); + } + + } // endDocument() + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException { + // fixes E15.1 + if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { + fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); + if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_CONTENT_INVALID_SPECIFIED", + new Object[]{ fCurrentElement.rawname, + "EMPTY", + "comment"}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.comment(text, augs); + } + + } // comment(XMLString) + + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException { + + // fixes E15.1 + if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { + fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); + if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_CONTENT_INVALID_SPECIFIED", + new Object[]{ fCurrentElement.rawname, + "EMPTY", + "processing instruction"}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.processingInstruction(target, data, augs); + } + } // processingInstruction(String,XMLString) + + /** + * This method notifies the start of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException { + if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { + fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); + // fixes E15.1 + if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_CONTENT_INVALID_SPECIFIED", + new Object[]{ fCurrentElement.rawname, + "EMPTY", "ENTITY"}, + XMLErrorReporter.SEVERITY_ERROR); + } + if (fGrammarBucket.getStandalone()) { + XMLDTDLoader.checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter); + } + } + if (fDocumentHandler != null) { + fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); + } + } + + /** + * This method notifies the end of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augs) throws XNIException { + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.endGeneralEntity(name, augs); + } + } // endEntity(String) + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startParameterEntity call. + *

+ * Note: This method is only called for external + * parameter entities referenced in the DTD. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.textDecl(version, encoding, augs); + } + } + + + public final boolean hasGrammar(){ + + return (fDTDGrammar != null); + } + + public final boolean validate(){ + // Do validation if all of the following are true: + // 1. The JAXP Schema Language property is not XML Schema + // REVISIT: since only DTD and Schema are supported at this time, + // such checking is sufficient. but if more schema types + // are introduced in the future, we'll need to change it + // to something like + // (fSchemaType == null || fSchemaType == NS_XML_DTD) + // 2. One of the following is true (validation features) + // 2.1 Dynamic validation is off, and validation is on + // 2.2 Dynamic validation is on, and DOCTYPE was seen + // 3 Xerces schema validation feature is off, or DOCTYPE was seen. + return (fSchemaType != Constants.NS_XMLSCHEMA) && + (!fDynamicValidation && fValidation || + fDynamicValidation && fSeenDoctypeDecl) && + (fDTDValidation || fSeenDoctypeDecl); + } + + //REVISIT:we can convert into functions.. adding default attribute values.. and one validating. + + /** Add default attributes and validate. */ + protected void addDTDDefaultAttrsAndValidate(QName elementName, int elementIndex, + XMLAttributes attributes) + throws XNIException { + + // is there anything to do? + if (elementIndex == -1 || fDTDGrammar == null) { + return; + } + + // + // Check after all specified attrs are scanned + // (1) report error for REQUIRED attrs that are missing (V_TAGc) + // (2) add default attrs (FIXED and NOT_FIXED) + // + int attlistIndex = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); + + while (attlistIndex != -1) { + + fDTDGrammar.getAttributeDecl(attlistIndex, fTempAttDecl); + + if (DEBUG_ATTRIBUTES) { + if (fTempAttDecl != null) { + XMLElementDecl elementDecl = new XMLElementDecl(); + fDTDGrammar.getElementDecl(elementIndex, elementDecl); + System.out.println("element: "+(elementDecl.name.localpart)); + System.out.println("attlistIndex " + attlistIndex + "\n"+ + "attName : '"+(fTempAttDecl.name.localpart) + "'\n" + + "attType : "+fTempAttDecl.simpleType.type + "\n" + + "attDefaultType : "+fTempAttDecl.simpleType.defaultType + "\n" + + "attDefaultValue : '"+fTempAttDecl.simpleType.defaultValue + "'\n" + + attributes.getLength() +"\n" + ); + } + } + String attPrefix = fTempAttDecl.name.prefix; + String attLocalpart = fTempAttDecl.name.localpart; + String attRawName = fTempAttDecl.name.rawname; + String attType = getAttributeTypeName(fTempAttDecl); + int attDefaultType =fTempAttDecl.simpleType.defaultType; + String attValue = null; + + if (fTempAttDecl.simpleType.defaultValue != null) { + attValue = fTempAttDecl.simpleType.defaultValue; + } + + boolean specified = false; + boolean required = attDefaultType == XMLSimpleType.DEFAULT_TYPE_REQUIRED; + boolean cdata = attType == XMLSymbols.fCDATASymbol; + + if (!cdata || required || attValue != null) { + int attrCount = attributes.getLength(); + for (int i = 0; i < attrCount; i++) { + if (attributes.getQName(i) == attRawName) { + specified = true; + break; + } + } + } + + if (!specified) { + if (required) { + if (fPerformValidation) { + Object[] args = {elementName.localpart, attRawName}; + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED", args, + XMLErrorReporter.SEVERITY_ERROR); + } + } + else if (attValue != null) { + if (fPerformValidation && fGrammarBucket.getStandalone()) { + if (fDTDGrammar.getAttributeDeclIsExternal(attlistIndex)) { + + Object[] args = { elementName.localpart, attRawName}; + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED", args, + XMLErrorReporter.SEVERITY_ERROR); + } + } + + // add namespace information + if (fNamespaces) { + int index = attRawName.indexOf(':'); + if (index != -1) { + attPrefix = attRawName.substring(0, index); + attPrefix = fSymbolTable.addSymbol(attPrefix); + attLocalpart = attRawName.substring(index + 1); + attLocalpart = fSymbolTable.addSymbol(attLocalpart); + } + } + + // add attribute + fTempQName.setValues(attPrefix, attLocalpart, attRawName, fTempAttDecl.name.uri); + int newAttr = attributes.addAttribute(fTempQName, attType, attValue); + } + } + // get next att decl in the Grammar for this element + attlistIndex = fDTDGrammar.getNextAttributeDeclIndex(attlistIndex); + } + + // now iterate through the expanded attributes for + // 1. if every attribute seen is declared in the DTD + // 2. check if the VC: default_fixed holds + // 3. validate every attribute. + int attrCount = attributes.getLength(); + for (int i = 0; i < attrCount; i++) { + String attrRawName = attributes.getQName(i); + boolean declared = false; + if (fPerformValidation) { + if (fGrammarBucket.getStandalone()) { + // check VC: Standalone Document Declaration, entities + // references appear in the document. + // REVISIT: this can be combined to a single check in + // startEntity if we add one more argument in + // startEnity, inAttrValue + String nonNormalizedValue = attributes.getNonNormalizedValue(i); + if (nonNormalizedValue != null) { + String entityName = getExternalEntityRefInAttrValue(nonNormalizedValue); + if (entityName != null) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", + new Object[]{entityName}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + } + } + int attDefIndex = -1; + int position = + fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); + while (position != -1) { + fDTDGrammar.getAttributeDecl(position, fTempAttDecl); + if (fTempAttDecl.name.rawname == attrRawName) { + // found the match att decl, + attDefIndex = position; + declared = true; + break; + } + position = fDTDGrammar.getNextAttributeDeclIndex(position); + } + if (!declared) { + if (fPerformValidation) { + // REVISIT - cache the elem/attr tuple so that we only + // give this error once for each unique occurrence + Object[] args = { elementName.rawname, attrRawName}; + + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_ATTRIBUTE_NOT_DECLARED", + args,XMLErrorReporter.SEVERITY_ERROR); + } + continue; + } + // attribute is declared + + // fTempAttDecl should have the right value set now, so + // the following is not needed + // fGrammar.getAttributeDecl(attDefIndex,fTempAttDecl); + + String type = getAttributeTypeName(fTempAttDecl); + attributes.setType(i, type); + attributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE); + + boolean changedByNormalization = false; + String oldValue = attributes.getValue(i); + String attrValue = oldValue; + if (attributes.isSpecified(i) && type != XMLSymbols.fCDATASymbol) { + changedByNormalization = normalizeAttrValue(attributes, i); + attrValue = attributes.getValue(i); + if (fPerformValidation && fGrammarBucket.getStandalone() + && changedByNormalization + && fDTDGrammar.getAttributeDeclIsExternal(position) + ) { + // check VC: Standalone Document Declaration + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE", + new Object[]{attrRawName, oldValue, attrValue}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + if (!fPerformValidation) { + continue; + } + if (fTempAttDecl.simpleType.defaultType == + XMLSimpleType.DEFAULT_TYPE_FIXED) { + String defaultValue = fTempAttDecl.simpleType.defaultValue; + + if (!attrValue.equals(defaultValue)) { + Object[] args = {elementName.localpart, + attrRawName, + attrValue, + defaultValue}; + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_FIXED_ATTVALUE_INVALID", + args, XMLErrorReporter.SEVERITY_ERROR); + } + } + + if (fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENTITY || + fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENUMERATION || + fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID || + fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_IDREF || + fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NMTOKEN || + fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NOTATION + ) { + validateDTDattribute(elementName, attrValue, fTempAttDecl); + } + } // for all attributes + + } // addDTDDefaultAttrsAndValidate(int,XMLAttrList) + + /** Checks entities in attribute values for standalone VC. */ + protected String getExternalEntityRefInAttrValue(String nonNormalizedValue) { + int valLength = nonNormalizedValue.length(); + int ampIndex = nonNormalizedValue.indexOf('&'); + while (ampIndex != -1) { + if (ampIndex + 1 < valLength && + nonNormalizedValue.charAt(ampIndex+1) != '#') { + int semicolonIndex = nonNormalizedValue.indexOf(';', ampIndex+1); + String entityName = nonNormalizedValue.substring(ampIndex+1, semicolonIndex); + entityName = fSymbolTable.addSymbol(entityName); + int entIndex = fDTDGrammar.getEntityDeclIndex(entityName); + if (entIndex > -1) { + fDTDGrammar.getEntityDecl(entIndex, fEntityDecl); + if (fEntityDecl.inExternal || + (entityName = getExternalEntityRefInAttrValue(fEntityDecl.value)) != null) { + return entityName; + } + } + } + ampIndex = nonNormalizedValue.indexOf('&', ampIndex+1); + } + return null; + } // isExternalEntityRefInAttrValue(String):String + + /** + * Validate attributes in DTD fashion. + */ + protected void validateDTDattribute(QName element, String attValue, + XMLAttributeDecl attributeDecl) + throws XNIException { + + switch (attributeDecl.simpleType.type) { + case XMLSimpleType.TYPE_ENTITY: { + // NOTE: Save this information because invalidStandaloneAttDef + boolean isAlistAttribute = attributeDecl.simpleType.list; + + try { + if (isAlistAttribute) { + fValENTITIES.validate(attValue, fValidationState); + } + else { + fValENTITY.validate(attValue, fValidationState); + } + } + catch (InvalidDatatypeValueException ex) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + ex.getKey(), + ex.getArgs(), + XMLErrorReporter.SEVERITY_ERROR ); + + } + break; + } + + case XMLSimpleType.TYPE_NOTATION: + case XMLSimpleType.TYPE_ENUMERATION: { + boolean found = false; + String [] enumVals = attributeDecl.simpleType.enumeration; + if (enumVals == null) { + found = false; + } + else + for (int i = 0; i < enumVals.length; i++) { + if (attValue == enumVals[i] || attValue.equals(enumVals[i])) { + found = true; + break; + } + } + + if (!found) { + StringBuffer enumValueString = new StringBuffer(); + if (enumVals != null) + for (int i = 0; i < enumVals.length; i++) { + enumValueString.append(enumVals[i]+" "); + } + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_ATTRIBUTE_VALUE_NOT_IN_LIST", + new Object[]{attributeDecl.name.rawname, attValue, enumValueString}, + XMLErrorReporter.SEVERITY_ERROR); + } + break; + } + + case XMLSimpleType.TYPE_ID: { + try { + fValID.validate(attValue, fValidationState); + } + catch (InvalidDatatypeValueException ex) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + ex.getKey(), + ex.getArgs(), + XMLErrorReporter.SEVERITY_ERROR ); + } + break; + } + + case XMLSimpleType.TYPE_IDREF: { + boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef + + try { + if (isAlistAttribute) { + fValIDRefs.validate(attValue, fValidationState); + } + else { + fValIDRef.validate(attValue, fValidationState); + } + } + catch (InvalidDatatypeValueException ex) { + if (isAlistAttribute) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "IDREFSInvalid", + new Object[]{attValue}, + XMLErrorReporter.SEVERITY_ERROR ); + } + else { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + ex.getKey(), + ex.getArgs(), + XMLErrorReporter.SEVERITY_ERROR ); + } + + } + break; + } + + case XMLSimpleType.TYPE_NMTOKEN: { + boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef + //changes fTempAttDef + try { + if (isAlistAttribute) { + fValNMTOKENS.validate(attValue, fValidationState); + } + else { + fValNMTOKEN.validate(attValue, fValidationState); + } + } + catch (InvalidDatatypeValueException ex) { + if (isAlistAttribute) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "NMTOKENSInvalid", + new Object[] { attValue}, + XMLErrorReporter.SEVERITY_ERROR); + } + else { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "NMTOKENInvalid", + new Object[] { attValue}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + break; + } + + } // switch + + } // validateDTDattribute(QName,String,XMLAttributeDecl) + + + /** Returns true if invalid standalone attribute definition. */ + protected boolean invalidStandaloneAttDef(QName element, QName attribute) { + // REVISIT: This obviously needs to be fixed! -Ac + boolean state = true; + /* + if (fStandaloneReader == -1) { + return false; + } + // we are normalizing a default att value... this ok? + if (element.rawname == -1) { + return false; + } + return getAttDefIsExternal(element, attribute); + */ + return state; + } + + + // + // Private methods + // + + + /** + * Normalize the attribute value of a non CDATA attributes collapsing + * sequences of space characters (x20) + * + * @param attributes The list of attributes + * @param index The index of the attribute to normalize + */ + private boolean normalizeAttrValue(XMLAttributes attributes, int index) { + // vars + boolean leadingSpace = true; + boolean spaceStart = false; + boolean readingNonSpace = false; + int count = 0; + int eaten = 0; + String attrValue = attributes.getValue(index); + char[] attValue = new char[attrValue.length()]; + + fBuffer.setLength(0); + attrValue.getChars(0, attrValue.length(), attValue, 0); + for (int i = 0; i < attValue.length; i++) { + + if (attValue[i] == ' ') { + + // now the tricky part + if (readingNonSpace) { + spaceStart = true; + readingNonSpace = false; + } + + if (spaceStart && !leadingSpace) { + spaceStart = false; + fBuffer.append(attValue[i]); + count++; + } + else { + if (leadingSpace || !spaceStart) { + eaten ++; + /*** BUG #3512 *** + int entityCount = attributes.getEntityCount(index); + for (int j = 0; j < entityCount; j++) { + int offset = attributes.getEntityOffset(index, j); + int length = attributes.getEntityLength(index, j); + if (offset <= i-eaten+1) { + if (offset+length >= i-eaten+1) { + if (length > 0) + length--; + } + } + else { + if (offset > 0) + offset--; + } + attributes.setEntityOffset(index, j, offset); + attributes.setEntityLength(index, j, length); + } + /***/ + } + } + + } + else { + readingNonSpace = true; + spaceStart = false; + leadingSpace = false; + fBuffer.append(attValue[i]); + count++; + } + } + + // check if the last appended character is a space. + if (count > 0 && fBuffer.charAt(count-1) == ' ') { + fBuffer.setLength(count-1); + /*** BUG #3512 *** + int entityCount = attributes.getEntityCount(index); + for (int j=0; j < entityCount; j++) { + int offset = attributes.getEntityOffset(index, j); + int length = attributes.getEntityLength(index, j); + if (offset < count-1) { + if (offset+length == count) { + length--; + } + } + else { + offset--; + } + attributes.setEntityOffset(index, j, offset); + attributes.setEntityLength(index, j, length); + } + /***/ + } + String newValue = fBuffer.toString(); + attributes.setValue(index, newValue); + return ! attrValue.equals(newValue); + } + + /** Root element specified. */ + private final void rootElementSpecified(QName rootElement) throws XNIException { + if (fPerformValidation) { + String root1 = fRootElement.rawname; + String root2 = rootElement.rawname; + if (root1 == null || !root1.equals(root2)) { + fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, + "RootElementTypeMustMatchDoctypedecl", + new Object[]{root1, root2}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + } // rootElementSpecified(QName) + + /** + * Check that the content of an element is valid. + *

+ * This is the method of primary concern to the validator. This method is called + * upon the scanner reaching the end tag of an element. At that time, the + * element's children must be structurally validated, so it calls this method. + * The index of the element being checked (in the decl pool), is provided as + * well as an array of element name indexes of the children. The validator must + * confirm that this element can have these children in this order. + *

+ * This can also be called to do 'what if' testing of content models just to see + * if they would be valid. + *

+ * Note that the element index is an index into the element decl pool, whereas + * the children indexes are name indexes, i.e. into the string pool. + *

+ * A value of -1 in the children array indicates a PCDATA node. All other + * indexes will be positive and represent child elements. The count can be + * zero, since some elements have the EMPTY content model and that must be + * confirmed. + * + * @param elementIndex The index within the ElementDeclPool of this + * element. + * @param childCount The number of entries in the children array. + * @param children The children of this element. + * + * @return The value -1 if fully valid, else the 0 based index of the child + * that first failed. If the value returned is equal to the number + * of children, then additional content is required to reach a valid + * ending state. + * + * @exception Exception Thrown on error. + */ + private int checkContent(int elementIndex, + QName[] children, + int childOffset, + int childCount) throws XNIException { + + fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl); + + // Get the element name index from the element + final String elementType = fCurrentElement.rawname; + + // Get out the content spec for this element + final int contentType = fCurrentContentSpecType; + + + // + // Deal with the possible types of content. We try to optimized here + // by dealing specially with content models that don't require the + // full DFA treatment. + // + if (contentType == XMLElementDecl.TYPE_EMPTY) { + // + // If the child count is greater than zero, then this is + // an error right off the bat at index 0. + // + if (childCount != 0) { + return 0; + } + } + else if (contentType == XMLElementDecl.TYPE_ANY) { + // + // This one is open game so we don't pass any judgement on it + // at all. Its assumed to fine since it can hold anything. + // + } + else if (contentType == XMLElementDecl.TYPE_MIXED || + contentType == XMLElementDecl.TYPE_CHILDREN) { + // Get the content model for this element, faulting it in if needed + ContentModelValidator cmElem = null; + cmElem = fTempElementDecl.contentModelValidator; + int result = cmElem.validate(children, childOffset, childCount); + return result; + } + else if (contentType == -1) { + //REVISIT + /**** + reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED, + XMLMessages.VC_ELEMENT_VALID, + elementType); + /****/ + } + else if (contentType == XMLElementDecl.TYPE_SIMPLE) { + + //REVISIT + // this should never be reached in the case of DTD validation. + + } + else { + //REVISIT + /**** + fErrorReporter.reportError(fErrorReporter.getLocator(), + ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN, + ImplementationMessages.VAL_CST, + 0, + null, + XMLErrorReporter.ERRORTYPE_FATAL_ERROR); + /****/ + } + + // We succeeded + return -1; + + } // checkContent(int,int,QName[]):int + + /** Returns the content spec type for an element index. */ + private int getContentSpecType(int elementIndex) { + + int contentSpecType = -1; + if (elementIndex > -1) { + if (fDTDGrammar.getElementDecl(elementIndex,fTempElementDecl)) { + contentSpecType = fTempElementDecl.type; + } + } + return contentSpecType; + } + + /** Character data in content. */ + private void charDataInContent() { + + if (DEBUG_ELEMENT_CHILDREN) { + System.out.println("charDataInContent()"); + } + if (fElementChildren.length <= fElementChildrenLength) { + QName[] newarray = new QName[fElementChildren.length * 2]; + System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length); + fElementChildren = newarray; + } + QName qname = fElementChildren[fElementChildrenLength]; + if (qname == null) { + for (int i = fElementChildrenLength; i < fElementChildren.length; i++) { + fElementChildren[i] = new QName(); + } + qname = fElementChildren[fElementChildrenLength]; + } + qname.clear(); + fElementChildrenLength++; + + } // charDataInCount() + + /** convert attribute type from ints to strings */ + private String getAttributeTypeName(XMLAttributeDecl attrDecl) { + + switch (attrDecl.simpleType.type) { + case XMLSimpleType.TYPE_ENTITY: { + return attrDecl.simpleType.list ? XMLSymbols.fENTITIESSymbol : XMLSymbols.fENTITYSymbol; + } + case XMLSimpleType.TYPE_ENUMERATION: { + StringBuffer buffer = new StringBuffer(); + buffer.append('('); + for (int i=0; i 0) { + buffer.append('|'); + } + buffer.append(attrDecl.simpleType.enumeration[i]); + } + buffer.append(')'); + return fSymbolTable.addSymbol(buffer.toString()); + } + case XMLSimpleType.TYPE_ID: { + return XMLSymbols.fIDSymbol; + } + case XMLSimpleType.TYPE_IDREF: { + return attrDecl.simpleType.list ? XMLSymbols.fIDREFSSymbol : XMLSymbols.fIDREFSymbol; + } + case XMLSimpleType.TYPE_NMTOKEN: { + return attrDecl.simpleType.list ? XMLSymbols.fNMTOKENSSymbol : XMLSymbols.fNMTOKENSymbol; + } + case XMLSimpleType.TYPE_NOTATION: { + return XMLSymbols.fNOTATIONSymbol; + } + } + return XMLSymbols.fCDATASymbol; + + } // getAttributeTypeName(XMLAttributeDecl):String + + /** initialization */ + protected void init() { + + // datatype validators + if (fValidation || fDynamicValidation) { + try { + //REVISIT: datatypeRegistry + initialization of datatype + // why do we cast to ListDatatypeValidator? + fValID = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDSymbol); + fValIDRef = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSymbol); + fValIDRefs = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSSymbol); + fValENTITY = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITYSymbol); + fValENTITIES = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITIESSymbol); + fValNMTOKEN = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSymbol); + fValNMTOKENS = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSSymbol); + fValNOTATION = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNOTATIONSymbol); + + } + catch (Exception e) { + // should never happen + e.printStackTrace(System.err); + } + + } + + } // init() + + /** ensure element stack capacity */ + private void ensureStackCapacity (int newElementDepth) { + if (newElementDepth == fElementQNamePartsStack.length) { + + QName[] newStackOfQueue = new QName[newElementDepth * 2]; + System.arraycopy(this.fElementQNamePartsStack, 0, newStackOfQueue, 0, newElementDepth ); + fElementQNamePartsStack = newStackOfQueue; + + QName qname = fElementQNamePartsStack[newElementDepth]; + if (qname == null) { + for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) { + fElementQNamePartsStack[i] = new QName(); + } + } + + int[] newStack = new int[newElementDepth * 2]; + System.arraycopy(fElementIndexStack, 0, newStack, 0, newElementDepth); + fElementIndexStack = newStack; + + newStack = new int[newElementDepth * 2]; + System.arraycopy(fContentSpecTypeStack, 0, newStack, 0, newElementDepth); + fContentSpecTypeStack = newStack; + + } + } // ensureStackCapacity + + + // + // Protected methods + // + + /** Handle element + * @return true if validator is removed from the pipeline + */ + protected boolean handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + + // VC: Root Element Type + // see if the root element's name matches the one in DoctypeDecl + if (!fSeenRootElement) { + // REVISIT: Here are current assumptions about validation features + // given that XMLSchema validator is in the pipeline + // + // http://xml.org/sax/features/validation = true + // http://apache.org/xml/features/validation/schema = true + // + // [1] XML instance document only has reference to a DTD + // Outcome: report validation errors only against dtd. + // + // [2] XML instance document has only XML Schema grammars: + // Outcome: report validation errors only against schemas (no errors produced from DTD validator) + // + // [3] XML instance document has DTD and XML schemas: + // [a] if schema language is not set outcome - validation errors reported against both grammars: DTD and schemas. + // [b] if schema language is set to XML Schema - do not report validation errors + // + // if dynamic validation is on + // validate only against grammar we've found (depending on settings + // for schema feature) + // + // + fPerformValidation = validate(); + fSeenRootElement = true; + fValidationManager.setEntityState(fDTDGrammar); + fValidationManager.setGrammarFound(fSeenDoctypeDecl); + rootElementSpecified(element); + } + if (fDTDGrammar == null) { + + if (!fPerformValidation) { + fCurrentElementIndex = -1; + fCurrentContentSpecType = -1; + fInElementContent = false; + } + if (fPerformValidation) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_GRAMMAR_NOT_FOUND", + new Object[]{ element.rawname}, + XMLErrorReporter.SEVERITY_ERROR); + } + // modify pipeline + if (fDocumentSource !=null ) { + fDocumentSource.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) + fDocumentHandler.setDocumentSource(fDocumentSource); + return true; + } + } + else { + // resolve the element + fCurrentElementIndex = fDTDGrammar.getElementDeclIndex(element); + //changed here.. new function for getContentSpecType + fCurrentContentSpecType = fDTDGrammar.getContentSpecType(fCurrentElementIndex); + if (fCurrentContentSpecType == -1 && fPerformValidation) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_ELEMENT_NOT_DECLARED", + new Object[]{ element.rawname}, + XMLErrorReporter.SEVERITY_ERROR); + } + + // 0. insert default attributes + // 1. normalize the attributes + // 2. validate the attrivute list. + // TO DO: + //changed here.. also pass element name, + addDTDDefaultAttrsAndValidate(element, fCurrentElementIndex, attributes); + } + + // set element content state + fInElementContent = fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN; + + // increment the element depth, add this element's + // QName to its enclosing element 's children list + fElementDepth++; + if (fPerformValidation) { + // push current length onto stack + if (fElementChildrenOffsetStack.length <= fElementDepth) { + int newarray[] = new int[fElementChildrenOffsetStack.length * 2]; + System.arraycopy(fElementChildrenOffsetStack, 0, newarray, 0, fElementChildrenOffsetStack.length); + fElementChildrenOffsetStack = newarray; + } + fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength; + + // add this element to children + if (fElementChildren.length <= fElementChildrenLength) { + QName[] newarray = new QName[fElementChildrenLength * 2]; + System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length); + fElementChildren = newarray; + } + QName qname = fElementChildren[fElementChildrenLength]; + if (qname == null) { + for (int i = fElementChildrenLength; i < fElementChildren.length; i++) { + fElementChildren[i] = new QName(); + } + qname = fElementChildren[fElementChildrenLength]; + } + qname.setValues(element); + fElementChildrenLength++; + } + + // save current element information + fCurrentElement.setValues(element); + ensureStackCapacity(fElementDepth); + fElementQNamePartsStack[fElementDepth].setValues(fCurrentElement); + fElementIndexStack[fElementDepth] = fCurrentElementIndex; + fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType; + startNamespaceScope(element, attributes, augs); + return false; + + } // handleStartElement(QName,XMLAttributes) + + protected void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs){ + } + + /** Handle end element. */ + protected void handleEndElement(QName element, Augmentations augs, boolean isEmpty) + throws XNIException { + + // decrease element depth + fElementDepth--; + + // validate + if (fPerformValidation) { + int elementIndex = fCurrentElementIndex; + if (elementIndex != -1 && fCurrentContentSpecType != -1) { + QName children[] = fElementChildren; + int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1; + int childrenLength = fElementChildrenLength - childrenOffset; + int result = checkContent(elementIndex, + children, childrenOffset, childrenLength); + + if (result != -1) { + fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl); + if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MSG_CONTENT_INVALID", + new Object[]{ element.rawname, "EMPTY"}, + XMLErrorReporter.SEVERITY_ERROR); + } + else { + String messageKey = result != childrenLength ? + "MSG_CONTENT_INVALID" : "MSG_CONTENT_INCOMPLETE"; + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + messageKey, + new Object[]{ element.rawname, + fDTDGrammar.getContentSpecAsString(elementIndex)}, + XMLErrorReporter.SEVERITY_ERROR); + } + } + } + fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1; + } + + endNamespaceScope(fCurrentElement, augs, isEmpty); + + // now pop this element off the top of the element stack + if (fElementDepth < -1) { + throw new RuntimeException("FWK008 Element stack underflow"); + } + if (fElementDepth < 0) { + fCurrentElement.clear(); + fCurrentElementIndex = -1; + fCurrentContentSpecType = -1; + fInElementContent = false; + + // TO DO : fix this + // + // Check after document is fully parsed + // (1) check that there was an element with a matching id for every + // IDREF and IDREFS attr (V_IDREF0) + // + if (fPerformValidation) { + Iterator invIdRefs = fValidationState.checkIDRefID(); + if (invIdRefs != null) { + while (invIdRefs.hasNext()) { + fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, + "MSG_ELEMENT_WITH_ID_REQUIRED", + new Object[]{invIdRefs.next()}, + XMLErrorReporter.SEVERITY_ERROR ); + } + } + } + return; + } + + // If Namespace enable then localName != rawName + fCurrentElement.setValues(fElementQNamePartsStack[fElementDepth]); + + fCurrentElementIndex = fElementIndexStack[fElementDepth]; + fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth]; + fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN); + + } // handleEndElement(QName,boolean) + + protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty){ + + // call handlers + if (fDocumentHandler != null && !isEmpty) { + // NOTE: The binding of the element doesn't actually happen + // yet because the namespace binder does that. However, + // if it does it before this point, then the endPrefix- + // Mapping calls get made too soon! As long as the + // rawnames match, we know it'll have a good binding, + // so we can just use the current element. -Ac + fDocumentHandler.endElement(fCurrentElement, augs); + } + } + + // returns whether a character is space according to the + // version of XML this validator supports. + protected boolean isSpace(int c) { + return XMLChar.isSpace(c); + } // isSpace(int): boolean + + public boolean characterData(String data, Augmentations augs) { + characters(new XMLString(data.toCharArray(), 0, data.length()), augs); + return true; + } + +} // class XMLDTDValidator diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDValidatorFilter.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDValidatorFilter.java new file mode 100644 index 0000000..164018d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLDTDValidatorFilter.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import org.apache.xerces.xni.parser.XMLDocumentFilter; + +/** + * Defines a DTD Validator filter to allow + * components to query the DTD validator. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * + * @version $Id$ + */ +public interface XMLDTDValidatorFilter + extends XMLDocumentFilter { + + /** + * Returns true if the validator has a DTD grammar + * + * @return true if the validator has a DTD grammar + */ + public boolean hasGrammar(); + + /** + * Return true if validator must validate the document + * + * @return true if validator must validate the document + */ + public boolean validate(); + + +} // interface XMLDTDValidatorFilter diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLElementDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLElementDecl.java new file mode 100644 index 0000000..0c59976 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLElementDecl.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import org.apache.xerces.impl.dtd.models.ContentModelValidator; +import org.apache.xerces.xni.QName; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public class XMLElementDecl { + + // + // Constants + // + + /** TYPE_ANY */ + public static final short TYPE_ANY = 0; + + /** TYPE_EMPTY */ + public static final short TYPE_EMPTY = 1; + + /** TYPE_MIXED */ + public static final short TYPE_MIXED = 2; + + /** TYPE_CHILDREN */ + public static final short TYPE_CHILDREN = 3; + + /** TYPE_SIMPLE */ + public static final short TYPE_SIMPLE = 4; + + // + // Data + // + + /** name */ + public final QName name = new QName(); + + /** scope */ + public int scope = -1; + + /** type */ + public short type = -1; + + /** contentModelValidator */ + public ContentModelValidator contentModelValidator; + + /** simpleType */ + public final XMLSimpleType simpleType = new XMLSimpleType(); + + // + // Methods + // + + /** + * setValues + * + * @param name + * @param scope + * @param type + * @param contentModelValidator + * @param simpleType + */ + public void setValues(QName name, int scope, short type, ContentModelValidator contentModelValidator, XMLSimpleType simpleType) { + this.name.setValues(name); + this.scope = scope; + this.type = type; + this.contentModelValidator = contentModelValidator; + this.simpleType.setValues(simpleType); + } // setValues + + /** + * clear + */ + public void clear() { + this.name.clear(); + this.type = -1; + this.scope = -1; + this.contentModelValidator = null; + this.simpleType.clear(); + } // clear + +} // class XMLElementDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLEntityDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLEntityDecl.java new file mode 100644 index 0000000..1d07157 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLEntityDecl.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public class XMLEntityDecl { + + // + // Data + // + + /** name */ + public String name; + + /** publicId */ + public String publicId; + + /** systemId */ + public String systemId; + + /** baseSystemId */ + public String baseSystemId; + + /** notation */ + public String notation; + + /** isPE */ + public boolean isPE; + + /** inExternal */ + /** Note: flag of where the entity is defined, not whether it is a external entity */ + public boolean inExternal; + + /** Value. */ + public String value; + + // + // Methods + // + + /** + * setValues + * + * @param name + * @param publicId + * @param systemId + * @param baseSystemId + * @param notation + * @param isPE + * @param inExternal + */ + public void setValues(String name, String publicId, String systemId, + String baseSystemId, String notation, + boolean isPE, boolean inExternal) { + setValues(name, publicId, systemId, baseSystemId, notation, null, isPE, inExternal); + } + + /** + * setValues + * + * @param name + * @param publicId + * @param systemId + * @param baseSystemId + * @param value + * @param notation + * @param isPE + * @param inExternal + */ + public void setValues(String name, String publicId, String systemId, + String baseSystemId, String notation, + String value, boolean isPE, boolean inExternal) { + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + this.baseSystemId = baseSystemId; + this.notation = notation; + this.value = value; + this.isPE = isPE; + this.inExternal = inExternal; + } // setValues(String,String,String,String,String,boolean,boolean) + + /** + * clear + */ + public void clear() { + this.name = null; + this.publicId = null; + this.systemId = null; + this.baseSystemId = null; + this.notation = null; + this.value = null; + this.isPE = false; + this.inExternal = false; + + } // clear + +} // class XMLEntityDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLNSDTDValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLNSDTDValidator.java new file mode 100644 index 0000000..f32d1b9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLNSDTDValidator.java @@ -0,0 +1,230 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XNIException; + + +/** + * The DTD validator. The validator implements a document + * filter: receiving document events from the scanner; validating + * the content and structure; augmenting the InfoSet, if applicable; + * and notifying the parser of the information resulting from the + * validation process. + *

Formerly, this component also handled DTD events and grammar construction. + * To facilitate the development of a meaningful DTD grammar caching/preparsing + * framework, this functionality has been moved into the XMLDTDLoader + * class. Therefore, this class no longer implements the DTDFilter + * or DTDContentModelFilter interfaces. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/namespaces
  • + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/features/validation/dynamic
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/grammar-pool
  • + *
  • http://apache.org/xml/properties/internal/datatype-validator-factory
  • + *
+ * + * @xerces.internal + * + * @author Elena Litani, IBM + * + * @version $Id$ + */ +public class XMLNSDTDValidator + extends XMLDTDValidator{ + + /** Attribute QName. */ + private final QName fAttributeQName = new QName(); + + /** Bind namespaces */ + protected final void startNamespaceScope (QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + + // add new namespace context + fNamespaceContext.pushContext(); + + if (element.prefix == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "ElementXMLNSPrefix", + new Object[]{element.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // search for new namespace bindings + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + String localpart = attributes.getLocalName(i); + String prefix = attributes.getPrefix(i); + // when it's of form xmlns="..." or xmlns:prefix="...", + // it's a namespace declaration. but prefix:xmlns="..." isn't. + if (prefix == XMLSymbols.PREFIX_XMLNS || + prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) { + + // get the internalized value of this attribute + String uri = fSymbolTable.addSymbol(attributes.getValue(i)); + + // 1. "xmlns" can't be bound to any namespace + if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 2. the namespace for "xmlns" can't be bound to any prefix + if (uri == NamespaceContext.XMLNS_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXMLNS", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // 3. "xml" can't be bound to any other namespace than it's own + if (localpart == XMLSymbols.PREFIX_XML) { + if (uri != NamespaceContext.XML_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + // 4. the namespace for "xml" can't be bound to any other prefix + else { + if (uri ==NamespaceContext.XML_URI) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "CantBindXML", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + + prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING; + + // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix + // We should only report an error if there is a prefix, + // that is, the local part is not "xmlns". -SG + if (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "EmptyPrefixedAttName", + new Object[]{attributes.getQName(i)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + continue; + } + + // declare prefix in context + fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null); + } + } + + // bind the element + String prefix = element.prefix != null + ? element.prefix : XMLSymbols.EMPTY_STRING; + element.uri = fNamespaceContext.getURI(prefix); + if (element.prefix == null && element.uri != null) { + element.prefix = XMLSymbols.EMPTY_STRING; + } + if (element.prefix != null && element.uri == null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "ElementPrefixUnbound", + new Object[]{element.prefix, element.rawname}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + + // bind the attributes + for (int i = 0; i < length; i++) { + attributes.getName(i, fAttributeQName); + String aprefix = fAttributeQName.prefix != null + ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; + String arawname = fAttributeQName.rawname; + if (arawname == XMLSymbols.PREFIX_XMLNS) { + fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS); + attributes.setName(i, fAttributeQName); + } + else if (aprefix != XMLSymbols.EMPTY_STRING) { + fAttributeQName.uri = fNamespaceContext.getURI(aprefix); + if (fAttributeQName.uri == null) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributePrefixUnbound", + new Object[]{element.rawname,arawname,aprefix}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + attributes.setName(i, fAttributeQName); + } + } + + // verify that duplicate attributes don't exist + // Example: + int attrCount = attributes.getLength(); + for (int i = 0; i < attrCount - 1; i++) { + String auri = attributes.getURI(i); + if (auri == null || auri == NamespaceContext.XMLNS_URI) { + continue; + } + String alocalpart = attributes.getLocalName(i); + for (int j = i + 1; j < attrCount; j++) { + String blocalpart = attributes.getLocalName(j); + String buri = attributes.getURI(j); + if (alocalpart == blocalpart && auri == buri) { + fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, + "AttributeNSNotUnique", + new Object[]{element.rawname,alocalpart, auri}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + } + + + } // startNamespaceScope(QName,XMLAttributes) + + + /** Handles end element. */ + protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty) + throws XNIException { + + // bind element + String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; + element.uri = fNamespaceContext.getURI(eprefix); + if (element.uri != null) { + element.prefix = eprefix; + } + + // call handlers + if (fDocumentHandler != null) { + if (!isEmpty) { + fDocumentHandler.endElement(element, augs); + } + } + + // pop context + fNamespaceContext.popContext(); + + } // endNamespaceScope(QName,boolean) + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLNotationDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLNotationDecl.java new file mode 100644 index 0000000..abfaac5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLNotationDecl.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public class XMLNotationDecl { + + // + // Data + // + + /** name */ + public String name; + + /** publicId */ + public String publicId; + + /** systemId */ + public String systemId; + + /** base systemId */ + public String baseSystemId; + + // + // Methods + // + + /** + * setValues + * + * @param name + * @param publicId + * @param systemId + */ + public void setValues(String name, String publicId, String systemId, String baseSystemId) { + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + this.baseSystemId = baseSystemId; + } // setValues + + /** + * clear + */ + public void clear() { + this.name = null; + this.publicId = null; + this.systemId = null; + this.baseSystemId = null; + } // clear + +} // class XMLNotationDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLSimpleType.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLSimpleType.java new file mode 100644 index 0000000..841ff1d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/XMLSimpleType.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd; + +import org.apache.xerces.impl.dv.DatatypeValidator; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public class XMLSimpleType { + + // + // Constants + // + + /** TYPE_CDATA */ + public static final short TYPE_CDATA = 0; + + /** TYPE_ENTITY */ + public static final short TYPE_ENTITY = 1; + + /** TYPE_ENUMERATION */ + public static final short TYPE_ENUMERATION = 2; + + /** TYPE_ID */ + public static final short TYPE_ID = 3; + + /** TYPE_IDREF */ + public static final short TYPE_IDREF = 4; + + /** TYPE_NMTOKEN */ + public static final short TYPE_NMTOKEN = 5; + + /** TYPE_NOTATION */ + public static final short TYPE_NOTATION = 6; + + /** TYPE_NAMED */ + public static final short TYPE_NAMED = 7; + + /** DEFAULT_TYPE_DEFAULT */ + public static final short DEFAULT_TYPE_DEFAULT = 3; + + /** DEFAULT_TYPE_FIXED */ + public static final short DEFAULT_TYPE_FIXED = 1; + + /** DEFAULT_TYPE_IMPLIED */ + public static final short DEFAULT_TYPE_IMPLIED = 0; + + /** DEFAULT_TYPE_REQUIRED */ + public static final short DEFAULT_TYPE_REQUIRED = 2; + + // + // Data + // + + /** type */ + public short type; + + /** name */ + public String name; + + /** enumeration */ + public String[] enumeration; + + /** list */ + public boolean list; + + /** defaultType */ + public short defaultType; + + /** defaultValue */ + public String defaultValue; + + /** non-normalized defaultValue */ + public String nonNormalizedDefaultValue; + + /** datatypeValidator */ + public DatatypeValidator datatypeValidator; + + // + // Methods + // + + /** + * setValues + * + * @param type + * @param name + * @param enumeration + * @param list + * @param defaultType + * @param defaultValue + * @param nonNormalizedDefaultValue + * @param datatypeValidator + */ + public void setValues(short type, String name, String[] enumeration, + boolean list, short defaultType, + String defaultValue, String nonNormalizedDefaultValue, + DatatypeValidator datatypeValidator) { + + this.type = type; + this.name = name; + // REVISIT: Should this be a copy? -Ac + if (enumeration != null && enumeration.length > 0) { + this.enumeration = new String[enumeration.length]; + System.arraycopy(enumeration, 0, this.enumeration, 0, this.enumeration.length); + } + else { + this.enumeration = null; + } + this.list = list; + this.defaultType = defaultType; + this.defaultValue = defaultValue; + this.nonNormalizedDefaultValue = nonNormalizedDefaultValue; + this.datatypeValidator = datatypeValidator; + + } // setValues(short,String,String[],boolean,short,String,String,DatatypeValidator) + + /** Set values. */ + public void setValues(XMLSimpleType simpleType) { + + type = simpleType.type; + name = simpleType.name; + // REVISIT: Should this be a copy? -Ac + if (simpleType.enumeration != null && simpleType.enumeration.length > 0) { + enumeration = new String[simpleType.enumeration.length]; + System.arraycopy(simpleType.enumeration, 0, enumeration, 0, enumeration.length); + } + else { + enumeration = null; + } + list = simpleType.list; + defaultType = simpleType.defaultType; + defaultValue = simpleType.defaultValue; + nonNormalizedDefaultValue = simpleType.nonNormalizedDefaultValue; + datatypeValidator = simpleType.datatypeValidator; + + } // setValues(XMLSimpleType) + + /** + * clear + */ + public void clear() { + this.type = -1; + this.name = null; + this.enumeration = null; + this.list = false; + this.defaultType = -1; + this.defaultValue = null; + this.nonNormalizedDefaultValue = null; + this.datatypeValidator = null; + } // clear + +} // class XMLSimpleType diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMAny.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMAny.java new file mode 100644 index 0000000..ed6d007 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMAny.java @@ -0,0 +1,146 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + + +/** + * Content model any node. + * + * @xerces.internal + * + * @version $Id$ + */ +public class CMAny + extends CMNode { + + // + // Data + // + + /** + * The any content model type. This value is one of the following: + * XMLContentSpec.CONTENTSPECNODE_ANY, + * XMLContentSpec.CONTENTSPECNODE_ANY_OTHER, + * XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL. + */ + private final int fType; + + /** + * URI of the any content model. This value is set if the type is + * of the following: + * XMLContentSpec.CONTENTSPECNODE_ANY, + * XMLContentSpec.CONTENTSPECNODE_ANY_OTHER. + */ + private final String fURI; + + /** + * Part of the algorithm to convert a regex directly to a DFA + * numbers each leaf sequentially. If its -1, that means its an + * epsilon node. Zero and greater are non-epsilon positions. + */ + private int fPosition = -1; + + // + // Constructors + // + + /** Constructs a content model any. */ + public CMAny(int type, String uri, int position) { + super(type); + + // Store the information + fType = type; + fURI = uri; + fPosition = position; + } + + // + // Package methods + // + + final int getType() { + return fType; + } + + final String getURI() { + return fURI; + } + + final int getPosition() + { + return fPosition; + } + + final void setPosition(int newPosition) + { + fPosition = newPosition; + } + + // + // CMNode methods + // + + // package + + public boolean isNullable() + { + // Leaf nodes are never nullable unless its an epsilon node + return (fPosition == -1); + } + + public String toString() + { + StringBuffer strRet = new StringBuffer(); + strRet.append('('); + strRet.append("##any:uri="); + strRet.append(fURI); + strRet.append(')'); + if (fPosition >= 0) { + strRet.append(" (Pos:") + .append(Integer.toString(fPosition)) + .append(')'); + } + return strRet.toString(); + } + + // protected + + protected void calcFirstPos(CMStateSet toSet) + { + // If we are an epsilon node, then the first pos is an empty set + if (fPosition == -1) + toSet.zeroBits(); + + // Otherwise, its just the one bit of our position + else + toSet.setBit(fPosition); + } + + protected void calcLastPos(CMStateSet toSet) + { + // If we are an epsilon node, then the last pos is an empty set + if (fPosition == -1) + toSet.zeroBits(); + + // Otherwise, its just the one bit of our position + else + toSet.setBit(fPosition); + } + +} // class CMAny + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMBinOp.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMBinOp.java new file mode 100644 index 0000000..ce24934 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMBinOp.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + +import org.apache.xerces.impl.dtd.XMLContentSpec; + +/** + * Content model Bin-Op node. + * + * @xerces.internal + * + * @version $Id$ + */ +public class CMBinOp extends CMNode +{ + // ------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------- + public CMBinOp(int type, CMNode leftNode, CMNode rightNode) + { + super(type); + + // Insure that its one of the types we require + if ((type() != XMLContentSpec.CONTENTSPECNODE_CHOICE) + && (type() != XMLContentSpec.CONTENTSPECNODE_SEQ)) + { + throw new RuntimeException("ImplementationMessages.VAL_BST"); + } + + // Store the nodes and init any data that needs it + fLeftChild = leftNode; + fRightChild = rightNode; + } + + + // ------------------------------------------------------------------- + // Package, final methods + // ------------------------------------------------------------------- + final CMNode getLeft() + { + return fLeftChild; + } + + final CMNode getRight() + { + return fRightChild; + } + + + // ------------------------------------------------------------------- + // Package, inherited methods + // ------------------------------------------------------------------- + public boolean isNullable() + { + // + // If its an alternation, then if either child is nullable then + // this node is nullable. If its a concatenation, then both of + // them have to be nullable. + // + if (type() == XMLContentSpec.CONTENTSPECNODE_CHOICE) + return (fLeftChild.isNullable() || fRightChild.isNullable()); + else if (type() == XMLContentSpec.CONTENTSPECNODE_SEQ) + return (fLeftChild.isNullable() && fRightChild.isNullable()); + else + throw new RuntimeException("ImplementationMessages.VAL_BST"); + } + + + // ------------------------------------------------------------------- + // Protected, inherited methods + // ------------------------------------------------------------------- + protected void calcFirstPos(CMStateSet toSet) + { + if (type() == XMLContentSpec.CONTENTSPECNODE_CHOICE) + { + // Its the the union of the first positions of our children. + toSet.setTo(fLeftChild.firstPos()); + toSet.union(fRightChild.firstPos()); + } + else if (type() == XMLContentSpec.CONTENTSPECNODE_SEQ) + { + // + // If our left child is nullable, then its the union of our + // children's first positions. Else is our left child's first + // positions. + // + toSet.setTo(fLeftChild.firstPos()); + if (fLeftChild.isNullable()) + toSet.union(fRightChild.firstPos()); + } + else + { + throw new RuntimeException("ImplementationMessages.VAL_BST"); + } + } + + protected void calcLastPos(CMStateSet toSet) + { + if (type() == XMLContentSpec.CONTENTSPECNODE_CHOICE) + { + // Its the the union of the first positions of our children. + toSet.setTo(fLeftChild.lastPos()); + toSet.union(fRightChild.lastPos()); + } + else if (type() == XMLContentSpec.CONTENTSPECNODE_SEQ) + { + // + // If our right child is nullable, then its the union of our + // children's last positions. Else is our right child's last + // positions. + // + toSet.setTo(fRightChild.lastPos()); + if (fRightChild.isNullable()) + toSet.union(fLeftChild.lastPos()); + } + else + { + throw new RuntimeException("ImplementationMessages.VAL_BST"); + } + } + + + // ------------------------------------------------------------------- + // Private data members + // + // fLeftChild + // fRightChild + // These are the references to the two nodes that are on either + // side of this binary operation. + // ------------------------------------------------------------------- + private final CMNode fLeftChild; + private final CMNode fRightChild; +}; + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMLeaf.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMLeaf.java new file mode 100644 index 0000000..12e80b1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMLeaf.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + +import org.apache.xerces.impl.dtd.XMLContentSpec; +import org.apache.xerces.xni.QName; + +/** + * Content model leaf node. + * + * @xerces.internal + * + * @version $Id$ + */ +public class CMLeaf + extends CMNode { + + // + // Data + // + + /** This is the element that this leaf represents. */ + private final QName fElement = new QName(); + + /** + * Part of the algorithm to convert a regex directly to a DFA + * numbers each leaf sequentially. If its -1, that means its an + * epsilon node. Zero and greater are non-epsilon positions. + */ + private int fPosition = -1; + + // + // Constructors + // + + /** Constructs a content model leaf. */ + public CMLeaf(QName element, int position) { + super(XMLContentSpec.CONTENTSPECNODE_LEAF); + + // Store the element index and position + fElement.setValues(element); + fPosition = position; + } + + /** Constructs a content model leaf. */ + public CMLeaf(QName element) { + super(XMLContentSpec.CONTENTSPECNODE_LEAF); + + // Store the element index and position + fElement.setValues(element); + } + + // + // Package methods + // + + final QName getElement() + { + return fElement; + } + + final int getPosition() + { + return fPosition; + } + + final void setPosition(int newPosition) + { + fPosition = newPosition; + } + + // + // CMNode methods + // + + // package + + public boolean isNullable() + { + // Leaf nodes are never nullable unless its an epsilon node + return (fPosition == -1); + } + + public String toString() + { + StringBuffer strRet = new StringBuffer(fElement.toString()); + strRet.append(" ("); + strRet.append(fElement.uri); + strRet.append(','); + strRet.append(fElement.localpart); + strRet.append(')'); + if (fPosition >= 0) { + strRet.append(" (Pos:") + .append(Integer.toString(fPosition)) + .append(')'); + } + return strRet.toString(); + } + + // protected + + protected void calcFirstPos(CMStateSet toSet) + { + // If we are an epsilon node, then the first pos is an empty set + if (fPosition == -1) + toSet.zeroBits(); + + // Otherwise, its just the one bit of our position + else + toSet.setBit(fPosition); + } + + protected void calcLastPos(CMStateSet toSet) + { + // If we are an epsilon node, then the last pos is an empty set + if (fPosition == -1) + toSet.zeroBits(); + + // Otherwise, its just the one bit of our position + else + toSet.setBit(fPosition); + } + +} // class CMLeaf + + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMNode.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMNode.java new file mode 100644 index 0000000..3847a45 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMNode.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + +/** + * A content model node. + * + * @xerces.internal + * + * @version $Id$ + */ +public abstract class CMNode +{ + // ------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------- + public CMNode(int type) + { + fType = type; + } + + + // ------------------------------------------------------------------- + // Package, abstract methods + // ------------------------------------------------------------------- + // made this public so it could be implemented and used outside this package -neilg. + public abstract boolean isNullable() ; + + + // ------------------------------------------------------------------- + // Package final methods + // ------------------------------------------------------------------- + public final int type() + { + return fType; + } + + // made this public so it could be implemented and used outside this package -neilg. + public final CMStateSet firstPos() + { + if (fFirstPos == null) + { + fFirstPos = new CMStateSet(fMaxStates); + calcFirstPos(fFirstPos); + } + return fFirstPos; + } + + // made this public so it could be implemented and used outside this package -neilg. + public final CMStateSet lastPos() + { + if (fLastPos == null) + { + fLastPos = new CMStateSet(fMaxStates); + calcLastPos(fLastPos); + } + return fLastPos; + } + + final void setFollowPos(CMStateSet setToAdopt) + { + fFollowPos = setToAdopt; + } + + public final void setMaxStates(int maxStates) + { + fMaxStates = maxStates; + } + + public boolean isCompactedForUPA() { + return fCompactedForUPA; + } + + public void setIsCompactUPAModel(boolean value) { + fCompactedForUPA = value; + } + + + // ------------------------------------------------------------------- + // Protected, abstract methods + // ------------------------------------------------------------------- + protected abstract void calcFirstPos(CMStateSet toSet) ; + + protected abstract void calcLastPos(CMStateSet toSet) ; + + + // ------------------------------------------------------------------- + // Private data members + // + // fType + // The type of node. This indicates whether its a leaf or an + // operation. Though we also do derived classes for these types, + // it is too expensive to use runtime typing to find this out. + // This is one of the ContentSpecNode.NODE_XXX types. + // + // fFirstPos + // The set of NFA states that represent the entry states of this + // node in the DFA. + // + // fFollowPos + // The set of NFA states that can be gotten to from from this + // node in the DFA. + // + // fLastPos + // The set of NFA states that represent the final states of this + // node in the DFA. + // + // fMaxStates + // The maximum number of states that the NFA has, which means the + // max number of NFA states that have to be traced in the state + // sets during the building of the DFA. Its unfortunate that it + // has to be stored redundantly, but we need to fault in the + // state set members and they have to be sized to this size. We + // init to to -1 so it will cause an error if its used without + // being initialized. + // ------------------------------------------------------------------- + private final int fType; + private CMStateSet fFirstPos = null; + private CMStateSet fFollowPos = null; + private CMStateSet fLastPos = null; + private int fMaxStates = -1; + + /* + * This boolean is true if the model represented by the CMNode does not represent + * the true model from the schema, but has had its min/maxOccurs modified for a + * more compact representation (for purposes of UPA). + */ + private boolean fCompactedForUPA = false; +}; \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMStateSet.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMStateSet.java new file mode 100644 index 0000000..6fef52c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMStateSet.java @@ -0,0 +1,300 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + + +/** + * This class is a very simple bitset class. The DFA content model code needs + * to support a bit set, but the java BitSet class is way, way overkill. Our + * bitset never needs to be expanded after creation, hash itself, etc... + * + * Since the vast majority of content models will never require more than 64 + * bits, and since allocation of anything in Java is expensive, this class + * provides a hybrid implementation that uses two ints for instances that use + * 64 bits or fewer. It has a byte array reference member which will only be + * used if more than 64 bits are required. + * + * Note that the code that uses this class will never perform operations + * on sets of different sizes, so that check does not have to be made here. + * + * @xerces.internal + * + * @version $Id$ + */ +// made this class public so it can be accessed by +// the XS content models from the schema package -neilg. +public class CMStateSet +{ + // ------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------- + public CMStateSet(int bitCount) + { + // Store the required bit count and insure its legal + fBitCount = bitCount; + if (fBitCount < 0) + throw new RuntimeException("ImplementationMessages.VAL_CMSI"); + + // + // See if we need to allocate the byte array or whether we can live + // within the 64 bit high performance scheme. + // + if (fBitCount > 64) + { + fByteCount = fBitCount / 8; + if (fBitCount % 8 != 0) + fByteCount++; + fByteArray = new byte[fByteCount]; + } + + // Init all the bits to zero + zeroBits(); + } + + + // ------------------------------------------------------------------- + // Public inherited methods + // ------------------------------------------------------------------- + public String toString() + { + StringBuffer strRet = new StringBuffer(); + try + { + strRet.append('{'); + for (int index = 0; index < fBitCount; index++) { + if (getBit(index)) { + strRet.append(' ').append(index); + } + } + strRet.append(" }"); + } + + catch(RuntimeException exToCatch) + { + // + // We know this won't happen but we have to catch it to avoid it + // having to be in our 'throws' list. + // + } + return strRet.toString(); + } + + + // ------------------------------------------------------------------- + // Package final methods + // ------------------------------------------------------------------- +// the XS content models from the schema package -neilg. + public final void intersection(CMStateSet setToAnd) + { + if (fBitCount < 65) + { + fBits1 &= setToAnd.fBits1; + fBits2 &= setToAnd.fBits2; + } + else + { + for (int index = fByteCount - 1; index >= 0; index--) + fByteArray[index] &= setToAnd.fByteArray[index]; + } + } + + public final boolean getBit(int bitToGet) + { + if (bitToGet >= fBitCount) + throw new RuntimeException("ImplementationMessages.VAL_CMSI"); + + if (fBitCount < 65) + { + final int mask = (0x1 << (bitToGet % 32)); + if (bitToGet < 32) + return (fBits1 & mask) != 0; + else + return (fBits2 & mask) != 0; + } + else + { + // Create the mask and byte values + final byte mask = (byte)(0x1 << (bitToGet % 8)); + final int ofs = bitToGet >> 3; + + // And access the right bit and byte + return ((fByteArray[ofs] & mask) != 0); + } + } + + public final boolean isEmpty() + { + if (fBitCount < 65) + { + return ((fBits1 == 0) && (fBits2 == 0)); + } + else + { + for (int index = fByteCount - 1; index >= 0; index--) + { + if (fByteArray[index] != 0) + return false; + } + } + return true; + } + + final boolean isSameSet(CMStateSet setToCompare) + { + if (fBitCount != setToCompare.fBitCount) + return false; + + if (fBitCount < 65) + { + return ((fBits1 == setToCompare.fBits1) + && (fBits2 == setToCompare.fBits2)); + } + + for (int index = fByteCount - 1; index >= 0; index--) + { + if (fByteArray[index] != setToCompare.fByteArray[index]) + return false; + } + return true; + } + +// the XS content models from the schema package -neilg. + public final void union(CMStateSet setToOr) + { + if (fBitCount < 65) + { + fBits1 |= setToOr.fBits1; + fBits2 |= setToOr.fBits2; + } + else + { + for (int index = fByteCount - 1; index >= 0; index--) + fByteArray[index] |= setToOr.fByteArray[index]; + } + } + + public final void setBit(int bitToSet) + { + if (bitToSet >= fBitCount) + throw new RuntimeException("ImplementationMessages.VAL_CMSI"); + + if (fBitCount < 65) + { + final int mask = (0x1 << (bitToSet % 32)); + if (bitToSet < 32) + { + fBits1 &= ~mask; + fBits1 |= mask; + } + else + { + fBits2 &= ~mask; + fBits2 |= mask; + } + } + else + { + // Create the mask and byte values + final byte mask = (byte)(0x1 << (bitToSet % 8)); + final int ofs = bitToSet >> 3; + + // And access the right bit and byte + fByteArray[ofs] &= ~mask; + fByteArray[ofs] |= mask; + } + } + +// the XS content models from the schema package -neilg. + public final void setTo(CMStateSet srcSet) + { + // They have to be the same size + if (fBitCount != srcSet.fBitCount) + throw new RuntimeException("ImplementationMessages.VAL_CMSI"); + + if (fBitCount < 65) + { + fBits1 = srcSet.fBits1; + fBits2 = srcSet.fBits2; + } + else + { + for (int index = fByteCount - 1; index >= 0; index--) + fByteArray[index] = srcSet.fByteArray[index]; + } + } + + // had to make this method public so it could be accessed from + // schema package - neilg. + public final void zeroBits() + { + if (fBitCount < 65) + { + fBits1 = 0; + fBits2 = 0; + } + else + { + for (int index = fByteCount - 1; index >= 0; index--) + fByteArray[index] = 0; + } + } + + + // ------------------------------------------------------------------- + // Private data members + // + // fBitCount + // The count of bits that the outside world wants to support, + // so its the max bit index plus one. + // + // fByteCount + // If the bit count is > 64, then we use the fByteArray member to + // store the bits, and this indicates its size in bytes. Otherwise + // its value is meaningless. + // + // fBits1 + // fBits2 + // When the bit count is < 64 (very common), these hold the bits. + // Otherwise, the fByteArray member holds htem. + // ------------------------------------------------------------------- + int fBitCount; + int fByteCount; + int fBits1; + int fBits2; + byte[] fByteArray; + /* Optimization(Jan, 2001) */ + public boolean equals(Object o) { + if (!(o instanceof CMStateSet)) return false; + return isSameSet((CMStateSet)o); + } + + public int hashCode() { + if (fBitCount < 65) + { + return fBits1+ fBits2 * 31; + } + else + { + int hash = 0; + for (int index = fByteCount - 1; index >= 0; index--) + hash = fByteArray[index] + hash * 31; + return hash; + } + } + /* Optimization(Jan, 2001) */ +}; diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMUniOp.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMUniOp.java new file mode 100644 index 0000000..f641892 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/CMUniOp.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + +import org.apache.xerces.impl.dtd.XMLContentSpec; + +/** + * Content model Uni-Op node. + * + * @xerces.internal + * + * @version $Id$ + */ +public class CMUniOp extends CMNode +{ + // ------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------- + public CMUniOp(int type, CMNode childNode) + { + super(type); + + // Insure that its one of the types we require + if ((type() != XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE) + && (type() != XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE) + && (type() != XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE)) + { + throw new RuntimeException("ImplementationMessages.VAL_UST"); + } + + // Store the node and init any data that needs it + fChild = childNode; + } + + + // ------------------------------------------------------------------- + // Package, final methods + // ------------------------------------------------------------------- + final CMNode getChild() + { + return fChild; + } + + + // ------------------------------------------------------------------- + // Package, inherited methods + // ------------------------------------------------------------------- + public boolean isNullable() + { + // + // For debugging purposes, make sure we got rid of all non '*' + // repetitions. Otherwise, '*' style nodes are always nullable. + // + if (type() == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) + return fChild.isNullable(); + else + return true; + } + + + // ------------------------------------------------------------------- + // Protected, inherited methods + // ------------------------------------------------------------------- + protected void calcFirstPos(CMStateSet toSet) + { + // Its just based on our child node's first pos + toSet.setTo(fChild.firstPos()); + } + + protected void calcLastPos(CMStateSet toSet) + { + // Its just based on our child node's last pos + toSet.setTo(fChild.lastPos()); + } + + + // ------------------------------------------------------------------- + // Private data members + // + // fChild + // This is the reference to the one child that we have for this + // unary operation. + // ------------------------------------------------------------------- + private final CMNode fChild; +}; + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/ContentModelValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/ContentModelValidator.java new file mode 100644 index 0000000..3fa775f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/ContentModelValidator.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + +import org.apache.xerces.xni.QName; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public interface ContentModelValidator { + + // + // Methods + // + + /** + * validate + * + * @param children + * @param offset + * @param length + * + * @return The value -1 if fully valid, else the 0 based index of the child + * that first failed. If the value returned is equal to the number + * of children, then the specified children are valid but additional + * content is required to reach a valid ending state. + */ + public int validate(QName[] children, int offset, int length); + +} // interface ContentModelValidator diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/DFAContentModel.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/DFAContentModel.java new file mode 100644 index 0000000..e24af20 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/DFAContentModel.java @@ -0,0 +1,987 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + +import java.util.HashMap; + +import org.apache.xerces.impl.dtd.XMLContentSpec; +import org.apache.xerces.xni.QName; + +/** + * DFAContentModel is the derivative of ContentModel that does + * all of the non-trivial element content validation. This class does + * the conversion from the regular expression to the DFA that + * it then uses in its validation algorithm. + *

+ * Note: Upstream work insures that this class will never see + * a content model with PCDATA in it. Any model with PCDATA is 'mixed' + * and is handled via the MixedContentModel class since mixed models + * are very constrained in form and easily handled via a special case. + * This also makes implementation of this class much easier. + * + * @xerces.internal + * + * @version $Id$ + */ +public class DFAContentModel + implements ContentModelValidator { + + // + // Constants + // + // special strings + + /** Epsilon string. */ + private static String fEpsilonString = "<>"; + + /** End-of-content string. */ + private static String fEOCString = "<>"; + + /** initializing static members **/ + static { + fEpsilonString = fEpsilonString.intern(); + fEOCString = fEOCString.intern(); + } + + // debugging + + /** Set to true to debug content model validation. */ + private static final boolean DEBUG_VALIDATE_CONTENT = false; + + // + // Data + // + + /* this is the EquivClassComparator object */ + //private EquivClassComparator comparator = null; + + /** + * This is the map of unique input symbol elements to indices into + * each state's per-input symbol transition table entry. This is part + * of the built DFA information that must be kept around to do the + * actual validation. + */ + private QName fElemMap[] = null; + + /** + * This is a map of whether the element map contains information + * related to ANY models. + */ + private int fElemMapType[] = null; + + /** The element map size. */ + private int fElemMapSize = 0; + + /** Boolean to distinguish Schema Mixed Content */ + private boolean fMixed; + + /** + * The NFA position of the special EOC (end of content) node. This + * is saved away since it's used during the DFA build. + */ + private int fEOCPos = 0; + + + /** + * This is an array of booleans, one per state (there are + * fTransTableSize states in the DFA) that indicates whether that + * state is a final state. + */ + private boolean fFinalStateFlags[] = null; + + /** + * The list of follow positions for each NFA position (i.e. for each + * non-epsilon leaf node.) This is only used during the building of + * the DFA, and is let go afterwards. + */ + private CMStateSet fFollowList[] = null; + + /** + * This is the head node of our intermediate representation. It is + * only non-null during the building of the DFA (just so that it + * does not have to be passed all around.) Once the DFA is built, + * this is no longer required so its nulled out. + */ + private CMNode fHeadNode = null; + + /** + * The count of leaf nodes. This is an important number that set some + * limits on the sizes of data structures in the DFA process. + */ + private int fLeafCount = 0; + + /** + * An array of non-epsilon leaf nodes, which is used during the DFA + * build operation, then dropped. + */ + private CMLeaf fLeafList[] = null; + + /** Array mapping ANY types to the leaf list. */ + private int fLeafListType[] = null; + + //private ContentLeafNameTypeVector fLeafNameTypeVector = null; + + /** + * The string pool of our parser session. This is set during construction + * and kept around. + */ + //private StringPool fStringPool = null; + + /** + * This is the transition table that is the main by product of all + * of the effort here. It is an array of arrays of ints. The first + * dimension is the number of states we end up with in the DFA. The + * second dimensions is the number of unique elements in the content + * model (fElemMapSize). Each entry in the second dimension indicates + * the new state given that input for the first dimension's start + * state. + *

+ * The fElemMap array handles mapping from element indexes to + * positions in the second dimension of the transition table. + */ + private int fTransTable[][] = null; + + /** + * The number of valid entries in the transition table, and in the other + * related tables such as fFinalStateFlags. + */ + private int fTransTableSize = 0; + + /** + * Flag that indicates that even though we have a "complicated" + * content model, it is valid to have no content. In other words, + * all parts of the content model are optional. For example: + *

+     *      <!ELEMENT AllOptional (Optional*,NotRequired?)>
+     * 
+ */ + private boolean fEmptyContentIsValid = false; + + // temp variables + + /** Temporary qualified name. */ + private final QName fQName = new QName(); + + // + // Constructors + // + + + // + // Constructors + // + + /** + * Constructs a DFA content model. + * + * @param syntaxTree The syntax tree of the content model. + * @param leafCount The number of leaves. + * @param mixed + * + */ + public DFAContentModel(CMNode syntaxTree, int leafCount, boolean mixed) { + // Store away our index and pools in members + //fStringPool = stringPool; + fLeafCount = leafCount; + + + // this is for Schema Mixed Content + fMixed = mixed; + + // + // Ok, so lets grind through the building of the DFA. This method + // handles the high level logic of the algorithm, but it uses a + // number of helper classes to do its thing. + // + // In order to avoid having hundreds of references to the error and + // string handlers around, this guy and all of his helper classes + // just throw a simple exception and we then pass it along. + // + buildDFA(syntaxTree); + } + + // + // ContentModelValidator methods + // + + /** + * Check that the specified content is valid according to this + * content model. This method can also be called to do 'what if' + * testing of content models just to see if they would be valid. + *

+ * A value of -1 in the children array indicates a PCDATA node. All other + * indexes will be positive and represent child elements. The count can be + * zero, since some elements have the EMPTY content model and that must be + * confirmed. + * + * @param children The children of this element. Each integer is an index within + * the StringPool of the child element name. An index + * of -1 is used to indicate an occurrence of non-whitespace character + * data. + * @param offset Offset into the array where the children starts. + * @param length The number of entries in the children array. + * + * @return The value -1 if fully valid, else the 0 based index of the child + * that first failed. If the value returned is equal to the number + * of children, then the specified children are valid but additional + * content is required to reach a valid ending state. + * + */ + public int validate(QName[] children, int offset, int length) { + + if (DEBUG_VALIDATE_CONTENT) + System.out.println("DFAContentModel#validateContent"); + + // + // A DFA content model must *always* have at least 1 child + // so a failure is given if no children present. + // + // Defect 782: This is an incorrect statement because a DFA + // content model is also used for constructions such as: + // + // (Optional*,NotRequired?) + // + // where a perfectly valid content would be NO CHILDREN. + // Therefore, if there are no children, we must check to + // see if the CMNODE_EOC marker is a valid start state! -Ac + // + if (length == 0) { + if (DEBUG_VALIDATE_CONTENT) { + System.out.println("!!! no children"); + System.out.println("elemMap="+fElemMap); + for (int i = 0; i < fElemMap.length; i++) { + String uri = fElemMap[i].uri; + String localpart = fElemMap[i].localpart; + + System.out.println("fElemMap["+i+"]="+uri+","+ + localpart+" ("+ + uri+", "+ + localpart+ + ')'); + + } + System.out.println("EOCIndex="+fEOCString); + } + + return fEmptyContentIsValid ? -1 : 0; + + } // if child count == 0 + + // + // Lets loop through the children in the array and move our way + // through the states. Note that we use the fElemMap array to map + // an element index to a state index. + // + int curState = 0; + for (int childIndex = 0; childIndex < length; childIndex++) + { + // Get the current element index out + final QName curElem = children[offset + childIndex]; + // ignore mixed text + if (fMixed && curElem.localpart == null) { + continue; + } + + // Look up this child in our element map + int elemIndex = 0; + for (; elemIndex < fElemMapSize; elemIndex++) + { + int type = fElemMapType[elemIndex] & 0x0f ; + if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) { + //System.out.println("fElemMap["+elemIndex+"]: "+fElemMap[elemIndex]); + if (fElemMap[elemIndex].rawname == curElem.rawname) { + break; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY) { + String uri = fElemMap[elemIndex].uri; + if (uri == null || uri == curElem.uri) { + break; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) { + if (curElem.uri == null) { + break; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) { + if (fElemMap[elemIndex].uri != curElem.uri) { + break; + } + } + } + + // If we didn't find it, then obviously not valid + if (elemIndex == fElemMapSize) { + if (DEBUG_VALIDATE_CONTENT) { + System.out.println("!!! didn't find it"); + + System.out.println("curElem : " +curElem ); + for (int i=0; i + * <!ELEMENT Foo ((#PCDATA|a|b|c|)*)> + * + * So, all we have to do is to keep an array of the possible children and + * validate by just looking up each child being validated by looking it up + * in the list. + * + * @xerces.internal + * + * @version $Id$ + */ +public class MixedContentModel + implements ContentModelValidator { + + // + // Data + // + + /** The count of possible children that we have to deal with. */ + private final int fCount; + + /** The list of possible children that we have to accept. */ + private final QName fChildren[]; + + /** The type of the children to support ANY. */ + private final int fChildrenType[]; + + /* this is the EquivClassComparator object */ + //private EquivClassComparator comparator = null; + + /** + * True if mixed content model is ordered. DTD mixed content models + * are always unordered. + */ + private final boolean fOrdered; + + // + // Constructors + // + + /** + * Constructs a mixed content model. + * + * @param children The list of allowed children. + * @param type The list of the types of the children. + * @param offset The start offset position in the children. + * @param length The child count. + * @param ordered True if content must be ordered. + */ + public MixedContentModel(QName[] children, int[] type, int offset, int length , boolean ordered) { + // Make our own copy now, which is exactly the right size + fCount = length; + fChildren = new QName[fCount]; + fChildrenType = new int[fCount]; + for (int i = 0; i < fCount; i++) { + fChildren[i] = new QName(children[offset + i]); + fChildrenType[i] = type[offset + i]; + } + fOrdered = ordered; + + } + + // + // ContentModelValidator methods + // + + + /** + * Check that the specified content is valid according to this + * content model. This method can also be called to do 'what if' + * testing of content models just to see if they would be valid. + *

+ * A value of -1 in the children array indicates a PCDATA node. All other + * indexes will be positive and represent child elements. The count can be + * zero, since some elements have the EMPTY content model and that must be + * confirmed. + * + * @param children The children of this element. Each integer is an index within + * the StringPool of the child element name. An index + * of -1 is used to indicate an occurrence of non-whitespace character + * data. + * @param offset Offset into the array where the children starts. + * @param length The number of entries in the children array. + * + * @return The value -1 if fully valid, else the 0 based index of the child + * that first failed. If the value returned is equal to the number + * of children, then the specified children are valid but additional + * content is required to reach a valid ending state. + * + */ + public int validate(QName[] children, int offset, int length) { + + // must match order + if (fOrdered) { + int inIndex = 0; + for (int outIndex = 0; outIndex < length; outIndex++) { + + // ignore mixed text + final QName curChild = children[offset + outIndex]; + if (curChild.localpart == null) { + continue; + } + + // element must match + int type = fChildrenType[inIndex]; + if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) { + if (fChildren[inIndex].rawname != children[offset + outIndex].rawname) { + return outIndex; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY) { + String uri = fChildren[inIndex].uri; + if (uri != null && uri != children[outIndex].uri) { + return outIndex; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) { + if (children[outIndex].uri != null) { + return outIndex; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) { + if (fChildren[inIndex].uri == children[outIndex].uri) { + return outIndex; + } + } + + // advance index + inIndex++; + } + } + + // can appear in any order + else { + for (int outIndex = 0; outIndex < length; outIndex++) + { + // Get the current child out of the source index + final QName curChild = children[offset + outIndex]; + + // If its PCDATA, then we just accept that + if (curChild.localpart == null) + continue; + + // And try to find it in our list + int inIndex = 0; + for (; inIndex < fCount; inIndex++) + { + int type = fChildrenType[inIndex]; + if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) { + if (curChild.rawname == fChildren[inIndex].rawname) { + break; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY) { + String uri = fChildren[inIndex].uri; + if (uri == null || uri == children[outIndex].uri) { + break; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) { + if (children[outIndex].uri == null) { + break; + } + } + else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) { + if (fChildren[inIndex].uri != children[outIndex].uri) { + break; + } + } + // REVISIT: What about checking for multiple ANY matches? + // The content model ambiguity *could* be checked + // by the caller before constructing the mixed + // content model. + } + + // We did not find this one, so the validation failed + if (inIndex == fCount) + return outIndex; + } + } + + // Everything seems to be in order, so return success + return -1; + } // validate + +} // class MixedContentModel diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/SimpleContentModel.java b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/SimpleContentModel.java new file mode 100644 index 0000000..51d60af --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dtd/models/SimpleContentModel.java @@ -0,0 +1,276 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dtd.models; + +import org.apache.xerces.impl.dtd.XMLContentSpec; +import org.apache.xerces.xni.QName; + +/** + * SimpleContentModel is a derivative of the abstract content model base + * class that handles a small set of simple content models that are just + * way overkill to give the DFA treatment. + *

+ * This class handles the following scenarios: + *

    + *
  • a + *
  • a? + *
  • a* + *
  • a+ + *
  • a,b + *
  • a|b + *
+ *

+ * These all involve a unary operation with one element type, or a binary + * operation with two elements. These are very simple and can be checked + * in a simple way without a DFA and without the overhead of setting up a + * DFA for such a simple check. + * + * @xerces.internal + * + * @version $Id$ + */ +public class SimpleContentModel + implements ContentModelValidator { + + // + // Constants + // + + /** CHOICE */ + public static final short CHOICE = -1; + + /** SEQUENCE */ + public static final short SEQUENCE = -1; + + // + // Data + // + + + /** + * The element decl pool indices of the first (and optional second) + * child node. The operation code tells us whether the second child + * is used or not. + */ + private final QName fFirstChild = new QName(); + + /** + * The element decl pool indices of the first (and optional second) + * child node. The operation code tells us whether the second child + * is used or not. + */ + private final QName fSecondChild = new QName(); + + /** + * The operation that this object represents. Since this class only + * does simple contents, there is only ever a single operation + * involved (i.e. the children of the operation are always one or + * two leafs.) This is one of the XMLDTDParams.CONTENTSPECNODE_XXX values. + */ + private final int fOperator; + + /* this is the EquivClassComparator object */ + //private EquivClassComparator comparator = null; + + + // + // Constructors + // + + /** + * Constructs a simple content model. + * + * @param operator The content model operator. + * @param firstChild qualified name of the first child + * @param secondChild qualified name of the second child + * + */ + public SimpleContentModel(short operator, QName firstChild, QName secondChild) { + // + // Store away the children and operation. This is all we need to + // do the content model check. + // + // The operation is one of the ContentSpecNode.NODE_XXX values! + // + fFirstChild.setValues(firstChild); + if (secondChild != null) { + fSecondChild.setValues(secondChild); + } + else { + fSecondChild.clear(); + } + fOperator = operator; + } + + // + // ContentModelValidator methods + // + + /** + * Check that the specified content is valid according to this + * content model. This method can also be called to do 'what if' + * testing of content models just to see if they would be valid. + *

+ * A value of -1 in the children array indicates a PCDATA node. All other + * indexes will be positive and represent child elements. The count can be + * zero, since some elements have the EMPTY content model and that must be + * confirmed. + * + * @param children The children of this element. Each integer is an index within + * the StringPool of the child element name. An index + * of -1 is used to indicate an occurrence of non-whitespace character + * data. + * @param offset Offset into the array where the children starts. + * @param length The number of entries in the children array. + * + * @return The value -1 if fully valid, else the 0 based index of the child + * that first failed. If the value returned is equal to the number + * of children, then the specified children are valid but additional + * content is required to reach a valid ending state. + * + */ + public int validate(QName[] children, int offset, int length) { + + // + // According to the type of operation, we do the correct type of + // content check. + // + switch(fOperator) + { + case XMLContentSpec.CONTENTSPECNODE_LEAF : + // If there is not a child, then report an error at index 0 + if (length == 0) + return 0; + + // If the 0th child is not the right kind, report an error at 0 + if (children[offset].rawname != fFirstChild.rawname) { + return 0; + } + + // If more than one child, report an error at index 1 + if (length > 1) + return 1; + break; + + case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE : + // + // If there is one child, make sure its the right type. If not, + // then its an error at index 0. + // + if (length == 1) { + if (children[offset].rawname != fFirstChild.rawname) { + return 0; + } + } + + // + // If the child count is greater than one, then obviously + // bad, so report an error at index 1. + // + if (length > 1) + return 1; + break; + + case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE : + // + // If the child count is zero, that's fine. If its more than + // zero, then make sure that all children are of the element + // type that we stored. If not, report the index of the first + // failed one. + // + if (length > 0) + { + for (int index = 0; index < length; index++) { + if (children[offset + index].rawname != fFirstChild.rawname) { + return index; + } + } + } + break; + + case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE : + // + // If the child count is zero, that's an error so report + // an error at index 0. + // + if (length == 0) + return 0; + + // + // Otherwise we have to check them all to make sure that they + // are of the correct child type. If not, then report the index + // of the first one that is not. + // + for (int index = 0; index < length; index++) { + if (children[offset + index].rawname != fFirstChild.rawname) { + return index; + } + } + break; + + case XMLContentSpec.CONTENTSPECNODE_CHOICE : + // + // There must be one and only one child, so if the element count + // is zero, return an error at index 0. + // + if (length == 0) + return 0; + + // If the zeroth element isn't one of our choices, error at 0 + if ((children[offset].rawname != fFirstChild.rawname) && + (children[offset].rawname != fSecondChild.rawname)) { + return 0; + } + + // If there is more than one element, then an error at 1 + if (length > 1) + return 1; + break; + + case XMLContentSpec.CONTENTSPECNODE_SEQ : + // + // There must be two children and they must be the two values + // we stored, in the stored order. + // + if (length == 2) { + if (children[offset].rawname != fFirstChild.rawname) { + return 0; + } + if (children[offset + 1].rawname != fSecondChild.rawname) { + return 1; + } + } + else { + if (length > 2) { + return 2; + } + + return length; + } + + break; + + default : + throw new RuntimeException("ImplementationMessages.VAL_CST"); + } + + // We survived, so return success status + return -1; + } // validate + +} // class SimpleContentModel diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/DTDDVFactory.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/DTDDVFactory.java new file mode 100644 index 0000000..35e7eee --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/DTDDVFactory.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import java.util.Hashtable; + +/** + * The factory to create and return DTD types. The implementation should + * store the created datatypes in static data, so that they can be shared by + * multiple parser instance, and multiple threads. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public abstract class DTDDVFactory { + + private static final String DEFAULT_FACTORY_CLASS = "org.apache.xerces.impl.dv.dtd.DTDDVFactoryImpl"; + + /** + * Get an instance of the default DTDDVFactory implementation. + * + * @return an instance of DTDDVFactory implementation + * @exception DVFactoryException cannot create an instance of the specified + * class name or the default class name + */ + public static final DTDDVFactory getInstance() throws DVFactoryException { + return getInstance(DEFAULT_FACTORY_CLASS); + } + + /** + * Get an instance of DTDDVFactory implementation. + * + * @param factoryClass name of the implementation to load. + * @return an instance of DTDDVFactory implementation + * @exception DVFactoryException cannot create an instance of the specified + * class name or the default class name + */ + public static final DTDDVFactory getInstance(String factoryClass) throws DVFactoryException { + try { + // if the class name is not specified, use the default one + return (DTDDVFactory) + (ObjectFactory.newInstance(factoryClass, ObjectFactory.findClassLoader(), true)); + } + catch (ClassCastException e) { + throw new DVFactoryException("DTD factory class " + factoryClass + " does not extend from DTDDVFactory."); + } + } + + // can't create a new object of this class + protected DTDDVFactory() {} + + /** + * return a dtd type of the given name + * + * @param name the name of the datatype + * @return the datatype validator of the given name + */ + public abstract DatatypeValidator getBuiltInDV(String name); + + /** + * get all built-in DVs, which are stored in a hashtable keyed by the name + * + * @return a hashtable which contains all datatypes + */ + public abstract Hashtable getBuiltInTypes(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/DVFactoryException.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/DVFactoryException.java new file mode 100644 index 0000000..7a7b879 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/DVFactoryException.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +/** + * A runtime exception that's thrown if an error happens when the application + * tries to get a DV factory instance. + * + * @xerces.internal + * + * @version $Id$ + */ +public class DVFactoryException extends RuntimeException { + + /** Serialization version. */ + static final long serialVersionUID = -3738854697928682412L; + + public DVFactoryException() { + super(); + } + + public DVFactoryException(String msg) { + super(msg); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/DatatypeException.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/DatatypeException.java new file mode 100644 index 0000000..ca06e63 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/DatatypeException.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * Base class for datatype exceptions. For DTD types, the exception can be + * created from an error message. For Schema types, it needs an error code + * (as defined in Appendix C of the structure spec), plus an array of arguments, + * for error message substitution. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class DatatypeException extends Exception { + + /** Serialization version. */ + static final long serialVersionUID = 1940805832730465578L; + + // used to store error code and error substitution arguments + protected final String key; + protected final Object[] args; + + /** + * Create a new datatype exception by providing an error code and a list + * of error message substitution arguments. + * + * @param key error code + * @param args error arguments + */ + public DatatypeException(String key, Object[] args) { + super(key); + this.key = key; + this.args = args; + } + + /** + * Return the error code + * + * @return error code + */ + public String getKey() { + return key; + } + + /** + * Return the list of error arguments + * + * @return error arguments + */ + public Object[] getArgs() { + return args; + } + + /** + * Overrides this method to get the formatted&localized error message. + * + * REVISIT: the system locale is used to load the property file. + * do we want to allow the appilcation to specify a + * different locale? + */ + public String getMessage() { + ResourceBundle resourceBundle = null; + resourceBundle = ResourceBundle.getBundle("org.apache.xerces.impl.msg.XMLSchemaMessages"); + if (resourceBundle == null) + throw new MissingResourceException("Property file not found!", "org.apache.xerces.impl.msg.XMLSchemaMessages", key); + + String msg = resourceBundle.getString(key); + if (msg == null) { + msg = resourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(msg, "org.apache.xerces.impl.msg.XMLSchemaMessages", key); + } + + if (args != null) { + try { + msg = java.text.MessageFormat.format(msg, args); + } catch (Exception e) { + msg = resourceBundle.getString("FormatFailed"); + msg += " " + resourceBundle.getString(key); + } + } + + return msg; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/DatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/DatatypeValidator.java new file mode 100644 index 0000000..2357e11 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/DatatypeValidator.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + + +/** + * The interface that a DTD datatype must implement. The implementation of this + * interface must be thread-safe. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public interface DatatypeValidator { + + /** + * validate a given string against this DV + * + * @param content the string value that needs to be validated + * @param context the validation context + */ + public void validate(String content, ValidationContext context) + throws InvalidDatatypeValueException; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/InvalidDatatypeFacetException.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/InvalidDatatypeFacetException.java new file mode 100644 index 0000000..8e8ea5a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/InvalidDatatypeFacetException.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +/** + * Datatype exception for invalid facet. This exception is only used by + * schema datatypes. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class InvalidDatatypeFacetException extends DatatypeException { + + /** Serialization version. */ + static final long serialVersionUID = -4104066085909970654L; + + /** + * Create a new datatype exception by providing an error code and a list + * of error message substitution arguments. + * + * @param key error code + * @param args error arguments + */ + public InvalidDatatypeFacetException(String key, Object[] args) { + super(key, args); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/InvalidDatatypeValueException.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/InvalidDatatypeValueException.java new file mode 100644 index 0000000..65672f0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/InvalidDatatypeValueException.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +/** + * Datatype exception for invalid values. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class InvalidDatatypeValueException extends DatatypeException { + + /** Serialization version. */ + static final long serialVersionUID = -5523739426958236125L; + + /** + * Create a new datatype exception by providing an error code and a list + * of error message substitution arguments. + * + * @param key error code + * @param args error arguments + */ + public InvalidDatatypeValueException(String key, Object[] args) { + super(key, args); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/ObjectFactory.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/ObjectFactory.java new file mode 100644 index 0000000..07a6aed --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/ObjectFactory.java @@ -0,0 +1,545 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; + +/** + * This class is duplicated for each JAXP subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of the JAXP + * API. + *

+ * This code is designed to implement the JAXP 1.1 spec pluggability + * feature and is designed to run on JDK version 1.1 and + * later, and to compile on JDK 1.2 and onward. + * The code also runs both as part of an unbundled jar file and + * when bundled as part of the JDK. + *

+ * + * @xerces.internal + * + * @version $Id$ + */ +final class ObjectFactory { + + // + // Constants + // + + // name of default properties file to look for in JDK's jre/lib directory + private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties"; + + /** Set to true for debugging */ + private static final boolean DEBUG = isDebugEnabled(); + + /** + * Default columns per line. + */ + private static final int DEFAULT_LINE_LENGTH = 80; + + /** cache the contents of the xerces.properties file. + * Until an attempt has been made to read this file, this will + * be null; if the file does not exist or we encounter some other error + * during the read, this will be empty. + */ + private static Properties fXercesProperties = null; + + /*** + * Cache the time stamp of the xerces.properties file so + * that we know if it's been modified and can invalidate + * the cache when necessary. + */ + private static long fLastModified = -1; + + // + // static methods + // + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *

    + *
  1. query the system property using System.getProperty + *
  2. read META-INF/services/factoryId file + *
  3. use fallback classname + *
+ * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, String fallbackClassName) + throws ConfigurationError { + return createObject(factoryId, null, fallbackClassName); + } // createObject(String,String):Object + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *
    + *
  1. query the system property using System.getProperty + *
  2. read $java.home/lib/propertiesFilename file + *
  3. read META-INF/services/factoryId file + *
  4. use fallback classname + *
+ * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param propertiesFilename The filename in the $java.home/lib directory + * of the properties file. If none specified, + * ${java.home}/lib/xerces.properties will be used. + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, + String propertiesFilename, + String fallbackClassName) + throws ConfigurationError + { + if (DEBUG) debugPrintln("debug is on"); + + ClassLoader cl = findClassLoader(); + + // Use the system property first + try { + String systemProp = SecuritySupport.getSystemProperty(factoryId); + if (systemProp != null && systemProp.length() > 0) { + if (DEBUG) debugPrintln("found system property, value=" + systemProp); + return newInstance(systemProp, cl, true); + } + } catch (SecurityException se) { + // Ignore and continue w/ next location + } + + // Try to read from propertiesFilename, or $java.home/lib/xerces.properties + String factoryClassName = null; + // no properties file name specified; use $JAVA_HOME/lib/xerces.properties: + if (propertiesFilename == null) { + File propertiesFile = null; + boolean propertiesFileExists = false; + try { + String javah = SecuritySupport.getSystemProperty("java.home"); + propertiesFilename = javah + File.separator + + "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME; + propertiesFile = new File(propertiesFilename); + propertiesFileExists = SecuritySupport.getFileExists(propertiesFile); + } catch (SecurityException e) { + // try again... + fLastModified = -1; + fXercesProperties = null; + } + + synchronized (ObjectFactory.class) { + boolean loadProperties = false; + FileInputStream fis = null; + try { + // file existed last time + if(fLastModified >= 0) { + if(propertiesFileExists && + (fLastModified < (fLastModified = SecuritySupport.getLastModified(propertiesFile)))) { + loadProperties = true; + } else { + // file has stopped existing... + if(!propertiesFileExists) { + fLastModified = -1; + fXercesProperties = null; + } // else, file wasn't modified! + } + } else { + // file has started to exist: + if(propertiesFileExists) { + loadProperties = true; + fLastModified = SecuritySupport.getLastModified(propertiesFile); + } // else, nothing's changed + } + if(loadProperties) { + // must never have attempted to read xerces.properties before (or it's outdeated) + fXercesProperties = new Properties(); + fis = SecuritySupport.getFileInputStream(propertiesFile); + fXercesProperties.load(fis); + } + } catch (Exception x) { + fXercesProperties = null; + fLastModified = -1; + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if(fXercesProperties != null) { + factoryClassName = fXercesProperties.getProperty(factoryId); + } + } else { + FileInputStream fis = null; + try { + fis = SecuritySupport.getFileInputStream(new File(propertiesFilename)); + Properties props = new Properties(); + props.load(fis); + factoryClassName = props.getProperty(factoryId); + } catch (Exception x) { + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if (factoryClassName != null) { + if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName); + return newInstance(factoryClassName, cl, true); + } + + // Try Jar Service Provider Mechanism + Object provider = findJarServiceProvider(factoryId); + if (provider != null) { + return provider; + } + + if (fallbackClassName == null) { + throw new ConfigurationError( + "Provider for " + factoryId + " cannot be found", null); + } + + if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); + return newInstance(fallbackClassName, cl, true); + } // createObject(String,String,String):Object + + // + // Private static methods + // + + /** Returns true if debug has been enabled. */ + private static boolean isDebugEnabled() { + try { + String val = SecuritySupport.getSystemProperty("xerces.debug"); + // Allow simply setting the prop to turn on debug + return (val != null && (!"false".equals(val))); + } + catch (SecurityException se) {} + return false; + } // isDebugEnabled() + + /** Prints a message to standard error if debugging is enabled. */ + private static void debugPrintln(String msg) { + if (DEBUG) { + System.err.println("XERCES: " + msg); + } + } // debugPrintln(String) + + /** + * Figure out which ClassLoader to use. For JDK 1.2 and later use + * the context ClassLoader. + */ + static ClassLoader findClassLoader() + throws ConfigurationError + { + // Figure out which ClassLoader to use for loading the provider + // class. If there is a Context ClassLoader then use it. + ClassLoader context = SecuritySupport.getContextClassLoader(); + ClassLoader system = SecuritySupport.getSystemClassLoader(); + + ClassLoader chain = system; + while (true) { + if (context == chain) { + // Assert: we are on JDK 1.1 or we have no Context ClassLoader + // or any Context ClassLoader in chain of system classloader + // (including extension ClassLoader) so extend to widest + // ClassLoader (always look in system ClassLoader if Xerces + // is in boot/extension/system classpath and in current + // ClassLoader otherwise); normal classloaders delegate + // back to system ClassLoader first so this widening doesn't + // change the fact that context ClassLoader will be consulted + ClassLoader current = ObjectFactory.class.getClassLoader(); + + chain = system; + while (true) { + if (current == chain) { + // Assert: Current ClassLoader in chain of + // boot/extension/system ClassLoaders + return system; + } + if (chain == null) { + break; + } + chain = SecuritySupport.getParentClassLoader(chain); + } + + // Assert: Current ClassLoader not in chain of + // boot/extension/system ClassLoaders + return current; + } + + if (chain == null) { + // boot ClassLoader reached + break; + } + + // Check for any extension ClassLoaders in chain up to + // boot ClassLoader + chain = SecuritySupport.getParentClassLoader(chain); + }; + + // Assert: Context ClassLoader not in chain of + // boot/extension/system ClassLoaders + return context; + } // findClassLoader():ClassLoader + + /** + * Create an instance of a class using the specified ClassLoader + */ + static Object newInstance(String className, ClassLoader cl, + boolean doFallback) + throws ConfigurationError + { + // assert(className != null); + try{ + Class providerClass = findProviderClass(className, cl, doFallback); + Object instance = providerClass.newInstance(); + if (DEBUG) debugPrintln("created new instance of " + providerClass + + " using ClassLoader: " + cl); + return instance; + } catch (ClassNotFoundException x) { + throw new ConfigurationError( + "Provider " + className + " not found", x); + } catch (Exception x) { + throw new ConfigurationError( + "Provider " + className + " could not be instantiated: " + x, + x); + } + } + + /** + * Find a Class using the specified ClassLoader + */ + static Class findProviderClass(String className, ClassLoader cl, + boolean doFallback) + throws ClassNotFoundException, ConfigurationError + { + //throw security exception if the calling thread is not allowed to access the package + //restrict the access to package as specified in java.security policy + SecurityManager security = System.getSecurityManager(); + if (security != null) { + final int lastDot = className.lastIndexOf('.'); + String packageName = className; + if (lastDot != -1) packageName = className.substring(0, lastDot); + security.checkPackageAccess(packageName); + } + Class providerClass; + if (cl == null) { + // XXX Use the bootstrap ClassLoader. There is no way to + // load a class using the bootstrap ClassLoader that works + // in both JDK 1.1 and Java 2. However, this should still + // work b/c the following should be true: + // + // (cl == null) iff current ClassLoader == null + // + // Thus Class.forName(String) will use the current + // ClassLoader which will be the bootstrap ClassLoader. + providerClass = Class.forName(className); + } else { + try { + providerClass = cl.loadClass(className); + } catch (ClassNotFoundException x) { + if (doFallback) { + // Fall back to current classloader + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (current == null) { + providerClass = Class.forName(className); + } else if (cl != current) { + cl = current; + providerClass = cl.loadClass(className); + } else { + throw x; + } + } else { + throw x; + } + } + } + + return providerClass; + } + + /* + * Try to find provider using Jar Service Provider Mechanism + * + * @return instance of provider class if found or null + */ + private static Object findJarServiceProvider(String factoryId) + throws ConfigurationError + { + String serviceId = "META-INF/services/" + factoryId; + InputStream is = null; + + // First try the Context ClassLoader + ClassLoader cl = findClassLoader(); + + is = SecuritySupport.getResourceAsStream(cl, serviceId); + + // If no provider found then try the current ClassLoader + if (is == null) { + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (cl != current) { + cl = current; + is = SecuritySupport.getResourceAsStream(cl, serviceId); + } + } + + if (is == null) { + // No provider found + return null; + } + + if (DEBUG) debugPrintln("found jar resource=" + serviceId + + " using ClassLoader: " + cl); + + // Read the service provider name in UTF-8 as specified in + // the jar spec. Unfortunately this fails in Microsoft + // VJ++, which does not implement the UTF-8 + // encoding. Theoretically, we should simply let it fail in + // that case, since the JVM is obviously broken if it + // doesn't support such a basic standard. But since there + // are still some users attempting to use VJ++ for + // development, we have dropped in a fallback which makes a + // second attempt using the platform's default encoding. In + // VJ++ this is apparently ASCII, which is a subset of + // UTF-8... and since the strings we'll be reading here are + // also primarily limited to the 7-bit ASCII range (at + // least, in English versions), this should work well + // enough to keep us on the air until we're ready to + // officially decommit from VJ++. [Edited comment from + // jkesselm] + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); + } catch (java.io.UnsupportedEncodingException e) { + rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); + } + + String factoryClassName = null; + try { + // XXX Does not handle all possible input as specified by the + // Jar Service Provider specification + factoryClassName = rd.readLine(); + } catch (IOException x) { + // No provider found + return null; + } + finally { + try { + // try to close the reader. + rd.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + + if (factoryClassName != null && + ! "".equals(factoryClassName)) { + if (DEBUG) debugPrintln("found in resource, value=" + + factoryClassName); + + // Note: here we do not want to fall back to the current + // ClassLoader because we want to avoid the case where the + // resource file was found using one ClassLoader and the + // provider class was instantiated using a different one. + return newInstance(factoryClassName, cl, false); + } + + // No provider found + return null; + } + + // + // Classes + // + + /** + * A configuration error. + */ + static final class ConfigurationError + extends Error { + + /** Serialization version. */ + static final long serialVersionUID = 8521878292694272124L; + + // + // Data + // + + /** Exception. */ + private Exception exception; + + // + // Constructors + // + + /** + * Construct a new instance with the specified detail string and + * exception. + */ + ConfigurationError(String msg, Exception x) { + super(msg); + this.exception = x; + } // (String,Exception) + + // + // methods + // + + /** Returns the exception associated to this error. */ + Exception getException() { + return exception; + } // getException():Exception + + } // class ConfigurationError + +} // class ObjectFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/SchemaDVFactory.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/SchemaDVFactory.java new file mode 100644 index 0000000..1f43963 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/SchemaDVFactory.java @@ -0,0 +1,145 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.xs.XSObjectList; + +/** + * Defines a factory API that enables applications to

+ * 1. to get the instance of specified SchemaDVFactory implementation

+ * 2. to create/return built-in schema simple types

+ * 3. to create user defined simple types.

+ * + * Implementations of this abstract class can be used to get built-in simple + * types and create user-defined simle types.

+ * + * The implementation should store the built-in datatypes in static data, so + * that they can be shared by multiple parser instance, and multiple threads. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public abstract class SchemaDVFactory { + + private static final String DEFAULT_FACTORY_CLASS = "org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl"; + + /** + * Get a default instance of SchemaDVFactory implementation. + * + * @return an instance of SchemaDVFactory implementation + * @exception DVFactoryException cannot create an instance of the specified + * class name or the default class name + */ + public static final SchemaDVFactory getInstance() throws DVFactoryException { + return getInstance(DEFAULT_FACTORY_CLASS); + } //getInstance(): SchemaDVFactory + + + /** + * Get an instance of SchemaDVFactory implementation. + * + * @param factoryClass name of the schema factory implementation to instantiate. + * @return an instance of SchemaDVFactory implementation + * @exception DVFactoryException cannot create an instance of the specified + * class name or the default class name + */ + public static final SchemaDVFactory getInstance(String factoryClass) throws DVFactoryException { + try { + // if the class name is not specified, use the default one + return (SchemaDVFactory)(ObjectFactory.newInstance( + factoryClass, ObjectFactory.findClassLoader(), true)); + } + catch (ClassCastException e4) { + throw new DVFactoryException("Schema factory class " + factoryClass + " does not extend from SchemaDVFactory."); + } + } + + // can't create a new object of this class + protected SchemaDVFactory() {} + + /** + * Get a built-in simple type of the given name + * REVISIT: its still not decided within the Schema WG how to define the + * ur-types and if all simple types should be derived from a + * complex type, so as of now we ignore the fact that anySimpleType + * is derived from anyType, and pass 'null' as the base of + * anySimpleType. It needs to be changed as per the decision taken. + * + * @param name the name of the datatype + * @return the datatype validator of the given name + */ + public abstract XSSimpleType getBuiltInType(String name); + + /** + * get all built-in simple types, which are stored in a SymbolHash keyed by + * the name + * + * @return a SymbolHash which contains all built-in simple types + */ + public abstract SymbolHash getBuiltInTypes(); + + /** + * Create a new simple type which is derived by restriction from another + * simple type. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param base base type of the new type + * @param annotations set of annotations + * @return the newly created simple type + */ + public abstract XSSimpleType createTypeRestriction(String name, String targetNamespace, + short finalSet, XSSimpleType base, + XSObjectList annotations); + + /** + * Create a new simple type which is derived by list from another simple + * type. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param itemType item type of the list type + * @param annotations set of annotations + * @return the newly created simple type + */ + public abstract XSSimpleType createTypeList(String name, String targetNamespace, + short finalSet, XSSimpleType itemType, + XSObjectList annotations); + + /** + * Create a new simple type which is derived by union from a list of other + * simple types. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param memberTypes member types of the union type + * @param annotations set of annotations + * @return the newly created simple type + */ + public abstract XSSimpleType createTypeUnion(String name, String targetNamespace, + short finalSet, XSSimpleType[] memberTypes, + XSObjectList annotations); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/SecuritySupport.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/SecuritySupport.java new file mode 100644 index 0000000..4b98ea7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/SecuritySupport.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * This class is duplicated for each subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of any API. + * + * @xerces.internal + * + * @version $Id$ + */ +final class SecuritySupport { + + static ClassLoader getContextClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (SecurityException ex) { } + return cl; + } + }); + } + + static ClassLoader getSystemClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (SecurityException ex) {} + return cl; + } + }); + } + + static ClassLoader getParentClassLoader(final ClassLoader cl) { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader parent = null; + try { + parent = cl.getParent(); + } catch (SecurityException ex) {} + + // eliminate loops in case of the boot + // ClassLoader returning itself as a parent + return (parent == cl) ? null : parent; + } + }); + } + + static String getSystemProperty(final String propName) { + return (String) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(propName); + } + }); + } + + static FileInputStream getFileInputStream(final File file) + throws FileNotFoundException + { + try { + return (FileInputStream) + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws FileNotFoundException { + return new FileInputStream(file); + } + }); + } catch (PrivilegedActionException e) { + throw (FileNotFoundException)e.getException(); + } + } + + static InputStream getResourceAsStream(final ClassLoader cl, + final String name) + { + return (InputStream) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + InputStream ris; + if (cl == null) { + ris = ClassLoader.getSystemResourceAsStream(name); + } else { + ris = cl.getResourceAsStream(name); + } + return ris; + } + }); + } + + static boolean getFileExists(final File f) { + return ((Boolean) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return f.exists() ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + } + + static long getLastModified(final File f) { + return ((Long) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return new Long(f.lastModified()); + } + })).longValue(); + } + + private SecuritySupport () {} +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/ValidatedInfo.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/ValidatedInfo.java new file mode 100644 index 0000000..4d094ee --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/ValidatedInfo.java @@ -0,0 +1,236 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import org.apache.xerces.impl.xs.util.ShortListImpl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSValue; + +/** + * Class to get the information back after content is validated. This info + * would be filled by validate(). + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * + * @version $Id$ + */ +public class ValidatedInfo implements XSValue { + + /** + * The normalized value of a string value + */ + public String normalizedValue; + + /** + * The actual value from a string value (QName, Boolean, etc.) + * An array of Objects if the type is a list. + */ + public Object actualValue; + + /** + * The type of the actual value. It's one of the _DT constants + * defined in XSConstants.java. The value is used to indicate + * the most specific built-in type. + * (i.e. short instead of decimal or integer). + */ + public short actualValueType; + + /** + * The declared type of the value. + */ + public XSSimpleType actualType; + + /** + * If the type is a union type, then the member type which + * actually validated the string value. + */ + public XSSimpleType memberType; + + /** + * If + * 1. the type is a union type where one of the member types is a list, or + * if the type is a list; and + * 2. the item type of the list is a union type + * then an array of member types used to validate the values. + */ + public XSSimpleType[] memberTypes; + + /** + * In the case the value is a list or a list of unions, this value + * indicates the type(s) of the items in the list. + * For a normal list, the length of the array is 1; for list of unions, + * the length of the array is the same as the length of the list. + */ + public ShortList itemValueTypes; + + /** + * reset the state of this object + */ + public void reset() { + this.normalizedValue = null; + this.actualValue = null; + this.actualValueType = XSConstants.UNAVAILABLE_DT; + this.actualType = null; + this.memberType = null; + this.memberTypes = null; + this.itemValueTypes = null; + } + + /** + * Return a string representation of the value. If there is an actual + * value, use toString; otherwise, use the normalized value. + */ + public String stringValue() { + if (actualValue == null) { + return normalizedValue; + } + else { + return actualValue.toString(); + } + } + + /** + * Returns true if the two ValidatedInfo objects can be compared in the same + * value space. + */ + public static boolean isComparable(ValidatedInfo info1, ValidatedInfo info2) { + final short primitiveType1 = convertToPrimitiveKind(info1.actualValueType); + final short primitiveType2 = convertToPrimitiveKind(info2.actualValueType); + if (primitiveType1 != primitiveType2) { + return (primitiveType1 == XSConstants.ANYSIMPLETYPE_DT && primitiveType2 == XSConstants.STRING_DT || + primitiveType1 == XSConstants.STRING_DT && primitiveType2 == XSConstants.ANYSIMPLETYPE_DT); + } + else if (primitiveType1 == XSConstants.LIST_DT || primitiveType1 == XSConstants.LISTOFUNION_DT) { + final ShortList typeList1 = info1.itemValueTypes; + final ShortList typeList2 = info2.itemValueTypes; + final int typeList1Length = typeList1 != null ? typeList1.getLength() : 0; + final int typeList2Length = typeList2 != null ? typeList2.getLength() : 0; + if (typeList1Length != typeList2Length) { + return false; + } + for (int i = 0; i < typeList1Length; ++i) { + final short primitiveItem1 = convertToPrimitiveKind(typeList1.item(i)); + final short primitiveItem2 = convertToPrimitiveKind(typeList2.item(i)); + if (primitiveItem1 != primitiveItem2) { + if (primitiveItem1 == XSConstants.ANYSIMPLETYPE_DT && primitiveItem2 == XSConstants.STRING_DT || + primitiveItem1 == XSConstants.STRING_DT && primitiveItem2 == XSConstants.ANYSIMPLETYPE_DT) { + continue; + } + return false; + } + } + } + return true; + } + + /** + * Returns the primitive type of the given type. + * @param valueType A value type as defined in XSConstants. + * @return The primitive type from which valueType was derived. + */ + private static short convertToPrimitiveKind(short valueType) { + /** Primitive datatypes. */ + if (valueType <= XSConstants.NOTATION_DT) { + return valueType; + } + /** Types derived from string. */ + if (valueType <= XSConstants.ENTITY_DT) { + return XSConstants.STRING_DT; + } + /** Types derived from decimal. */ + if (valueType <= XSConstants.POSITIVEINTEGER_DT) { + return XSConstants.DECIMAL_DT; + } + /** Other types. */ + return valueType; + } + + // XSValue methods + + public Object getActualValue() { + return actualValue; + } + + public short getActualValueType() { + return actualValueType; + } + + public ShortList getListValueTypes() { + return itemValueTypes == null ? ShortListImpl.EMPTY_LIST : itemValueTypes; + } + + public XSObjectList getMemberTypeDefinitions() { + if (memberTypes == null) { + return XSObjectListImpl.EMPTY_LIST; + } + return new XSObjectListImpl(memberTypes, memberTypes.length); + } + + public String getNormalizedValue() { + return normalizedValue; + } + + public XSSimpleTypeDefinition getTypeDefinition() { + return actualType; + } + + public XSSimpleTypeDefinition getMemberTypeDefinition() { + return memberType; + } + + public void copyFrom(XSValue o) { + if (o == null) { + reset(); + } + else if (o instanceof ValidatedInfo) { + ValidatedInfo other = (ValidatedInfo)o; + normalizedValue = other.normalizedValue; + actualValue = other.actualValue; + actualValueType = other.actualValueType; + actualType = other.actualType; + memberType = other.memberType; + memberTypes = other.memberTypes; + itemValueTypes = other.itemValueTypes; + } + else { + normalizedValue = o.getNormalizedValue(); + actualValue = o.getActualValue(); + actualValueType = o.getActualValueType(); + actualType = (XSSimpleType)o.getTypeDefinition(); + memberType = (XSSimpleType)o.getMemberTypeDefinition(); + XSSimpleType realType = memberType == null ? actualType : memberType; + if (realType != null && realType.getBuiltInKind() == XSConstants.LISTOFUNION_DT) { + XSObjectList members = o.getMemberTypeDefinitions(); + memberTypes = new XSSimpleType[members.getLength()]; + for (int i = 0; i < members.getLength(); i++) { + memberTypes[i] = (XSSimpleType)members.get(i); + } + } + else { + memberTypes = null; + } + itemValueTypes = o.getListValueTypes(); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/ValidationContext.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/ValidationContext.java new file mode 100644 index 0000000..30cf41f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/ValidationContext.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import java.util.Locale; + +/** + * ValidationContext has all the information required for the + * validation of: id, idref, entity, notation, qname + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @version $Id$ + */ +public interface ValidationContext { + // whether to validate against facets + public boolean needFacetChecking(); + + // whether to do extra id/idref/entity checking + public boolean needExtraChecking(); + + // whether we need to normalize the value that is passed! + public boolean needToNormalize(); + + // are namespaces relevant in this context? + public boolean useNamespaces(); + + // entity + public boolean isEntityDeclared (String name); + public boolean isEntityUnparsed (String name); + + // id + public boolean isIdDeclared (String name); + public void addId(String name); + + // idref + public void addIdRef(String name); + + // get symbol from symbol table + public String getSymbol (String symbol); + + // qname + public String getURI(String prefix); + + // Locale + public Locale getLocale(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/XSFacets.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/XSFacets.java new file mode 100644 index 0000000..df72a83 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/XSFacets.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import java.util.Vector; + +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSObjectList; + +/** + * The class used to pass all facets to {@link XSSimpleType#applyFacets}. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class XSFacets { + + /** + * value of length facet. + */ + public int length; + + /** + * value of minLength facet. + */ + public int minLength; + + /** + * value of maxLength facet. + */ + public int maxLength; + + /** + * value of whiteSpace facet. + */ + public short whiteSpace; + + /** + * value of totalDigits facet. + */ + public int totalDigits; + + /** + * value of fractionDigits facet. + */ + public int fractionDigits; + + /** + * string containing value of pattern facet, for multiple patterns values + * are ORed together. + */ + public String pattern; + + /** + * Vector containing values of Enumeration facet, as String's. + */ + public Vector enumeration; + + /** + * An array parallel to "Vector enumeration". It contains namespace context + * of each enumeration value. Elements of this vector are NamespaceContext + * objects. + */ + public Vector enumNSDecls; + + /** + * value of maxInclusive facet. + */ + public String maxInclusive; + + /** + * value of maxExclusive facet. + */ + public String maxExclusive; + + /** + * value of minInclusive facet. + */ + public String minInclusive; + + /** + * value of minExclusive facet. + */ + public String minExclusive; + + + + public XSAnnotation lengthAnnotation; + public XSAnnotation minLengthAnnotation; + public XSAnnotation maxLengthAnnotation; + public XSAnnotation whiteSpaceAnnotation; + public XSAnnotation totalDigitsAnnotation; + public XSAnnotation fractionDigitsAnnotation; + public XSObjectListImpl patternAnnotations; + public XSObjectList enumAnnotations; + public XSAnnotation maxInclusiveAnnotation; + public XSAnnotation maxExclusiveAnnotation; + public XSAnnotation minInclusiveAnnotation; + public XSAnnotation minExclusiveAnnotation; + + public void reset(){ + lengthAnnotation = null; + minLengthAnnotation = null; + maxLengthAnnotation = null; + whiteSpaceAnnotation = null; + totalDigitsAnnotation = null; + fractionDigitsAnnotation = null; + patternAnnotations = null; + enumAnnotations = null; + maxInclusiveAnnotation = null; + maxExclusiveAnnotation = null; + minInclusiveAnnotation = null; + minExclusiveAnnotation = null; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/XSSimpleType.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/XSSimpleType.java new file mode 100644 index 0000000..fb7e74a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/XSSimpleType.java @@ -0,0 +1,201 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv; + +import org.apache.xerces.xs.XSSimpleTypeDefinition; + +/** + * This interface XSSimpleType represents the simple type + * definition of schema component and defines methods to query the information + * contained. + * Any simple type (atomic, list or union) will implement this interface. + * It inherits from XSTypeDecl. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public interface XSSimpleType extends XSSimpleTypeDefinition { + + /** + * constants defined for the values of 'whitespace' facet. + * see XML Schema + * Part 2: Datatypes + */ + /** preserve the white spaces */ + public static final short WS_PRESERVE = 0; + /** replace the white spaces */ + public static final short WS_REPLACE = 1; + /** collapse the white spaces */ + public static final short WS_COLLAPSE = 2; + + /** + * Constant defined for the primitive built-in simple tpyes. + * see + * XML Schema Part 2: Datatypes + */ + /** "string" type */ + public static final short PRIMITIVE_STRING = 1; + /** "boolean" type */ + public static final short PRIMITIVE_BOOLEAN = 2; + /** "decimal" type */ + public static final short PRIMITIVE_DECIMAL = 3; + /** "float" type */ + public static final short PRIMITIVE_FLOAT = 4; + /** "double" type */ + public static final short PRIMITIVE_DOUBLE = 5; + /** "duration" type */ + public static final short PRIMITIVE_DURATION = 6; + /** "dataTime" type */ + public static final short PRIMITIVE_DATETIME = 7; + /** "time" type */ + public static final short PRIMITIVE_TIME = 8; + /** "date" type */ + public static final short PRIMITIVE_DATE = 9; + /** "gYearMonth" type */ + public static final short PRIMITIVE_GYEARMONTH = 10; + /** "gYear" type */ + public static final short PRIMITIVE_GYEAR = 11; + /** "gMonthDay" type */ + public static final short PRIMITIVE_GMONTHDAY = 12; + /** "gDay" type */ + public static final short PRIMITIVE_GDAY = 13; + /** "gMonth" type */ + public static final short PRIMITIVE_GMONTH = 14; + /** "hexBinary" type */ + public static final short PRIMITIVE_HEXBINARY = 15; + /** "base64Binary" type */ + public static final short PRIMITIVE_BASE64BINARY = 16; + /** "anyURI" type */ + public static final short PRIMITIVE_ANYURI = 17; + /** "QName" type */ + public static final short PRIMITIVE_QNAME = 18; + /** "precisionDecimal" type */ + public static final short PRIMITIVE_PRECISIONDECIMAL = 19; + /** "NOTATION" type */ + public static final short PRIMITIVE_NOTATION = 20; + + /** + * return an ID representing the built-in primitive base type. + * REVISIT: This method is (currently) for internal use only. + * the constants returned from this method are not finalized yet. + * the names and values might change in the further. + * + * @return an ID representing the built-in primitive base type + */ + public short getPrimitiveKind(); + + /** + * validate a given string against this simple type. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @param validatedInfo used to store validation result + * + * @return the actual value (QName, Boolean) of the string value + */ + public Object validate(String content, ValidationContext context, ValidatedInfo validatedInfo) + throws InvalidDatatypeValueException; + + /** + * validate a given string value, represented by content.toString(). + * note that if content is a StringBuffer, for performance reasons, + * it's possible that the content of the string buffer is modified. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @param validatedInfo used to store validation result + * + * @return the actual value (QName, Boolean) of the string value + */ + public Object validate(Object content, ValidationContext context, ValidatedInfo validatedInfo) + throws InvalidDatatypeValueException; + + /** + * Validate an actual value against this simple type. + * + * @param context the validation context + * @param validatedInfo used to provide the actual value and member types + * @exception InvalidDatatypeValueException exception for invalid values. + */ + public void validate(ValidationContext context, ValidatedInfo validatedInfo) + throws InvalidDatatypeValueException; + + /** + * If this type is created from restriction, then some facets can be applied + * to the simple type. XSFacets is used to pass the value of + * different facets. + * + * @param facets the value of all the facets + * @param presentFacet bit combination value of the costraining facet + * constants which are present. + * @param fixedFacet bit combination value of the costraining facet + * constants which are fixed. + * @param context the validation context + * @exception InvalidDatatypeFacetException exception for invalid facet values. + */ + public void applyFacets(XSFacets facets, short presentFacet, short fixedFacet, ValidationContext context) + throws InvalidDatatypeFacetException; + + /** + * Check whether two actual values are equal. + * + * @param value1 the first value + * @param value2 the second value + * @return true if the two value are equal + */ + public boolean isEqual(Object value1, Object value2); + + /** + * Check the order of the two actual values. (May not be supported by all + * simple types. + * REVISIT: Andy believes that a compare() method is necessary. + * I don't see the necessity for schema (the only place where we + * need to compare two values is to check min/maxIn/Exclusive + * facets, but we only need a private method for this case.) + * But Andy thinks XPATH potentially needs this compare() method. + * + * @param value1 the first value + * @prarm value2 the second value + * @return > 0 if value1 > value2 + * = 0 if value1 == value2 + * < = if value1 < value2 + */ + //public short compare(Object value1, Object value2); + + /** + * Check whether this type is or is derived from ID. + * REVISIT: this method makes ID special, which is not a good design. + * but since ID is not a primitive, there doesn't seem to be a + * clean way of doing it except to define special method like this. + * + * @return whether this simple type is or is derived from ID. + */ + public boolean isIDType(); + + /** + * Return the whitespace corresponding to this datatype. + * + * @return valid values are WS_PRESERVE, WS_REPLACE, WS_COLLAPSE. + * @exception DatatypeException + * union datatypes don't have whitespace facet associated with them + */ + public short getWhitespace() throws DatatypeException; +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/DTDDVFactoryImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/DTDDVFactoryImpl.java new file mode 100644 index 0000000..efff35c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/DTDDVFactoryImpl.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import java.util.Hashtable; + +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.dv.DatatypeValidator; + +/** + * the factory to create/return built-in schema DVs and create user-defined DVs + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class DTDDVFactoryImpl extends DTDDVFactory { + + static final Hashtable fBuiltInTypes = new Hashtable(); + static { + createBuiltInTypes(); + } + + /** + * return a dtd type of the given name + * + * @param name the name of the datatype + * @return the datatype validator of the given name + */ + public DatatypeValidator getBuiltInDV(String name) { + return (DatatypeValidator)fBuiltInTypes.get(name); + } + + /** + * get all built-in DVs, which are stored in a hashtable keyed by the name + * + * @return a hashtable which contains all datatypes + */ + public Hashtable getBuiltInTypes() { + return (Hashtable)fBuiltInTypes.clone(); + } + + // create all built-in types + static void createBuiltInTypes() { + + DatatypeValidator dvTemp; + + fBuiltInTypes.put("string", new StringDatatypeValidator()); + fBuiltInTypes.put("ID", new IDDatatypeValidator()); + dvTemp = new IDREFDatatypeValidator(); + fBuiltInTypes.put("IDREF", dvTemp); + fBuiltInTypes.put("IDREFS", new ListDatatypeValidator(dvTemp)); + dvTemp = new ENTITYDatatypeValidator(); + fBuiltInTypes.put("ENTITY", new ENTITYDatatypeValidator()); + fBuiltInTypes.put("ENTITIES", new ListDatatypeValidator(dvTemp)); + fBuiltInTypes.put("NOTATION", new NOTATIONDatatypeValidator()); + dvTemp = new NMTOKENDatatypeValidator(); + fBuiltInTypes.put("NMTOKEN", dvTemp); + fBuiltInTypes.put("NMTOKENS", new ListDatatypeValidator(dvTemp)); + + }//createBuiltInTypes() + +}// DTDDVFactoryImpl + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/ENTITYDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/ENTITYDatatypeValidator.java new file mode 100644 index 0000000..ed748b5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/ENTITYDatatypeValidator.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + *

ENTITYDatatypeValidator implements the + * DatattypeValidator interface. + * This validator embodies the ENTITY attribute type + * from XML1.0 recommendation. + * The Value space of ENTITY is the set of all strings + * that match the NCName production and have been + * declared as an unparsed entity in a document + * type definition. + * The Lexical space of Entity is the set of all + * strings that match the NCName production. + * The value space of ENTITY is scoped to a specific + * instance document.

+ * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class ENTITYDatatypeValidator implements DatatypeValidator { + + // construct an ENTITY datatype validator + public ENTITYDatatypeValidator() { + } + + /** + * Checks that "content" string is valid ID value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + + if (!context.isEntityUnparsed(content)) + throw new InvalidDatatypeValueException("ENTITYNotUnparsed", new Object[]{content}); + + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/IDDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/IDDatatypeValidator.java new file mode 100644 index 0000000..7057fd5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/IDDatatypeValidator.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XMLChar; + +/** + *

IDDatatypeValidator - ID represents the ID attribute + * type from XML 1.0 Recommendation. The value space + * od ID is the set of all strings that match the + * NCName production and have been used in an XML + * document. The lexical space of ID is the set of all + * strings that match the NCName production.

+ *

The value space of ID is scoped to a specific + * instance document.

+ *

The following constraint applies: + * An ID must not appear more than once in an XML + * document as a value of this type; i.e., ID values + * must uniquely identify the elements which bear + * them.

+ * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class IDDatatypeValidator implements DatatypeValidator { + + // construct an ID datatype validator + public IDDatatypeValidator() { + } + + /** + * Checks that "content" string is valid ID value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + + //Check if is valid key-[81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + if(context.useNamespaces()) { + if (!XMLChar.isValidNCName(content)) { + throw new InvalidDatatypeValueException("IDInvalidWithNamespaces", new Object[]{content}); + } + } + else { + if (!XMLChar.isValidName(content)) { + throw new InvalidDatatypeValueException("IDInvalid", new Object[]{content}); + } + } + + if (context.isIdDeclared(content)) { + throw new InvalidDatatypeValueException("IDNotUnique", new Object[]{content}); + } + + context.addId(content); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/IDREFDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/IDREFDatatypeValidator.java new file mode 100644 index 0000000..fa6685a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/IDREFDatatypeValidator.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XMLChar; + +/** + *

IDREFDatatypeValidator - represents the IDREFS + * attribute type from XML 1.0 recommendation. The + * Value Space of IDREF is the set of all strings + * that match the NCName production and have been + * used in an XML Document as the value of an element + * or attribute of Type ID. The Lexical space of + * IDREF is the set of strings that match the NCName + * production.

+ *

The Value space of IDREF is scoped to a specific + * instance document

+ * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class IDREFDatatypeValidator implements DatatypeValidator { + + // construct an IDREF datatype validator + public IDREFDatatypeValidator() { + } + + /** + * Checks that "content" string is valid IDREF value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + + //Check if is valid key-[81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + if(context.useNamespaces()) { + if (!XMLChar.isValidNCName(content)) { + throw new InvalidDatatypeValueException("IDREFInvalidWithNamespaces", new Object[]{content}); + } + } + else { + if (!XMLChar.isValidName(content)) { + throw new InvalidDatatypeValueException("IDREFInvalid", new Object[]{content}); + } + } + + context.addIdRef(content); + + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/ListDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/ListDatatypeValidator.java new file mode 100644 index 0000000..a7a1988 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/ListDatatypeValidator.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import java.util.StringTokenizer; + +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * For list types: ENTITIES, IDREFS, NMTOKENS. + * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class ListDatatypeValidator implements DatatypeValidator { + + // the type of items in the list + final DatatypeValidator fItemValidator; + + // construct a list datatype validator + public ListDatatypeValidator(DatatypeValidator itemDV) { + fItemValidator = itemDV; + } + + /** + * Checks that "content" string is valid. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + + StringTokenizer parsedList = new StringTokenizer(content," "); + int numberOfTokens = parsedList.countTokens(); + if (numberOfTokens == 0) { + throw new InvalidDatatypeValueException("EmptyList", null); + } + //Check each token in list against base type + while (parsedList.hasMoreTokens()) { + this.fItemValidator.validate(parsedList.nextToken(), context); + } + } + +} + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/NMTOKENDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/NMTOKENDatatypeValidator.java new file mode 100644 index 0000000..3b9cb3e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/NMTOKENDatatypeValidator.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XMLChar; + +/** + * NMTOKEN datatype validator. + * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class NMTOKENDatatypeValidator implements DatatypeValidator { + + // construct a NMTOKEN datatype validator + public NMTOKENDatatypeValidator() { + } + + /** + * Checks that "content" string is valid NMTOKEN value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + if (!XMLChar.isValidNmtoken(content)) { + throw new InvalidDatatypeValueException("NMTOKENInvalid", new Object[]{content}); + } + } + +} // class NMTOKENDatatypeValidator diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/NOTATIONDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/NOTATIONDatatypeValidator.java new file mode 100644 index 0000000..e5b0c8a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/NOTATIONDatatypeValidator.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * NOTATIONValidator defines the interface that data type validators must obey. + * These validators can be supplied by the application writer and may be useful as + * standalone code as well as plugins to the validator architecture. + * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * + * @version $Id$ + */ + public class NOTATIONDatatypeValidator implements DatatypeValidator { + + // construct a NOTATION datatype validator + public NOTATIONDatatypeValidator() { + } + + /** + * Checks that "content" string is valid NOTATION value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/StringDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/StringDatatypeValidator.java new file mode 100644 index 0000000..58bf330 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/StringDatatypeValidator.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.DatatypeValidator; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + *

StringValidator validates that XML content is a W3C string type.

+ *

The string datatype represents character strings in XML. The + * value space of string is the set of finite-length sequences + * of characters (as defined in [XML 1.0 Recommendation + * (Second Edition)]) that match the Char production + * from [XML 1.0 Recommendation (Second Edition)]. + * A character is an atomic unit of communication; it + * is not further specified except to note that every + * character has a corresponding Universal Code Set + * code point ([ISO 10646],[Unicode] and [Unicode3]), + * which is an integer.

+ * + * @xerces.internal + * + * @version $Id$ + */ +public class StringDatatypeValidator implements DatatypeValidator { + + // construct a string datatype validator + public StringDatatypeValidator() { + } + + /** + * Checks that "content" string is valid string value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11DTDDVFactoryImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11DTDDVFactoryImpl.java new file mode 100644 index 0000000..f1d4d1e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11DTDDVFactoryImpl.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +import org.apache.xerces.impl.dv.DatatypeValidator; + +/** + * the factory to create/return built-in XML 1.1 DVs and create user-defined DVs + * + * @xerces.internal + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XML11DTDDVFactoryImpl extends DTDDVFactoryImpl { + + static final Hashtable fXML11BuiltInTypes = new Hashtable(); + + /** + * return a dtd type of the given name + * This will call the super class if and only if it does not + * recognize the passed-in name. + * + * @param name the name of the datatype + * @return the datatype validator of the given name + */ + public DatatypeValidator getBuiltInDV(String name) { + if(fXML11BuiltInTypes.get(name) != null) { + return (DatatypeValidator)fXML11BuiltInTypes.get(name); + } + return (DatatypeValidator)fBuiltInTypes.get(name); + } + + /** + * get all built-in DVs, which are stored in a hashtable keyed by the name + * New XML 1.1 datatypes are inserted. + * + * @return a hashtable which contains all datatypes + */ + public Hashtable getBuiltInTypes() { + Hashtable toReturn = (Hashtable)fBuiltInTypes.clone(); + Iterator entries = fXML11BuiltInTypes.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + Object key = entry.getKey(); + Object dv = entry.getValue(); + toReturn.put(key, dv); + } + return toReturn; + } + + static { + fXML11BuiltInTypes.put("XML11ID", new XML11IDDatatypeValidator()); + DatatypeValidator dvTemp = new XML11IDREFDatatypeValidator(); + fXML11BuiltInTypes.put("XML11IDREF", dvTemp); + fXML11BuiltInTypes.put("XML11IDREFS", new ListDatatypeValidator(dvTemp)); + dvTemp = new XML11NMTOKENDatatypeValidator(); + fXML11BuiltInTypes.put("XML11NMTOKEN", dvTemp); + fXML11BuiltInTypes.put("XML11NMTOKENS", new ListDatatypeValidator(dvTemp)); + } // + + +}//XML11DTDDVFactoryImpl + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11IDDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11IDDatatypeValidator.java new file mode 100644 index 0000000..9a28664 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11IDDatatypeValidator.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XML11Char; + +/** + *

IDDatatypeValidator - ID represents the ID attribute + * type from XML 1.1 Recommendation. The value space + * of ID is the set of all strings that match the + * NCName production and have been used in an XML + * document. The lexical space of ID is the set of all + * strings that match the NCName production.

+ *

The value space of ID is scoped to a specific + * instance document.

+ *

The following constraint applies: + * An ID must not appear more than once in an XML + * document as a value of this type; i.e., ID values + * must uniquely identify the elements which bear + * them.

+ * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XML11IDDatatypeValidator extends IDDatatypeValidator { + + // construct an ID datatype validator + public XML11IDDatatypeValidator() { + super(); + } + + /** + * Checks that "content" string is valid ID value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + + //Check if is valid key-[81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + if(context.useNamespaces()) { + if (!XML11Char.isXML11ValidNCName(content)) { + throw new InvalidDatatypeValueException("IDInvalidWithNamespaces", new Object[]{content}); + } + } + else { + if (!XML11Char.isXML11ValidName(content)) { + throw new InvalidDatatypeValueException("IDInvalid", new Object[]{content}); + } + } + + if (context.isIdDeclared(content)) { + throw new InvalidDatatypeValueException("IDNotUnique", new Object[]{content}); + } + + context.addId(content); + } + +} + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11IDREFDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11IDREFDatatypeValidator.java new file mode 100644 index 0000000..41000c5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11IDREFDatatypeValidator.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XML11Char; + +/** + *

IDREFDatatypeValidator - represents the IDREFS + * attribute type from XML 1.1 recommendation. The + * Value Space of IDREF is the set of all strings + * that match the NCName production and have been + * used in an XML Document as the value of an element + * or attribute of Type ID. The Lexical space of + * IDREF is the set of strings that match the NCName + * production.

+ *

The Value space of IDREF is scoped to a specific + * instance document

+ * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XML11IDREFDatatypeValidator extends IDREFDatatypeValidator { + + // construct an IDREF datatype validator + public XML11IDREFDatatypeValidator() { + super(); + } + + /** + * Checks that "content" string is valid IDREF value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + + //Check if is valid key-[81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + if(context.useNamespaces()) { + if (!XML11Char.isXML11ValidNCName(content)) { + throw new InvalidDatatypeValueException("IDREFInvalidWithNamespaces", new Object[]{content}); + } + } + else { + if (!XML11Char.isXML11ValidName(content)) { + throw new InvalidDatatypeValueException("IDREFInvalid", new Object[]{content}); + } + } + + context.addIdRef(content); + + } + +} + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11NMTOKENDatatypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11NMTOKENDatatypeValidator.java new file mode 100644 index 0000000..3d226d9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/dtd/XML11NMTOKENDatatypeValidator.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.dtd; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XML11Char; + +/** + * NMTOKEN datatype validator for NMTokens from XML 1.1. + * + * @xerces.internal + * + * @author Jeffrey Rodriguez, IBM + * @author Sandy Gao, IBM + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XML11NMTOKENDatatypeValidator extends NMTOKENDatatypeValidator { + + // construct a NMTOKEN datatype validator + public XML11NMTOKENDatatypeValidator() { + super(); + } + + /** + * Checks that "content" string is valid NMTOKEN value. + * If invalid a Datatype validation exception is thrown. + * + * @param content the string value that needs to be validated + * @param context the validation context + * @throws InvalidDatatypeException if the content is + * invalid according to the rules for the validators + * @see InvalidDatatypeValueException + */ + public void validate(String content, ValidationContext context) throws InvalidDatatypeValueException { + if (!XML11Char.isXML11ValidNmtoken(content)) { + throw new InvalidDatatypeValueException("NMTOKENInvalid", new Object[]{content}); + } + } + +} // class XML11NMTOKENDatatypeValidator + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/Base64.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/Base64.java new file mode 100644 index 0000000..61c6f8f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/Base64.java @@ -0,0 +1,305 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.util; + +/** + * This class provides encode/decode for RFC 2045 Base64 as + * defined by RFC 2045, N. Freed and N. Borenstein. + * RFC 2045: Multipurpose Internet Mail Extensions (MIME) + * Part One: Format of Internet Message Bodies. Reference + * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt + * This class is used by XML Schema binary format validation + * + * This implementation does not encode/decode streaming + * data. You need the data that you will encode/decode + * already on a byte arrray. + * + * @xerces.internal + * + * @author Jeffrey Rodriguez + * @author Sandy Gao + * @version $Id$ + */ +public final class Base64 { + + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int SIXBIT = 6; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static private final boolean fDebug = false; + static final private byte [] base64Alphabet = new byte[BASELENGTH]; + static final private char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static { + + for (int i = 0; i < BASELENGTH; ++i) { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) { + base64Alphabet[i] = (byte) (i-'A'); + } + for (int i = 'z'; i>= 'a'; i--) { + base64Alphabet[i] = (byte) ( i-'a' + 26); + } + + for (int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i-'0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i<=25; i++) + lookUpBase64Alphabet[i] = (char)('A'+i); + + for (int i = 26, j = 0; i<=51; i++, j++) + lookUpBase64Alphabet[i] = (char)('a'+ j); + + for (int i = 52, j = 0; i<=61; i++, j++) + lookUpBase64Alphabet[i] = (char)('0' + j); + lookUpBase64Alphabet[62] = (char)'+'; + lookUpBase64Alphabet[63] = (char)'/'; + + } + + protected static boolean isWhiteSpace(char octect) { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + protected static boolean isPad(char octect) { + return (octect == PAD); + } + + protected static boolean isData(char octect) { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + protected static boolean isBase64(char octect) { + return (isWhiteSpace(octect) || isPad(octect) || isData(octect)); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static String encode(byte[] binaryData) { + + if (binaryData == null) + return null; + + int lengthDataBits = binaryData.length*EIGHTBIT; + if (lengthDataBits == 0) { + return ""; + } + + int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets; + char encodedData[] = null; + + encodedData = new char[numberQuartet*4]; + + byte k=0, l=0, b1=0,b2=0,b3=0; + + int encodedIndex = 0; + int dataIndex = 0; + if (fDebug) { + System.out.println("number of triplets = " + numberTriplets ); + } + + for (int i=0; i>4 ) ; + decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + decodedData[encodedIndex++] = (byte)( b3<<6 | b4 ); + } + + if (!isData( (d1 = base64Data[dataIndex++]) ) || + !isData( (d2 = base64Data[dataIndex++]) )) { + return null;//if found "no data" just return null + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + if (!isData( (d3 ) ) || + !isData( (d4 ) )) {//Check if they are PAD characters + if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad] + if ((b2 & 0xf) != 0)//last 4 bits should be zero + return null; + byte[] tmp = new byte[ i*3 + 1 ]; + System.arraycopy( decodedData, 0, tmp, 0, i*3 ); + tmp[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ; + return tmp; + } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad] + b3 = base64Alphabet[ d3 ]; + if ((b3 & 0x3 ) != 0)//last 2 bits should be zero + return null; + byte[] tmp = new byte[ i*3 + 2 ]; + System.arraycopy( decodedData, 0, tmp, 0, i*3 ); + tmp[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ); + tmp[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + return tmp; + } else { + return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data + } + } else { //No PAD e.g 3cQl + b3 = base64Alphabet[ d3 ]; + b4 = base64Alphabet[ d4 ]; + decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ; + decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ); + decodedData[encodedIndex++] = (byte)( b3<<6 | b4 ); + + } + + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * @return the new length + */ + protected static int removeWhiteSpace(char[] data) { + if (data == null) + return 0; + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0; i < len; i++) { + if (!isWhiteSpace(data[i])) + data[newSize++] = data[i]; + } + return newSize; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/ByteListImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/ByteListImpl.java new file mode 100644 index 0000000..f714d7f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/ByteListImpl.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.util; + +import java.util.AbstractList; + +import org.apache.xerces.xs.XSException; +import org.apache.xerces.xs.datatypes.ByteList; + +/** + * Implementation of org.apache.xerces.xs.datatypes.ByteList. + * + * @xerces.internal + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +public class ByteListImpl extends AbstractList implements ByteList { + + // actually data stored in a byte array + protected final byte[] data; + + // canonical representation of the data + protected String canonical; + + public ByteListImpl(byte[] data) { + this.data = data; + } + + /** + * The number of bytes in the list. The range of + * valid child object indices is 0 to length-1 inclusive. + */ + public int getLength() { + return data.length; + } + + /** + * Checks if the byte item is a + * member of this list. + * @param item byte whose presence in this list + * is to be tested. + * @return True if this list contains the byte + * item. + */ + public boolean contains(byte item) { + for (int i = 0; i < data.length; ++i) { + if (data[i] == item) { + return true; + } + } + return false; + } + + /** + * Returns the indexth item in the collection. The index + * starts at 0. + * @param index index into the collection. + * @return The byte at the indexth + * position in the ByteList. + * @exception XSException + * INDEX_SIZE_ERR: if index is greater than or equal to the + * number of objects in the list. + */ + public byte item(int index) + throws XSException { + + if(index < 0 || index > data.length - 1) { + throw new XSException(XSException.INDEX_SIZE_ERR, null); + } + return data[index]; + } + + /* + * List methods + */ + + public Object get(int index) { + if (index >= 0 && index < data.length) { + return new Byte(data[index]); + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + + public byte[] toByteArray() { + byte[] ret = new byte[data.length]; + System.arraycopy(data, 0, ret, 0, data.length); + return ret; + } +} + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/HexBin.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/HexBin.java new file mode 100644 index 0000000..11b5f8d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/util/HexBin.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.util; + +/** + * format validation + * + * This class encodes/decodes hexadecimal data + * + * @xerces.internal + * + * @author Jeffrey Rodriguez + * @version $Id$ + */ +public final class HexBin { + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 16; + static final private byte [] hexNumberTable = new byte[BASELENGTH]; + static final private char [] lookUpHexAlphabet = new char[LOOKUPLENGTH]; + + + static { + for (int i = 0; i < BASELENGTH; i++ ) { + hexNumberTable[i] = -1; + } + for ( int i = '9'; i >= '0'; i--) { + hexNumberTable[i] = (byte) (i-'0'); + } + for ( int i = 'F'; i>= 'A'; i--) { + hexNumberTable[i] = (byte) ( i-'A' + 10 ); + } + for ( int i = 'f'; i>= 'a'; i--) { + hexNumberTable[i] = (byte) ( i-'a' + 10 ); + } + + for(int i = 0; i<10; i++ ) { + lookUpHexAlphabet[i] = (char)('0'+i); + } + for(int i = 10; i<=15; i++ ) { + lookUpHexAlphabet[i] = (char)('A'+i -10); + } + } + + /** + * Encode a byte array to hex string + * + * @param binaryData array of byte to encode + * @return return encoded string + */ + static public String encode(byte[] binaryData) { + if (binaryData == null) + return null; + int lengthData = binaryData.length; + int lengthEncode = lengthData * 2; + char[] encodedData = new char[lengthEncode]; + int temp; + for (int i = 0; i < lengthData; i++) { + temp = binaryData[i]; + if (temp < 0) + temp += 256; + encodedData[i*2] = lookUpHexAlphabet[temp >> 4]; + encodedData[i*2+1] = lookUpHexAlphabet[temp & 0xf]; + } + return new String(encodedData); + } + + /** + * Decode hex string to a byte array + * + * @param encoded encoded string + * @return return array of byte to encode + */ + static public byte[] decode(String encoded) { + if (encoded == null) + return null; + int lengthData = encoded.length(); + if (lengthData % 2 != 0) + return null; + + char[] binaryData = encoded.toCharArray(); + int lengthDecode = lengthData / 2; + byte[] decodedData = new byte[lengthDecode]; + byte temp1, temp2; + char tempChar; + for( int i = 0; i=(date2 with time zone +14) + // + cloneDate(date2, tempDate); //clones date1 value to global temporary storage: tempDate + tempDate.timezoneHr = -14; + tempDate.timezoneMin = 0; + tempDate.utc='-'; + normalize(tempDate); + c2 = compareOrder(date1, tempDate); + if (c2 == GREATER_THAN) + return c2; + + return INDETERMINATE; + } + else if ( date2.utc=='Z' ) { + + //compare (date1 with time zone -14)<=date2 + // + cloneDate(date1, tempDate); //clones date1 value to global temporary storage: tempDate + tempDate.timezoneHr = -14; + tempDate.timezoneMin = 0; + tempDate.utc='-'; + if (DEBUG) { + System.out.println("tempDate=" + dateToString(tempDate)); + } + normalize(tempDate); + c1 = compareOrder(tempDate, date2); + if (DEBUG) { + System.out.println("date=" + dateToString(date2)); + System.out.println("tempDate=" + dateToString(tempDate)); + } + if (c1 == LESS_THAN) + return c1; + + //compare (date1 with time zone +14)<=date2 + // + cloneDate(date1, tempDate); //clones date1 value to global temporary storage: tempDate + tempDate.timezoneHr = 14; + tempDate.timezoneMin = 0; + tempDate.utc='+'; + normalize(tempDate); + c2 = compareOrder(tempDate, date2); + if (DEBUG) { + System.out.println("tempDate=" + dateToString(tempDate)); + } + if (c2 == GREATER_THAN) + return c2; + + return INDETERMINATE; + } + return INDETERMINATE; + + } + + /** + * Given normalized values, determines order-relation + * between give date/time objects. + * + * @param date1 date/time object + * @param date2 date/time object + * @return 0 if date1 and date2 are equal, a value less than 0 if date1 is less than date2, a value greater than 0 if date1 is greater than date2 + */ + protected short compareOrder(DateTimeData date1, DateTimeData date2) { + if(date1.position < 1) { + if (date1.year < date2.year) + return -1; + if (date1.year > date2.year) + return 1; + } + if(date1.position < 2) { + if (date1.month < date2.month) + return -1; + if (date1.month > date2.month) + return 1; + } + if (date1.day < date2.day) + return -1; + if (date1.day > date2.day) + return 1; + if (date1.hour < date2.hour) + return -1; + if (date1.hour > date2.hour) + return 1; + if (date1.minute < date2.minute) + return -1; + if (date1.minute > date2.minute) + return 1; + if (date1.second < date2.second) + return -1; + if (date1.second > date2.second) + return 1; + if (date1.utc < date2.utc) + return -1; + if (date1.utc > date2.utc) + return 1; + return 0; + } + + /** + * Parses time hh:mm:ss.sss and time zone if any + * + * @param start + * @param end + * @param data + * @exception RuntimeException + */ + protected void getTime (String buffer, int start, int end, DateTimeData data) throws RuntimeException{ + + int stop = start+2; + + //get hours (hh) + data.hour=parseInt(buffer, start,stop); + + //get minutes (mm) + + if (buffer.charAt(stop++)!=':') { + throw new RuntimeException("Error in parsing time zone" ); + } + start = stop; + stop = stop+2; + data.minute=parseInt(buffer, start,stop); + + //get seconds (ss) + if (buffer.charAt(stop++)!=':') { + throw new RuntimeException("Error in parsing time zone" ); + } + + //find UTC sign if any + int sign = findUTCSign(buffer, start, end); + + //get seconds (ms) + start = stop; + stop = sign < 0 ? end : sign; + data.second = parseSecond(buffer, start, stop); + + //parse UTC time zone (hh:mm) + if (sign > 0) { + getTimeZone(buffer, data, sign, end); + } + } + + /** + * Parses date CCYY-MM-DD + * + * @param buffer + * @param start start position + * @param end end position + * @param date + * @exception RuntimeException + */ + protected int getDate (String buffer, int start, int end, DateTimeData date) throws RuntimeException{ + + start = getYearMonth(buffer, start, end, date); + + if (buffer.charAt(start++) !='-') { + throw new RuntimeException("CCYY-MM must be followed by '-' sign"); + } + int stop = start + 2; + date.day=parseInt(buffer, start, stop); + return stop; + } + + /** + * Parses date CCYY-MM + * + * @param buffer + * @param start start position + * @param end end position + * @param date + * @exception RuntimeException + */ + protected int getYearMonth (String buffer, int start, int end, DateTimeData date) throws RuntimeException{ + + if ( buffer.charAt(0)=='-' ) { + // REVISIT: date starts with preceding '-' sign + // do we have to do anything with it? + // + start++; + } + int i = indexOf(buffer, start, end, '-'); + if ( i==-1 ) throw new RuntimeException("Year separator is missing or misplaced"); + int length = i-start; + if (length<4) { + throw new RuntimeException("Year must have 'CCYY' format"); + } + else if (length > 4 && buffer.charAt(start)=='0'){ + throw new RuntimeException("Leading zeros are required if the year value would otherwise have fewer than four digits; otherwise they are forbidden"); + } + date.year= parseIntYear(buffer, i); + if (buffer.charAt(i)!='-') { + throw new RuntimeException("CCYY must be followed by '-' sign"); + } + start = ++i; + i = start +2; + date.month=parseInt(buffer, start, i); + return i; //fStart points right after the MONTH + } + + /** + * Shared code from Date and YearMonth datatypes. + * Finds if time zone sign is present + * + * @param end + * @param date + * @exception RuntimeException + */ + protected void parseTimeZone (String buffer, int start, int end, DateTimeData date) throws RuntimeException{ + + //fStart points right after the date + + if ( start < end ) { + if (!isNextCharUTCSign(buffer, start, end)) { + throw new RuntimeException ("Error in month parsing"); + } + else { + getTimeZone(buffer, date, start, end); + } + } + } + + /** + * Parses time zone: 'Z' or {+,-} followed by hh:mm + * + * @param data + * @param sign + * @exception RuntimeException + */ + protected void getTimeZone (String buffer, DateTimeData data, int sign, int end) throws RuntimeException{ + data.utc=buffer.charAt(sign); + + if ( buffer.charAt(sign) == 'Z' ) { + if (end>(++sign)) { + throw new RuntimeException("Error in parsing time zone"); + } + return; + } + if ( sign<=(end-6) ) { + + int negate = buffer.charAt(sign) == '-'?-1:1; + //parse hr + int stop = ++sign+2; + data.timezoneHr = negate*parseInt(buffer, sign, stop); + if (buffer.charAt(stop++)!=':') { + throw new RuntimeException("Error in parsing time zone" ); + } + + //parse min + data.timezoneMin = negate*parseInt(buffer, stop, stop+2); + + if ( stop+2!=end ) { + throw new RuntimeException("Error in parsing time zone"); + } + if(data.timezoneHr != 0 || data.timezoneMin != 0) + data.normalized = false; + } + else { + throw new RuntimeException("Error in parsing time zone"); + } + if ( DEBUG ) { + System.out.println("time[hh]="+data.timezoneHr + " time[mm]=" +data.timezoneMin); + } + } + + /** + * Computes index of given char within StringBuffer + * + * @param start + * @param end + * @param ch character to look for in StringBuffer + * @return index of ch within StringBuffer + */ + protected int indexOf (String buffer, int start, int end, char ch) { + for ( int i=start;i12 ) { + throw new RuntimeException("The month must have values 1 to 12"); + + } + + //validate days + if ( data.day>maxDayInMonthFor(data.year, data.month) || data.day<1 ) { + throw new RuntimeException("The day must have values 1 to 31"); + } + + //validate hours + if ( data.hour>23 || data.hour<0 ) { + if (data.hour == 24 && data.minute == 0 && data.second == 0) { + data.hour = 0; + if (++data.day > maxDayInMonthFor(data.year, data.month)) { + data.day = 1; + if (++data.month > 12) { + data.month = 1; + if (Constants.SCHEMA_1_1_SUPPORT) { + ++data.year; + } + else if (++data.year == 0) { + data.year = 1; + } + } + } + } + else { + throw new RuntimeException("Hour must have values 0-23, unless 24:00:00"); + } + } + + //validate + if ( data.minute>59 || data.minute<0 ) { + throw new RuntimeException("Minute must have values 0-59"); + } + + //validate + if ( data.second>=60 || data.second<0 ) { + throw new RuntimeException("Second must have values 0-59"); + + } + + //validate + if ( data.timezoneHr>14 || data.timezoneHr<-14 ) { + throw new RuntimeException("Time zone should have range -14:00 to +14:00"); + } + else { + if((data.timezoneHr == 14 || data.timezoneHr == -14) && data.timezoneMin != 0) + throw new RuntimeException("Time zone should have range -14:00 to +14:00"); + else if(data.timezoneMin > 59 || data.timezoneMin < -59) + throw new RuntimeException("Minute must have values 0-59"); + } + + } + + /** + * Return index of UTC char: 'Z', '+', '-' + * + * @param start + * @param end + * @return index of the UTC character that was found + */ + protected int findUTCSign (String buffer, int start, int end) { + int c; + for ( int i=start;itrue if the character at start is 'Z', '+' or '-'. + */ + protected final boolean isNextCharUTCSign(String buffer, int start, int end) { + if (start < end) { + char c = buffer.charAt(start); + return (c == 'Z' || c == '+' || c == '-'); + } + return false; + } + + /** + * Given start and end position, parses string value + * + * @param buffer string to parse + * @param start start position + * @param end end position + * @return return integer representation of characters + */ + protected int parseInt (String buffer, int start, int end) + throws NumberFormatException{ + //REVISIT: more testing on this parsing needs to be done. + int radix=10; + int result = 0; + int digit=0; + int limit = -Integer.MAX_VALUE; + int multmin = limit / radix; + int i = start; + do { + digit = getDigit(buffer.charAt(i)); + if ( digit < 0 ) throw new NumberFormatException("'" + buffer + "' has wrong format"); + if ( result < multmin ) throw new NumberFormatException("'" + buffer + "' has wrong format"); + result *= radix; + if ( result < limit + digit ) throw new NumberFormatException("'" + buffer + "' has wrong format"); + result -= digit; + + }while ( ++i < end ); + return -result; + } + + // parse Year differently to support negative value. + protected int parseIntYear (String buffer, int end){ + int radix=10; + int result = 0; + boolean negative = false; + int i=0; + int limit; + int multmin; + int digit=0; + + if (buffer.charAt(0) == '-'){ + negative = true; + limit = Integer.MIN_VALUE; + i++; + + } + else{ + limit = -Integer.MAX_VALUE; + } + multmin = limit / radix; + while (i < end) + { + digit = getDigit(buffer.charAt(i++)); + if (digit < 0) throw new NumberFormatException("'" + buffer + "' has wrong format"); + if (result < multmin) throw new NumberFormatException("'" + buffer + "' has wrong format"); + result *= radix; + if (result < limit + digit) throw new NumberFormatException("'" + buffer + "' has wrong format"); + result -= digit; + } + + if (negative) + { + if (i > 1) return result; + else throw new NumberFormatException("'" + buffer + "' has wrong format"); + } + return -result; + + } + + /** + * If timezone present - normalize dateTime [E Adding durations to dateTimes] + * + * @param date CCYY-MM-DDThh:mm:ss+03 + */ + protected void normalize(DateTimeData date) { + + // REVISIT: we have common code in addDuration() for durations + // should consider reorganizing it. + // + + //add minutes (from time zone) + int negate = -1; + + if ( DEBUG ) { + System.out.println("==>date.minute"+date.minute); + System.out.println("==>date.timezoneMin" +date.timezoneMin); + } + int temp = date.minute + negate * date.timezoneMin; + int carry = fQuotient (temp, 60); + date.minute= mod(temp, 60, carry); + + if ( DEBUG ) { + System.out.println("==>carry: " + carry); + } + //add hours + temp = date.hour + negate * date.timezoneHr + carry; + carry = fQuotient(temp, 24); + date.hour=mod(temp, 24, carry); + if ( DEBUG ) { + System.out.println("==>date.hour"+date.hour); + System.out.println("==>carry: " + carry); + } + + date.day=date.day+carry; + + while ( true ) { + temp=maxDayInMonthFor(date.year, date.month); + if (date.day<1) { + date.day = date.day + maxDayInMonthFor(date.year, date.month-1); + carry=-1; + } + else if ( date.day>temp ) { + date.day=date.day-temp; + carry=1; + } + else { + break; + } + temp=date.month+carry; + date.month=modulo(temp, 1, 13); + date.year=date.year+fQuotient(temp, 1, 13); + if(date.year == 0 && !Constants.SCHEMA_1_1_SUPPORT) { + date.year = (date.timezoneHr < 0 || date.timezoneMin < 0)?1:-1; + } + } + date.utc='Z'; + } + + + /** + * @param date + */ + protected void saveUnnormalized(DateTimeData date) { + date.unNormYear = date.year; + date.unNormMonth = date.month; + date.unNormDay = date.day; + date.unNormHour = date.hour; + date.unNormMinute = date.minute; + date.unNormSecond = date.second; + } + + /** + * Resets object representation of date/time + * + * @param data date/time object + */ + protected void resetDateObj(DateTimeData data) { + data.year = 0; + data.month = 0; + data.day = 0; + data.hour = 0; + data.minute = 0; + data.second = 0; + data.utc = 0; + data.timezoneHr = 0; + data.timezoneMin = 0; + } + + /** + * Given {year,month} computes maximum + * number of days for given month + * + * @param year + * @param month + * @return integer containg the number of days in a given month + */ + protected int maxDayInMonthFor(int year, int month) { + //validate days + if ( month==4 || month==6 || month==9 || month==11 ) { + return 30; + } + else if ( month==2 ) { + if ( isLeapYear(year) ) { + return 29; + } + else { + return 28; + } + } + else { + return 31; + } + } + + private boolean isLeapYear(int year) { + + //REVISIT: should we take care about Julian calendar? + return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))); + } + + // + // help function described in W3C PR Schema [E Adding durations to dateTimes] + // + protected int mod (int a, int b, int quotient) { + //modulo(a, b) = a - fQuotient(a,b)*b + return (a - quotient*b) ; + } + + // + // help function described in W3C PR Schema [E Adding durations to dateTimes] + // + protected int fQuotient (int a, int b) { + + //fQuotient(a, b) = the greatest integer less than or equal to a/b + return (int)Math.floor((float)a/b); + } + + // + // help function described in W3C PR Schema [E Adding durations to dateTimes] + // + protected int modulo (int temp, int low, int high) { + //modulo(a - low, high - low) + low + int a = temp - low; + int b = high - low; + return (mod (a, b, fQuotient(a, b)) + low) ; + } + + // + // help function described in W3C PR Schema [E Adding durations to dateTimes] + // + protected int fQuotient (int temp, int low, int high) { + //fQuotient(a - low, high - low) + + return fQuotient(temp - low, high - low); + } + + + protected String dateToString(DateTimeData date) { + StringBuffer message = new StringBuffer(25); + append(message, date.year, 4); + message.append('-'); + append(message, date.month, 2); + message.append('-'); + append(message, date.day, 2); + message.append('T'); + append(message, date.hour, 2); + message.append(':'); + append(message, date.minute, 2); + message.append(':'); + append(message, date.second); + append(message, (char)date.utc, 0); + return message.toString(); + } + + protected final void append(StringBuffer message, int value, int nch) { + if (value == Integer.MIN_VALUE) { + message.append(value); + return; + } + if (value < 0) { + message.append('-'); + value = -value; + } + if (nch == 4) { + if (value < 10) + message.append("000"); + else if (value < 100) + message.append("00"); + else if (value < 1000) + message.append('0'); + message.append(value); + } + else if (nch == 2) { + if (value < 10) + message.append('0'); + message.append(value); + } + else { + if (value != 0) + message.append((char)value); + } + } + + protected final void append(StringBuffer message, double value) { + if (value < 0) { + message.append('-'); + value = -value; + } + if (value < 10) { + message.append('0'); + } + append2(message, value); + } + + protected final void append2(StringBuffer message, double value) { + final int intValue = (int) value; + if (value == intValue) { + message.append(intValue); + } + else { + append3(message, value); + } + } + + private void append3(StringBuffer message, double value) { + String d = String.valueOf(value); + int eIndex = d.indexOf('E'); + if (eIndex == -1) { + message.append(d); + return; + } + int exp; + if (value < 1) { + // Need to convert from scientific notation of the form + // n.nnn...E-N (N >= 4) to a normal decimal value. + try { + exp = parseInt(d, eIndex+2, d.length()); + } + // This should never happen. + // It's only possible if String.valueOf(double) is broken. + catch (Exception e) { + message.append(d); + return; + } + message.append("0."); + for (int i = 1; i < exp; ++i) { + message.append('0'); + } + // Remove trailing zeros. + int end = eIndex - 1; + while (end > 0) { + char c = d.charAt(end); + if (c != '0') { + break; + } + --end; + } + // Now append the digits to the end. Skip over the decimal point. + for (int i = 0; i <= end; ++i) { + char c = d.charAt(i); + if (c != '.') { + message.append(c); + } + } + } + else { + // Need to convert from scientific notation of the form + // n.nnn...EN (N >= 7) to a normal decimal value. + try { + exp = parseInt(d, eIndex+1, d.length()); + } + // This should never happen. + // It's only possible if String.valueOf(double) is broken. + catch (Exception e) { + message.append(d); + return; + } + final int integerEnd = exp + 2; + for (int i = 0; i < eIndex; ++i) { + char c = d.charAt(i); + if (c != '.') { + if (i == integerEnd) { + message.append('.'); + } + message.append(c); + } + } + // Append trailing zeroes if necessary. + for (int i = integerEnd - eIndex; i > 0; --i) { + message.append('0'); + } + } + } + + protected double parseSecond(String buffer, int start, int end) + throws NumberFormatException { + int dot = -1; + for (int i = start; i < end; i++) { + char ch = buffer.charAt(i); + if (ch == '.') + dot = i; + else if (ch > '9' || ch < '0') + throw new NumberFormatException("'" + buffer + "' has wrong format"); + } + if (dot == -1) { + if (start+2 != end) + throw new NumberFormatException("'" + buffer + "' has wrong format"); + } + else if (start+2 != dot || dot+1 == end) { + throw new NumberFormatException("'" + buffer + "' has wrong format"); + } + return Double.parseDouble(buffer.substring(start, end)); + } + + // + //Private help functions + // + + private void cloneDate (DateTimeData finalValue, DateTimeData tempDate) { + tempDate.year = finalValue.year; + tempDate.month = finalValue.month; + tempDate.day = finalValue.day; + tempDate.hour = finalValue.hour; + tempDate.minute = finalValue.minute; + tempDate.second = finalValue.second; + tempDate.utc = finalValue.utc; + tempDate.timezoneHr = finalValue.timezoneHr; + tempDate.timezoneMin = finalValue.timezoneMin; + } + + /** + * Represents date time data + */ + static final class DateTimeData implements XSDateTime { + int year, month, day, hour, minute, utc; + double second; + int timezoneHr, timezoneMin; + private String originalValue; + boolean normalized = true; + + int unNormYear; + int unNormMonth; + int unNormDay; + int unNormHour; + int unNormMinute; + double unNormSecond; + + // used for comparisons - to decide the 'interesting' portions of + // a date/time based data type. + int position; + // a pointer to the type that was used go generate this data + // note that this is not the actual simple type, but one of the + // statically created XXXDV objects, so this won't cause any GC problem. + final AbstractDateTimeDV type; + private String canonical; + public DateTimeData(String originalValue, AbstractDateTimeDV type) { + this.originalValue = originalValue; + this.type = type; + } + public DateTimeData(int year, int month, int day, int hour, int minute, + double second, int utc, String originalValue, boolean normalized, AbstractDateTimeDV type) { + this.year = year; + this.month = month; + this.day = day; + this.hour = hour; + this.minute = minute; + this.second = second; + this.utc = utc; + this.type = type; + this.originalValue = originalValue; + } + public boolean equals(Object obj) { + if (!(obj instanceof DateTimeData)) + return false; + return type.compareDates(this, (DateTimeData)obj, true)==0; + } + public synchronized String toString() { + if (canonical == null) { + canonical = type.dateToString(this); + } + return canonical; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getYear() + */ + public int getYears() { + if(type instanceof DurationDV) + return 0; + return normalized?year:unNormYear; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getMonth() + */ + public int getMonths() { + if(type instanceof DurationDV) { + return year*12 + month; + } + return normalized?month:unNormMonth; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getDay() + */ + public int getDays() { + if(type instanceof DurationDV) + return 0; + return normalized?day:unNormDay; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getHour() + */ + public int getHours() { + if(type instanceof DurationDV) + return 0; + return normalized?hour:unNormHour; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getMinutes() + */ + public int getMinutes() { + if(type instanceof DurationDV) + return 0; + return normalized?minute:unNormMinute; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getSeconds() + */ + public double getSeconds() { + if(type instanceof DurationDV) { + return day*24*60*60 + hour*60*60 + minute*60 + second; + } + return normalized?second:unNormSecond; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#hasTimeZone() + */ + public boolean hasTimeZone() { + return utc != 0; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getTimeZoneHours() + */ + public int getTimeZoneHours() { + return timezoneHr; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getTimeZoneMinutes() + */ + public int getTimeZoneMinutes() { + return timezoneMin; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getLexicalValue() + */ + public String getLexicalValue() { + return originalValue; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#normalize() + */ + public XSDateTime normalize() { + if(!normalized) { + DateTimeData dt = (DateTimeData)this.clone(); + dt.normalized = true; + return dt; + } + return this; + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#isNormalized() + */ + public boolean isNormalized() { + return normalized; + } + + public Object clone() { + DateTimeData dt = new DateTimeData(this.year, this.month, this.day, this.hour, + this.minute, this.second, this.utc, this.originalValue, this.normalized, this.type); + dt.canonical = this.canonical; + dt.position = position; + dt.timezoneHr = this.timezoneHr; + dt.timezoneMin = this.timezoneMin; + dt.unNormYear = this.unNormYear; + dt.unNormMonth = this.unNormMonth; + dt.unNormDay = this.unNormDay; + dt.unNormHour = this.unNormHour; + dt.unNormMinute = this.unNormMinute; + dt.unNormSecond = this.unNormSecond; + return dt; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getXMLGregorianCalendar() + */ + public XMLGregorianCalendar getXMLGregorianCalendar() { + return type.getXMLGregorianCalendar(this); + } + /* (non-Javadoc) + * @see org.apache.xerces.xs.datatypes.XSDateTime#getDuration() + */ + public Duration getDuration() { + return type.getDuration(this); + } + } + + protected XMLGregorianCalendar getXMLGregorianCalendar(DateTimeData data) { + return null; + } + + protected Duration getDuration(DateTimeData data) { + return null; + } + + protected final BigDecimal getFractionalSecondsAsBigDecimal(DateTimeData data) { + final StringBuffer buf = new StringBuffer(); + append3(buf, data.unNormSecond); + String value = buf.toString(); + final int index = value.indexOf('.'); + if (index == -1) { + return null; + } + value = value.substring(index); + final BigDecimal _val = new BigDecimal(value); + if (_val.compareTo(BigDecimal.valueOf(0)) == 0) { + return null; + } + return _val; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnyAtomicDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnyAtomicDV.java new file mode 100644 index 0000000..7e9bbeb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnyAtomicDV.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Represent the schema type "anyAtomicType" + * + * @xerces.experimental + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +class AnyAtomicDV extends TypeValidator { + + public short getAllowedFacets() { + return 0; + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + return content; + } + +} // class AnyAtomicDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnySimpleDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnySimpleDV.java new file mode 100644 index 0000000..a805db4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnySimpleDV.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Represent the schema type "anySimpleType" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class AnySimpleDV extends TypeValidator { + + public short getAllowedFacets() { + // anySimpleType doesn't allow any facet, not even whiteSpace + return 0; + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + return content; + } + +} // class AnySimpleDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnyURIDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnyURIDV.java new file mode 100644 index 0000000..31534fa --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/AnyURIDV.java @@ -0,0 +1,169 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.URI; + +/** + * Represent the schema type "anyURI" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class AnyURIDV extends TypeValidator { + + private static final URI BASE_URI; + static { + URI uri = null; + try { + uri = new URI("abc://def.ghi.jkl"); + } catch (URI.MalformedURIException ex) { + } + BASE_URI = uri; + } + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE ); + } + + // before we return string we have to make sure it is correct URI as per spec. + // for some types (string and derived), they just return the string itself + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + // check 3.2.17.c0 must: URI (rfc 2396/2723) + try { + if( content.length() != 0 ) { + // encode special characters using XLink 5.4 algorithm + final String encoded = encode(content); + // Support for relative URLs + // According to Java 1.1: URLs may also be specified with a + // String and the URL object that it is related to. + new URI(BASE_URI, encoded ); + } + } catch (URI.MalformedURIException ex) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "anyURI"}); + } + + // REVISIT: do we need to return the new URI object? + return content; + } + + // which ASCII characters need to be escaped + private static boolean gNeedEscaping[] = new boolean[128]; + // the first hex character if a character needs to be escaped + private static char gAfterEscaping1[] = new char[128]; + // the second hex character if a character needs to be escaped + private static char gAfterEscaping2[] = new char[128]; + private static char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + // initialize the above 3 arrays + static { + for (int i = 0; i <= 0x1f; i++) { + gNeedEscaping[i] = true; + gAfterEscaping1[i] = gHexChs[i >> 4]; + gAfterEscaping2[i] = gHexChs[i & 0xf]; + } + gNeedEscaping[0x7f] = true; + gAfterEscaping1[0x7f] = '7'; + gAfterEscaping2[0x7f] = 'F'; + char[] escChs = {' ', '<', '>', '"', '{', '}', + '|', '\\', '^', '~', '`'}; + int len = escChs.length; + char ch; + for (int i = 0; i < len; i++) { + ch = escChs[i]; + gNeedEscaping[ch] = true; + gAfterEscaping1[ch] = gHexChs[ch >> 4]; + gAfterEscaping2[ch] = gHexChs[ch & 0xf]; + } + } + + // To encode special characters in anyURI, by using %HH to represent + // special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', etc. + // and non-ASCII characters (whose value >= 128). + private static String encode(String anyURI){ + int len = anyURI.length(), ch; + StringBuffer buffer = new StringBuffer(len*3); + + // for each character in the anyURI + int i = 0; + for (; i < len; i++) { + ch = anyURI.charAt(i); + // if it's not an ASCII character, break here, and use UTF-8 encoding + if (ch >= 128) + break; + if (gNeedEscaping[ch]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[ch]); + buffer.append(gAfterEscaping2[ch]); + } + else { + buffer.append((char)ch); + } + } + + // we saw some non-ascii character + if (i < len) { + // get UTF-8 bytes for the remaining sub-string + byte[] bytes = null; + byte b; + try { + bytes = anyURI.substring(i).getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException e) { + // should never happen + return anyURI; + } + len = bytes.length; + + // for each byte + for (i = 0; i < len; i++) { + b = bytes[i]; + // for non-ascii character: make it positive, then escape + if (b < 0) { + ch = b + 256; + buffer.append('%'); + buffer.append(gHexChs[ch >> 4]); + buffer.append(gHexChs[ch & 0xf]); + } + else if (gNeedEscaping[b]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[b]); + buffer.append(gAfterEscaping2[b]); + } + else { + buffer.append((char)b); + } + } + } + + // If encoding happened, create a new string; + // otherwise, return the orginal one. + if (buffer.length() != len) { + return buffer.toString(); + } + else { + return anyURI; + } + } + +} // class AnyURIDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/Base64BinaryDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/Base64BinaryDV.java new file mode 100644 index 0000000..274320e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/Base64BinaryDV.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.impl.dv.util.Base64; +import org.apache.xerces.impl.dv.util.ByteListImpl; + +/** + * Represent the schema type "base64Binary" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class Base64BinaryDV extends TypeValidator { + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE ); + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + byte[] decoded = Base64.decode(content); + if (decoded == null) + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "base64Binary"}); + + return new XBase64(decoded); + } + + // length of a binary type is the number of bytes + public int getDataLength(Object value) { + return ((XBase64)value).getLength(); + } + + /** + * represent base64 data + */ + private static final class XBase64 extends ByteListImpl { + + public XBase64(byte[] data) { + super(data); + } + public synchronized String toString() { + if (canonical == null) { + canonical = Base64.encode(data); + } + return canonical; + } + + public boolean equals(Object obj) { + if (!(obj instanceof XBase64)) + return false; + byte[] odata = ((XBase64)obj).data; + int len = data.length; + if (len != odata.length) + return false; + for (int i = 0; i < len; i++) { + if (data[i] != odata[i]) + return false; + } + return true; + } + + public int hashCode() { + int hash = 0; + for (int i = 0; i < data.length; ++i) { + hash = hash * 37 + (((int) data[i]) & 0xff); + } + return hash; + } + } +} // class Base64BinaryDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BaseDVFactory.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BaseDVFactory.java new file mode 100644 index 0000000..43754c2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BaseDVFactory.java @@ -0,0 +1,247 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.SchemaDVFactory; +import org.apache.xerces.impl.dv.XSFacets; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; + +/** + * the factory to create/return built-in schema DVs and create user-defined DVs + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class BaseDVFactory extends SchemaDVFactory { + + static final String URI_SCHEMAFORSCHEMA = "http://www.w3.org/2001/XMLSchema"; + + // there are 27 types. 53 is the closest prime number to 27*2=54. + static SymbolHash fBaseTypes = new SymbolHash(53); + static { + createBuiltInTypes(fBaseTypes); + } + + /** + * Get a built-in simple type of the given name + * REVISIT: its still not decided within the Schema WG how to define the + * ur-types and if all simple types should be derived from a + * complex type, so as of now we ignore the fact that anySimpleType + * is derived from anyType, and pass 'null' as the base of + * anySimpleType. It needs to be changed as per the decision taken. + * + * @param name the name of the datatype + * @return the datatype validator of the given name + */ + public XSSimpleType getBuiltInType(String name) { + return (XSSimpleType)fBaseTypes.get(name); + } + + /** + * get all built-in simple types, which are stored in a hashtable keyed by + * the name + * + * @return a hashtable which contains all built-in simple types + */ + public SymbolHash getBuiltInTypes() { + return (SymbolHash)fBaseTypes.makeClone(); + } + + /** + * Create a new simple type which is derived by restriction from another + * simple type. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param base base type of the new type + * @param annotations set of annotations + * @return the newly created simple type + */ + public XSSimpleType createTypeRestriction(String name, String targetNamespace, + short finalSet, XSSimpleType base, XSObjectList annotations) { + return new XSSimpleTypeDecl((XSSimpleTypeDecl)base, name, targetNamespace, finalSet, false, annotations); + } + + /** + * Create a new simple type which is derived by list from another simple + * type. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param itemType item type of the list type + * @param annotations set of annotations + * @return the newly created simple type + */ + public XSSimpleType createTypeList(String name, String targetNamespace, + short finalSet, XSSimpleType itemType, + XSObjectList annotations) { + return new XSSimpleTypeDecl(name, targetNamespace, finalSet, (XSSimpleTypeDecl)itemType, false, annotations); + } + + /** + * Create a new simple type which is derived by union from a list of other + * simple types. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param memberTypes member types of the union type + * @param annotations set of annotations + * @return the newly created simple type + */ + public XSSimpleType createTypeUnion(String name, String targetNamespace, + short finalSet, XSSimpleType[] memberTypes, + XSObjectList annotations) { + int typeNum = memberTypes.length; + XSSimpleTypeDecl[] mtypes = new XSSimpleTypeDecl[typeNum]; + System.arraycopy(memberTypes, 0, mtypes, 0, typeNum); + + return new XSSimpleTypeDecl(name, targetNamespace, finalSet, mtypes, annotations); + } + + // create all built-in types + static void createBuiltInTypes(SymbolHash types) { + // base schema simple type names + final String ANYSIMPLETYPE = "anySimpleType"; + final String ANYURI = "anyURI"; + final String BASE64BINARY = "base64Binary"; + final String BOOLEAN = "boolean"; + final String BYTE = "byte"; + final String DATE = "date"; + final String DATETIME = "dateTime"; + final String DAY = "gDay"; + final String DECIMAL = "decimal"; + final String INT = "int"; + final String INTEGER = "integer"; + final String LONG = "long"; + final String NEGATIVEINTEGER = "negativeInteger"; + final String MONTH = "gMonth"; + final String MONTHDAY = "gMonthDay"; + final String NONNEGATIVEINTEGER= "nonNegativeInteger"; + final String NONPOSITIVEINTEGER= "nonPositiveInteger"; + final String POSITIVEINTEGER = "positiveInteger"; + final String SHORT = "short"; + final String STRING = "string"; + final String TIME = "time"; + final String UNSIGNEDBYTE = "unsignedByte"; + final String UNSIGNEDINT = "unsignedInt"; + final String UNSIGNEDLONG = "unsignedLong"; + final String UNSIGNEDSHORT = "unsignedShort"; + final String YEAR = "gYear"; + final String YEARMONTH = "gYearMonth"; + + final XSFacets facets = new XSFacets(); + + XSSimpleTypeDecl anySimpleType = XSSimpleTypeDecl.fAnySimpleType; + types.put(ANYSIMPLETYPE, anySimpleType); + XSSimpleTypeDecl stringDV = new XSSimpleTypeDecl(anySimpleType, STRING, XSSimpleTypeDecl.DV_STRING, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.STRING_DT); + types.put(STRING, stringDV); + types.put(BOOLEAN, new XSSimpleTypeDecl(anySimpleType, BOOLEAN, XSSimpleTypeDecl.DV_BOOLEAN, XSSimpleType.ORDERED_FALSE, false, true, false, true, XSConstants.BOOLEAN_DT)); + XSSimpleTypeDecl decimalDV = new XSSimpleTypeDecl(anySimpleType, DECIMAL, XSSimpleTypeDecl.DV_DECIMAL, XSSimpleType.ORDERED_TOTAL, false, false, true, true, XSConstants.DECIMAL_DT); + types.put(DECIMAL, decimalDV); + + types.put(ANYURI, new XSSimpleTypeDecl(anySimpleType, ANYURI, XSSimpleTypeDecl.DV_ANYURI, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.ANYURI_DT)); + types.put(BASE64BINARY, new XSSimpleTypeDecl(anySimpleType, BASE64BINARY, XSSimpleTypeDecl.DV_BASE64BINARY, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.BASE64BINARY_DT)); + types.put(DATETIME, new XSSimpleTypeDecl(anySimpleType, DATETIME, XSSimpleTypeDecl.DV_DATETIME, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.DATETIME_DT)); + types.put(TIME, new XSSimpleTypeDecl(anySimpleType, TIME, XSSimpleTypeDecl.DV_TIME, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.TIME_DT)); + types.put(DATE, new XSSimpleTypeDecl(anySimpleType, DATE, XSSimpleTypeDecl.DV_DATE, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.DATE_DT)); + types.put(YEARMONTH, new XSSimpleTypeDecl(anySimpleType, YEARMONTH, XSSimpleTypeDecl.DV_GYEARMONTH, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GYEARMONTH_DT)); + types.put(YEAR, new XSSimpleTypeDecl(anySimpleType, YEAR, XSSimpleTypeDecl.DV_GYEAR, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GYEAR_DT)); + types.put(MONTHDAY, new XSSimpleTypeDecl(anySimpleType, MONTHDAY, XSSimpleTypeDecl.DV_GMONTHDAY, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GMONTHDAY_DT)); + types.put(DAY, new XSSimpleTypeDecl(anySimpleType, DAY, XSSimpleTypeDecl.DV_GDAY, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GDAY_DT)); + types.put(MONTH, new XSSimpleTypeDecl(anySimpleType, MONTH, XSSimpleTypeDecl.DV_GMONTH, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GMONTH_DT)); + + XSSimpleTypeDecl integerDV = new XSSimpleTypeDecl(decimalDV, INTEGER, XSSimpleTypeDecl.DV_INTEGER, XSSimpleType.ORDERED_TOTAL, false, false, true, true, XSConstants.INTEGER_DT); + types.put(INTEGER, integerDV); + + facets.maxInclusive = "0"; + XSSimpleTypeDecl nonPositiveDV = new XSSimpleTypeDecl(integerDV, NONPOSITIVEINTEGER, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NONPOSITIVEINTEGER_DT); + nonPositiveDV.applyFacets1(facets , XSSimpleType.FACET_MAXINCLUSIVE, (short)0); + types.put(NONPOSITIVEINTEGER, nonPositiveDV); + + facets.maxInclusive = "-1"; + XSSimpleTypeDecl negativeDV = new XSSimpleTypeDecl(nonPositiveDV, NEGATIVEINTEGER, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NEGATIVEINTEGER_DT); + negativeDV.applyFacets1(facets , XSSimpleType.FACET_MAXINCLUSIVE, (short)0); + types.put(NEGATIVEINTEGER, negativeDV); + + facets.maxInclusive = "9223372036854775807"; + facets.minInclusive = "-9223372036854775808"; + XSSimpleTypeDecl longDV = new XSSimpleTypeDecl(integerDV, LONG, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.LONG_DT); + longDV.applyFacets1(facets , (short)(XSSimpleType.FACET_MAXINCLUSIVE | XSSimpleType.FACET_MININCLUSIVE), (short)0 ); + types.put(LONG, longDV); + + + facets.maxInclusive = "2147483647"; + facets.minInclusive = "-2147483648"; + XSSimpleTypeDecl intDV = new XSSimpleTypeDecl(longDV, INT, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.INT_DT); + intDV.applyFacets1(facets, (short)(XSSimpleType.FACET_MAXINCLUSIVE | XSSimpleType.FACET_MININCLUSIVE), (short)0 ); + types.put(INT, intDV); + + facets.maxInclusive = "32767"; + facets.minInclusive = "-32768"; + XSSimpleTypeDecl shortDV = new XSSimpleTypeDecl(intDV, SHORT , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.SHORT_DT); + shortDV.applyFacets1(facets, (short)(XSSimpleType.FACET_MAXINCLUSIVE | XSSimpleType.FACET_MININCLUSIVE), (short)0 ); + types.put(SHORT, shortDV); + + facets.maxInclusive = "127"; + facets.minInclusive = "-128"; + XSSimpleTypeDecl byteDV = new XSSimpleTypeDecl(shortDV, BYTE , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.BYTE_DT); + byteDV.applyFacets1(facets, (short)(XSSimpleType.FACET_MAXINCLUSIVE | XSSimpleType.FACET_MININCLUSIVE), (short)0 ); + types.put(BYTE, byteDV); + + facets.minInclusive = "0" ; + XSSimpleTypeDecl nonNegativeDV = new XSSimpleTypeDecl(integerDV, NONNEGATIVEINTEGER , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NONNEGATIVEINTEGER_DT); + nonNegativeDV.applyFacets1(facets, XSSimpleType.FACET_MININCLUSIVE, (short)0 ); + types.put(NONNEGATIVEINTEGER, nonNegativeDV); + + facets.maxInclusive = "18446744073709551615" ; + XSSimpleTypeDecl unsignedLongDV = new XSSimpleTypeDecl(nonNegativeDV, UNSIGNEDLONG , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.UNSIGNEDLONG_DT); + unsignedLongDV.applyFacets1(facets, XSSimpleType.FACET_MAXINCLUSIVE, (short)0 ); + types.put(UNSIGNEDLONG, unsignedLongDV); + + facets.maxInclusive = "4294967295" ; + XSSimpleTypeDecl unsignedIntDV = new XSSimpleTypeDecl(unsignedLongDV, UNSIGNEDINT , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.UNSIGNEDINT_DT); + unsignedIntDV.applyFacets1(facets, XSSimpleType.FACET_MAXINCLUSIVE, (short)0 ); + types.put(UNSIGNEDINT, unsignedIntDV); + + facets.maxInclusive = "65535" ; + XSSimpleTypeDecl unsignedShortDV = new XSSimpleTypeDecl(unsignedIntDV, UNSIGNEDSHORT , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.UNSIGNEDSHORT_DT); + unsignedShortDV.applyFacets1(facets, XSSimpleType.FACET_MAXINCLUSIVE, (short)0 ); + types.put(UNSIGNEDSHORT, unsignedShortDV); + + facets.maxInclusive = "255" ; + XSSimpleTypeDecl unsignedByteDV = new XSSimpleTypeDecl(unsignedShortDV, UNSIGNEDBYTE , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.UNSIGNEDBYTE_DT); + unsignedByteDV.applyFacets1(facets, XSSimpleType.FACET_MAXINCLUSIVE, (short)0 ); + types.put(UNSIGNEDBYTE, unsignedByteDV); + + facets.minInclusive = "1" ; + XSSimpleTypeDecl positiveIntegerDV = new XSSimpleTypeDecl(nonNegativeDV, POSITIVEINTEGER , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.POSITIVEINTEGER_DT); + positiveIntegerDV.applyFacets1(facets, XSSimpleType.FACET_MININCLUSIVE, (short)0 ); + types.put(POSITIVEINTEGER, positiveIntegerDV); + }//createBuiltInTypes(SymbolHash) + +}//BaseDVFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BaseSchemaDVFactory.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BaseSchemaDVFactory.java new file mode 100644 index 0000000..5627ba3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BaseSchemaDVFactory.java @@ -0,0 +1,325 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.SchemaDVFactory; +import org.apache.xerces.impl.dv.XSFacets; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xs.XSDeclarationPool; +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; + +/** + * the base factory to create/return built-in schema DVs and create user-defined DVs + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * @author Khaled Noaman, IBM + * + * @version $Id$ + */ +public abstract class BaseSchemaDVFactory extends SchemaDVFactory { + + static final String URI_SCHEMAFORSCHEMA = "http://www.w3.org/2001/XMLSchema"; + + protected XSDeclarationPool fDeclPool = null; + + // create common built-in types + protected static void createBuiltInTypes(SymbolHash builtInTypes, XSSimpleTypeDecl baseAtomicType) { + // all schema simple type names + final String ANYSIMPLETYPE = "anySimpleType"; + final String ANYURI = "anyURI"; + final String BASE64BINARY = "base64Binary"; + final String BOOLEAN = "boolean"; + final String BYTE = "byte"; + final String DATE = "date"; + final String DATETIME = "dateTime"; + final String DAY = "gDay"; + final String DECIMAL = "decimal"; + final String DOUBLE = "double"; + final String DURATION = "duration"; + final String ENTITY = "ENTITY"; + final String ENTITIES = "ENTITIES"; + final String FLOAT = "float"; + final String HEXBINARY = "hexBinary"; + final String ID = "ID"; + final String IDREF = "IDREF"; + final String IDREFS = "IDREFS"; + final String INT = "int"; + final String INTEGER = "integer"; + final String LONG = "long"; + final String NAME = "Name"; + final String NEGATIVEINTEGER = "negativeInteger"; + final String MONTH = "gMonth"; + final String MONTHDAY = "gMonthDay"; + final String NCNAME = "NCName"; + final String NMTOKEN = "NMTOKEN"; + final String NMTOKENS = "NMTOKENS"; + final String LANGUAGE = "language"; + final String NONNEGATIVEINTEGER= "nonNegativeInteger"; + final String NONPOSITIVEINTEGER= "nonPositiveInteger"; + final String NORMALIZEDSTRING = "normalizedString"; + final String NOTATION = "NOTATION"; + final String POSITIVEINTEGER = "positiveInteger"; + final String QNAME = "QName"; + final String SHORT = "short"; + final String STRING = "string"; + final String TIME = "time"; + final String TOKEN = "token"; + final String UNSIGNEDBYTE = "unsignedByte"; + final String UNSIGNEDINT = "unsignedInt"; + final String UNSIGNEDLONG = "unsignedLong"; + final String UNSIGNEDSHORT = "unsignedShort"; + final String YEAR = "gYear"; + final String YEARMONTH = "gYearMonth"; + + final XSFacets facets = new XSFacets(); + + builtInTypes.put(ANYSIMPLETYPE, XSSimpleTypeDecl.fAnySimpleType); + + XSSimpleTypeDecl stringDV = new XSSimpleTypeDecl(baseAtomicType, STRING, XSSimpleTypeDecl.DV_STRING, XSSimpleType.ORDERED_FALSE, false, false, false , true, XSConstants.STRING_DT); + builtInTypes.put(STRING, stringDV); + builtInTypes.put(BOOLEAN, new XSSimpleTypeDecl(baseAtomicType, BOOLEAN, XSSimpleTypeDecl.DV_BOOLEAN, XSSimpleType.ORDERED_FALSE, false, true, false, true, XSConstants.BOOLEAN_DT)); + XSSimpleTypeDecl decimalDV = new XSSimpleTypeDecl(baseAtomicType, DECIMAL, XSSimpleTypeDecl.DV_DECIMAL, XSSimpleType.ORDERED_TOTAL, false, false, true, true, XSConstants.DECIMAL_DT); + builtInTypes.put(DECIMAL, decimalDV); + + builtInTypes.put(ANYURI, new XSSimpleTypeDecl(baseAtomicType, ANYURI, XSSimpleTypeDecl.DV_ANYURI, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.ANYURI_DT)); + builtInTypes.put(BASE64BINARY, new XSSimpleTypeDecl(baseAtomicType, BASE64BINARY, XSSimpleTypeDecl.DV_BASE64BINARY, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.BASE64BINARY_DT)); + + XSSimpleTypeDecl durationDV = new XSSimpleTypeDecl(baseAtomicType, DURATION, XSSimpleTypeDecl.DV_DURATION, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.DURATION_DT); + builtInTypes.put(DURATION, durationDV); + + builtInTypes.put(DATETIME, new XSSimpleTypeDecl(baseAtomicType, DATETIME, XSSimpleTypeDecl.DV_DATETIME, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.DATETIME_DT)); + builtInTypes.put(TIME, new XSSimpleTypeDecl(baseAtomicType, TIME, XSSimpleTypeDecl.DV_TIME, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.TIME_DT)); + builtInTypes.put(DATE, new XSSimpleTypeDecl(baseAtomicType, DATE, XSSimpleTypeDecl.DV_DATE, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.DATE_DT)); + builtInTypes.put(YEARMONTH, new XSSimpleTypeDecl(baseAtomicType, YEARMONTH, XSSimpleTypeDecl.DV_GYEARMONTH, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GYEARMONTH_DT)); + builtInTypes.put(YEAR, new XSSimpleTypeDecl(baseAtomicType, YEAR, XSSimpleTypeDecl.DV_GYEAR, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GYEAR_DT)); + builtInTypes.put(MONTHDAY, new XSSimpleTypeDecl(baseAtomicType, MONTHDAY, XSSimpleTypeDecl.DV_GMONTHDAY, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GMONTHDAY_DT)); + builtInTypes.put(DAY, new XSSimpleTypeDecl(baseAtomicType, DAY, XSSimpleTypeDecl.DV_GDAY, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GDAY_DT)); + builtInTypes.put(MONTH, new XSSimpleTypeDecl(baseAtomicType, MONTH, XSSimpleTypeDecl.DV_GMONTH, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.GMONTH_DT)); + + XSSimpleTypeDecl integerDV = new XSSimpleTypeDecl(decimalDV, INTEGER, XSSimpleTypeDecl.DV_INTEGER, XSSimpleType.ORDERED_TOTAL, false, false, true, true, XSConstants.INTEGER_DT); + builtInTypes.put(INTEGER, integerDV); + + facets.maxInclusive = "0"; + XSSimpleTypeDecl nonPositiveDV = new XSSimpleTypeDecl(integerDV, NONPOSITIVEINTEGER, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NONPOSITIVEINTEGER_DT); + nonPositiveDV.applyFacets1(facets , XSSimpleType.FACET_MAXINCLUSIVE, (short)0); + builtInTypes.put(NONPOSITIVEINTEGER, nonPositiveDV); + + facets.maxInclusive = "-1"; + XSSimpleTypeDecl negativeDV = new XSSimpleTypeDecl(nonPositiveDV, NEGATIVEINTEGER, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NEGATIVEINTEGER_DT); + negativeDV.applyFacets1(facets , XSSimpleType.FACET_MAXINCLUSIVE, (short)0); + builtInTypes.put(NEGATIVEINTEGER, negativeDV); + + facets.maxInclusive = "9223372036854775807"; + facets.minInclusive = "-9223372036854775808"; + XSSimpleTypeDecl longDV = new XSSimpleTypeDecl(integerDV, LONG, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.LONG_DT); + longDV.applyFacets1(facets , (short)(XSSimpleType.FACET_MAXINCLUSIVE | XSSimpleType.FACET_MININCLUSIVE), (short)0 ); + builtInTypes.put(LONG, longDV); + + facets.maxInclusive = "2147483647"; + facets.minInclusive = "-2147483648"; + XSSimpleTypeDecl intDV = new XSSimpleTypeDecl(longDV, INT, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.INT_DT); + intDV.applyFacets1(facets, (short)(XSSimpleType.FACET_MAXINCLUSIVE | XSSimpleType.FACET_MININCLUSIVE), (short)0 ); + builtInTypes.put(INT, intDV); + + facets.maxInclusive = "32767"; + facets.minInclusive = "-32768"; + XSSimpleTypeDecl shortDV = new XSSimpleTypeDecl(intDV, SHORT , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.SHORT_DT); + shortDV.applyFacets1(facets, (short)(XSSimpleType.FACET_MAXINCLUSIVE | XSSimpleType.FACET_MININCLUSIVE), (short)0 ); + builtInTypes.put(SHORT, shortDV); + + facets.maxInclusive = "127"; + facets.minInclusive = "-128"; + XSSimpleTypeDecl byteDV = new XSSimpleTypeDecl(shortDV, BYTE , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.BYTE_DT); + byteDV.applyFacets1(facets, (short)(XSSimpleType.FACET_MAXINCLUSIVE | XSSimpleType.FACET_MININCLUSIVE), (short)0 ); + builtInTypes.put(BYTE, byteDV); + + facets.minInclusive = "0" ; + XSSimpleTypeDecl nonNegativeDV = new XSSimpleTypeDecl(integerDV, NONNEGATIVEINTEGER , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NONNEGATIVEINTEGER_DT); + nonNegativeDV.applyFacets1(facets, XSSimpleType.FACET_MININCLUSIVE, (short)0 ); + builtInTypes.put(NONNEGATIVEINTEGER, nonNegativeDV); + + facets.maxInclusive = "18446744073709551615" ; + XSSimpleTypeDecl unsignedLongDV = new XSSimpleTypeDecl(nonNegativeDV, UNSIGNEDLONG , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.UNSIGNEDLONG_DT); + unsignedLongDV.applyFacets1(facets, XSSimpleType.FACET_MAXINCLUSIVE, (short)0 ); + builtInTypes.put(UNSIGNEDLONG, unsignedLongDV); + + facets.maxInclusive = "4294967295" ; + XSSimpleTypeDecl unsignedIntDV = new XSSimpleTypeDecl(unsignedLongDV, UNSIGNEDINT , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.UNSIGNEDINT_DT); + unsignedIntDV.applyFacets1(facets, XSSimpleType.FACET_MAXINCLUSIVE, (short)0 ); + builtInTypes.put(UNSIGNEDINT, unsignedIntDV); + + facets.maxInclusive = "65535" ; + XSSimpleTypeDecl unsignedShortDV = new XSSimpleTypeDecl(unsignedIntDV, UNSIGNEDSHORT , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.UNSIGNEDSHORT_DT); + unsignedShortDV.applyFacets1(facets, XSSimpleType.FACET_MAXINCLUSIVE, (short)0 ); + builtInTypes.put(UNSIGNEDSHORT, unsignedShortDV); + + facets.maxInclusive = "255" ; + XSSimpleTypeDecl unsignedByteDV = new XSSimpleTypeDecl(unsignedShortDV, UNSIGNEDBYTE , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.UNSIGNEDBYTE_DT); + unsignedByteDV.applyFacets1(facets, XSSimpleType.FACET_MAXINCLUSIVE, (short)0 ); + builtInTypes.put(UNSIGNEDBYTE, unsignedByteDV); + + facets.minInclusive = "1" ; + XSSimpleTypeDecl positiveIntegerDV = new XSSimpleTypeDecl(nonNegativeDV, POSITIVEINTEGER , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.POSITIVEINTEGER_DT); + positiveIntegerDV.applyFacets1(facets, XSSimpleType.FACET_MININCLUSIVE, (short)0 ); + builtInTypes.put(POSITIVEINTEGER, positiveIntegerDV); + + builtInTypes.put(FLOAT, new XSSimpleTypeDecl(baseAtomicType, FLOAT, XSSimpleTypeDecl.DV_FLOAT, XSSimpleType.ORDERED_PARTIAL, true, true, true, true, XSConstants.FLOAT_DT)); + builtInTypes.put(DOUBLE, new XSSimpleTypeDecl(baseAtomicType, DOUBLE, XSSimpleTypeDecl.DV_DOUBLE, XSSimpleType.ORDERED_PARTIAL, true, true, true, true, XSConstants.DOUBLE_DT)); + builtInTypes.put(HEXBINARY, new XSSimpleTypeDecl(baseAtomicType, HEXBINARY, XSSimpleTypeDecl.DV_HEXBINARY, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.HEXBINARY_DT)); + builtInTypes.put(NOTATION, new XSSimpleTypeDecl(baseAtomicType, NOTATION, XSSimpleTypeDecl.DV_NOTATION, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.NOTATION_DT)); + + facets.whiteSpace = XSSimpleType.WS_REPLACE; + XSSimpleTypeDecl normalizedDV = new XSSimpleTypeDecl(stringDV, NORMALIZEDSTRING , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NORMALIZEDSTRING_DT); + normalizedDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0 ); + builtInTypes.put(NORMALIZEDSTRING, normalizedDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + XSSimpleTypeDecl tokenDV = new XSSimpleTypeDecl(normalizedDV, TOKEN , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.TOKEN_DT); + tokenDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0 ); + builtInTypes.put(TOKEN, tokenDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + facets.pattern = "([a-zA-Z]{1,8})(-[a-zA-Z0-9]{1,8})*"; + XSSimpleTypeDecl languageDV = new XSSimpleTypeDecl(tokenDV, LANGUAGE , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.LANGUAGE_DT); + languageDV.applyFacets1(facets, (short)(XSSimpleType.FACET_WHITESPACE | XSSimpleType.FACET_PATTERN) ,(short)0); + builtInTypes.put(LANGUAGE, languageDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + XSSimpleTypeDecl nameDV = new XSSimpleTypeDecl(tokenDV, NAME , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NAME_DT); + nameDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0, XSSimpleTypeDecl.SPECIAL_PATTERN_NAME); + builtInTypes.put(NAME, nameDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + XSSimpleTypeDecl ncnameDV = new XSSimpleTypeDecl(nameDV, NCNAME , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NCNAME_DT) ; + ncnameDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0, XSSimpleTypeDecl.SPECIAL_PATTERN_NCNAME); + builtInTypes.put(NCNAME, ncnameDV); + + builtInTypes.put(QNAME, new XSSimpleTypeDecl(baseAtomicType, QNAME, XSSimpleTypeDecl.DV_QNAME, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.QNAME_DT)); + + builtInTypes.put(ID, new XSSimpleTypeDecl(ncnameDV, ID, XSSimpleTypeDecl.DV_ID, XSSimpleType.ORDERED_FALSE, false, false, false , true, XSConstants.ID_DT)); + XSSimpleTypeDecl idrefDV = new XSSimpleTypeDecl(ncnameDV, IDREF , XSSimpleTypeDecl.DV_IDREF, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.IDREF_DT); + builtInTypes.put(IDREF, idrefDV); + + facets.minLength = 1; + XSSimpleTypeDecl tempDV = new XSSimpleTypeDecl(null, URI_SCHEMAFORSCHEMA, (short)0, idrefDV, true, null); + XSSimpleTypeDecl idrefsDV = new XSSimpleTypeDecl(tempDV, IDREFS, URI_SCHEMAFORSCHEMA, (short)0, false, null); + idrefsDV.applyFacets1(facets, XSSimpleType.FACET_MINLENGTH, (short)0); + builtInTypes.put(IDREFS, idrefsDV); + + XSSimpleTypeDecl entityDV = new XSSimpleTypeDecl(ncnameDV, ENTITY , XSSimpleTypeDecl.DV_ENTITY, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.ENTITY_DT); + builtInTypes.put(ENTITY, entityDV); + + facets.minLength = 1; + tempDV = new XSSimpleTypeDecl(null, URI_SCHEMAFORSCHEMA, (short)0, entityDV, true, null); + XSSimpleTypeDecl entitiesDV = new XSSimpleTypeDecl(tempDV, ENTITIES, URI_SCHEMAFORSCHEMA, (short)0, false, null); + entitiesDV.applyFacets1(facets, XSSimpleType.FACET_MINLENGTH, (short)0); + builtInTypes.put(ENTITIES, entitiesDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + XSSimpleTypeDecl nmtokenDV = new XSSimpleTypeDecl(tokenDV, NMTOKEN, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NMTOKEN_DT); + nmtokenDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0, XSSimpleTypeDecl.SPECIAL_PATTERN_NMTOKEN); + builtInTypes.put(NMTOKEN, nmtokenDV); + + facets.minLength = 1; + tempDV = new XSSimpleTypeDecl(null, URI_SCHEMAFORSCHEMA, (short)0, nmtokenDV, true, null); + XSSimpleTypeDecl nmtokensDV = new XSSimpleTypeDecl(tempDV, NMTOKENS, URI_SCHEMAFORSCHEMA, (short)0, false, null); + nmtokensDV.applyFacets1(facets, XSSimpleType.FACET_MINLENGTH, (short)0); + builtInTypes.put(NMTOKENS, nmtokensDV); + } //createBuiltInTypes() + + /** + * Create a new simple type which is derived by restriction from another + * simple type. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param base base type of the new type + * @param annotations set of annotations + * @return the newly created simple type + */ + public XSSimpleType createTypeRestriction(String name, String targetNamespace, + short finalSet, XSSimpleType base, XSObjectList annotations) { + + if (fDeclPool != null) { + XSSimpleTypeDecl st= fDeclPool.getSimpleTypeDecl(); + return st.setRestrictionValues((XSSimpleTypeDecl)base, name, targetNamespace, finalSet, annotations); + } + return new XSSimpleTypeDecl((XSSimpleTypeDecl)base, name, targetNamespace, finalSet, false, annotations); + } + + /** + * Create a new simple type which is derived by list from another simple + * type. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param itemType item type of the list type + * @param annotations set of annotations + * @return the newly created simple type + */ + public XSSimpleType createTypeList(String name, String targetNamespace, + short finalSet, XSSimpleType itemType, + XSObjectList annotations) { + if (fDeclPool != null) { + XSSimpleTypeDecl st= fDeclPool.getSimpleTypeDecl(); + return st.setListValues(name, targetNamespace, finalSet, (XSSimpleTypeDecl)itemType, annotations); + } + return new XSSimpleTypeDecl(name, targetNamespace, finalSet, (XSSimpleTypeDecl)itemType, false, annotations); + } + + /** + * Create a new simple type which is derived by union from a list of other + * simple types. + * + * @param name name of the new type, could be null + * @param targetNamespace target namespace of the new type, could be null + * @param finalSet value of "final" + * @param memberTypes member types of the union type + * @param annotations set of annotations + * @return the newly created simple type + */ + public XSSimpleType createTypeUnion(String name, String targetNamespace, + short finalSet, XSSimpleType[] memberTypes, + XSObjectList annotations) { + int typeNum = memberTypes.length; + XSSimpleTypeDecl[] mtypes = new XSSimpleTypeDecl[typeNum]; + System.arraycopy(memberTypes, 0, mtypes, 0, typeNum); + + if (fDeclPool != null) { + XSSimpleTypeDecl st= fDeclPool.getSimpleTypeDecl(); + return st.setUnionValues(name, targetNamespace, finalSet, mtypes, annotations); + } + return new XSSimpleTypeDecl(name, targetNamespace, finalSet, mtypes, annotations); + } + + public void setDeclPool (XSDeclarationPool declPool){ + fDeclPool = declPool; + } + + /** Implementation internal **/ + public XSSimpleTypeDecl newXSSimpleTypeDecl() { + return new XSSimpleTypeDecl(); + } +} //BaseSchemaDVFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BooleanDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BooleanDV.java new file mode 100644 index 0000000..56fdc96 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/BooleanDV.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Represent the schema type "boolean" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class BooleanDV extends TypeValidator { + + public short getAllowedFacets() { + return (XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE); + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + if ("false".equals(content) || "0".equals(content)) { + return Boolean.FALSE; + } + else if ("true".equals(content) || "1".equals(content)) { + return Boolean.TRUE; + } + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "boolean"}); + } + +} // class BooleanDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DateDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DateDV.java new file mode 100644 index 0000000..abe1d9b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DateDV.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Validator for datatype (W3C Schema datatypes) + * + * @xerces.internal + * + * @author Elena Litani + * @author Gopal Sharma, SUN Microsystems Inc. + * + * @version $Id$ + */ +public class DateDV extends DateTimeDV { + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + try{ + return parse(content); + } catch(Exception ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "date"}); + } + } + + /** + * Parses, validates and computes normalized version of dateTime object + * + * @param str The lexical representation of dateTime object CCYY-MM-DD + * with possible time zone Z or (-),(+)hh:mm + * @return normalized dateTime representation + * @exception SchemaDateTimeException Invalid lexical representation + */ + protected DateTimeData parse(String str) throws SchemaDateTimeException { + DateTimeData date = new DateTimeData(str, this); + int len = str.length(); + + int end = getDate(str, 0, len, date); + parseTimeZone (str, end, len, date); + + //validate and normalize + //REVISIT: do we need SchemaDateTimeException? + validateDateTime(date); + + //save unnormalized values + saveUnnormalized(date); + + if (date.utc!=0 && date.utc!='Z') { + normalize(date); + } + return date; + } + + protected String dateToString(DateTimeData date) { + StringBuffer message = new StringBuffer(25); + append(message, date.year, 4); + message.append('-'); + append(message, date.month, 2); + message.append('-'); + append(message, date.day, 2); + append(message, (char)date.utc, 0); + return message.toString(); + } + + protected XMLGregorianCalendar getXMLGregorianCalendar(DateTimeData date) { + return datatypeFactory.newXMLGregorianCalendar(date.unNormYear, date.unNormMonth, + date.unNormDay, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, + DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, + date.hasTimeZone() ? (date.timezoneHr * 60 + date.timezoneMin) : DatatypeConstants.FIELD_UNDEFINED); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DateTimeDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DateTimeDV.java new file mode 100644 index 0000000..fe739f8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DateTimeDV.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import java.math.BigInteger; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Validator for <dateTime> datatype (W3C Schema Datatypes) + * + * @xerces.internal + * + * @author Elena Litani + * @author Gopal Sharma, SUN Microsystem Inc. + * + * @version $Id$ + */ +public class DateTimeDV extends AbstractDateTimeDV { + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + try{ + return parse(content); + } catch(Exception ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "dateTime"}); + } + } + + /** + * Parses, validates and computes normalized version of dateTime object + * + * @param str The lexical representation of dateTime object CCYY-MM-DDThh:mm:ss.sss + * with possible time zone Z or (-),(+)hh:mm + * @return normalized dateTime representation + * @exception SchemaDateTimeException Invalid lexical representation + */ + protected DateTimeData parse(String str) throws SchemaDateTimeException { + DateTimeData date = new DateTimeData(str, this); + int len = str.length(); + + int end = indexOf (str, 0, len, 'T'); + + // both time and date + int dateEnd = getDate(str, 0, end, date); + getTime(str, end+1, len, date); + + //Check the separator character between Date and Time + if (dateEnd != end) { + throw new RuntimeException(str + + " is an invalid dateTime dataype value. " + + "Invalid character(s) seprating date and time values."); + } + + //validate and normalize + + //REVISIT: do we need SchemaDateTimeException? + validateDateTime(date); + + //save unnormalized values + saveUnnormalized(date); + + if (date.utc!=0 && date.utc!='Z') { + normalize(date); + } + return date; + } + + protected XMLGregorianCalendar getXMLGregorianCalendar(DateTimeData date) { + return datatypeFactory.newXMLGregorianCalendar(BigInteger.valueOf(date.unNormYear), date.unNormMonth, + date.unNormDay, date.unNormHour, date.unNormMinute, + (int)date.unNormSecond, date.unNormSecond != 0 ? getFractionalSecondsAsBigDecimal(date) : null, + date.hasTimeZone() ? (date.timezoneHr * 60 + date.timezoneMin) : DatatypeConstants.FIELD_UNDEFINED); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DayDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DayDV.java new file mode 100644 index 0000000..c2073ae --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DayDV.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Validator for <gDay> datatype (W3C Schema datatypes) + * + * @xerces.internal + * + * @author Elena Litani + * @author Gopal Sharma, SUN Microsystem Inc. + * @version $Id$ + */ +public class DayDV extends AbstractDateTimeDV { + + //size without time zone: ---09 + private final static int DAY_SIZE=5; + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + try{ + return parse(content); + } catch(Exception ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "gDay"}); + } + } + + /** + * Parses, validates and computes normalized version of gDay object + * + * @param str The lexical representation of gDay object ---DD + * with possible time zone Z or (-),(+)hh:mm + * Pattern: ---(\\d\\d)(Z|(([-+])(\\d\\d)(:(\\d\\d))? + * @return normalized date representation + * @exception SchemaDateTimeException Invalid lexical representation + */ + protected DateTimeData parse(String str) throws SchemaDateTimeException { + DateTimeData date = new DateTimeData(str, this); + int len = str.length(); + + if (str.charAt(0)!='-' || str.charAt(1)!='-' || str.charAt(2)!='-') { + throw new SchemaDateTimeException ("Error in day parsing"); + } + + //initialize values + date.year=YEAR; + date.month=MONTH; + + date.day=parseInt(str, 3,5); + + if ( DAY_SIZE type + * + * @xerces.internal + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +class DayTimeDurationDV extends DurationDV { + + public Object getActualValue(String content, ValidationContext context) + throws InvalidDatatypeValueException { + try { + return parse(content, DurationDV.DAYTIMEDURATION_TYPE); + } + catch (Exception ex) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "dayTimeDuration"}); + } + } + + protected Duration getDuration(DateTimeData date) { + int sign = 1; + if (date.day<0 || date.hour<0 || date.minute<0 || date.second<0) { + sign = -1; + } + return datatypeFactory.newDuration(sign == 1, null, null, + date.day != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.day):null, + date.hour != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.hour):null, + date.minute != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.minute):null, + date.second != DatatypeConstants.FIELD_UNDEFINED?new BigDecimal(String.valueOf(sign*date.second)):null); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DecimalDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DecimalDV.java new file mode 100644 index 0000000..32685f0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DecimalDV.java @@ -0,0 +1,362 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.xs.datatypes.XSDecimal; + +/** + * Represent the schema type "decimal" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class DecimalDV extends TypeValidator { + + public final short getAllowedFacets(){ + return ( XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE | XSSimpleTypeDecl.FACET_ENUMERATION |XSSimpleTypeDecl.FACET_MAXINCLUSIVE |XSSimpleTypeDecl.FACET_MININCLUSIVE | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE | XSSimpleTypeDecl.FACET_MINEXCLUSIVE | XSSimpleTypeDecl.FACET_TOTALDIGITS | XSSimpleTypeDecl.FACET_FRACTIONDIGITS); + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + try { + return new XDecimal(content); + } catch (NumberFormatException nfe) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "decimal"}); + } + } + + public final int compare(Object value1, Object value2){ + return ((XDecimal)value1).compareTo((XDecimal)value2); + } + + public final int getTotalDigits(Object value){ + return ((XDecimal)value).totalDigits; + } + + public final int getFractionDigits(Object value){ + return ((XDecimal)value).fracDigits; + } + + // Avoid using the heavy-weight java.math.BigDecimal + static class XDecimal implements XSDecimal { + // sign: 0 for vlaue 0; 1 for positive values; -1 for negative values + int sign = 1; + // total digits. >= 1 + int totalDigits = 0; + // integer digits when sign != 0 + int intDigits = 0; + // fraction digits when sign != 0 + int fracDigits = 0; + // the string representing the integer part + String ivalue = ""; + // the string representing the fraction part + String fvalue = ""; + // whether the canonical form contains decimal point + boolean integer = false; + + XDecimal(String content) throws NumberFormatException { + initD(content); + } + XDecimal(String content, boolean integer) throws NumberFormatException { + if (integer) + initI(content); + else + initD(content); + } + void initD(String content) throws NumberFormatException { + int len = content.length(); + if (len == 0) + throw new NumberFormatException(); + + // these 4 variables are used to indicate where the integre/fraction + // parts start/end. + int intStart = 0, intEnd = 0, fracStart = 0, fracEnd = 0; + + // Deal with leading sign symbol if present + if (content.charAt(0) == '+') { + // skip '+', so intStart should be 1 + intStart = 1; + } + else if (content.charAt(0) == '-') { + // keep '-', so intStart is stil 0 + intStart = 1; + sign = -1; + } + + // skip leading zeroes in integer part + int actualIntStart = intStart; + while (actualIntStart < len && content.charAt(actualIntStart) == '0') { + actualIntStart++; + } + + // Find the ending position of the integer part + for (intEnd = actualIntStart; + intEnd < len && TypeValidator.isDigit(content.charAt(intEnd)); + intEnd++); + + // Not reached the end yet + if (intEnd < len) { + // the remaining part is not ".DDD", error + if (content.charAt(intEnd) != '.') + throw new NumberFormatException(); + + // fraction part starts after '.', and ends at the end of the input + fracStart = intEnd + 1; + fracEnd = len; + } + + // no integer part, no fraction part, error. + if (intStart == intEnd && fracStart == fracEnd) + throw new NumberFormatException(); + + // ignore trailing zeroes in fraction part + while (fracEnd > fracStart && content.charAt(fracEnd-1) == '0') { + fracEnd--; + } + + // check whether there is non-digit characters in the fraction part + for (int fracPos = fracStart; fracPos < fracEnd; fracPos++) { + if (!TypeValidator.isDigit(content.charAt(fracPos))) + throw new NumberFormatException(); + } + + intDigits = intEnd - actualIntStart; + fracDigits = fracEnd - fracStart; + totalDigits = intDigits + fracDigits; + + if (intDigits > 0) { + ivalue = content.substring(actualIntStart, intEnd); + if (fracDigits > 0) + fvalue = content.substring(fracStart, fracEnd); + } + else { + if (fracDigits > 0) { + fvalue = content.substring(fracStart, fracEnd); + } + else { + // ".00", treat it as "0" + sign = 0; + } + } + } + void initI(String content) throws NumberFormatException { + int len = content.length(); + if (len == 0) + throw new NumberFormatException(); + + // these 2 variables are used to indicate where the integre start/end. + int intStart = 0, intEnd = 0; + + // Deal with leading sign symbol if present + if (content.charAt(0) == '+') { + // skip '+', so intStart should be 1 + intStart = 1; + } + else if (content.charAt(0) == '-') { + // keep '-', so intStart is stil 0 + intStart = 1; + sign = -1; + } + + // skip leading zeroes in integer part + int actualIntStart = intStart; + while (actualIntStart < len && content.charAt(actualIntStart) == '0') { + actualIntStart++; + } + + // Find the ending position of the integer part + for (intEnd = actualIntStart; + intEnd < len && TypeValidator.isDigit(content.charAt(intEnd)); + intEnd++); + + // Not reached the end yet, error + if (intEnd < len) + throw new NumberFormatException(); + + // no integer part, error. + if (intStart == intEnd) + throw new NumberFormatException(); + + intDigits = intEnd - actualIntStart; + fracDigits = 0; + totalDigits = intDigits; + + if (intDigits > 0) { + ivalue = content.substring(actualIntStart, intEnd); + } + else { + // "00", treat it as "0" + sign = 0; + } + + integer = true; + } + public boolean equals(Object val) { + if (val == this) + return true; + + if (!(val instanceof XDecimal)) + return false; + XDecimal oval = (XDecimal)val; + + if (sign != oval.sign) + return false; + if (sign == 0) + return true; + + return intDigits == oval.intDigits && fracDigits == oval.fracDigits && + ivalue.equals(oval.ivalue) && fvalue.equals(oval.fvalue); + } + public int compareTo(XDecimal val) { + if (sign != val.sign) + return sign > val.sign ? 1 : -1; + if (sign == 0) + return 0; + return sign * intComp(val); + } + private int intComp(XDecimal val) { + if (intDigits != val.intDigits) + return intDigits > val.intDigits ? 1 : -1; + int ret = ivalue.compareTo(val.ivalue); + if (ret != 0) + return ret > 0 ? 1 : -1;; + ret = fvalue.compareTo(val.fvalue); + return ret == 0 ? 0 : (ret > 0 ? 1 : -1); + } + private String canonical; + public synchronized String toString() { + if (canonical == null) { + makeCanonical(); + } + return canonical; + } + + private void makeCanonical() { + if (sign == 0) { + if (integer) + canonical = "0"; + else + canonical = "0.0"; + return; + } + if (integer && sign > 0) { + canonical = ivalue; + return; + } + // for -0.1, total digits is 1, so we need 3 extra spots + StringBuffer buffer = new StringBuffer(totalDigits+3); + if (sign == -1) + buffer.append('-'); + if (intDigits != 0) + buffer.append(ivalue); + else + buffer.append('0'); + if (!integer) { + buffer.append('.'); + if (fracDigits != 0) { + buffer.append(fvalue); + } + else { + buffer.append('0'); + } + } + canonical = buffer.toString(); + } + + public BigDecimal getBigDecimal() { + if (sign == 0) { + return new BigDecimal(BigInteger.ZERO); + } + return new BigDecimal(toString()); + } + + public BigInteger getBigInteger() throws NumberFormatException { + if (fracDigits != 0) { + throw new NumberFormatException(); + } + if (sign == 0) { + return BigInteger.ZERO; + } + if (sign == 1) { + return new BigInteger(ivalue); + } + return new BigInteger("-" + ivalue); + } + + public long getLong() throws NumberFormatException { + if (fracDigits != 0) { + throw new NumberFormatException(); + } + if (sign == 0) { + return 0L; + } + if (sign == 1) { + return Long.parseLong(ivalue); + } + return Long.parseLong("-" + ivalue); + } + + public int getInt() throws NumberFormatException { + if (fracDigits != 0) { + throw new NumberFormatException(); + } + if (sign == 0) { + return 0; + } + if (sign == 1) { + return Integer.parseInt(ivalue); + } + return Integer.parseInt("-" + ivalue); + } + + public short getShort() throws NumberFormatException { + if (fracDigits != 0) { + throw new NumberFormatException(); + } + if (sign == 0) { + return 0; + } + if (sign == 1) { + return Short.parseShort(ivalue); + } + return Short.parseShort("-" + ivalue); + } + + public byte getByte() throws NumberFormatException { + if (fracDigits != 0) { + throw new NumberFormatException(); + } + if (sign == 0) { + return 0; + } + if (sign == 1) { + return Byte.parseByte(ivalue); + } + return Byte.parseByte("-" + ivalue); + } + } +} // class DecimalDV + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DoubleDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DoubleDV.java new file mode 100644 index 0000000..61454bf --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DoubleDV.java @@ -0,0 +1,257 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.xs.datatypes.XSDouble; + +/** + * Represent the schema type "double" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class DoubleDV extends TypeValidator { + + public short getAllowedFacets(){ + return ( XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE | XSSimpleTypeDecl.FACET_ENUMERATION |XSSimpleTypeDecl.FACET_MAXINCLUSIVE |XSSimpleTypeDecl.FACET_MININCLUSIVE | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE | XSSimpleTypeDecl.FACET_MINEXCLUSIVE ); + }//getAllowedFacets() + + //convert a String to Double form, we have to take care of cases specified in spec like INF, -INF and NaN + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + try{ + return new XDouble(content); + } catch (NumberFormatException ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "double"}); + } + }//getActualValue() + + // Can't call Double#compareTo method, because it's introduced in jdk 1.2 + public int compare(Object value1, Object value2) { + return ((XDouble)value1).compareTo((XDouble)value2); + }//compare() + + //distinguishes between identity and equality for double datatype + //0.0 is equal but not identical to -0.0 + public boolean isIdentical (Object value1, Object value2) { + if (value2 instanceof XDouble) { + return ((XDouble)value1).isIdentical((XDouble)value2); + } + return false; + }//isIdentical() + + /** + * Returns true if it's possible that the given + * string represents a valid floating point value + * (excluding NaN, INF and -INF). + */ + static boolean isPossibleFP(String val) { + final int length = val.length(); + for (int i = 0; i < length; ++i) { + char c = val.charAt(i); + if (!(c >= '0' && c <= '9' || c == '.' || + c == '-' || c == '+' || c == 'E' || c == 'e')) { + return false; + } + } + return true; + } + + private static final class XDouble implements XSDouble { + private final double value; + public XDouble(String s) throws NumberFormatException { + if (isPossibleFP(s)) { + value = Double.parseDouble(s); + } + else if ( s.equals("INF") ) { + value = Double.POSITIVE_INFINITY; + } + else if ( s.equals("-INF") ) { + value = Double.NEGATIVE_INFINITY; + } + else if ( s.equals("NaN" ) ) { + value = Double.NaN; + } + else { + throw new NumberFormatException(s); + } + } + + public boolean equals(Object val) { + if (val == this) + return true; + + if (!(val instanceof XDouble)) + return false; + XDouble oval = (XDouble)val; + + // NOTE: we don't distinguish 0.0 from -0.0 + if (value == oval.value) + return true; + + if (value != value && oval.value != oval.value) + return true; + + return false; + } + + public int hashCode() { + // This check is necessary because doubleToLongBits(+0) != doubleToLongBits(-0) + if (value == 0d) { + return 0; + } + long v = Double.doubleToLongBits(value); + return (int) (v ^ (v >>> 32)); + } + + // NOTE: 0.0 is equal but not identical to -0.0 + public boolean isIdentical (XDouble val) { + if (val == this) { + return true; + } + + if (value == val.value) { + return (value != 0.0d || + (Double.doubleToLongBits(value) == Double.doubleToLongBits(val.value))); + } + + if (value != value && val.value != val.value) + return true; + + return false; + } + + private int compareTo(XDouble val) { + double oval = val.value; + + // this < other + if (value < oval) + return -1; + // this > other + if (value > oval) + return 1; + // this == other + // NOTE: we don't distinguish 0.0 from -0.0 + if (value == oval) + return 0; + + // one of the 2 values or both is/are NaN(s) + + if (value != value) { + // this = NaN = other + if (oval != oval) + return 0; + // this is NaN <> other + return INDETERMINATE; + } + + // other is NaN <> this + return INDETERMINATE; + } + + private String canonical; + public synchronized String toString() { + if (canonical == null) { + if (value == Double.POSITIVE_INFINITY) + canonical = "INF"; + else if (value == Double.NEGATIVE_INFINITY) + canonical = "-INF"; + else if (value != value) + canonical = "NaN"; + // NOTE: we don't distinguish 0.0 from -0.0 + else if (value == 0) + canonical = "0.0E1"; + else { + // REVISIT: use the java algorithm for now, because we + // don't know what to output for 1.1d (which is no + // actually 1.1) + canonical = Double.toString(value); + // if it contains 'E', then it should be a valid schema + // canonical representation + if (canonical.indexOf('E') == -1) { + int len = canonical.length(); + // at most 3 longer: E, -, 9 + char[] chars = new char[len+3]; + canonical.getChars(0, len, chars, 0); + // expected decimal point position + int edp = chars[0] == '-' ? 2 : 1; + // for non-zero integer part + if (value >= 1 || value <= -1) { + // decimal point position + int dp = canonical.indexOf('.'); + // move the digits: ddd.d --> d.ddd + for (int i = dp; i > edp; i--) { + chars[i] = chars[i-1]; + } + chars[edp] = '.'; + // trim trailing zeros: d00.0 --> d.000 --> d. + while (chars[len-1] == '0') + len--; + // add the last zero if necessary: d. --> d.0 + if (chars[len-1] == '.') + len++; + // append E: d.dd --> d.ddE + chars[len++] = 'E'; + // how far we shifted the decimal point + int shift = dp - edp; + // append the exponent --> d.ddEd + // the exponent is at most 7 + chars[len++] = (char)(shift + '0'); + } + else { + // non-zero digit point + int nzp = edp + 1; + // skip zeros: 0.003 + while (chars[nzp] == '0') + nzp++; + // put the first non-zero digit to the left of '.' + chars[edp-1] = chars[nzp]; + chars[edp] = '.'; + // move other digits (non-zero) to the right of '.' + for (int i = nzp+1, j = edp+1; i < len; i++, j++) + chars[j] = chars[i]; + // adjust the length + len -= nzp - edp; + // append 0 if nessary: 0.03 --> 3. --> 3.0 + if (len == edp + 1) + chars[len++] = '0'; + // append E-: d.dd --> d.ddE- + chars[len++] = 'E'; + chars[len++] = '-'; + // how far we shifted the decimal point + int shift = nzp - edp; + // append the exponent --> d.ddEd + // the exponent is at most 3 + chars[len++] = (char)(shift + '0'); + } + canonical = new String(chars, 0, len); + } + } + } + return canonical; + } + public double getValue() { + return value; + } + } +} // class DoubleDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DurationDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DurationDV.java new file mode 100644 index 0000000..4ba3cd3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/DurationDV.java @@ -0,0 +1,387 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.Duration; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Validator for <duration> datatype (W3C Schema Datatypes) + * + * @xerces.internal + * + * @author Elena Litani + * @author Gopal Sharma, SUN Microsystem Inc. + * @version $Id$ + */ +public class DurationDV extends AbstractDateTimeDV { + + public static final int DURATION_TYPE = 0; + public static final int YEARMONTHDURATION_TYPE = 1; + public static final int DAYTIMEDURATION_TYPE = 2; + // order-relation on duration is a partial order. The dates below are used to + // for comparison of 2 durations, based on the fact that + // duration x and y is x<=y iff s+x<=s+y + // see 3.2.6 duration W3C schema datatype specs + // + // the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone} + private final static DateTimeData[] DATETIMES= { + new DateTimeData(1696, 9, 1, 0, 0, 0, 'Z', null, true, null), + new DateTimeData(1697, 2, 1, 0, 0, 0, 'Z', null, true, null), + new DateTimeData(1903, 3, 1, 0, 0, 0, 'Z', null, true, null), + new DateTimeData(1903, 7, 1, 0, 0, 0, 'Z', null, true, null)}; + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{ + try{ + return parse(content, DURATION_TYPE); + } catch (Exception ex) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "duration"}); + } + } + + /** + * Parses, validates and computes normalized version of duration object + * + * @param str The lexical representation of duration object PnYn MnDTnH nMnS + * @param durationType + * @return normalized date representation + * @exception SchemaDateTimeException Invalid lexical representation + */ + protected DateTimeData parse(String str, int durationType) throws SchemaDateTimeException{ + int len = str.length(); + DateTimeData date= new DateTimeData(str, this); + + int start = 0; + char c=str.charAt(start++); + if ( c!='P' && c!='-' ) { + throw new SchemaDateTimeException(); + } + else { + date.utc=(c=='-')?'-':0; + if ( c=='-' && str.charAt(start++)!='P' ) { + throw new SchemaDateTimeException(); + } + } + + int negate = 1; + //negative duration + if ( date.utc=='-' ) { + negate = -1; + + } + //at least one number and designator must be seen after P + boolean designator = false; + + int endDate = indexOf (str, start, len, 'T'); + if ( endDate == -1 ) { + endDate = len; + } + else if (durationType == YEARMONTHDURATION_TYPE) { + throw new SchemaDateTimeException(); + } + + //find 'Y' + int end = indexOf (str, start, endDate, 'Y'); + if ( end!=-1 ) { + + if (durationType == DAYTIMEDURATION_TYPE) { + throw new SchemaDateTimeException(); + } + + //scan year + date.year=negate * parseInt(str,start,end); + start = end+1; + designator = true; + } + + end = indexOf (str, start, endDate, 'M'); + if ( end!=-1 ) { + + if (durationType == DAYTIMEDURATION_TYPE) { + throw new SchemaDateTimeException(); + } + + //scan month + date.month=negate * parseInt(str,start,end); + start = end+1; + designator = true; + } + + end = indexOf (str, start, endDate, 'D'); + if ( end!=-1 ) { + + if(durationType == YEARMONTHDURATION_TYPE) { + throw new SchemaDateTimeException(); + } + + //scan day + date.day=negate * parseInt(str,start,end); + start = end+1; + designator = true; + } + + if ( len == endDate && start!=len ) { + throw new SchemaDateTimeException(); + } + if ( len !=endDate ) { + + //scan hours, minutes, seconds + //REVISIT: can any item include a decimal fraction or only seconds? + // + + end = indexOf (str, ++start, len, 'H'); + if ( end!=-1 ) { + //scan hours + date.hour=negate * parseInt(str,start,end); + start=end+1; + designator = true; + } + + end = indexOf (str, start, len, 'M'); + if ( end!=-1 ) { + //scan min + date.minute=negate * parseInt(str,start,end); + start=end+1; + designator = true; + } + + end = indexOf (str, start, len, 'S'); + if ( end!=-1 ) { + //scan seconds + date.second = negate * parseSecond(str, start, end); + start=end+1; + designator = true; + } + // no additional data shouls appear after last item + // P1Y1M1DT is illigal value as well + if ( start != len || str.charAt(--start)=='T' ) { + throw new SchemaDateTimeException(); + } + } + + if ( !designator ) { + throw new SchemaDateTimeException(); + } + + return date; + } + + /** + * Compares 2 given durations. (refer to W3C Schema Datatypes "3.2.6 duration") + * + * @param date1 Unnormalized duration + * @param date2 Unnormalized duration + * @param strict (min/max)Exclusive strict == true ( LESS_THAN ) or ( GREATER_THAN ) + * (min/max)Inclusive strict == false (LESS_EQUAL) or (GREATER_EQUAL) + * @return INDETERMINATE if the order relationship between date1 and date2 is indeterminate. + * EQUAL if the order relation between date1 and date2 is EQUAL. + * If the strict parameter is true, return LESS_THAN if date1 is less than date2 and + * return GREATER_THAN if date1 is greater than date2. + * If the strict parameter is false, return LESS_THAN if date1 is less than OR equal to date2 and + * return GREATER_THAN if date1 is greater than OR equal to date2 + */ + protected short compareDates(DateTimeData date1, DateTimeData date2, boolean strict) { + + //REVISIT: this is unoptimazed vs of comparing 2 durations + // Algorithm is described in 3.2.6.2 W3C Schema Datatype specs + // + + //add constA to both durations + short resultA, resultB= INDETERMINATE; + //try and see if the objects are equal + resultA = compareOrder (date1, date2); + if ( resultA == 0 ) { + return 0; + } + + DateTimeData[] result = new DateTimeData[2]; + result[0] = new DateTimeData(null, this); + result[1] = new DateTimeData(null, this); + + //long comparison algorithm is required + DateTimeData tempA = addDuration (date1, DATETIMES[0], result[0]); + DateTimeData tempB = addDuration (date2, DATETIMES[0], result[1]); + resultA = compareOrder(tempA, tempB); + if ( resultA == INDETERMINATE ) { + return INDETERMINATE; + } + + tempA = addDuration(date1, DATETIMES[1], result[0]); + tempB = addDuration(date2, DATETIMES[1], result[1]); + resultB = compareOrder(tempA, tempB); + resultA = compareResults(resultA, resultB, strict); + if (resultA == INDETERMINATE) { + return INDETERMINATE; + } + + tempA = addDuration(date1, DATETIMES[2], result[0]); + tempB = addDuration(date2, DATETIMES[2], result[1]); + resultB = compareOrder(tempA, tempB); + resultA = compareResults(resultA, resultB, strict); + if (resultA == INDETERMINATE) { + return INDETERMINATE; + } + + tempA = addDuration(date1, DATETIMES[3], result[0]); + tempB = addDuration(date2, DATETIMES[3], result[1]); + resultB = compareOrder(tempA, tempB); + resultA = compareResults(resultA, resultB, strict); + + return resultA; + } + + private short compareResults(short resultA, short resultB, boolean strict){ + + if ( resultB == INDETERMINATE ) { + return INDETERMINATE; + } + else if ( resultA!=resultB && strict ) { + return INDETERMINATE; + } + else if ( resultA!=resultB && !strict ) { + if ( resultA!=0 && resultB!=0 ) { + return INDETERMINATE; + } + else { + return (resultA!=0)?resultA:resultB; + } + } + return resultA; + } + + private DateTimeData addDuration(DateTimeData date, DateTimeData addto, DateTimeData duration) { + + //REVISIT: some code could be shared between normalize() and this method, + // however is it worth moving it? The structures are different... + // + + resetDateObj(duration); + //add months (may be modified additionaly below) + int temp = addto.month + date.month; + duration.month = modulo (temp, 1, 13); + int carry = fQuotient (temp, 1, 13); + + //add years (may be modified additionaly below) + duration.year=addto.year + date.year + carry; + + //add seconds + double dtemp = addto.second + date.second; + carry = (int)Math.floor(dtemp/60); + duration.second = dtemp - carry*60; + + //add minutes + temp = addto.minute +date.minute + carry; + carry = fQuotient (temp, 60); + duration.minute= mod(temp, 60, carry); + + //add hours + temp = addto.hour + date.hour + carry; + carry = fQuotient(temp, 24); + duration.hour = mod(temp, 24, carry); + + + duration.day=addto.day + date.day + carry; + + while ( true ) { + + temp=maxDayInMonthFor(duration.year, duration.month); + if ( duration.day < 1 ) { //original duration was negative + duration.day = duration.day + maxDayInMonthFor(duration.year, duration.month-1); + carry=-1; + } + else if ( duration.day > temp ) { + duration.day = duration.day - temp; + carry=1; + } + else { + break; + } + temp = duration.month+carry; + duration.month = modulo(temp, 1, 13); + duration.year = duration.year+fQuotient(temp, 1, 13); + } + + duration.utc='Z'; + return duration; + } + + protected double parseSecond(String buffer, int start, int end) + throws NumberFormatException { + int dot = -1; + for (int i = start; i < end; i++) { + char ch = buffer.charAt(i); + if (ch == '.') + dot = i; + else if (ch > '9' || ch < '0') + throw new NumberFormatException("'" + buffer + "' has wrong format"); + } + if (dot+1 == end) { + throw new NumberFormatException("'" + buffer + "' has wrong format"); + } + double value = Double.parseDouble(buffer.substring(start, end)); + if (value == Double.POSITIVE_INFINITY) { + throw new NumberFormatException("'" + buffer + "' has wrong format"); + } + return value; + } + + protected String dateToString(DateTimeData date) { + StringBuffer message = new StringBuffer(30); + if ( date.year<0 || date.month<0 || date.day<0 + || date.hour<0 || date.minute<0 || date.second<0) { + message.append('-'); + } + message.append('P'); + message.append((date.year < 0?-1:1) * date.year); + message.append('Y'); + message.append((date.month < 0?-1:1) * date.month); + message.append('M'); + message.append((date.day < 0?-1:1) * date.day); + message.append('D'); + message.append('T'); + message.append((date.hour < 0?-1:1) * date.hour); + message.append('H'); + message.append((date.minute < 0?-1:1) * date.minute); + message.append('M'); + append2(message, (date.second < 0?-1:1) * date.second); + message.append('S'); + + return message.toString(); + } + + protected Duration getDuration(DateTimeData date) { + int sign = 1; + if ( date.year<0 || date.month<0 || date.day<0 + || date.hour<0 || date.minute<0 || date.second<0) { + sign = -1; + } + return datatypeFactory.newDuration(sign == 1, + date.year != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.year):null, + date.month != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.month):null, + date.day != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.day):null, + date.hour != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.hour):null, + date.minute != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.minute):null, + date.second != DatatypeConstants.FIELD_UNDEFINED?new BigDecimal(String.valueOf(sign*date.second)):null); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/EntityDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/EntityDV.java new file mode 100644 index 0000000..8b268eb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/EntityDV.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XMLChar; + +/** + * Represent the schema type "entity" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class EntityDV extends TypeValidator { + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE ); + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + if (!XMLChar.isValidNCName(content)) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "NCName"}); + } + + return content; + } + + public void checkExtraRules(Object value, ValidationContext context) throws InvalidDatatypeValueException { + if (!context.isEntityUnparsed((String)value)) { + throw new InvalidDatatypeValueException("UndeclaredEntity", new Object[]{value}); + } + } + +} // class EntityDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/ExtendedSchemaDVFactoryImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/ExtendedSchemaDVFactoryImpl.java new file mode 100644 index 0000000..110bd15 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/ExtendedSchemaDVFactoryImpl.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.util.SymbolHash; + +/** + * A special factory to create/return built-in schema DVs and create user-defined DVs + * that includes anyAtomicType, yearMonthDuration and dayTimeDuration + * + * @xerces.internal + * + * @author Khaled Noaman, IBM + * + * @version $Id$ + */ +public class ExtendedSchemaDVFactoryImpl extends BaseSchemaDVFactory { + + static SymbolHash fBuiltInTypes = new SymbolHash(); + static { + createBuiltInTypes(); + } + + // create all built-in types + static void createBuiltInTypes() { + final String ANYATOMICTYPE = "anyAtomicType"; + final String DURATION = "duration"; + final String YEARMONTHDURATION = "yearMonthDuration"; + final String DAYTIMEDURATION = "dayTimeDuration"; + + createBuiltInTypes(fBuiltInTypes, XSSimpleTypeDecl.fAnyAtomicType); + + // add anyAtomicType + fBuiltInTypes.put(ANYATOMICTYPE, XSSimpleTypeDecl.fAnyAtomicType); + + // add 2 duration types + XSSimpleTypeDecl durationDV = (XSSimpleTypeDecl)fBuiltInTypes.get(DURATION); + fBuiltInTypes.put(YEARMONTHDURATION, new XSSimpleTypeDecl(durationDV, YEARMONTHDURATION, XSSimpleTypeDecl.DV_YEARMONTHDURATION, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSSimpleTypeDecl.YEARMONTHDURATION_DT)); + fBuiltInTypes.put(DAYTIMEDURATION, new XSSimpleTypeDecl(durationDV, DAYTIMEDURATION, XSSimpleTypeDecl.DV_DAYTIMEDURATION, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSSimpleTypeDecl.DAYTIMEDURATION_DT)); + } //createBuiltInTypes() + + /** + * Get a built-in simple type of the given name + * REVISIT: its still not decided within the Schema WG how to define the + * ur-types and if all simple types should be derived from a + * complex type, so as of now we ignore the fact that anySimpleType + * is derived from anyType, and pass 'null' as the base of + * anySimpleType. It needs to be changed as per the decision taken. + * + * @param name the name of the datatype + * @return the datatype validator of the given name + */ + public XSSimpleType getBuiltInType(String name) { + return (XSSimpleType)fBuiltInTypes.get(name); + } + + /** + * get all built-in simple types, which are stored in a hashtable keyed by + * the name + * + * @return a hashtable which contains all built-in simple types + */ + public SymbolHash getBuiltInTypes() { + return (SymbolHash)fBuiltInTypes.makeClone(); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/FloatDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/FloatDV.java new file mode 100644 index 0000000..ce5f984 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/FloatDV.java @@ -0,0 +1,238 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.xs.datatypes.XSFloat; + +/** + * Represent the schema type "float" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class FloatDV extends TypeValidator { + + public short getAllowedFacets(){ + return ( XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE | XSSimpleTypeDecl.FACET_ENUMERATION |XSSimpleTypeDecl.FACET_MAXINCLUSIVE |XSSimpleTypeDecl.FACET_MININCLUSIVE | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE | XSSimpleTypeDecl.FACET_MINEXCLUSIVE ); + }//getAllowedFacets() + + //convert a String to Float form, we have to take care of cases specified in spec like INF, -INF and NaN + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + try{ + return new XFloat(content); + } catch (NumberFormatException ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "float"}); + } + }//getActualValue() + + // Can't call Float#compareTo method, because it's introduced in jdk 1.2 + public int compare(Object value1, Object value2){ + return ((XFloat)value1).compareTo((XFloat)value2); + }//compare() + + //distinguishes between identity and equality for float datatype + //0.0 is equal but not identical to -0.0 + public boolean isIdentical (Object value1, Object value2) { + if (value2 instanceof XFloat) { + return ((XFloat)value1).isIdentical((XFloat)value2); + } + return false; + }//isIdentical() + + private static final class XFloat implements XSFloat { + + private final float value; + public XFloat(String s) throws NumberFormatException { + if (DoubleDV.isPossibleFP(s)) { + value = Float.parseFloat(s); + } + else if ( s.equals("INF") ) { + value = Float.POSITIVE_INFINITY; + } + else if ( s.equals("-INF") ) { + value = Float.NEGATIVE_INFINITY; + } + else if ( s.equals("NaN") ) { + value = Float.NaN; + } + else { + throw new NumberFormatException(s); + } + } + + public boolean equals(Object val) { + if (val == this) + return true; + + if (!(val instanceof XFloat)) + return false; + XFloat oval = (XFloat)val; + + // NOTE: we don't distinguish 0.0 from -0.0 + if (value == oval.value) + return true; + + if (value != value && oval.value != oval.value) + return true; + + return false; + } + + public int hashCode() { + // This check is necessary because floatToIntBits(+0) != floatToIntBits(-0) + return (value == 0f) ? 0 : Float.floatToIntBits(value); + } + + // NOTE: 0.0 is equal but not identical to -0.0 + public boolean isIdentical (XFloat val) { + if (val == this) { + return true; + } + + if (value == val.value) { + return (value != 0.0f || + (Float.floatToIntBits(value) == Float.floatToIntBits(val.value))); + } + + if (value != value && val.value != val.value) + return true; + + return false; + } + + private int compareTo(XFloat val) { + float oval = val.value; + + // this < other + if (value < oval) + return -1; + // this > other + if (value > oval) + return 1; + // this == other + // NOTE: we don't distinguish 0.0 from -0.0 + if (value == oval) + return 0; + + // one of the 2 values or both is/are NaN(s) + + if (value != value) { + // this = NaN = other + if (oval != oval) + return 0; + // this is NaN <> other + return INDETERMINATE; + } + + // other is NaN <> this + return INDETERMINATE; + } + + private String canonical; + public synchronized String toString() { + if (canonical == null) { + if (value == Float.POSITIVE_INFINITY) + canonical = "INF"; + else if (value == Float.NEGATIVE_INFINITY) + canonical = "-INF"; + else if (value != value) + canonical = "NaN"; + // NOTE: we don't distinguish 0.0 from -0.0 + else if (value == 0) + canonical = "0.0E1"; + else { + // REVISIT: use the java algorithm for now, because we + // don't know what to output for 1.1f (which is no + // actually 1.1) + canonical = Float.toString(value); + // if it contains 'E', then it should be a valid schema + // canonical representation + if (canonical.indexOf('E') == -1) { + int len = canonical.length(); + // at most 3 longer: E, -, 9 + char[] chars = new char[len+3]; + canonical.getChars(0, len, chars, 0); + // expected decimal point position + int edp = chars[0] == '-' ? 2 : 1; + // for non-zero integer part + if (value >= 1 || value <= -1) { + // decimal point position + int dp = canonical.indexOf('.'); + // move the digits: ddd.d --> d.ddd + for (int i = dp; i > edp; i--) { + chars[i] = chars[i-1]; + } + chars[edp] = '.'; + // trim trailing zeros: d00.0 --> d.000 --> d. + while (chars[len-1] == '0') + len--; + // add the last zero if necessary: d. --> d.0 + if (chars[len-1] == '.') + len++; + // append E: d.dd --> d.ddE + chars[len++] = 'E'; + // how far we shifted the decimal point + int shift = dp - edp; + // append the exponent --> d.ddEd + // the exponent is at most 7 + chars[len++] = (char)(shift + '0'); + } + else { + // non-zero digit point + int nzp = edp + 1; + // skip zeros: 0.003 + while (chars[nzp] == '0') + nzp++; + // put the first non-zero digit to the left of '.' + chars[edp-1] = chars[nzp]; + chars[edp] = '.'; + // move other digits (non-zero) to the right of '.' + for (int i = nzp+1, j = edp+1; i < len; i++, j++) + chars[j] = chars[i]; + // adjust the length + len -= nzp - edp; + // append 0 if nessary: 0.03 --> 3. --> 3.0 + if (len == edp + 1) + chars[len++] = '0'; + // append E-: d.dd --> d.ddE- + chars[len++] = 'E'; + chars[len++] = '-'; + // how far we shifted the decimal point + int shift = nzp - edp; + // append the exponent --> d.ddEd + // the exponent is at most 3 + chars[len++] = (char)(shift + '0'); + } + canonical = new String(chars, 0, len); + } + } + } + return canonical; + } + + public float getValue() { + return value; + } + } +} // class FloatDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/FullDVFactory.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/FullDVFactory.java new file mode 100644 index 0000000..5731aeb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/FullDVFactory.java @@ -0,0 +1,166 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.XSFacets; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.xs.XSConstants; + +/** + * the factory to create/return built-in schema DVs and create user-defined DVs + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class FullDVFactory extends BaseDVFactory { + + static final String URI_SCHEMAFORSCHEMA = "http://www.w3.org/2001/XMLSchema"; + + // there are 45 types. 89 is the closest prime number to 45*2=90. + static SymbolHash fFullTypes = new SymbolHash(89); + static { + createBuiltInTypes(fFullTypes); + } + + /** + * Get a built-in simple type of the given name + * REVISIT: its still not decided within the Schema WG how to define the + * ur-types and if all simple types should be derived from a + * complex type, so as of now we ignore the fact that anySimpleType + * is derived from anyType, and pass 'null' as the base of + * anySimpleType. It needs to be changed as per the decision taken. + * + * @param name the name of the datatype + * @return the datatype validator of the given name + */ + public XSSimpleType getBuiltInType(String name) { + return (XSSimpleType)fFullTypes.get(name); + } + + /** + * get all built-in simple types, which are stored in a hashtable keyed by + * the name + * + * @return a hashtable which contains all built-in simple types + */ + public SymbolHash getBuiltInTypes() { + return (SymbolHash)fFullTypes.makeClone(); + } + + // create all built-in types + static void createBuiltInTypes(SymbolHash types) { + // create base types first + BaseDVFactory.createBuiltInTypes(types); + + // full schema simple type names + final String DOUBLE = "double"; + final String DURATION = "duration"; + final String ENTITY = "ENTITY"; + final String ENTITIES = "ENTITIES"; + final String FLOAT = "float"; + final String HEXBINARY = "hexBinary"; + final String ID = "ID"; + final String IDREF = "IDREF"; + final String IDREFS = "IDREFS"; + final String NAME = "Name"; + final String NCNAME = "NCName"; + final String NMTOKEN = "NMTOKEN"; + final String NMTOKENS = "NMTOKENS"; + final String LANGUAGE = "language"; + final String NORMALIZEDSTRING = "normalizedString"; + final String NOTATION = "NOTATION"; + final String QNAME = "QName"; + final String STRING = "string"; + final String TOKEN = "token"; + + final XSFacets facets = new XSFacets(); + + XSSimpleTypeDecl anySimpleType = XSSimpleTypeDecl.fAnySimpleType; + XSSimpleTypeDecl stringDV = (XSSimpleTypeDecl)types.get(STRING); + + types.put(FLOAT, new XSSimpleTypeDecl(anySimpleType, FLOAT, XSSimpleTypeDecl.DV_FLOAT, XSSimpleType.ORDERED_PARTIAL, true, true, true, true, XSConstants.FLOAT_DT)); + types.put(DOUBLE, new XSSimpleTypeDecl(anySimpleType, DOUBLE, XSSimpleTypeDecl.DV_DOUBLE, XSSimpleType.ORDERED_PARTIAL, true, true, true, true, XSConstants.DOUBLE_DT)); + types.put(DURATION, new XSSimpleTypeDecl(anySimpleType, DURATION, XSSimpleTypeDecl.DV_DURATION, XSSimpleType.ORDERED_PARTIAL, false, false, false, true, XSConstants.DURATION_DT)); + types.put(HEXBINARY, new XSSimpleTypeDecl(anySimpleType, HEXBINARY, XSSimpleTypeDecl.DV_HEXBINARY, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.HEXBINARY_DT)); + types.put(QNAME, new XSSimpleTypeDecl(anySimpleType, QNAME, XSSimpleTypeDecl.DV_QNAME, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.QNAME_DT)); + types.put(NOTATION, new XSSimpleTypeDecl(anySimpleType, NOTATION, XSSimpleTypeDecl.DV_NOTATION, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.NOTATION_DT)); + + facets.whiteSpace = XSSimpleType.WS_REPLACE; + XSSimpleTypeDecl normalizedDV = new XSSimpleTypeDecl(stringDV, NORMALIZEDSTRING , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NORMALIZEDSTRING_DT); + normalizedDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0 ); + types.put(NORMALIZEDSTRING, normalizedDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + XSSimpleTypeDecl tokenDV = new XSSimpleTypeDecl(normalizedDV, TOKEN , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.TOKEN_DT); + tokenDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0 ); + types.put(TOKEN, tokenDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + facets.pattern = "([a-zA-Z]{1,8})(-[a-zA-Z0-9]{1,8})*"; + XSSimpleTypeDecl languageDV = new XSSimpleTypeDecl(tokenDV, LANGUAGE , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.LANGUAGE_DT); + languageDV.applyFacets1(facets, (short)(XSSimpleType.FACET_WHITESPACE | XSSimpleType.FACET_PATTERN) ,(short)0); + types.put(LANGUAGE, languageDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + XSSimpleTypeDecl nameDV = new XSSimpleTypeDecl(tokenDV, NAME , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NAME_DT); + nameDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0, XSSimpleTypeDecl.SPECIAL_PATTERN_NAME); + types.put(NAME, nameDV); + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + XSSimpleTypeDecl ncnameDV = new XSSimpleTypeDecl(nameDV, NCNAME , URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NCNAME_DT) ; + ncnameDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0, XSSimpleTypeDecl.SPECIAL_PATTERN_NCNAME); + types.put(NCNAME, ncnameDV); + + types.put(ID, new XSSimpleTypeDecl(ncnameDV, ID, XSSimpleTypeDecl.DV_ID, XSSimpleType.ORDERED_FALSE, false, false, false , true, XSConstants.ID_DT)); + XSSimpleTypeDecl idrefDV = new XSSimpleTypeDecl(ncnameDV, IDREF , XSSimpleTypeDecl.DV_IDREF, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.IDREF_DT); + types.put(IDREF, idrefDV); + + facets.minLength = 1; + XSSimpleTypeDecl tempDV = new XSSimpleTypeDecl(null, URI_SCHEMAFORSCHEMA, (short)0, idrefDV, true, null); + XSSimpleTypeDecl idrefsDV = new XSSimpleTypeDecl(tempDV, IDREFS, URI_SCHEMAFORSCHEMA, (short)0, false, null); + idrefsDV.applyFacets1(facets, XSSimpleType.FACET_MINLENGTH, (short)0); + types.put(IDREFS, idrefsDV); + + XSSimpleTypeDecl entityDV = new XSSimpleTypeDecl(ncnameDV, ENTITY , XSSimpleTypeDecl.DV_ENTITY, XSSimpleType.ORDERED_FALSE, false, false, false, true, XSConstants.ENTITY_DT); + types.put(ENTITY, entityDV); + + facets.minLength = 1; + tempDV = new XSSimpleTypeDecl(null, URI_SCHEMAFORSCHEMA, (short)0, entityDV, true, null); + XSSimpleTypeDecl entitiesDV = new XSSimpleTypeDecl(tempDV, ENTITIES, URI_SCHEMAFORSCHEMA, (short)0, false, null); + entitiesDV.applyFacets1(facets, XSSimpleType.FACET_MINLENGTH, (short)0); + types.put(ENTITIES, entitiesDV); + + + facets.whiteSpace = XSSimpleType.WS_COLLAPSE; + XSSimpleTypeDecl nmtokenDV = new XSSimpleTypeDecl(tokenDV, NMTOKEN, URI_SCHEMAFORSCHEMA, (short)0, false, null, XSConstants.NMTOKEN_DT); + nmtokenDV.applyFacets1(facets, XSSimpleType.FACET_WHITESPACE, (short)0, XSSimpleTypeDecl.SPECIAL_PATTERN_NMTOKEN); + types.put(NMTOKEN, nmtokenDV); + + facets.minLength = 1; + tempDV = new XSSimpleTypeDecl(null, URI_SCHEMAFORSCHEMA, (short)0, nmtokenDV, true, null); + XSSimpleTypeDecl nmtokensDV = new XSSimpleTypeDecl(tempDV, NMTOKENS, URI_SCHEMAFORSCHEMA, (short)0, false, null); + nmtokensDV.applyFacets1(facets, XSSimpleType.FACET_MINLENGTH, (short)0); + types.put(NMTOKENS, nmtokensDV); + }//createBuiltInTypes(SymbolHash) + +}//XFormsDVFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/HexBinaryDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/HexBinaryDV.java new file mode 100644 index 0000000..44591cb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/HexBinaryDV.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.impl.dv.util.ByteListImpl; +import org.apache.xerces.impl.dv.util.HexBin; + +/** + * Represent the schema type "hexBinary" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class HexBinaryDV extends TypeValidator { + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE ); + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + byte[] decoded = HexBin.decode(content); + if (decoded == null) + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "hexBinary"}); + + return new XHex(decoded); + } + + // length of a binary type is the number of bytes + public int getDataLength(Object value) { + return ((XHex)value).getLength(); + } + + private static final class XHex extends ByteListImpl { + + public XHex(byte[] data) { + super(data); + } + public synchronized String toString() { + if (canonical == null) { + canonical = HexBin.encode(data); + } + return canonical; + } + + public boolean equals(Object obj) { + if (!(obj instanceof XHex)) + return false; + byte[] odata = ((XHex)obj).data; + int len = data.length; + if (len != odata.length) + return false; + for (int i = 0; i < len; i++) { + if (data[i] != odata[i]) + return false; + } + return true; + } + + public int hashCode() { + int hash = 0; + for (int i = 0; i < data.length; ++i) { + hash = hash * 37 + (((int) data[i]) & 0xff); + } + return hash; + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IDDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IDDV.java new file mode 100644 index 0000000..bee86c8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IDDV.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XMLChar; + +/** + * Represent the schema type "ID" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class IDDV extends TypeValidator{ + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE ); + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + if (!XMLChar.isValidNCName(content)) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "NCName"}); + } + return content; + } + + public void checkExtraRules(Object value, ValidationContext context) throws InvalidDatatypeValueException { + String content = (String)value; + if (context.isIdDeclared(content)) + throw new InvalidDatatypeValueException("cvc-id.2", new Object[]{content}); + context.addId(content); + } +} // class IDDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IDREFDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IDREFDV.java new file mode 100644 index 0000000..c48696e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IDREFDV.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XMLChar; + +/** + * Represent the schema type "IDREF" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class IDREFDV extends TypeValidator{ + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE ); + } + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + if (!XMLChar.isValidNCName(content)) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "NCName"}); + } + return content; + } + + public void checkExtraRules(Object value, ValidationContext context) throws InvalidDatatypeValueException { + context.addIdRef((String)value); + } + +}//IDREF class + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IntegerDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IntegerDV.java new file mode 100644 index 0000000..3e24cb6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/IntegerDV.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Represent the schema type "integer" + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class IntegerDV extends DecimalDV { + + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + try { + return new XDecimal(content, true); + } catch (NumberFormatException nfe) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "integer"}); + } + } + +} // class EntityDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/ListDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/ListDV.java new file mode 100644 index 0000000..88c6b4b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/ListDV.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import java.util.AbstractList; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.xs.datatypes.ObjectList; + +/** + * Represent the schema list types + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class ListDV extends TypeValidator{ + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE ); + } + + // this method should never be called: XSSimpleTypeDecl is responsible for + // calling the item type for the convertion + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{ + return content; + } + + // length of a list type is the number of items in the list + public int getDataLength(Object value) { + return ((ListData)value).getLength(); + } + + final static class ListData extends AbstractList implements ObjectList { + final Object[] data; + private String canonical; + public ListData(Object[] data) { + this.data = data; + } + public synchronized String toString() { + if (canonical == null) { + int len = data.length; + StringBuffer buf = new StringBuffer(); + if (len > 0) { + buf.append(data[0].toString()); + } + for (int i = 1; i < len; i++) { + buf.append(' '); + buf.append(data[i].toString()); + } + canonical = buf.toString(); + } + return canonical; + } + public int getLength() { + return data.length; + } + public boolean equals(Object obj) { + if (!(obj instanceof ListData)) + return false; + Object[] odata = ((ListData)obj).data; + + int count = data.length; + if (count != odata.length) + return false; + + for (int i = 0 ; i < count ; i++) { + if (!data[i].equals(odata[i])) + return false; + }//end of loop + + //everything went fine. + return true; + } + + public int hashCode() { + int hash = 0; + for (int i = 0; i < data.length; ++i) { + hash ^= data[i].hashCode(); + } + return hash; + } + + public boolean contains(Object item) { + for (int i = 0;i < data.length; i++) { + if (item == data[i]) { + return true; + } + } + return false; + } + + public Object item(int index) { + if (index < 0 || index >= data.length) { + return null; + } + return data[index]; + } + + /* + * List methods + */ + + public Object get(int index) { + if (index >= 0 && index < data.length) { + return data[index]; + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + } +} // class ListDV + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/MonthDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/MonthDV.java new file mode 100644 index 0000000..3e4259c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/MonthDV.java @@ -0,0 +1,165 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Validator for <gMonth> datatype (W3C Schema Datatypes) + * + * @xerces.internal + * + * @author Elena Litani + * @author Gopal Sharma, SUN Microsystem Inc. + * + * @version $Id$ + */ + +public class MonthDV extends AbstractDateTimeDV { + + /** + * Convert a string to a compiled form + * + * @param content The lexical representation of gMonth + * @return a valid and normalized gMonth object + */ + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{ + try{ + return parse(content); + } catch(Exception ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "gMonth"}); + } + } + + /** + * Parses, validates and computes normalized version of gMonth object + * + * @param str The lexical representation of gMonth object --MM + * with possible time zone Z or (-),(+)hh:mm + * @return normalized date representation + * @exception SchemaDateTimeException Invalid lexical representation + */ + protected DateTimeData parse(String str) throws SchemaDateTimeException{ + DateTimeData date = new DateTimeData(str, this); + int len = str.length(); + + //set constants + date.year=YEAR; + date.day=DAY; + if (str.charAt(0)!='-' || str.charAt(1)!='-') { + throw new SchemaDateTimeException("Invalid format for gMonth: "+str); + } + int stop = 4; + date.month=parseInt(str,2,stop); + + // REVISIT: allow both --MM and --MM-- now. + // need to remove the following 4 lines to disallow --MM-- + // when the errata is offically in the rec. + if (str.length() >= stop+2 && + str.charAt(stop) == '-' && str.charAt(stop+1) == '-') { + stop += 2; + } + if (stop < len) { + if (!isNextCharUTCSign(str, stop, len)) { + throw new SchemaDateTimeException ("Error in month parsing: "+str); + } + else { + getTimeZone(str, date, stop, len); + } + } + //validate and normalize + validateDateTime(date); + + //save unnormalized values + saveUnnormalized(date); + + if ( date.utc!=0 && date.utc!='Z' ) { + normalize(date); + } + date.position = 1; + return date; + } + + /** + * Overwrite compare algorithm to optimize month comparison + * + * REVISIT: this one is lack of the third parameter: boolean strict, so it + * doesn't override the method in the base. But maybe this method + * is not correctly implemented, and I did encounter errors when + * trying to add the extra parameter. I'm leaving it as is. -SG + * + * @param date1 + * @param date2 + * @return less, greater, equal, indeterminate + */ + /*protected short compareDates(DateTimeData date1, DateTimeData date2) { + + if ( date1.utc==date2.utc ) { + return (short)((date1.month>=date2.month)?(date1.month>date2.month)?1:0:-1); + } + + if ( date1.utc=='Z' || date2.utc=='Z' ) { + + if ( date1.month==date2.month ) { + //--05--Z and --05-- + return INDETERMINATE; + } + if ( (date1.month+1 == date2.month || date1.month-1 == date2.month) ) { + //--05--Z and (--04-- or --05--) + //REVISIT: should this case be less than or equal? + // maxExclusive should fail but what about maxInclusive + // + return INDETERMINATE; + } + } + + if ( date1.month datatype (W3C Schema 1.1) + * + * @xerces.experimental + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +class PrecisionDecimalDV extends TypeValidator { + + static class XPrecisionDecimal { + + // sign: 0 for absent; 1 for positive values; -1 for negative values (except in case of INF, -INF) + int sign = 1; + // total digits. >= 1 + int totalDigits = 0; + // integer digits when sign != 0 + int intDigits = 0; + // fraction digits when sign != 0 + int fracDigits = 0; + //precision + //int precision = 0; + // the string representing the integer part + String ivalue = ""; + // the string representing the fraction part + String fvalue = ""; + + int pvalue = 0; + + + XPrecisionDecimal(String content) throws NumberFormatException { + if(content.equals("NaN")) { + ivalue = content; + sign = 0; + } + if(content.equals("+INF") || content.equals("INF") || content.equals("-INF")) { + ivalue = content.charAt(0) == '+' ? content.substring(1) : content; + return; + } + initD(content); + } + + void initD(String content) throws NumberFormatException { + int len = content.length(); + if (len == 0) + throw new NumberFormatException(); + + // these 4 variables are used to indicate where the integre/fraction + // parts start/end. + int intStart = 0, intEnd = 0, fracStart = 0, fracEnd = 0; + + // Deal with leading sign symbol if present + if (content.charAt(0) == '+') { + // skip '+', so intStart should be 1 + intStart = 1; + } + else if (content.charAt(0) == '-') { + intStart = 1; + sign = -1; + } + + // skip leading zeroes in integer part + int actualIntStart = intStart; + while (actualIntStart < len && content.charAt(actualIntStart) == '0') { + actualIntStart++; + } + + // Find the ending position of the integer part + for (intEnd = actualIntStart; intEnd < len && TypeValidator.isDigit(content.charAt(intEnd)); intEnd++); + + // Not reached the end yet + if (intEnd < len) { + // the remaining part is not ".DDD" or "EDDD" or "eDDD", error + if (content.charAt(intEnd) != '.' && content.charAt(intEnd) != 'E' && content.charAt(intEnd) != 'e') + throw new NumberFormatException(); + + if(content.charAt(intEnd) == '.') { + // fraction part starts after '.', and ends at the end of the input + fracStart = intEnd + 1; + + // find location of E or e (if present) + // Find the ending position of the fracion part + for (fracEnd = fracStart; + fracEnd < len && TypeValidator.isDigit(content.charAt(fracEnd)); + fracEnd++); + } + else { + pvalue = Integer.parseInt(content.substring(intEnd + 1, len)); + } + } + + // no integer part, no fraction part, error. + if (intStart == intEnd && fracStart == fracEnd) + throw new NumberFormatException(); + + // ignore trailing zeroes in fraction part + /*while (fracEnd > fracStart && content.charAt(fracEnd-1) == '0') { + fracEnd--; + }*/ + + // check whether there is non-digit characters in the fraction part + for (int fracPos = fracStart; fracPos < fracEnd; fracPos++) { + if (!TypeValidator.isDigit(content.charAt(fracPos))) + throw new NumberFormatException(); + } + + intDigits = intEnd - actualIntStart; + fracDigits = fracEnd - fracStart; + + if (intDigits > 0) { + ivalue = content.substring(actualIntStart, intEnd); + } + + if (fracDigits > 0) { + fvalue = content.substring(fracStart, fracEnd); + if(fracEnd < len) { + pvalue = Integer.parseInt(content.substring(fracEnd + 1, len)); + } + } + totalDigits = intDigits + fracDigits; + } + + + public boolean equals(Object val) { + if (val == this) + return true; + + if (!(val instanceof XPrecisionDecimal)) + return false; + XPrecisionDecimal oval = (XPrecisionDecimal)val; + + return this.compareTo(oval) == EQUAL; + } + + /** + * @return + */ + private int compareFractionalPart(XPrecisionDecimal oval) { + if(fvalue.equals(oval.fvalue)) + return EQUAL; + + StringBuffer temp1 = new StringBuffer(fvalue); + StringBuffer temp2 = new StringBuffer(oval.fvalue); + + truncateTrailingZeros(temp1, temp2); + return temp1.toString().compareTo(temp2.toString()); + } + + private void truncateTrailingZeros(StringBuffer fValue, StringBuffer otherFValue) { + for(int i = fValue.length() - 1;i >= 0; i--) + if(fValue.charAt(i) == '0') + fValue.deleteCharAt(i); + else + break; + + for(int i = otherFValue.length() - 1;i >= 0; i--) + if(otherFValue.charAt(i) == '0') + otherFValue.deleteCharAt(i); + else + break; + } + + public int compareTo(XPrecisionDecimal val) { + + // seen NaN + if(sign == 0) + return INDETERMINATE; + + //INF is greater than everything and equal to itself + if(ivalue.equals("INF") || val.ivalue.equals("INF")) { + if(ivalue.equals(val.ivalue)) + return EQUAL; + else if(ivalue.equals("INF")) + return GREATER_THAN; + return LESS_THAN; + } + + //-INF is smaller than everything and equal itself + if(ivalue.equals("-INF") || val.ivalue.equals("-INF")) { + if(ivalue.equals(val.ivalue)) + return EQUAL; + else if(ivalue.equals("-INF")) + return LESS_THAN; + return GREATER_THAN; + } + + if (sign != val.sign) + return sign > val.sign ? GREATER_THAN : LESS_THAN; + + return sign * compare(val); + } + + // To enable comparison - the exponent part of the decimal will be limited + // to the max value of int. + private int compare(XPrecisionDecimal val) { + + if(pvalue != 0 || val.pvalue != 0) { + if(pvalue == val.pvalue) + return intComp(val); + else { + + if(intDigits + pvalue != val.intDigits + val.pvalue) + return intDigits + pvalue > val.intDigits + val.pvalue ? GREATER_THAN : LESS_THAN; + + //otherwise the 2 combined values are the same + if(pvalue > val.pvalue) { + int expDiff = pvalue - val.pvalue; + StringBuffer buffer = new StringBuffer(ivalue); + StringBuffer fbuffer = new StringBuffer(fvalue); + for(int i = 0;i < expDiff; i++) { + if(i < fracDigits) { + buffer.append(fvalue.charAt(i)); + fbuffer.deleteCharAt(i); + } + else + buffer.append('0'); + } + return compareDecimal(buffer.toString(), val.ivalue, fbuffer.toString(), val.fvalue); + } + else { + int expDiff = val.pvalue - pvalue; + StringBuffer buffer = new StringBuffer(val.ivalue); + StringBuffer fbuffer = new StringBuffer(val.fvalue); + for(int i = 0;i < expDiff; i++) { + if(i < val.fracDigits) { + buffer.append(val.fvalue.charAt(i)); + fbuffer.deleteCharAt(i); + } + else + buffer.append('0'); + } + return compareDecimal(ivalue, buffer.toString(), fvalue, fbuffer.toString()); + } + } + } + else { + return intComp(val); + } + } + + /** + * @param val + * @return + */ + private int intComp(XPrecisionDecimal val) { + if (intDigits != val.intDigits) + return intDigits > val.intDigits ? GREATER_THAN : LESS_THAN; + + return compareDecimal(ivalue, val.ivalue, fvalue, val.fvalue); + } + + /** + * @param val + * @return + */ + private int compareDecimal(String iValue, String fValue, String otherIValue, String otherFValue) { + int ret = iValue.compareTo(otherIValue); + if (ret != 0) + return ret > 0 ? GREATER_THAN : LESS_THAN; + + if(fValue.equals(otherFValue)) + return EQUAL; + + StringBuffer temp1=new StringBuffer(fValue); + StringBuffer temp2=new StringBuffer(otherFValue); + + truncateTrailingZeros(temp1, temp2); + ret = temp1.toString().compareTo(temp2.toString()); + return ret == 0 ? EQUAL : (ret > 0 ? GREATER_THAN : LESS_THAN); + } + + private String canonical; + + public synchronized String toString() { + if (canonical == null) { + makeCanonical(); + } + return canonical; + } + + private void makeCanonical() { + // REVISIT: to be determined by working group + canonical = "TBD by Working Group"; + } + + /** + * @param decimal + * @return + */ + public boolean isIdentical(XPrecisionDecimal decimal) { + if(ivalue.equals(decimal.ivalue) && (ivalue.equals("INF") || ivalue.equals("-INF") || ivalue.equals("NaN"))) + return true; + + if(sign == decimal.sign && intDigits == decimal.intDigits && fracDigits == decimal.fracDigits && pvalue == decimal.pvalue + && ivalue.equals(decimal.ivalue) && fvalue.equals(decimal.fvalue)) + return true; + return false; + } + + } + /* (non-Javadoc) + * @see org.apache.xerces.impl.dv.xs.TypeValidator#getAllowedFacets() + */ + public short getAllowedFacets() { + return ( XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE | XSSimpleTypeDecl.FACET_ENUMERATION |XSSimpleTypeDecl.FACET_MAXINCLUSIVE |XSSimpleTypeDecl.FACET_MININCLUSIVE | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE | XSSimpleTypeDecl.FACET_MINEXCLUSIVE | XSSimpleTypeDecl.FACET_TOTALDIGITS | XSSimpleTypeDecl.FACET_FRACTIONDIGITS); + } + + /* (non-Javadoc) + * @see org.apache.xerces.impl.dv.xs.TypeValidator#getActualValue(java.lang.String, org.apache.xerces.impl.dv.ValidationContext) + */ + public Object getActualValue(String content, ValidationContext context) + throws InvalidDatatypeValueException { + try { + return new XPrecisionDecimal(content); + } catch (NumberFormatException nfe) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "precisionDecimal"}); + } + } + + public int compare(Object value1, Object value2) { + return ((XPrecisionDecimal)value1).compareTo((XPrecisionDecimal)value2); + } + + public int getFractionDigits(Object value) { + return ((XPrecisionDecimal)value).fracDigits; + } + + public int getTotalDigits(Object value) { + return ((XPrecisionDecimal)value).totalDigits; + } + + public boolean isIdentical(Object value1, Object value2) { + if(!(value2 instanceof XPrecisionDecimal) || !(value1 instanceof XPrecisionDecimal)) + return false; + return ((XPrecisionDecimal)value1).isIdentical((XPrecisionDecimal)value2); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/QNameDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/QNameDV.java new file mode 100644 index 0000000..1ea2560 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/QNameDV.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.datatypes.XSQName; + +/** + * Represent the schema type "QName" and "NOTATION" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class QNameDV extends TypeValidator { + + private static final String EMPTY_STRING = "".intern(); + + public short getAllowedFacets() { + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE); + } + + public Object getActualValue(String content, ValidationContext context) + throws InvalidDatatypeValueException { + + // "prefix:localpart" or "localpart" + // get prefix and local part out of content + String prefix, localpart; + int colonptr = content.indexOf(":"); + if (colonptr > 0) { + prefix = context.getSymbol(content.substring(0,colonptr)); + localpart = content.substring(colonptr+1); + } else { + prefix = EMPTY_STRING; + localpart = content; + } + + // both prefix (if any) a nd localpart must be valid NCName + if (prefix.length() > 0 && !XMLChar.isValidNCName(prefix)) + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "QName"}); + + if(!XMLChar.isValidNCName(localpart)) + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "QName"}); + + // resove prefix to a uri, report an error if failed + String uri = context.getURI(prefix); + if (prefix.length() > 0 && uri == null) + throw new InvalidDatatypeValueException("UndeclaredPrefix", new Object[]{content, prefix}); + + return new XQName(prefix, context.getSymbol(localpart), context.getSymbol(content), uri); + + } + + // REVISIT: qname and notation shouldn't support length facets. + // now we just return the length of the rawname + public int getDataLength(Object value) { + return ((XQName)value).rawname.length(); + } + + /** + * represent QName data + */ + private static final class XQName extends QName implements XSQName { + /** Constructs a QName with the specified values. */ + public XQName(String prefix, String localpart, String rawname, String uri) { + setValues(prefix, localpart, rawname, uri); + } // (String,String,String,String) + + /** Returns true if the two objects are equal. */ + public boolean equals(Object object) { + if (object instanceof QName) { + QName qname = (QName)object; + return uri == qname.uri && localpart == qname.localpart; + } + return false; + } // equals(Object):boolean + + public String toString() { + return rawname; + } + public javax.xml.namespace.QName getJAXPQName() { + return new javax.xml.namespace.QName(uri, localpart, prefix); + } + public QName getXNIQName() { + return this; + } + } +} // class QNameDVDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/SchemaDVFactoryImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/SchemaDVFactoryImpl.java new file mode 100644 index 0000000..09a1d60 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/SchemaDVFactoryImpl.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.util.SymbolHash; + +/** + * the factory to create/return built-in schema 1.0 DVs and create user-defined DVs + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * @author Khaled Noaman, IBM + * + * @version $Id$ + */ +public class SchemaDVFactoryImpl extends BaseSchemaDVFactory { + + static final SymbolHash fBuiltInTypes = new SymbolHash(); + + static { + createBuiltInTypes(); + } + + // create all built-in types + static void createBuiltInTypes() { + createBuiltInTypes(fBuiltInTypes, XSSimpleTypeDecl.fAnySimpleType); + + // TODO: move specific 1.0 DV implementation from base + } //createBuiltInTypes() + + /** + * Get a built-in simple type of the given name + * REVISIT: its still not decided within the Schema WG how to define the + * ur-types and if all simple types should be derived from a + * complex type, so as of now we ignore the fact that anySimpleType + * is derived from anyType, and pass 'null' as the base of + * anySimpleType. It needs to be changed as per the decision taken. + * + * @param name the name of the datatype + * @return the datatype validator of the given name + */ + public XSSimpleType getBuiltInType(String name) { + return (XSSimpleType)fBuiltInTypes.get(name); + } + + /** + * get all built-in simple types, which are stored in a hashtable keyed by + * the name + * + * @return a hashtable which contains all built-in simple types + */ + public SymbolHash getBuiltInTypes() { + return (SymbolHash)fBuiltInTypes.makeClone(); + } + +}//SchemaDVFactoryImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/SchemaDateTimeException.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/SchemaDateTimeException.java new file mode 100644 index 0000000..7d0d6fd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/SchemaDateTimeException.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public class SchemaDateTimeException extends RuntimeException { + + /** Serialization version. */ + static final long serialVersionUID = -8520832235337769040L; + + public SchemaDateTimeException () { + super(); + } + + public SchemaDateTimeException (String s) { + super (s); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/StringDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/StringDV.java new file mode 100644 index 0000000..5436151 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/StringDV.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Represent the schema type "string" + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class StringDV extends TypeValidator { + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_LENGTH | XSSimpleTypeDecl.FACET_MINLENGTH | XSSimpleTypeDecl.FACET_MAXLENGTH | XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION | XSSimpleTypeDecl.FACET_WHITESPACE ); + } + + public Object getActualValue(String content, ValidationContext context) + throws InvalidDatatypeValueException { + return content; + } + +} // class StringDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/TimeDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/TimeDV.java new file mode 100644 index 0000000..10d4880 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/TimeDV.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Validator for <time> datatype (W3C Schema Datatypes) + * + * @xerces.internal + * + * @author Elena Litani + * @author Gopal Sharma, SUN Microsystem Inc. + * + * @version $Id$ + */ +public class TimeDV extends AbstractDateTimeDV { + + /** + * Convert a string to a compiled form + * + * @param content The lexical representation of time + * @return a valid and normalized time object + */ + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{ + try{ + return parse(content); + } catch(Exception ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "time"}); + } + } + + /** + * Parses, validates and computes normalized version of time object + * + * @param str The lexical representation of time object hh:mm:ss.sss + * with possible time zone Z or (-),(+)hh:mm + * Pattern: "(\\d\\d):(\\d\\d):(\\d\\d)(\\.(\\d)*)?(Z|(([-+])(\\d\\d)(:(\\d\\d))?))?") + * @return normalized time representation + * @exception SchemaDateTimeException Invalid lexical representation + */ + protected DateTimeData parse(String str) throws SchemaDateTimeException{ + DateTimeData date = new DateTimeData(str, this); + int len = str.length(); + + // time + // initialize to default values + date.year=YEAR; + date.month=MONTH; + date.day=15; + getTime(str, 0, len, date); + + //validate and normalize + + validateDateTime(date); + + //save unnormalized values + saveUnnormalized(date); + + if ( date.utc!=0 && date.utc != 'Z') { + normalize(date); + date.day = 15; + } + date.position = 2; + return date; + } + + /** + * Converts time object representation to String + * + * @param date time object + * @return lexical representation of time: hh:mm:ss.sss with an optional time zone sign + */ + protected String dateToString(DateTimeData date) { + StringBuffer message = new StringBuffer(16); + append(message, date.hour, 2); + message.append(':'); + append(message, date.minute, 2); + message.append(':'); + append(message, date.second); + + append(message, (char)date.utc, 0); + return message.toString(); + } + + protected XMLGregorianCalendar getXMLGregorianCalendar(DateTimeData date) { + return datatypeFactory.newXMLGregorianCalendar(null, DatatypeConstants.FIELD_UNDEFINED, + DatatypeConstants.FIELD_UNDEFINED, date.unNormHour, date.unNormMinute, + (int)date.unNormSecond, date.unNormSecond != 0 ? getFractionalSecondsAsBigDecimal(date) : null, + date.hasTimeZone() ? (date.timezoneHr * 60 + date.timezoneMin) : DatatypeConstants.FIELD_UNDEFINED); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/TypeValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/TypeValidator.java new file mode 100644 index 0000000..2a645a2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/TypeValidator.java @@ -0,0 +1,147 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.XMLChar; + +/** + * All primitive types plus ID/IDREF/ENTITY/INTEGER are derived from this abstract + * class. It provides extra information XSSimpleTypeDecl requires from each + * type: allowed facets, converting String to actual value, check equality, + * comparison, etc. + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public abstract class TypeValidator { + + private static final boolean USE_CODE_POINT_COUNT_FOR_STRING_LENGTH = AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + return Boolean.getBoolean("org.apache.xerces.impl.dv.xs.useCodePointCountForStringLength") ? Boolean.TRUE : Boolean.FALSE; + } + catch (SecurityException ex) {} + return Boolean.FALSE; + }}) == Boolean.TRUE; + + // which facets are allowed for this type + public abstract short getAllowedFacets(); + + // convert a string to an actual value. for example, + // for number types (decimal, double, float, and types derived from them), + // get the BigDecimal, Double, Flout object. + // for some types (string and derived), they just return the string itself + public abstract Object getActualValue(String content, ValidationContext context) + throws InvalidDatatypeValueException; + + // for ID/IDREF/ENTITY types, do some extra checking after the value is + // checked to be valid with respect to both lexical representation and + // facets + public void checkExtraRules(Object value, ValidationContext context) throws InvalidDatatypeValueException { + } + + // the following methods might not be supported by every DV. + // but XSSimpleTypeDecl should know which type supports which methods, + // and it's an *internal* error if a method is called on a DV that + // doesn't support it. + + //order constants + public static final short LESS_THAN = -1; + public static final short EQUAL = 0; + public static final short GREATER_THAN = 1; + public static final short INDETERMINATE = 2; + + // where there is distinction between identity and equality, this method + // will be overwritten + // checks whether the two values are identical; for ex, this distinguishes + // -0.0 from 0.0 + public boolean isIdentical (Object value1, Object value2) { + return value1.equals(value2); + } + + // check the order relation between the two values + // the parameters are in compiled form (from getActualValue) + public int compare(Object value1, Object value2) { + return -1; + } + + // get the length of the value + // the parameters are in compiled form (from getActualValue) + public int getDataLength(Object value) { + if (value instanceof String) { + final String str = (String)value; + if (!USE_CODE_POINT_COUNT_FOR_STRING_LENGTH) { + return str.length(); + } + return getCodePointLength(str); + } + return -1; + } + + // get the number of digits of the value + // the parameters are in compiled form (from getActualValue) + public int getTotalDigits(Object value) { + return -1; + } + + // get the number of fraction digits of the value + // the parameters are in compiled form (from getActualValue) + public int getFractionDigits(Object value) { + return -1; + } + + // Returns the length of the string in Unicode code points. + private int getCodePointLength(String value) { + // Count the number of surrogate pairs, and subtract them from + // the total length. + final int len = value.length(); + int surrogatePairCount = 0; + for (int i = 0; i < len - 1; ++i) { + if (XMLChar.isHighSurrogate(value.charAt(i))) { + if (XMLChar.isLowSurrogate(value.charAt(++i))) { + ++surrogatePairCount; + } + else { + --i; + } + } + } + return len - surrogatePairCount; + } + + // check whether the character is in the range 0x30 ~ 0x39 + public static final boolean isDigit(char ch) { + return ch >= '0' && ch <= '9'; + } + + // if the character is in the range 0x30 ~ 0x39, return its int value (0~9), + // otherwise, return -1 + public static final int getDigit(char ch) { + return isDigit(ch) ? ch - '0' : -1; + } + +} // interface TypeValidator diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/UnionDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/UnionDV.java new file mode 100644 index 0000000..89f63ca --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/UnionDV.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Represent the schema union types + * + * @xerces.internal + * + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class UnionDV extends TypeValidator{ + + public short getAllowedFacets(){ + return (XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_ENUMERATION ); + } + + // this method should never be called: XSSimpleTypeDecl is responsible for + // calling the member types for the convertion + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{ + return content; + } + +} // class UnionDV diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/XSSimpleTypeDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/XSSimpleTypeDecl.java new file mode 100644 index 0000000..0e75e13 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/XSSimpleTypeDecl.java @@ -0,0 +1,3487 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import java.math.BigInteger; +import java.util.AbstractList; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.dv.DatatypeException; +import org.apache.xerces.impl.dv.InvalidDatatypeFacetException; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.impl.dv.XSFacets; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xpath.regex.RegularExpression; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.util.ObjectListImpl; +import org.apache.xerces.impl.xs.util.ShortListImpl; +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSFacet; +import org.apache.xerces.xs.XSMultiValueFacet; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObject; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; +import org.apache.xerces.xs.datatypes.ObjectList; +import org.w3c.dom.TypeInfo; + +/** + * @xerces.internal + * + * @author Sandy Gao, IBM + * @author Neeraj Bajaj, Sun Microsystems, inc. + * + * @version $Id$ + */ +public class XSSimpleTypeDecl implements XSSimpleType, TypeInfo { + + protected static final short DV_STRING = PRIMITIVE_STRING; + protected static final short DV_BOOLEAN = PRIMITIVE_BOOLEAN; + protected static final short DV_DECIMAL = PRIMITIVE_DECIMAL; + protected static final short DV_FLOAT = PRIMITIVE_FLOAT; + protected static final short DV_DOUBLE = PRIMITIVE_DOUBLE; + protected static final short DV_DURATION = PRIMITIVE_DURATION; + protected static final short DV_DATETIME = PRIMITIVE_DATETIME; + protected static final short DV_TIME = PRIMITIVE_TIME; + protected static final short DV_DATE = PRIMITIVE_DATE; + protected static final short DV_GYEARMONTH = PRIMITIVE_GYEARMONTH; + protected static final short DV_GYEAR = PRIMITIVE_GYEAR; + protected static final short DV_GMONTHDAY = PRIMITIVE_GMONTHDAY; + protected static final short DV_GDAY = PRIMITIVE_GDAY; + protected static final short DV_GMONTH = PRIMITIVE_GMONTH; + protected static final short DV_HEXBINARY = PRIMITIVE_HEXBINARY; + protected static final short DV_BASE64BINARY = PRIMITIVE_BASE64BINARY; + protected static final short DV_ANYURI = PRIMITIVE_ANYURI; + protected static final short DV_QNAME = PRIMITIVE_QNAME; + protected static final short DV_PRECISIONDECIMAL = PRIMITIVE_PRECISIONDECIMAL; + protected static final short DV_NOTATION = PRIMITIVE_NOTATION; + + protected static final short DV_ANYSIMPLETYPE = 0; + protected static final short DV_ID = DV_NOTATION + 1; + protected static final short DV_IDREF = DV_NOTATION + 2; + protected static final short DV_ENTITY = DV_NOTATION + 3; + protected static final short DV_INTEGER = DV_NOTATION + 4; + protected static final short DV_LIST = DV_NOTATION + 5; + protected static final short DV_UNION = DV_NOTATION + 6; + protected static final short DV_YEARMONTHDURATION = DV_NOTATION + 7; + protected static final short DV_DAYTIMEDURATION = DV_NOTATION + 8; + protected static final short DV_ANYATOMICTYPE = DV_NOTATION + 9; + + private static final TypeValidator[] gDVs = { + new AnySimpleDV(), + new StringDV(), + new BooleanDV(), + new DecimalDV(), + new FloatDV(), + new DoubleDV(), + new DurationDV(), + new DateTimeDV(), + new TimeDV(), + new DateDV(), + new YearMonthDV(), + new YearDV(), + new MonthDayDV(), + new DayDV(), + new MonthDV(), + new HexBinaryDV(), + new Base64BinaryDV(), + new AnyURIDV(), + new QNameDV(), + new PrecisionDecimalDV(), // XML Schema 1.1 type + new QNameDV(), // notation use the same one as qname + new IDDV(), + new IDREFDV(), + new EntityDV(), + new IntegerDV(), + new ListDV(), + new UnionDV(), + new YearMonthDurationDV(), // XML Schema 1.1 type + new DayTimeDurationDV(), // XML Schema 1.1 type + new AnyAtomicDV() // XML Schema 1.1 type + }; + + static final short NORMALIZE_NONE = 0; + static final short NORMALIZE_TRIM = 1; + static final short NORMALIZE_FULL = 2; + static final short[] fDVNormalizeType = { + NORMALIZE_NONE, //AnySimpleDV(), + NORMALIZE_FULL, //StringDV(), + NORMALIZE_TRIM, //BooleanDV(), + NORMALIZE_TRIM, //DecimalDV(), + NORMALIZE_TRIM, //FloatDV(), + NORMALIZE_TRIM, //DoubleDV(), + NORMALIZE_TRIM, //DurationDV(), + NORMALIZE_TRIM, //DateTimeDV(), + NORMALIZE_TRIM, //TimeDV(), + NORMALIZE_TRIM, //DateDV(), + NORMALIZE_TRIM, //YearMonthDV(), + NORMALIZE_TRIM, //YearDV(), + NORMALIZE_TRIM, //MonthDayDV(), + NORMALIZE_TRIM, //DayDV(), + NORMALIZE_TRIM, //MonthDV(), + NORMALIZE_TRIM, //HexBinaryDV(), + NORMALIZE_NONE, //Base64BinaryDV(), // Base64 know how to deal with spaces + NORMALIZE_TRIM, //AnyURIDV(), + NORMALIZE_TRIM, //QNameDV(), + NORMALIZE_TRIM, //PrecisionDecimalDV() (Schema 1.1) + NORMALIZE_TRIM, //QNameDV(), // notation + NORMALIZE_TRIM, //IDDV(), + NORMALIZE_TRIM, //IDREFDV(), + NORMALIZE_TRIM, //EntityDV(), + NORMALIZE_TRIM, //IntegerDV(), + NORMALIZE_FULL, //ListDV(), + NORMALIZE_NONE, //UnionDV(), + NORMALIZE_TRIM, //YearMonthDurationDV() (Schema 1.1) + NORMALIZE_TRIM, //DayTimeDurationDV() (Schema 1.1) + NORMALIZE_NONE, //AnyAtomicDV() (Schema 1.1) + }; + + static final short SPECIAL_PATTERN_NONE = 0; + static final short SPECIAL_PATTERN_NMTOKEN = 1; + static final short SPECIAL_PATTERN_NAME = 2; + static final short SPECIAL_PATTERN_NCNAME = 3; + + static final String[] SPECIAL_PATTERN_STRING = { + "NONE", "NMTOKEN", "Name", "NCName" + }; + + static final String[] WS_FACET_STRING = { + "preserve", "replace", "collapse" + }; + + static final String URI_SCHEMAFORSCHEMA = "http://www.w3.org/2001/XMLSchema"; + static final String ANY_TYPE = "anyType"; + + // XML Schema 1.1 type constants + public static final short YEARMONTHDURATION_DT = 46; + public static final short DAYTIMEDURATION_DT = 47; + public static final short PRECISIONDECIMAL_DT = 48; + public static final short ANYATOMICTYPE_DT = 49; + + // DOM Level 3 TypeInfo Derivation Method constants + static final int DERIVATION_ANY = 0; + static final int DERIVATION_RESTRICTION = 1; + static final int DERIVATION_EXTENSION = 2; + static final int DERIVATION_UNION = 4; + static final int DERIVATION_LIST = 8; + + static final ValidationContext fEmptyContext = new ValidationContext() { + public boolean needFacetChecking() { + return true; + } + public boolean needExtraChecking() { + return false; + } + public boolean needToNormalize() { + return true; + } + public boolean useNamespaces () { + return true; + } + public boolean isEntityDeclared (String name) { + return false; + } + public boolean isEntityUnparsed (String name) { + return false; + } + public boolean isIdDeclared (String name) { + return false; + } + public void addId(String name) { + } + public void addIdRef(String name) { + } + public String getSymbol (String symbol) { + return symbol.intern(); + } + public String getURI(String prefix) { + return null; + } + public Locale getLocale() { + return Locale.getDefault(); + } + }; + + protected static TypeValidator[] getGDVs() { + return (TypeValidator[])gDVs.clone(); + } + private TypeValidator[] fDVs = gDVs; + protected void setDVs(TypeValidator[] dvs) { + fDVs = dvs; + } + + // this will be true if this is a static XSSimpleTypeDecl + // and hence must remain immutable (i.e., applyFacets + // may not be permitted to have any effect). + private boolean fIsImmutable = false; + + private XSSimpleTypeDecl fItemType; + private XSSimpleTypeDecl[] fMemberTypes; + // The most specific built-in type kind. + private short fBuiltInKind; + + private String fTypeName; + private String fTargetNamespace; + private short fFinalSet = 0; + private XSSimpleTypeDecl fBase; + private short fVariety = -1; + private short fValidationDV = -1; + + private short fFacetsDefined = 0; + private short fFixedFacet = 0; + + //for constraining facets + private short fWhiteSpace = 0; + private int fLength = -1; + private int fMinLength = -1; + private int fMaxLength = -1; + private int fTotalDigits = -1; + private int fFractionDigits = -1; + private Vector fPattern; + private Vector fPatternStr; + private ValidatedInfo[] fEnumeration; + private int fEnumerationSize; + private ShortList fEnumerationTypeList; + private ObjectList fEnumerationItemTypeList; + private StringList fLexicalPattern; + private StringList fLexicalEnumeration; + private ObjectList fActualEnumeration; + private Object fMaxInclusive; + private Object fMaxExclusive; + private Object fMinExclusive; + private Object fMinInclusive; + + // annotations for constraining facets + public XSAnnotation lengthAnnotation; + public XSAnnotation minLengthAnnotation; + public XSAnnotation maxLengthAnnotation; + public XSAnnotation whiteSpaceAnnotation; + public XSAnnotation totalDigitsAnnotation; + public XSAnnotation fractionDigitsAnnotation; + public XSObjectListImpl patternAnnotations; + public XSObjectList enumerationAnnotations; + public XSAnnotation maxInclusiveAnnotation; + public XSAnnotation maxExclusiveAnnotation; + public XSAnnotation minInclusiveAnnotation; + public XSAnnotation minExclusiveAnnotation; + + // facets as objects + private XSObjectListImpl fFacets; + + // enumeration and pattern facets + private XSObjectListImpl fMultiValueFacets; + + // simpleType annotations + private XSObjectList fAnnotations = null; + + private short fPatternType = SPECIAL_PATTERN_NONE; + + // for fundamental facets + private short fOrdered; + private boolean fFinite; + private boolean fBounded; + private boolean fNumeric; + + // The namespace schema information item corresponding to the target namespace + // of the simple type definition, if it is globally declared; or null otherwise. + private XSNamespaceItem fNamespaceItem = null; + + // default constructor + public XSSimpleTypeDecl(){} + + //Create a new built-in primitive types (and id/idref/entity/integer/yearMonthDuration) + protected XSSimpleTypeDecl(XSSimpleTypeDecl base, String name, short validateDV, + short ordered, boolean bounded, boolean finite, + boolean numeric, boolean isImmutable, short builtInKind) { + fIsImmutable = isImmutable; + fBase = base; + fTypeName = name; + fTargetNamespace = URI_SCHEMAFORSCHEMA; + // To simplify the code for anySimpleType, we treat it as an atomic type + fVariety = VARIETY_ATOMIC; + fValidationDV = validateDV; + fFacetsDefined = FACET_WHITESPACE; + if (validateDV == DV_ANYSIMPLETYPE || + validateDV == DV_ANYATOMICTYPE || + validateDV == DV_STRING) { + fWhiteSpace = WS_PRESERVE; + } + else { + fWhiteSpace = WS_COLLAPSE; + fFixedFacet = FACET_WHITESPACE; + } + this.fOrdered = ordered; + this.fBounded = bounded; + this.fFinite = finite; + this.fNumeric = numeric; + fAnnotations = null; + + // Specify the build in kind for this primitive type + fBuiltInKind = builtInKind; + } + + //Create a new simple type for restriction for built-in types + protected XSSimpleTypeDecl(XSSimpleTypeDecl base, String name, String uri, short finalSet, boolean isImmutable, + XSObjectList annotations, short builtInKind) { + this(base, name, uri, finalSet, isImmutable, annotations); + // Specify the build in kind for this built-in type + fBuiltInKind = builtInKind; + } + + //Create a new simple type for restriction. + protected XSSimpleTypeDecl(XSSimpleTypeDecl base, String name, String uri, short finalSet, boolean isImmutable, + XSObjectList annotations) { + fBase = base; + fTypeName = name; + fTargetNamespace = uri; + fFinalSet = finalSet; + fAnnotations = annotations; + + fVariety = fBase.fVariety; + fValidationDV = fBase.fValidationDV; + switch (fVariety) { + case VARIETY_ATOMIC: + break; + case VARIETY_LIST: + fItemType = fBase.fItemType; + break; + case VARIETY_UNION: + fMemberTypes = fBase.fMemberTypes; + break; + } + + // always inherit facets from the base. + // in case a type is created, but applyFacets is not called + fLength = fBase.fLength; + fMinLength = fBase.fMinLength; + fMaxLength = fBase.fMaxLength; + fPattern = fBase.fPattern; + fPatternStr = fBase.fPatternStr; + fEnumeration = fBase.fEnumeration; + fEnumerationSize = fBase.fEnumerationSize; + fWhiteSpace = fBase.fWhiteSpace; + fMaxExclusive = fBase.fMaxExclusive; + fMaxInclusive = fBase.fMaxInclusive; + fMinExclusive = fBase.fMinExclusive; + fMinInclusive = fBase.fMinInclusive; + fTotalDigits = fBase.fTotalDigits; + fFractionDigits = fBase.fFractionDigits; + fPatternType = fBase.fPatternType; + fFixedFacet = fBase.fFixedFacet; + fFacetsDefined = fBase.fFacetsDefined; + + // always inherit facet annotations in case applyFacets is not called. + lengthAnnotation = fBase.lengthAnnotation; + minLengthAnnotation = fBase.minLengthAnnotation; + maxLengthAnnotation = fBase.maxLengthAnnotation; + patternAnnotations = fBase.patternAnnotations; + enumerationAnnotations = fBase.enumerationAnnotations; + whiteSpaceAnnotation = fBase.whiteSpaceAnnotation; + maxExclusiveAnnotation = fBase.maxExclusiveAnnotation; + maxInclusiveAnnotation = fBase.maxInclusiveAnnotation; + minExclusiveAnnotation = fBase.minExclusiveAnnotation; + minInclusiveAnnotation = fBase.minInclusiveAnnotation; + totalDigitsAnnotation = fBase.totalDigitsAnnotation; + fractionDigitsAnnotation = fBase.fractionDigitsAnnotation; + + //we also set fundamental facets information in case applyFacets is not called. + calcFundamentalFacets(); + fIsImmutable = isImmutable; + + // Inherit from the base type + fBuiltInKind = base.fBuiltInKind; + } + + //Create a new simple type for list. + protected XSSimpleTypeDecl(String name, String uri, short finalSet, XSSimpleTypeDecl itemType, boolean isImmutable, + XSObjectList annotations) { + fBase = fAnySimpleType; + fTypeName = name; + fTargetNamespace = uri; + fFinalSet = finalSet; + fAnnotations = annotations; + + fVariety = VARIETY_LIST; + fItemType = (XSSimpleTypeDecl)itemType; + fValidationDV = DV_LIST; + fFacetsDefined = FACET_WHITESPACE; + fFixedFacet = FACET_WHITESPACE; + fWhiteSpace = WS_COLLAPSE; + + //setting fundamental facets + calcFundamentalFacets(); + fIsImmutable = isImmutable; + + // Values of this type are lists + fBuiltInKind = XSConstants.LIST_DT; + } + + //Create a new simple type for union. + protected XSSimpleTypeDecl(String name, String uri, short finalSet, XSSimpleTypeDecl[] memberTypes, + XSObjectList annotations) { + fBase = fAnySimpleType; + fTypeName = name; + fTargetNamespace = uri; + fFinalSet = finalSet; + fAnnotations = annotations; + + fVariety = VARIETY_UNION; + fMemberTypes = memberTypes; + fValidationDV = DV_UNION; + // even for union, we set whitespace to something + // this will never be used, but we can use fFacetsDefined to check + // whether applyFacets() is allwwed: it's not allowed + // if fFacetsDefined != 0 + fFacetsDefined = FACET_WHITESPACE; + fWhiteSpace = WS_COLLAPSE; + + //setting fundamental facets + calcFundamentalFacets(); + // none of the schema-defined types are unions, so just set + // fIsImmutable to false. + fIsImmutable = false; + + // No value can be of this type, so it's unavailable. + fBuiltInKind = XSConstants.UNAVAILABLE_DT; + } + + //set values for restriction. + protected XSSimpleTypeDecl setRestrictionValues(XSSimpleTypeDecl base, String name, String uri, short finalSet, + XSObjectList annotations) { + //decline to do anything if the object is immutable. + if(fIsImmutable) return null; + fBase = base; + fAnonymous = false; + fTypeName = name; + fTargetNamespace = uri; + fFinalSet = finalSet; + fAnnotations = annotations; + + fVariety = fBase.fVariety; + fValidationDV = fBase.fValidationDV; + switch (fVariety) { + case VARIETY_ATOMIC: + break; + case VARIETY_LIST: + fItemType = fBase.fItemType; + break; + case VARIETY_UNION: + fMemberTypes = fBase.fMemberTypes; + break; + } + + // always inherit facets from the base. + // in case a type is created, but applyFacets is not called + fLength = fBase.fLength; + fMinLength = fBase.fMinLength; + fMaxLength = fBase.fMaxLength; + fPattern = fBase.fPattern; + fPatternStr = fBase.fPatternStr; + fEnumeration = fBase.fEnumeration; + fEnumerationSize = fBase.fEnumerationSize; + fWhiteSpace = fBase.fWhiteSpace; + fMaxExclusive = fBase.fMaxExclusive; + fMaxInclusive = fBase.fMaxInclusive; + fMinExclusive = fBase.fMinExclusive; + fMinInclusive = fBase.fMinInclusive; + fTotalDigits = fBase.fTotalDigits; + fFractionDigits = fBase.fFractionDigits; + fPatternType = fBase.fPatternType; + fFixedFacet = fBase.fFixedFacet; + fFacetsDefined = fBase.fFacetsDefined; + + //we also set fundamental facets information in case applyFacets is not called. + calcFundamentalFacets(); + + // Inherit from the base type + fBuiltInKind = base.fBuiltInKind; + + return this; + } + + //set values for list. + protected XSSimpleTypeDecl setListValues(String name, String uri, short finalSet, XSSimpleTypeDecl itemType, + XSObjectList annotations) { + //decline to do anything if the object is immutable. + if(fIsImmutable) return null; + fBase = fAnySimpleType; + fAnonymous = false; + fTypeName = name; + fTargetNamespace = uri; + fFinalSet = finalSet; + fAnnotations = annotations; + + fVariety = VARIETY_LIST; + fItemType = (XSSimpleTypeDecl)itemType; + fValidationDV = DV_LIST; + fFacetsDefined = FACET_WHITESPACE; + fFixedFacet = FACET_WHITESPACE; + fWhiteSpace = WS_COLLAPSE; + + //setting fundamental facets + calcFundamentalFacets(); + + // Values of this type are lists + fBuiltInKind = XSConstants.LIST_DT; + + return this; + } + + //set values for union. + protected XSSimpleTypeDecl setUnionValues(String name, String uri, short finalSet, XSSimpleTypeDecl[] memberTypes, + XSObjectList annotations) { + //decline to do anything if the object is immutable. + if(fIsImmutable) return null; + fBase = fAnySimpleType; + fAnonymous = false; + fTypeName = name; + fTargetNamespace = uri; + fFinalSet = finalSet; + fAnnotations = annotations; + + fVariety = VARIETY_UNION; + fMemberTypes = memberTypes; + fValidationDV = DV_UNION; + // even for union, we set whitespace to something + // this will never be used, but we can use fFacetsDefined to check + // whether applyFacets() is allwwed: it's not allowed + // if fFacetsDefined != 0 + fFacetsDefined = FACET_WHITESPACE; + fWhiteSpace = WS_COLLAPSE; + + //setting fundamental facets + calcFundamentalFacets(); + + // No value can be of this type, so it's unavailable. + fBuiltInKind = XSConstants.UNAVAILABLE_DT; + + return this; + } + + public short getType () { + return XSConstants.TYPE_DEFINITION; + } + + public short getTypeCategory () { + return SIMPLE_TYPE; + } + + public String getName() { + return getAnonymous()?null:fTypeName; + } + + public String getTypeName() { + return fTypeName; + } + + public String getNamespace() { + return fTargetNamespace; + } + + public short getFinal(){ + return fFinalSet; + } + + public boolean isFinal(short derivation) { + return (fFinalSet & derivation) != 0; + } + + public XSTypeDefinition getBaseType(){ + return fBase; + } + + public boolean getAnonymous() { + return fAnonymous || (fTypeName == null); + } + + public short getVariety(){ + // for anySimpleType, return absent variaty + return fValidationDV == DV_ANYSIMPLETYPE ? VARIETY_ABSENT : fVariety; + } + + public boolean isIDType(){ + switch (fVariety) { + case VARIETY_ATOMIC: + return fValidationDV == DV_ID; + case VARIETY_LIST: + return fItemType.isIDType(); + case VARIETY_UNION: + for (int i = 0; i < fMemberTypes.length; i++) { + if (fMemberTypes[i].isIDType()) + return true; + } + } + return false; + } + + public short getWhitespace() throws DatatypeException{ + if (fVariety == VARIETY_UNION) { + throw new DatatypeException("dt-whitespace", new Object[]{fTypeName}); + } + return fWhiteSpace; + } + + public short getPrimitiveKind() { + if (fVariety == VARIETY_ATOMIC && fValidationDV != DV_ANYSIMPLETYPE) { + if (fValidationDV == DV_ID || fValidationDV == DV_IDREF || fValidationDV == DV_ENTITY) { + return DV_STRING; + } + else if (fValidationDV == DV_INTEGER) { + return DV_DECIMAL; + } + else if (Constants.SCHEMA_1_1_SUPPORT && (fValidationDV == DV_YEARMONTHDURATION || fValidationDV == DV_DAYTIMEDURATION)) { + return DV_DURATION; + } + else { + return fValidationDV; + } + } + else { + // REVISIT: error situation. runtime exception? + return (short)0; + } + } + + /** + * Returns the closest built-in type category this type represents or + * derived from. For example, if this simple type is a built-in derived + * type integer the INTEGER_DV is returned. + */ + public short getBuiltInKind() { + return this.fBuiltInKind; + } + + /** + * If variety is atomic the primitive type definition (a + * built-in primitive datatype definition or the simple ur-type + * definition) is available, otherwise null. + */ + public XSSimpleTypeDefinition getPrimitiveType() { + if (fVariety == VARIETY_ATOMIC && fValidationDV != DV_ANYSIMPLETYPE) { + XSSimpleTypeDecl pri = this; + // recursively get base, until we reach anySimpleType + while (pri.fBase != fAnySimpleType) + pri = pri.fBase; + return pri; + } + else { + // REVISIT: error situation. runtime exception? + return null; + } + } + + /** + * If variety is list the item type definition (an atomic or + * union simple type definition) is available, otherwise + * null. + */ + public XSSimpleTypeDefinition getItemType() { + if (fVariety == VARIETY_LIST) { + return fItemType; + } + else { + // REVISIT: error situation. runtime exception? + return null; + } + } + + /** + * If variety is union the list of member type definitions (a + * non-empty sequence of simple type definitions) is available, + * otherwise an empty XSObjectList. + */ + public XSObjectList getMemberTypes() { + if (fVariety == VARIETY_UNION) { + return new XSObjectListImpl(fMemberTypes, fMemberTypes.length); + } + else { + return XSObjectListImpl.EMPTY_LIST; + } + } + + /** + * If is chosen + */ + public void applyFacets(XSFacets facets, short presentFacet, short fixedFacet, ValidationContext context) + throws InvalidDatatypeFacetException { + if (context == null) { + context = fEmptyContext; + } + applyFacets(facets, presentFacet, fixedFacet, SPECIAL_PATTERN_NONE, context); + } + + /** + * built-in derived types by restriction + */ + void applyFacets1(XSFacets facets, short presentFacet, short fixedFacet) { + + try { + applyFacets(facets, presentFacet, fixedFacet, SPECIAL_PATTERN_NONE, fDummyContext); + } catch (InvalidDatatypeFacetException e) { + // should never gets here, internel error + throw new RuntimeException("internal error"); + } + // we've now applied facets; so lock this object: + fIsImmutable = true; + } + + /** + * built-in derived types by restriction + */ + void applyFacets1(XSFacets facets, short presentFacet, short fixedFacet, short patternType) { + + try { + applyFacets(facets, presentFacet, fixedFacet, patternType, fDummyContext); + } catch (InvalidDatatypeFacetException e) { + // should never gets here, internel error + throw new RuntimeException("internal error"); + } + // we've now applied facets; so lock this object: + fIsImmutable = true; + } + + /** + * If is chosen, or built-in derived types by restriction + */ + void applyFacets(XSFacets facets, short presentFacet, short fixedFacet, short patternType, ValidationContext context) + throws InvalidDatatypeFacetException { + + // if the object is immutable, should not apply facets... + if(fIsImmutable) return; + ValidatedInfo tempInfo = new ValidatedInfo(); + + // clear facets. because we always inherit facets in the constructor + // REVISIT: in fact, we don't need to clear them. + // we can convert 5 string values (4 bounds + 1 enum) to actual values, + // store them somewhere, then do facet checking at once, instead of + // going through the following steps. (lots of checking are redundant: + // for example, ((presentFacet & FACET_XXX) != 0)) + + fFacetsDefined = 0; + fFixedFacet = 0; + + int result = 0 ; + + // step 1: parse present facets + short allowedFacet = fDVs[fValidationDV].getAllowedFacets(); + + // length + if ((presentFacet & FACET_LENGTH) != 0) { + if ((allowedFacet & FACET_LENGTH) == 0) { + reportError("cos-applicable-facets", new Object[]{"length", fTypeName}); + } else { + fLength = facets.length; + lengthAnnotation = facets.lengthAnnotation; + fFacetsDefined |= FACET_LENGTH; + if ((fixedFacet & FACET_LENGTH) != 0) + fFixedFacet |= FACET_LENGTH; + } + } + // minLength + if ((presentFacet & FACET_MINLENGTH) != 0) { + if ((allowedFacet & FACET_MINLENGTH) == 0) { + reportError("cos-applicable-facets", new Object[]{"minLength", fTypeName}); + } else { + fMinLength = facets.minLength; + minLengthAnnotation = facets.minLengthAnnotation; + fFacetsDefined |= FACET_MINLENGTH; + if ((fixedFacet & FACET_MINLENGTH) != 0) + fFixedFacet |= FACET_MINLENGTH; + } + } + // maxLength + if ((presentFacet & FACET_MAXLENGTH) != 0) { + if ((allowedFacet & FACET_MAXLENGTH) == 0) { + reportError("cos-applicable-facets", new Object[]{"maxLength", fTypeName}); + } else { + fMaxLength = facets.maxLength; + maxLengthAnnotation = facets.maxLengthAnnotation; + fFacetsDefined |= FACET_MAXLENGTH; + if ((fixedFacet & FACET_MAXLENGTH) != 0) + fFixedFacet |= FACET_MAXLENGTH; + } + } + // pattern + if ((presentFacet & FACET_PATTERN) != 0) { + if ((allowedFacet & FACET_PATTERN) == 0) { + reportError("cos-applicable-facets", new Object[]{"pattern", fTypeName}); + } else { + patternAnnotations = facets.patternAnnotations; + RegularExpression regex = null; + try { + regex = new RegularExpression(facets.pattern, "X", context.getLocale()); + } catch (Exception e) { + reportError("InvalidRegex", new Object[]{facets.pattern, e.getLocalizedMessage()}); + } + if (regex != null) { + fPattern = new Vector(); + fPattern.addElement(regex); + fPatternStr = new Vector(); + fPatternStr.addElement(facets.pattern); + fFacetsDefined |= FACET_PATTERN; + if ((fixedFacet & FACET_PATTERN) != 0) + fFixedFacet |= FACET_PATTERN; + } + } + } + + // whiteSpace + if ((presentFacet & FACET_WHITESPACE) != 0) { + if ((allowedFacet & FACET_WHITESPACE) == 0) { + reportError("cos-applicable-facets", new Object[]{"whiteSpace", fTypeName}); + } else { + fWhiteSpace = facets.whiteSpace; + whiteSpaceAnnotation = facets.whiteSpaceAnnotation; + fFacetsDefined |= FACET_WHITESPACE; + if ((fixedFacet & FACET_WHITESPACE) != 0) + fFixedFacet |= FACET_WHITESPACE; + } + } + // enumeration + if ((presentFacet & FACET_ENUMERATION) != 0) { + if ((allowedFacet & FACET_ENUMERATION) == 0) { + reportError("cos-applicable-facets", new Object[]{"enumeration", fTypeName}); + } else { + Vector enumVals = facets.enumeration; + int size = enumVals.size(); + fEnumeration = new ValidatedInfo[size]; + Vector enumNSDecls = facets.enumNSDecls; + ValidationContextImpl ctx = new ValidationContextImpl(context); + enumerationAnnotations = facets.enumAnnotations; + fEnumerationSize = 0; + for (int i = 0; i < size; i++) { + if (enumNSDecls != null) + ctx.setNSContext((NamespaceContext)enumNSDecls.elementAt(i)); + try { + ValidatedInfo info = getActualEnumValue((String)enumVals.elementAt(i), ctx, null); + // check 4.3.5.c0 must: enumeration values from the value space of base + fEnumeration[fEnumerationSize++] = info; + } catch (InvalidDatatypeValueException ide) { + reportError("enumeration-valid-restriction", new Object[]{enumVals.elementAt(i), this.getBaseType().getName()}); + } + } + fFacetsDefined |= FACET_ENUMERATION; + if ((fixedFacet & FACET_ENUMERATION) != 0) + fFixedFacet |= FACET_ENUMERATION; + } + } + + // maxInclusive + if ((presentFacet & FACET_MAXINCLUSIVE) != 0) { + if ((allowedFacet & FACET_MAXINCLUSIVE) == 0) { + reportError("cos-applicable-facets", new Object[]{"maxInclusive", fTypeName}); + } else { + maxInclusiveAnnotation = facets.maxInclusiveAnnotation; + try { + fMaxInclusive = fBase.getActualValue(facets.maxInclusive, context, tempInfo, true); + fFacetsDefined |= FACET_MAXINCLUSIVE; + if ((fixedFacet & FACET_MAXINCLUSIVE) != 0) + fFixedFacet |= FACET_MAXINCLUSIVE; + } catch (InvalidDatatypeValueException ide) { + reportError(ide.getKey(), ide.getArgs()); + reportError("FacetValueFromBase", new Object[]{fTypeName, facets.maxInclusive, + "maxInclusive", fBase.getName()}); + } + + // check against fixed value in base + if (((fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + if ((fBase.fFixedFacet & FACET_MAXINCLUSIVE) != 0) { + if (fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMaxInclusive) != 0) + reportError( "FixedFacetValue", new Object[]{"maxInclusive", fMaxInclusive, fBase.fMaxInclusive, fTypeName}); + } + } + // maxInclusive from base + try { + fBase.validate(context, tempInfo); + } catch (InvalidDatatypeValueException ide) { + reportError(ide.getKey(), ide.getArgs()); + reportError("FacetValueFromBase", new Object[]{fTypeName, facets.maxInclusive, + "maxInclusive", fBase.getName()}); + } + } + } + + // maxExclusive + boolean needCheckBase = true; + if ((presentFacet & FACET_MAXEXCLUSIVE) != 0) { + if ((allowedFacet & FACET_MAXEXCLUSIVE) == 0) { + reportError("cos-applicable-facets", new Object[]{"maxExclusive", fTypeName}); + } else { + maxExclusiveAnnotation = facets.maxExclusiveAnnotation; + try { + fMaxExclusive = fBase.getActualValue(facets.maxExclusive, context, tempInfo, true); + fFacetsDefined |= FACET_MAXEXCLUSIVE; + if ((fixedFacet & FACET_MAXEXCLUSIVE) != 0) + fFixedFacet |= FACET_MAXEXCLUSIVE; + } catch (InvalidDatatypeValueException ide) { + reportError(ide.getKey(), ide.getArgs()); + reportError("FacetValueFromBase", new Object[]{fTypeName, facets.maxExclusive, + "maxExclusive", fBase.getName()}); + } + + // check against fixed value in base + if (((fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0)) { + result = fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMaxExclusive); + if ((fBase.fFixedFacet & FACET_MAXEXCLUSIVE) != 0 && result != 0) { + reportError( "FixedFacetValue", new Object[]{"maxExclusive", facets.maxExclusive, fBase.fMaxExclusive, fTypeName}); + } + if (result == 0) { + needCheckBase = false; + } + } + // maxExclusive from base + if (needCheckBase) { + try { + fBase.validate(context, tempInfo); + } catch (InvalidDatatypeValueException ide) { + reportError(ide.getKey(), ide.getArgs()); + reportError("FacetValueFromBase", new Object[]{fTypeName, facets.maxExclusive, + "maxExclusive", fBase.getName()}); + } + } + // If maxExclusive == base.maxExclusive, then we only need to check + // maxExclusive <= base.maxInclusive + else if (((fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + if (fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMaxInclusive) > 0) { + reportError( "maxExclusive-valid-restriction.2", new Object[]{facets.maxExclusive, fBase.fMaxInclusive}); + } + } + } + } + // minExclusive + needCheckBase = true; + if ((presentFacet & FACET_MINEXCLUSIVE) != 0) { + if ((allowedFacet & FACET_MINEXCLUSIVE) == 0) { + reportError("cos-applicable-facets", new Object[]{"minExclusive", fTypeName}); + } else { + minExclusiveAnnotation = facets.minExclusiveAnnotation; + try { + fMinExclusive = fBase.getActualValue(facets.minExclusive, context, tempInfo, true); + fFacetsDefined |= FACET_MINEXCLUSIVE; + if ((fixedFacet & FACET_MINEXCLUSIVE) != 0) + fFixedFacet |= FACET_MINEXCLUSIVE; + } catch (InvalidDatatypeValueException ide) { + reportError(ide.getKey(), ide.getArgs()); + reportError("FacetValueFromBase", new Object[]{fTypeName, facets.minExclusive, + "minExclusive", fBase.getName()}); + } + + // check against fixed value in base + if (((fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) { + result = fDVs[fValidationDV].compare(fMinExclusive, fBase.fMinExclusive); + if ((fBase.fFixedFacet & FACET_MINEXCLUSIVE) != 0 && result != 0) { + reportError( "FixedFacetValue", new Object[]{"minExclusive", facets.minExclusive, fBase.fMinExclusive, fTypeName}); + } + if (result == 0) { + needCheckBase = false; + } + } + // minExclusive from base + if (needCheckBase) { + try { + fBase.validate(context, tempInfo); + } catch (InvalidDatatypeValueException ide) { + reportError(ide.getKey(), ide.getArgs()); + reportError("FacetValueFromBase", new Object[]{fTypeName, facets.minExclusive, + "minExclusive", fBase.getName()}); + } + } + // If minExclusive == base.minExclusive, then we only need to check + // minExclusive >= base.minInclusive + else if (((fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + if (fDVs[fValidationDV].compare(fMinExclusive, fBase.fMinInclusive) < 0) { + reportError( "minExclusive-valid-restriction.3", new Object[]{facets.minExclusive, fBase.fMinInclusive}); + } + } + } + } + // minInclusive + if ((presentFacet & FACET_MININCLUSIVE) != 0) { + if ((allowedFacet & FACET_MININCLUSIVE) == 0) { + reportError("cos-applicable-facets", new Object[]{"minInclusive", fTypeName}); + } else { + minInclusiveAnnotation = facets.minInclusiveAnnotation; + try { + fMinInclusive = fBase.getActualValue(facets.minInclusive, context, tempInfo, true); + fFacetsDefined |= FACET_MININCLUSIVE; + if ((fixedFacet & FACET_MININCLUSIVE) != 0) + fFixedFacet |= FACET_MININCLUSIVE; + } catch (InvalidDatatypeValueException ide) { + reportError(ide.getKey(), ide.getArgs()); + reportError("FacetValueFromBase", new Object[]{fTypeName, facets.minInclusive, + "minInclusive", fBase.getName()}); + } + + // check against fixed value in base + if (((fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + if ((fBase.fFixedFacet & FACET_MININCLUSIVE) != 0) { + if (fDVs[fValidationDV].compare(fMinInclusive, fBase.fMinInclusive) != 0) + reportError( "FixedFacetValue", new Object[]{"minInclusive", facets.minInclusive, fBase.fMinInclusive, fTypeName}); + } + } + // minInclusive from base + try { + fBase.validate(context, tempInfo); + } catch (InvalidDatatypeValueException ide) { + reportError(ide.getKey(), ide.getArgs()); + reportError("FacetValueFromBase", new Object[]{fTypeName, facets.minInclusive, + "minInclusive", fBase.getName()}); + } + } + } + + // totalDigits + if ((presentFacet & FACET_TOTALDIGITS) != 0) { + if ((allowedFacet & FACET_TOTALDIGITS) == 0) { + reportError("cos-applicable-facets", new Object[]{"totalDigits", fTypeName}); + } else { + totalDigitsAnnotation = facets.totalDigitsAnnotation; + fTotalDigits = facets.totalDigits; + fFacetsDefined |= FACET_TOTALDIGITS; + if ((fixedFacet & FACET_TOTALDIGITS) != 0) + fFixedFacet |= FACET_TOTALDIGITS; + } + } + // fractionDigits + if ((presentFacet & FACET_FRACTIONDIGITS) != 0) { + if ((allowedFacet & FACET_FRACTIONDIGITS) == 0) { + reportError("cos-applicable-facets", new Object[]{"fractionDigits", fTypeName}); + } else { + fFractionDigits = facets.fractionDigits; + fractionDigitsAnnotation = facets.fractionDigitsAnnotation; + fFacetsDefined |= FACET_FRACTIONDIGITS; + if ((fixedFacet & FACET_FRACTIONDIGITS) != 0) + fFixedFacet |= FACET_FRACTIONDIGITS; + } + } + + // token type: internal use, so do less checking + if (patternType != SPECIAL_PATTERN_NONE) { + fPatternType = patternType; + } + + // step 2: check facets against each other: length, bounds + if(fFacetsDefined != 0) { + + // check 4.3.2.c1 must: minLength <= maxLength + if(((fFacetsDefined & FACET_MINLENGTH ) != 0 ) && ((fFacetsDefined & FACET_MAXLENGTH) != 0)) + { + if(fMinLength > fMaxLength) + reportError("minLength-less-than-equal-to-maxLength", new Object[]{Integer.toString(fMinLength), Integer.toString(fMaxLength), fTypeName}); + } + + // check 4.3.8.c1 error: maxInclusive + maxExclusive + if (((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && ((fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + reportError( "maxInclusive-maxExclusive", new Object[]{fMaxInclusive, fMaxExclusive, fTypeName}); + } + + // check 4.3.9.c1 error: minInclusive + minExclusive + if (((fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && ((fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + reportError("minInclusive-minExclusive", new Object[]{fMinInclusive, fMinExclusive, fTypeName}); + } + + // check 4.3.7.c1 must: minInclusive <= maxInclusive + if (((fFacetsDefined & FACET_MAXINCLUSIVE) != 0) && ((fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + result = fDVs[fValidationDV].compare(fMinInclusive, fMaxInclusive); + if (result != -1 && result != 0) + reportError("minInclusive-less-than-equal-to-maxInclusive", new Object[]{fMinInclusive, fMaxInclusive, fTypeName}); + } + + // check 4.3.8.c2 must: minExclusive <= maxExclusive ??? minExclusive < maxExclusive + if (((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && ((fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) { + result = fDVs[fValidationDV].compare(fMinExclusive, fMaxExclusive); + if (result != -1 && result != 0) + reportError( "minExclusive-less-than-equal-to-maxExclusive", new Object[]{fMinExclusive, fMaxExclusive, fTypeName}); + } + + // check 4.3.9.c2 must: minExclusive < maxInclusive + if (((fFacetsDefined & FACET_MAXINCLUSIVE) != 0) && ((fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) { + if (fDVs[fValidationDV].compare(fMinExclusive, fMaxInclusive) != -1) + reportError( "minExclusive-less-than-maxInclusive", new Object[]{fMinExclusive, fMaxInclusive, fTypeName}); + } + + // check 4.3.10.c1 must: minInclusive < maxExclusive + if (((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && ((fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + if (fDVs[fValidationDV].compare(fMinInclusive, fMaxExclusive) != -1) + reportError( "minInclusive-less-than-maxExclusive", new Object[]{fMinInclusive, fMaxExclusive, fTypeName}); + } + + // check 4.3.12.c1 must: fractionDigits <= totalDigits + if (((fFacetsDefined & FACET_FRACTIONDIGITS) != 0) && + ((fFacetsDefined & FACET_TOTALDIGITS) != 0)) { + if (fFractionDigits > fTotalDigits) + reportError( "fractionDigits-totalDigits", new Object[]{Integer.toString(fFractionDigits), Integer.toString(fTotalDigits), fTypeName}); + } + + // step 3: check facets against base + // check 4.3.1.c1 error: length & (fBase.maxLength | fBase.minLength) + if((fFacetsDefined & FACET_LENGTH) != 0 ){ + if ((fBase.fFacetsDefined & FACET_MINLENGTH) != 0 && + fLength < fBase.fMinLength) { + // length, fBase.minLength and fBase.maxLength defined + reportError("length-minLength-maxLength.1.1", new Object[]{fTypeName, Integer.toString(fLength), Integer.toString(fBase.fMinLength)}); + } + if ((fBase.fFacetsDefined & FACET_MAXLENGTH) != 0 && + fLength > fBase.fMaxLength) { + // length and fBase.maxLength defined + reportError("length-minLength-maxLength.2.1", new Object[]{fTypeName, Integer.toString(fLength), Integer.toString(fBase.fMaxLength)}); + } + if ( (fBase.fFacetsDefined & FACET_LENGTH) != 0 ) { + // check 4.3.1.c2 error: length != fBase.length + if ( fLength != fBase.fLength ) + reportError( "length-valid-restriction", new Object[]{Integer.toString(fLength), Integer.toString(fBase.fLength), fTypeName}); + } + } + + // check 4.3.1.c1 error: fBase.length & (maxLength | minLength) + if((fBase.fFacetsDefined & FACET_LENGTH) != 0 || (fFacetsDefined & FACET_LENGTH) != 0){ + if ((fFacetsDefined & FACET_MINLENGTH) != 0){ + if (fBase.fLength < fMinLength) { + // fBase.length, minLength and maxLength defined + reportError("length-minLength-maxLength.1.1", new Object[]{fTypeName, Integer.toString(fBase.fLength), Integer.toString(fMinLength)}); + } + if ((fBase.fFacetsDefined & FACET_MINLENGTH) == 0){ + reportError("length-minLength-maxLength.1.2.a", new Object[]{fTypeName}); + } + if (fMinLength != fBase.fMinLength){ + reportError("length-minLength-maxLength.1.2.b", new Object[]{fTypeName, Integer.toString(fMinLength), Integer.toString(fBase.fMinLength)}); + } + } + if ((fFacetsDefined & FACET_MAXLENGTH) != 0){ + if (fBase.fLength > fMaxLength) { + // fBase.length, minLength and maxLength defined + reportError("length-minLength-maxLength.2.1", new Object[]{fTypeName, Integer.toString(fBase.fLength), Integer.toString(fMaxLength)}); + } + if ((fBase.fFacetsDefined & FACET_MAXLENGTH) == 0){ + reportError("length-minLength-maxLength.2.2.a", new Object[]{fTypeName}); + } + if (fMaxLength != fBase.fMaxLength){ + reportError("length-minLength-maxLength.2.2.b", new Object[]{fTypeName, Integer.toString(fMaxLength), Integer.toString(fBase.fBase.fMaxLength)}); + } + } + } + + // check 4.3.2.c1 must: minLength <= fBase.maxLength + if ( ((fFacetsDefined & FACET_MINLENGTH ) != 0 ) ) { + if ( (fBase.fFacetsDefined & FACET_MAXLENGTH ) != 0 ) { + if ( fMinLength > fBase.fMaxLength ) { + reportError("minLength-less-than-equal-to-maxLength", new Object[]{Integer.toString(fMinLength), Integer.toString(fBase.fMaxLength), fTypeName}); + } + } + else if ( (fBase.fFacetsDefined & FACET_MINLENGTH) != 0 ) { + if ( (fBase.fFixedFacet & FACET_MINLENGTH) != 0 && fMinLength != fBase.fMinLength ) { + reportError( "FixedFacetValue", new Object[]{"minLength", Integer.toString(fMinLength), Integer.toString(fBase.fMinLength), fTypeName}); + } + + // check 4.3.2.c2 error: minLength < fBase.minLength + if ( fMinLength < fBase.fMinLength ) { + reportError( "minLength-valid-restriction", new Object[]{Integer.toString(fMinLength), Integer.toString(fBase.fMinLength), fTypeName}); + } + } + } + + + // check 4.3.2.c1 must: maxLength < fBase.minLength + if ( ((fFacetsDefined & FACET_MAXLENGTH ) != 0 ) && ((fBase.fFacetsDefined & FACET_MINLENGTH ) != 0 )) { + if ( fMaxLength < fBase.fMinLength) { + reportError("minLength-less-than-equal-to-maxLength", new Object[]{Integer.toString(fBase.fMinLength), Integer.toString(fMaxLength)}); + } + } + + // check 4.3.3.c1 error: maxLength > fBase.maxLength + if ( (fFacetsDefined & FACET_MAXLENGTH) != 0 ) { + if ( (fBase.fFacetsDefined & FACET_MAXLENGTH) != 0 ){ + if(( (fBase.fFixedFacet & FACET_MAXLENGTH) != 0 )&& fMaxLength != fBase.fMaxLength ) { + reportError( "FixedFacetValue", new Object[]{"maxLength", Integer.toString(fMaxLength), Integer.toString(fBase.fMaxLength), fTypeName}); + } + if ( fMaxLength > fBase.fMaxLength ) { + reportError( "maxLength-valid-restriction", new Object[]{Integer.toString(fMaxLength), Integer.toString(fBase.fMaxLength), fTypeName}); + } + } + } + + /* // check 4.3.7.c2 error: + // maxInclusive > fBase.maxInclusive + // maxInclusive >= fBase.maxExclusive + // maxInclusive < fBase.minInclusive + // maxInclusive <= fBase.minExclusive + + if (((fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + if (((fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + result = fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMaxInclusive); + if ((fBase.fFixedFacet & FACET_MAXINCLUSIVE) != 0 && result != 0) { + reportError( "FixedFacetValue", new Object[]{"maxInclusive", fMaxInclusive, fBase.fMaxInclusive, fTypeName}); + } + if (result != -1 && result != 0) { + reportError( "maxInclusive-valid-restriction.1", new Object[]{fMaxInclusive, fBase.fMaxInclusive, fTypeName}); + } + } + if (((fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && + fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMaxExclusive) != -1){ + reportError( "maxInclusive-valid-restriction.1", new Object[]{fMaxInclusive, fBase.fMaxExclusive, fTypeName}); + } + + if ((( fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + result = fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMinInclusive); + if (result != 1 && result != 0) { + reportError( "maxInclusive-valid-restriction.1", new Object[]{fMaxInclusive, fBase.fMinInclusive, fTypeName}); + } + } + + if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && + fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMinExclusive ) != 1) + reportError( "maxInclusive-valid-restriction.1", new Object[]{fMaxInclusive, fBase.fMinExclusive, fTypeName}); + } + + // check 4.3.8.c3 error: + // maxExclusive > fBase.maxExclusive + // maxExclusive > fBase.maxInclusive + // maxExclusive <= fBase.minInclusive + // maxExclusive <= fBase.minExclusive + if (((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0)) { + if ((( fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0)) { + result= fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMaxExclusive); + if ((fBase.fFixedFacet & FACET_MAXEXCLUSIVE) != 0 && result != 0) { + reportError( "FixedFacetValue", new Object[]{"maxExclusive", fMaxExclusive, fBase.fMaxExclusive, fTypeName}); + } + if (result != -1 && result != 0) { + reportError( "maxExclusive-valid-restriction.1", new Object[]{fMaxExclusive, fBase.fMaxExclusive, fTypeName}); + } + } + + if ((( fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + result= fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMaxInclusive); + if (result != -1 && result != 0) { + reportError( "maxExclusive-valid-restriction.2", new Object[]{fMaxExclusive, fBase.fMaxInclusive, fTypeName}); + } + } + + if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && + fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMinExclusive ) != 1) + reportError( "maxExclusive-valid-restriction.3", new Object[]{fMaxExclusive, fBase.fMinExclusive, fTypeName}); + + if ((( fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0) && + fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMinInclusive) != 1) + reportError( "maxExclusive-valid-restriction.4", new Object[]{fMaxExclusive, fBase.fMinInclusive, fTypeName}); + } + + // check 4.3.9.c3 error: + // minExclusive < fBase.minExclusive + // minExclusive > fBase.maxInclusive + // minExclusive < fBase.minInclusive + // minExclusive >= fBase.maxExclusive + if (((fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) { + if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) { + result= fDVs[fValidationDV].compare(fMinExclusive, fBase.fMinExclusive); + if ((fBase.fFixedFacet & FACET_MINEXCLUSIVE) != 0 && result != 0) { + reportError( "FixedFacetValue", new Object[]{"minExclusive", fMinExclusive, fBase.fMinExclusive, fTypeName}); + } + if (result != 1 && result != 0) { + reportError( "minExclusive-valid-restriction.1", new Object[]{fMinExclusive, fBase.fMinExclusive, fTypeName}); + } + } + + if ((( fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + result=fDVs[fValidationDV].compare(fMinExclusive, fBase.fMaxInclusive); + + if (result != -1 && result != 0) { + reportError( "minExclusive-valid-restriction.2", new Object[]{fMinExclusive, fBase.fMaxInclusive, fTypeName}); + } + } + + if ((( fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + result = fDVs[fValidationDV].compare(fMinExclusive, fBase.fMinInclusive); + + if (result != 1 && result != 0) { + reportError( "minExclusive-valid-restriction.3", new Object[]{fMinExclusive, fBase.fMinInclusive, fTypeName}); + } + } + + if ((( fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && + fDVs[fValidationDV].compare(fMinExclusive, fBase.fMaxExclusive) != -1) + reportError( "minExclusive-valid-restriction.4", new Object[]{fMinExclusive, fBase.fMaxExclusive, fTypeName}); + } + + // check 4.3.10.c2 error: + // minInclusive < fBase.minInclusive + // minInclusive > fBase.maxInclusive + // minInclusive <= fBase.minExclusive + // minInclusive >= fBase.maxExclusive + if (((fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + if (((fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + result = fDVs[fValidationDV].compare(fMinInclusive, fBase.fMinInclusive); + + if ((fBase.fFixedFacet & FACET_MININCLUSIVE) != 0 && result != 0) { + reportError( "FixedFacetValue", new Object[]{"minInclusive", fMinInclusive, fBase.fMinInclusive, fTypeName}); + } + if (result != 1 && result != 0) { + reportError( "minInclusive-valid-restriction.1", new Object[]{fMinInclusive, fBase.fMinInclusive, fTypeName}); + } + } + if ((( fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + result=fDVs[fValidationDV].compare(fMinInclusive, fBase.fMaxInclusive); + if (result != -1 && result != 0) { + reportError( "minInclusive-valid-restriction.2", new Object[]{fMinInclusive, fBase.fMaxInclusive, fTypeName}); + } + } + if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && + fDVs[fValidationDV].compare(fMinInclusive, fBase.fMinExclusive ) != 1) + reportError( "minInclusive-valid-restriction.3", new Object[]{fMinInclusive, fBase.fMinExclusive, fTypeName}); + if ((( fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && + fDVs[fValidationDV].compare(fMinInclusive, fBase.fMaxExclusive) != -1) + reportError( "minInclusive-valid-restriction.4", new Object[]{fMinInclusive, fBase.fMaxExclusive, fTypeName}); + } + */ + // check 4.3.11.c1 error: totalDigits > fBase.totalDigits + if (((fFacetsDefined & FACET_TOTALDIGITS) != 0)) { + if ((( fBase.fFacetsDefined & FACET_TOTALDIGITS) != 0)) { + if ((fBase.fFixedFacet & FACET_TOTALDIGITS) != 0 && fTotalDigits != fBase.fTotalDigits) { + reportError("FixedFacetValue", new Object[]{"totalDigits", Integer.toString(fTotalDigits), Integer.toString(fBase.fTotalDigits), fTypeName}); + } + if (fTotalDigits > fBase.fTotalDigits) { + reportError( "totalDigits-valid-restriction", new Object[]{Integer.toString(fTotalDigits), Integer.toString(fBase.fTotalDigits), fTypeName}); + } + } + } + + // check 4.3.12.c1 must: fractionDigits <= base.totalDigits + if ((fFacetsDefined & FACET_FRACTIONDIGITS) != 0) { + if ((fBase.fFacetsDefined & FACET_TOTALDIGITS) != 0) { + if (fFractionDigits > fBase.fTotalDigits) + reportError( "fractionDigits-totalDigits", new Object[]{Integer.toString(fFractionDigits), Integer.toString(fTotalDigits), fTypeName}); + } + } + + // check 4.3.12.c2 error: fractionDigits > fBase.fractionDigits + // check fixed value for fractionDigits + if (((fFacetsDefined & FACET_FRACTIONDIGITS) != 0)) { + if ((( fBase.fFacetsDefined & FACET_FRACTIONDIGITS) != 0)) { + if (((fBase.fFixedFacet & FACET_FRACTIONDIGITS) != 0 && fFractionDigits != fBase.fFractionDigits) || + (fValidationDV == DV_INTEGER && fFractionDigits != 0)) { + reportError("FixedFacetValue", new Object[]{"fractionDigits", Integer.toString(fFractionDigits), Integer.toString(fBase.fFractionDigits), fTypeName}); + } + if (fFractionDigits > fBase.fFractionDigits) { + reportError( "fractionDigits-valid-restriction", new Object[]{Integer.toString(fFractionDigits), Integer.toString(fBase.fFractionDigits), fTypeName}); + } + } + else if (fValidationDV == DV_INTEGER && fFractionDigits != 0) { + reportError("FixedFacetValue", new Object[]{"fractionDigits", Integer.toString(fFractionDigits), "0", fTypeName}); + } + } + + // check 4.3.6.c1 error: + // (whiteSpace = preserve || whiteSpace = replace) && fBase.whiteSpace = collapese or + // whiteSpace = preserve && fBase.whiteSpace = replace + + if ( (fFacetsDefined & FACET_WHITESPACE) != 0 && (fBase.fFacetsDefined & FACET_WHITESPACE) != 0 ){ + if ( (fBase.fFixedFacet & FACET_WHITESPACE) != 0 && fWhiteSpace != fBase.fWhiteSpace ) { + reportError( "FixedFacetValue", new Object[]{"whiteSpace", whiteSpaceValue(fWhiteSpace), whiteSpaceValue(fBase.fWhiteSpace), fTypeName}); + } + + if ( fWhiteSpace == WS_PRESERVE && fBase.fWhiteSpace == WS_COLLAPSE ){ + reportError( "whiteSpace-valid-restriction.1", new Object[]{fTypeName, "preserve"}); + } + if ( fWhiteSpace == WS_REPLACE && fBase.fWhiteSpace == WS_COLLAPSE ){ + reportError( "whiteSpace-valid-restriction.1", new Object[]{fTypeName, "replace"}); + } + if ( fWhiteSpace == WS_PRESERVE && fBase.fWhiteSpace == WS_REPLACE ){ + reportError( "whiteSpace-valid-restriction.2", new Object[]{fTypeName}); + } + } + }//fFacetsDefined != null + + // step 4: inherit other facets from base (including fTokeyType) + + // inherit length + if ( (fFacetsDefined & FACET_LENGTH) == 0 && (fBase.fFacetsDefined & FACET_LENGTH) != 0 ) { + fFacetsDefined |= FACET_LENGTH; + fLength = fBase.fLength; + lengthAnnotation = fBase.lengthAnnotation; + } + // inherit minLength + if ( (fFacetsDefined & FACET_MINLENGTH) == 0 && (fBase.fFacetsDefined & FACET_MINLENGTH) != 0 ) { + fFacetsDefined |= FACET_MINLENGTH; + fMinLength = fBase.fMinLength; + minLengthAnnotation = fBase.minLengthAnnotation; + } + // inherit maxLength + if ((fFacetsDefined & FACET_MAXLENGTH) == 0 && (fBase.fFacetsDefined & FACET_MAXLENGTH) != 0 ) { + fFacetsDefined |= FACET_MAXLENGTH; + fMaxLength = fBase.fMaxLength; + maxLengthAnnotation = fBase.maxLengthAnnotation; + } + // inherit pattern + if ( (fBase.fFacetsDefined & FACET_PATTERN) != 0 ) { + if ((fFacetsDefined & FACET_PATTERN) == 0) { + fFacetsDefined |= FACET_PATTERN; + fPattern = fBase.fPattern; + fPatternStr = fBase.fPatternStr; + patternAnnotations = fBase.patternAnnotations; + } + else { + for (int i = fBase.fPattern.size()-1; i >= 0; --i) { + fPattern.addElement(fBase.fPattern.elementAt(i)); + fPatternStr.addElement(fBase.fPatternStr.elementAt(i)); + } + if (fBase.patternAnnotations != null) { + if (patternAnnotations != null) { + for (int i = fBase.patternAnnotations.getLength()-1; i >= 0; --i) { + patternAnnotations.addXSObject(fBase.patternAnnotations.item(i)); + } + } + else { + patternAnnotations = fBase.patternAnnotations; + } + } + } + } + // inherit whiteSpace + if ( (fFacetsDefined & FACET_WHITESPACE) == 0 && (fBase.fFacetsDefined & FACET_WHITESPACE) != 0 ) { + fFacetsDefined |= FACET_WHITESPACE; + fWhiteSpace = fBase.fWhiteSpace; + whiteSpaceAnnotation = fBase.whiteSpaceAnnotation; + } + // inherit enumeration + if ((fFacetsDefined & FACET_ENUMERATION) == 0 && (fBase.fFacetsDefined & FACET_ENUMERATION) != 0) { + fFacetsDefined |= FACET_ENUMERATION; + fEnumeration = fBase.fEnumeration; + fEnumerationSize = fBase.fEnumerationSize; + enumerationAnnotations = fBase.enumerationAnnotations; + } + // inherit maxExclusive + if ((( fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && + !((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && !((fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + fFacetsDefined |= FACET_MAXEXCLUSIVE; + fMaxExclusive = fBase.fMaxExclusive; + maxExclusiveAnnotation = fBase.maxExclusiveAnnotation; + } + // inherit maxInclusive + if ((( fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0) && + !((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && !((fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) { + fFacetsDefined |= FACET_MAXINCLUSIVE; + fMaxInclusive = fBase.fMaxInclusive; + maxInclusiveAnnotation = fBase.maxInclusiveAnnotation; + } + // inherit minExclusive + if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && + !((fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && !((fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + fFacetsDefined |= FACET_MINEXCLUSIVE; + fMinExclusive = fBase.fMinExclusive; + minExclusiveAnnotation = fBase.minExclusiveAnnotation; + } + // inherit minExclusive + if ((( fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0) && + !((fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && !((fFacetsDefined & FACET_MININCLUSIVE) != 0)) { + fFacetsDefined |= FACET_MININCLUSIVE; + fMinInclusive = fBase.fMinInclusive; + minInclusiveAnnotation = fBase.minInclusiveAnnotation; + } + // inherit totalDigits + if ((( fBase.fFacetsDefined & FACET_TOTALDIGITS) != 0) && + !((fFacetsDefined & FACET_TOTALDIGITS) != 0)) { + fFacetsDefined |= FACET_TOTALDIGITS; + fTotalDigits = fBase.fTotalDigits; + totalDigitsAnnotation = fBase.totalDigitsAnnotation; + } + // inherit fractionDigits + if ((( fBase.fFacetsDefined & FACET_FRACTIONDIGITS) != 0) + && !((fFacetsDefined & FACET_FRACTIONDIGITS) != 0)) { + fFacetsDefined |= FACET_FRACTIONDIGITS; + fFractionDigits = fBase.fFractionDigits; + fractionDigitsAnnotation = fBase.fractionDigitsAnnotation; + } + //inherit tokeytype + if ((fPatternType == SPECIAL_PATTERN_NONE ) && (fBase.fPatternType != SPECIAL_PATTERN_NONE)) { + fPatternType = fBase.fPatternType ; + } + + // step 5: mark fixed values + fFixedFacet |= fBase.fFixedFacet; + + //step 6: setting fundamental facets + calcFundamentalFacets(); + + } //applyFacets() + + /** + * validate a value, and return the compiled form + */ + public Object validate(String content, ValidationContext context, ValidatedInfo validatedInfo) throws InvalidDatatypeValueException { + + if (context == null) + context = fEmptyContext; + + if (validatedInfo == null) + validatedInfo = new ValidatedInfo(); + else + validatedInfo.memberType = null; + + // first normalize string value, and convert it to actual value + boolean needNormalize = context==null||context.needToNormalize(); + Object ob = getActualValue(content, context, validatedInfo, needNormalize); + + validate(context, validatedInfo); + + return ob; + + } + + protected ValidatedInfo getActualEnumValue(String lexical, ValidationContext ctx, ValidatedInfo info) + throws InvalidDatatypeValueException { + return fBase.validateWithInfo(lexical, ctx, info); + } + + /** + * validate a value, and return the compiled form + */ + public ValidatedInfo validateWithInfo(String content, ValidationContext context, ValidatedInfo validatedInfo) throws InvalidDatatypeValueException { + + if (context == null) + context = fEmptyContext; + + if (validatedInfo == null) + validatedInfo = new ValidatedInfo(); + else + validatedInfo.memberType = null; + + // first normalize string value, and convert it to actual value + boolean needNormalize = context==null||context.needToNormalize(); + getActualValue(content, context, validatedInfo, needNormalize); + + validate(context, validatedInfo); + + return validatedInfo; + + } + + /** + * validate a value, and return the compiled form + */ + public Object validate(Object content, ValidationContext context, ValidatedInfo validatedInfo) throws InvalidDatatypeValueException { + + if (context == null) + context = fEmptyContext; + + if (validatedInfo == null) + validatedInfo = new ValidatedInfo(); + else + validatedInfo.memberType = null; + + // first normalize string value, and convert it to actual value + boolean needNormalize = context==null||context.needToNormalize(); + Object ob = getActualValue(content, context, validatedInfo, needNormalize); + + validate(context, validatedInfo); + + return ob; + + } + + /** + * validate an actual value against this DV + * + * @param context the validation context + * @param validatedInfo used to provide the actual value and member types + */ + public void validate(ValidationContext context, ValidatedInfo validatedInfo) + throws InvalidDatatypeValueException { + + if (context == null) + context = fEmptyContext; + + // then validate the actual value against the facets + if (context.needFacetChecking() && + (fFacetsDefined != 0 && fFacetsDefined != FACET_WHITESPACE)) { + checkFacets(validatedInfo); + } + + // now check extra rules: for ID/IDREF/ENTITY + if (context.needExtraChecking()) { + checkExtraRules(context, validatedInfo); + } + + } + + private void checkFacets(ValidatedInfo validatedInfo) throws InvalidDatatypeValueException { + + Object ob = validatedInfo.actualValue; + String content = validatedInfo.normalizedValue; + short type = validatedInfo.actualValueType; + ShortList itemType = validatedInfo.itemValueTypes; + + // For QName and NOTATION types, we don't check length facets + if (fValidationDV != DV_QNAME && fValidationDV != DV_NOTATION) { + int length = fDVs[fValidationDV].getDataLength(ob); + + // maxLength + if ( (fFacetsDefined & FACET_MAXLENGTH) != 0 ) { + if ( length > fMaxLength ) { + throw new InvalidDatatypeValueException("cvc-maxLength-valid", + new Object[]{content, Integer.toString(length), Integer.toString(fMaxLength), fTypeName}); + } + } + + //minLength + if ( (fFacetsDefined & FACET_MINLENGTH) != 0 ) { + if ( length < fMinLength ) { + throw new InvalidDatatypeValueException("cvc-minLength-valid", + new Object[]{content, Integer.toString(length), Integer.toString(fMinLength), fTypeName}); + } + } + + //length + if ( (fFacetsDefined & FACET_LENGTH) != 0 ) { + if ( length != fLength ) { + throw new InvalidDatatypeValueException("cvc-length-valid", + new Object[]{content, Integer.toString(length), Integer.toString(fLength), fTypeName}); + } + } + } + + //enumeration + if ( ((fFacetsDefined & FACET_ENUMERATION) != 0 ) ) { + boolean present = false; + final int enumSize = fEnumerationSize; + final short primitiveType1 = convertToPrimitiveKind(type); + for (int i = 0; i < enumSize; i++) { + final short primitiveType2 = convertToPrimitiveKind(fEnumeration[i].actualValueType); + if ((primitiveType1 == primitiveType2 || + primitiveType1 == XSConstants.ANYSIMPLETYPE_DT && primitiveType2 == XSConstants.STRING_DT || + primitiveType1 == XSConstants.STRING_DT && primitiveType2 == XSConstants.ANYSIMPLETYPE_DT) + && fEnumeration[i].actualValue.equals(ob)) { + if (primitiveType1 == XSConstants.LIST_DT || primitiveType1 == XSConstants.LISTOFUNION_DT) { + ShortList enumItemType = fEnumeration[i].itemValueTypes; + final int typeList1Length = itemType != null ? itemType.getLength() : 0; + final int typeList2Length = enumItemType != null ? enumItemType.getLength() : 0; + if (typeList1Length == typeList2Length) { + int j; + for (j = 0; j < typeList1Length; ++j) { + final short primitiveItem1 = convertToPrimitiveKind(itemType.item(j)); + final short primitiveItem2 = convertToPrimitiveKind(enumItemType.item(j)); + if (primitiveItem1 != primitiveItem2) { + if (primitiveItem1 == XSConstants.ANYSIMPLETYPE_DT && primitiveItem2 == XSConstants.STRING_DT || + primitiveItem1 == XSConstants.STRING_DT && primitiveItem2 == XSConstants.ANYSIMPLETYPE_DT) { + continue; + } + break; + } + } + if (j == typeList1Length) { + present = true; + break; + } + } + } + else { + present = true; + break; + } + } + } + if(!present){ + StringBuffer sb = new StringBuffer(); + appendEnumString(sb); + throw new InvalidDatatypeValueException("cvc-enumeration-valid", + new Object [] {content, sb.toString()}); + } + } + + //fractionDigits + if ((fFacetsDefined & FACET_FRACTIONDIGITS) != 0) { + int scale = fDVs[fValidationDV].getFractionDigits(ob); + if (scale > fFractionDigits) { + throw new InvalidDatatypeValueException("cvc-fractionDigits-valid", + new Object[] {content, Integer.toString(scale), Integer.toString(fFractionDigits)}); + } + } + + //totalDigits + if ((fFacetsDefined & FACET_TOTALDIGITS)!=0) { + int totalDigits = fDVs[fValidationDV].getTotalDigits(ob); + if (totalDigits > fTotalDigits) { + throw new InvalidDatatypeValueException("cvc-totalDigits-valid", + new Object[] {content, Integer.toString(totalDigits), Integer.toString(fTotalDigits)}); + } + } + + int compare; + + //maxinclusive + if ( (fFacetsDefined & FACET_MAXINCLUSIVE) != 0 ) { + compare = fDVs[fValidationDV].compare(ob, fMaxInclusive); + if (compare != -1 && compare != 0) { + throw new InvalidDatatypeValueException("cvc-maxInclusive-valid", + new Object[] {content, fMaxInclusive, fTypeName}); + } + } + + //maxExclusive + if ( (fFacetsDefined & FACET_MAXEXCLUSIVE) != 0 ) { + compare = fDVs[fValidationDV].compare(ob, fMaxExclusive ); + if (compare != -1) { + throw new InvalidDatatypeValueException("cvc-maxExclusive-valid", + new Object[] {content, fMaxExclusive, fTypeName}); + } + } + + //minInclusive + if ( (fFacetsDefined & FACET_MININCLUSIVE) != 0 ) { + compare = fDVs[fValidationDV].compare(ob, fMinInclusive); + if (compare != 1 && compare != 0) { + throw new InvalidDatatypeValueException("cvc-minInclusive-valid", + new Object[] {content, fMinInclusive, fTypeName}); + } + } + + //minExclusive + if ( (fFacetsDefined & FACET_MINEXCLUSIVE) != 0 ) { + compare = fDVs[fValidationDV].compare(ob, fMinExclusive); + if (compare != 1) { + throw new InvalidDatatypeValueException("cvc-minExclusive-valid", + new Object[] {content, fMinExclusive, fTypeName}); + } + } + + } + + private void checkExtraRules(ValidationContext context, ValidatedInfo validatedInfo) throws InvalidDatatypeValueException { + + Object ob = validatedInfo.actualValue; + + if (fVariety == VARIETY_ATOMIC) { + + fDVs[fValidationDV].checkExtraRules(ob, context); + + } else if (fVariety == VARIETY_LIST) { + + ListDV.ListData values = (ListDV.ListData)ob; + XSSimpleType memberType = validatedInfo.memberType; + int len = values.getLength(); + try { + if (fItemType.fVariety == VARIETY_UNION) { + XSSimpleTypeDecl[] memberTypes = (XSSimpleTypeDecl[])validatedInfo.memberTypes; + for (int i = len-1; i >= 0; i--) { + validatedInfo.actualValue = values.item(i); + validatedInfo.memberType = memberTypes[i]; + fItemType.checkExtraRules(context, validatedInfo); + } + } else { // (fVariety == VARIETY_ATOMIC) + for (int i = len-1; i >= 0; i--) { + validatedInfo.actualValue = values.item(i); + fItemType.checkExtraRules(context, validatedInfo); + } + } + } + finally { + validatedInfo.actualValue = values; + validatedInfo.memberType = memberType; + } + + } else { // (fVariety == VARIETY_UNION) + + ((XSSimpleTypeDecl)validatedInfo.memberType).checkExtraRules(context, validatedInfo); + + } + + }// checkExtraRules() + + //we can still return object for internal use. + private Object getActualValue(Object content, ValidationContext context, + ValidatedInfo validatedInfo, boolean needNormalize) + throws InvalidDatatypeValueException{ + + String nvalue; + if (needNormalize) { + nvalue = normalize(content, fWhiteSpace); + } else { + nvalue = content.toString(); + } + if ( (fFacetsDefined & FACET_PATTERN ) != 0 ) { + RegularExpression regex; + for (int idx = fPattern.size()-1; idx >= 0; idx--) { + regex = (RegularExpression)fPattern.elementAt(idx); + if (!regex.matches(nvalue)){ + throw new InvalidDatatypeValueException("cvc-pattern-valid", + new Object[]{content, + fPatternStr.elementAt(idx), + + fTypeName}); + } + } + } + + if (fVariety == VARIETY_ATOMIC) { + + // validate special kinds of token, in place of old pattern matching + if (fPatternType != SPECIAL_PATTERN_NONE) { + + boolean seenErr = false; + if (fPatternType == SPECIAL_PATTERN_NMTOKEN) { + // PATTERN "\\c+" + seenErr = !XMLChar.isValidNmtoken(nvalue); + } + else if (fPatternType == SPECIAL_PATTERN_NAME) { + // PATTERN "\\i\\c*" + seenErr = !XMLChar.isValidName(nvalue); + } + else if (fPatternType == SPECIAL_PATTERN_NCNAME) { + // PATTERN "[\\i-[:]][\\c-[:]]*" + seenErr = !XMLChar.isValidNCName(nvalue); + } + if (seenErr) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", + new Object[]{nvalue, SPECIAL_PATTERN_STRING[fPatternType]}); + } + } + + validatedInfo.normalizedValue = nvalue; + Object avalue = fDVs[fValidationDV].getActualValue(nvalue, context); + validatedInfo.actualValue = avalue; + validatedInfo.actualValueType = fBuiltInKind; + validatedInfo.actualType = this; + + return avalue; + + } else if (fVariety == VARIETY_LIST) { + + StringTokenizer parsedList = new StringTokenizer(nvalue, " "); + int countOfTokens = parsedList.countTokens() ; + Object[] avalue = new Object[countOfTokens]; + boolean isUnion = fItemType.getVariety() == VARIETY_UNION; + short[] itemTypes = new short[isUnion ? countOfTokens : 1]; + if (!isUnion) + itemTypes[0] = fItemType.fBuiltInKind; + XSSimpleTypeDecl[] memberTypes = new XSSimpleTypeDecl[countOfTokens]; + for(int i = 0 ; i < countOfTokens ; i ++){ + // we can't call fItemType.validate(), otherwise checkExtraRules() + // will be called twice: once in fItemType.validate, once in + // validate method of this type. + // so we take two steps to get the actual value: + // 1. fItemType.getActualValue() + // 2. fItemType.chekcFacets() + avalue[i] = fItemType.getActualValue(parsedList.nextToken(), context, validatedInfo, false); + if (context.needFacetChecking() && + (fItemType.fFacetsDefined != 0 && fItemType.fFacetsDefined != FACET_WHITESPACE)) { + fItemType.checkFacets(validatedInfo); + } + memberTypes[i] = (XSSimpleTypeDecl)validatedInfo.memberType; + if (isUnion) + itemTypes[i] = memberTypes[i].fBuiltInKind; + } + + ListDV.ListData v = new ListDV.ListData(avalue); + validatedInfo.actualValue = v; + validatedInfo.actualValueType = isUnion ? XSConstants.LISTOFUNION_DT : XSConstants.LIST_DT; + validatedInfo.memberType = null; + validatedInfo.memberTypes = memberTypes; + validatedInfo.itemValueTypes = new ShortListImpl(itemTypes, itemTypes.length); + validatedInfo.normalizedValue = nvalue; + // Need to set it here or it will become the item type + validatedInfo.actualType = this; + + return v; + + } else { // (fVariety == VARIETY_UNION) + final Object _content = (fMemberTypes.length > 1 && content != null) ? content.toString() : content; + for (int i = 0; i < fMemberTypes.length; i++) { + try { + // we can't call fMemberType[i].validate(), otherwise checkExtraRules() + // will be called twice: once in fMemberType[i].validate, once in + // validate method of this type. + // so we take two steps to get the actual value: + // 1. fMemberType[i].getActualValue() + // 2. fMemberType[i].chekcFacets() + Object aValue = fMemberTypes[i].getActualValue(_content, context, validatedInfo, true); + if (context.needFacetChecking() && + (fMemberTypes[i].fFacetsDefined != 0 && fMemberTypes[i].fFacetsDefined != FACET_WHITESPACE)) { + fMemberTypes[i].checkFacets(validatedInfo); + } + validatedInfo.memberType = fMemberTypes[i]; + // Need to set it here or it will become the member type + validatedInfo.actualType = this; + return aValue; + } catch(InvalidDatatypeValueException invalidValue) { + } + } + StringBuffer typesBuffer = new StringBuffer(); + XSSimpleTypeDecl decl; + for(int i = 0;i < fMemberTypes.length; i++) { + if(i != 0) + typesBuffer.append(" | "); + decl = fMemberTypes[i]; + if(decl.fTargetNamespace != null) { + typesBuffer.append('{'); + typesBuffer.append(decl.fTargetNamespace); + typesBuffer.append('}'); + } + typesBuffer.append(decl.fTypeName); + if(decl.fEnumeration != null) { + typesBuffer.append(" : "); + decl.appendEnumString(typesBuffer); + } + } + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.3", + new Object[]{content, fTypeName, typesBuffer.toString()}); + } + + }//getActualValue() + + public boolean isEqual(Object value1, Object value2) { + if (value1 == null) { + return false; + } + return value1.equals(value2); + }//isEqual() + + // determine whether the two values are identical + public boolean isIdentical (Object value1, Object value2) { + if (value1 == null) { + return false; + } + return fDVs[fValidationDV].isIdentical(value1, value2); + }//isIdentical() + + // normalize the string according to the whiteSpace facet + public static String normalize(String content, short ws) { + int len = content == null ? 0 : content.length(); + if (len == 0 || ws == WS_PRESERVE) + return content; + + StringBuffer sb = new StringBuffer(); + if (ws == WS_REPLACE) { + char ch; + // when it's replace, just replace #x9, #xa, #xd by #x20 + for (int i = 0; i < len; i++) { + ch = content.charAt(i); + if (ch != 0x9 && ch != 0xa && ch != 0xd) + sb.append(ch); + else + sb.append((char)0x20); + } + } else { + char ch; + int i; + boolean isLeading = true; + // when it's collapse + for (i = 0; i < len; i++) { + ch = content.charAt(i); + // append real characters, so we passed leading ws + if (ch != 0x9 && ch != 0xa && ch != 0xd && ch != 0x20) { + sb.append(ch); + isLeading = false; + } + else { + // for whitespaces, we skip all following ws + for (; i < len-1; i++) { + ch = content.charAt(i+1); + if (ch != 0x9 && ch != 0xa && ch != 0xd && ch != 0x20) + break; + } + // if it's not a leading or tailing ws, then append a space + if (i < len - 1 && !isLeading) + sb.append((char)0x20); + } + } + } + + return sb.toString(); + } + + // normalize the string according to the whiteSpace facet + protected String normalize(Object content, short ws) { + if (content == null) + return null; + + // If pattern is not defined, we can skip some of the normalization. + // Otherwise we have to normalize the data for correct result of + // pattern validation. + if ( (fFacetsDefined & FACET_PATTERN ) == 0 ) { + short norm_type = fDVNormalizeType[fValidationDV]; + if (norm_type == NORMALIZE_NONE) { + return content.toString(); + } + else if (norm_type == NORMALIZE_TRIM) { + return XMLChar.trim(content.toString()); + } + } + + if (!(content instanceof StringBuffer)) { + String strContent = content.toString(); + return normalize(strContent, ws); + } + + StringBuffer sb = (StringBuffer)content; + int len = sb.length(); + if (len == 0) + return ""; + if (ws == WS_PRESERVE) + return sb.toString(); + + if (ws == WS_REPLACE) { + char ch; + // when it's replace, just replace #x9, #xa, #xd by #x20 + for (int i = 0; i < len; i++) { + ch = sb.charAt(i); + if (ch == 0x9 || ch == 0xa || ch == 0xd) + sb.setCharAt(i, (char)0x20); + } + } else { + char ch; + int i, j = 0; + boolean isLeading = true; + // when it's collapse + for (i = 0; i < len; i++) { + ch = sb.charAt(i); + // append real characters, so we passed leading ws + if (ch != 0x9 && ch != 0xa && ch != 0xd && ch != 0x20) { + sb.setCharAt(j++, ch); + isLeading = false; + } + else { + // for whitespaces, we skip all following ws + for (; i < len-1; i++) { + ch = sb.charAt(i+1); + if (ch != 0x9 && ch != 0xa && ch != 0xd && ch != 0x20) + break; + } + // if it's not a leading or tailing ws, then append a space + if (i < len - 1 && !isLeading) + sb.setCharAt(j++, (char)0x20); + } + } + sb.setLength(j); + } + + return sb.toString(); + } + + void reportError(String key, Object[] args) throws InvalidDatatypeFacetException { + throw new InvalidDatatypeFacetException(key, args); + } + + + private String whiteSpaceValue(short ws){ + return WS_FACET_STRING[ws]; + } + + /** + * Fundamental Facet: ordered. + */ + public short getOrdered() { + return fOrdered; + } + + /** + * Fundamental Facet: bounded. + */ + public boolean getBounded(){ + return fBounded; + } + + /** + * Fundamental Facet: cardinality. + */ + public boolean getFinite(){ + return fFinite; + } + + /** + * Fundamental Facet: numeric. + */ + public boolean getNumeric(){ + return fNumeric; + } + + /** + * Convenience method. [Facets]: check whether a facet is defined on this + * type. + * @param facetName The name of the facet. + * @return True if the facet is defined, false otherwise. + */ + public boolean isDefinedFacet(short facetName) { + if (fValidationDV == DV_ANYSIMPLETYPE || + fValidationDV == DV_ANYATOMICTYPE) { + return false; + } + if ((fFacetsDefined & facetName) != 0) { + return true; + } + if (fPatternType != SPECIAL_PATTERN_NONE) { + return facetName == FACET_PATTERN; + } + if (fValidationDV == DV_INTEGER) { + return facetName == FACET_PATTERN || facetName == FACET_FRACTIONDIGITS; + } + return false; + } + + /** + * [facets]: all facets defined on this type. The value is a bit + * combination of FACET_XXX constants of all defined facets. + */ + public short getDefinedFacets() { + if (fValidationDV == DV_ANYSIMPLETYPE || + fValidationDV == DV_ANYATOMICTYPE) { + return FACET_NONE; + } + if (fPatternType != SPECIAL_PATTERN_NONE) { + return (short)(fFacetsDefined | FACET_PATTERN); + } + if (fValidationDV == DV_INTEGER) { + return (short)(fFacetsDefined | FACET_PATTERN | FACET_FRACTIONDIGITS); + } + return fFacetsDefined; + } + + /** + * Convenience method. [Facets]: check whether a facet is defined and + * fixed on this type. + * @param facetName The name of the facet. + * @return True if the facet is fixed, false otherwise. + */ + public boolean isFixedFacet(short facetName) { + if ((fFixedFacet & facetName) != 0) + return true; + if (fValidationDV == DV_INTEGER) + return facetName == FACET_FRACTIONDIGITS; + return false; + } + + /** + * [facets]: all defined facets for this type which are fixed. + */ + public short getFixedFacets() { + if (fValidationDV == DV_INTEGER) + return (short)(fFixedFacet | FACET_FRACTIONDIGITS); + return fFixedFacet; + } + + /** + * Convenience method. Returns a value of a single constraining facet for + * this simple type definition. This method must not be used to retrieve + * values for enumeration and pattern facets. + * @param facetName The name of the facet, i.e. + * FACET_LENGTH, FACET_TOTALDIGITS (see + * XSConstants). To retrieve the value for a pattern or + * an enumeration, see enumeration and + * pattern. + * @return A value of the facet specified in facetName for + * this simple type definition or null. + */ + public String getLexicalFacetValue(short facetName) { + switch (facetName) { + case FACET_LENGTH: + return (fLength == -1)?null:Integer.toString(fLength); + case FACET_MINLENGTH: + return (fMinLength == -1)?null:Integer.toString(fMinLength); + case FACET_MAXLENGTH: + return (fMaxLength == -1)?null:Integer.toString(fMaxLength); + case FACET_WHITESPACE: + if (fValidationDV == DV_ANYSIMPLETYPE || + fValidationDV == DV_ANYATOMICTYPE) { + return null; + } + return WS_FACET_STRING[fWhiteSpace]; + case FACET_MAXINCLUSIVE: + return (fMaxInclusive == null)?null:fMaxInclusive.toString(); + case FACET_MAXEXCLUSIVE: + return (fMaxExclusive == null)?null:fMaxExclusive.toString(); + case FACET_MINEXCLUSIVE: + return (fMinExclusive == null)?null:fMinExclusive.toString(); + case FACET_MININCLUSIVE: + return (fMinInclusive == null)?null:fMinInclusive.toString(); + case FACET_TOTALDIGITS: + return (fTotalDigits == -1)?null:Integer.toString(fTotalDigits); + case FACET_FRACTIONDIGITS: + if (fValidationDV == DV_INTEGER) { + return "0"; + } + return (fFractionDigits == -1)?null:Integer.toString(fFractionDigits); + } + return null; + } + + /** + * A list of enumeration values if it exists, otherwise an empty + * StringList. + */ + public StringList getLexicalEnumeration() { + if (fLexicalEnumeration == null){ + if (fEnumeration == null) + return StringListImpl.EMPTY_LIST; + int size = fEnumerationSize; + String[] strs = new String[size]; + for (int i = 0; i < size; i++) + strs[i] = fEnumeration[i].normalizedValue; + fLexicalEnumeration = new StringListImpl(strs, size); + } + return fLexicalEnumeration; + } + + /** + * A list of actual enumeration values if it exists, otherwise an empty + * ObjectList. + */ + public ObjectList getActualEnumeration() { + if (fActualEnumeration == null) { + fActualEnumeration = new AbstractObjectList() { + public int getLength() { + return (fEnumeration != null) ? fEnumerationSize : 0; + } + public boolean contains(Object item) { + if (fEnumeration == null) { + return false; + } + for (int i = 0; i < fEnumerationSize; i++) { + if (fEnumeration[i].getActualValue().equals(item)) { + return true; + } + } + return false; + } + public Object item(int index) { + if (index < 0 || index >= getLength()) { + return null; + } + return fEnumeration[index].getActualValue(); + } + }; + } + return fActualEnumeration; + } + + /** + * A list of enumeration type values (as a list of ShortList objects) if it exists, otherwise returns + * null + */ + public ObjectList getEnumerationItemTypeList() { + if (fEnumerationItemTypeList == null) { + if (fEnumeration == null) { + return null; + } + fEnumerationItemTypeList = new AbstractObjectList() { + public int getLength() { + return (fEnumeration != null) ? fEnumerationSize : 0; + } + public boolean contains(Object item) { + if (fEnumeration == null || !(item instanceof ShortList)) + return false; + for (int i = 0;i < fEnumerationSize; i++) + if (fEnumeration[i].itemValueTypes == item) + return true; + return false; + } + public Object item(int index) { + if (index < 0 || index >= getLength()) { + return null; + } + return fEnumeration[index].itemValueTypes; + } + }; + } + return fEnumerationItemTypeList; + } + + public ShortList getEnumerationTypeList() { + if (fEnumerationTypeList == null) { + if (fEnumeration == null) { + return ShortListImpl.EMPTY_LIST; + } + short[] list = new short[fEnumerationSize]; + for (int i = 0; i < fEnumerationSize; i++) { + list[i] = fEnumeration[i].actualValueType; + } + fEnumerationTypeList = new ShortListImpl(list, fEnumerationSize); + } + return fEnumerationTypeList; + } + + /** + * A list of pattern values if it exists, otherwise an empty + * StringList. + */ + public StringList getLexicalPattern() { + if (fPatternType == SPECIAL_PATTERN_NONE && fValidationDV != DV_INTEGER && fPatternStr == null) + return StringListImpl.EMPTY_LIST; + if (fLexicalPattern == null){ + int size = fPatternStr == null ? 0 : fPatternStr.size(); + String[] strs; + if (fPatternType == SPECIAL_PATTERN_NMTOKEN) { + strs = new String[size+1]; + strs[size] = "\\c+"; + } + else if (fPatternType == SPECIAL_PATTERN_NAME) { + strs = new String[size+1]; + strs[size] = "\\i\\c*"; + } + else if (fPatternType == SPECIAL_PATTERN_NCNAME) { + strs = new String[size+2]; + strs[size] = "\\i\\c*"; + strs[size+1] = "[\\i-[:]][\\c-[:]]*"; + } + else if (fValidationDV == DV_INTEGER) { + strs = new String[size+1]; + strs[size] = "[\\-+]?[0-9]+"; + } + else { + strs = new String[size]; + } + for (int i = 0; i < size; i++) + strs[i] = (String)fPatternStr.elementAt(i); + fLexicalPattern = new StringListImpl(strs, strs.length); + } + return fLexicalPattern; + } + + /** + * [annotations]: a set of annotations for this simple type component if + * it exists, otherwise an empty XSObjectList. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + private void calcFundamentalFacets() { + setOrdered(); + setNumeric(); + setBounded(); + setCardinality(); + } + + private void setOrdered(){ + + // When {variety} is atomic, {value} is inherited from {value} of {base type definition}. For all "primitive" types {value} is as specified in the table in Fundamental Facets (C.1). + if(fVariety == VARIETY_ATOMIC){ + this.fOrdered = fBase.fOrdered; + } + + // When {variety} is list, {value} is false. + else if(fVariety == VARIETY_LIST){ + this.fOrdered = ORDERED_FALSE; + } + + // When {variety} is union, the {value} is partial unless one of the following: + // 1. If every member of {member type definitions} is derived from a common ancestor other than the simple ur-type, then {value} is the same as that ancestor's ordered facet. + // 2. If every member of {member type definitions} has a {value} of false for the ordered facet, then {value} is false. + else if(fVariety == VARIETY_UNION){ + int length = fMemberTypes.length; + // REVISIT: is the length possible to be 0? + if (length == 0) { + this.fOrdered = ORDERED_PARTIAL; + return; + } + // we need to process the first member type before entering the loop + short ancestorId = getPrimitiveDV(fMemberTypes[0].fValidationDV); + boolean commonAnc = ancestorId != DV_ANYSIMPLETYPE; + boolean allFalse = fMemberTypes[0].fOrdered == ORDERED_FALSE; + // for the other member types, check whether the value is false + // and whether they have the same ancestor as the first one + for (int i = 1; i < fMemberTypes.length && (commonAnc || allFalse); i++) { + if (commonAnc) + commonAnc = ancestorId == getPrimitiveDV(fMemberTypes[i].fValidationDV); + if (allFalse) + allFalse = fMemberTypes[i].fOrdered == ORDERED_FALSE; + } + if (commonAnc) { + // REVISIT: all member types should have the same ordered value + // just use the first one. Can we assume this? + this.fOrdered = fMemberTypes[0].fOrdered; + } else if (allFalse) { + this.fOrdered = ORDERED_FALSE; + } else { + this.fOrdered = ORDERED_PARTIAL; + } + } + + }//setOrdered + + private void setNumeric(){ + if(fVariety == VARIETY_ATOMIC){ + this.fNumeric = fBase.fNumeric; + } + else if(fVariety == VARIETY_LIST){ + this.fNumeric = false; + } + else if(fVariety == VARIETY_UNION){ + XSSimpleType[] memberTypes = fMemberTypes; + for(int i = 0 ; i < memberTypes.length ; i++){ + if(!memberTypes[i].getNumeric() ){ + this.fNumeric = false; + return; + } + } + this.fNumeric = true; + } + + }//setNumeric + + private void setBounded(){ + if(fVariety == VARIETY_ATOMIC){ + if( (((this.fFacetsDefined & FACET_MININCLUSIVE) != 0) || ((this.fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) + && (((this.fFacetsDefined & FACET_MAXINCLUSIVE) != 0) || ((this.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0)) ){ + this.fBounded = true; + } + else{ + this.fBounded = false; + } + } + else if(fVariety == VARIETY_LIST){ + if( ((this.fFacetsDefined & FACET_LENGTH) != 0 ) || ( ((this.fFacetsDefined & FACET_MINLENGTH) != 0 ) + && ((this.fFacetsDefined & FACET_MAXLENGTH) != 0 )) ){ + this.fBounded = true; + } + else{ + this.fBounded = false; + } + + } + else if(fVariety == VARIETY_UNION){ + + XSSimpleTypeDecl [] memberTypes = this.fMemberTypes; + short ancestorId = 0 ; + + if(memberTypes.length > 0){ + ancestorId = getPrimitiveDV(memberTypes[0].fValidationDV); + } + + for(int i = 0 ; i < memberTypes.length ; i++){ + if(!memberTypes[i].getBounded() || (ancestorId != getPrimitiveDV(memberTypes[i].fValidationDV)) ){ + this.fBounded = false; + return; + } + } + this.fBounded = true; + } + + }//setBounded + + private boolean specialCardinalityCheck(){ + if( (fBase.fValidationDV == XSSimpleTypeDecl.DV_DATE) || (fBase.fValidationDV == XSSimpleTypeDecl.DV_GYEARMONTH) + || (fBase.fValidationDV == XSSimpleTypeDecl.DV_GYEAR) || (fBase.fValidationDV == XSSimpleTypeDecl.DV_GMONTHDAY) + || (fBase.fValidationDV == XSSimpleTypeDecl.DV_GDAY) || (fBase.fValidationDV == XSSimpleTypeDecl.DV_GMONTH) ){ + return true; + } + return false; + + } //specialCardinalityCheck() + + private void setCardinality(){ + if(fVariety == VARIETY_ATOMIC){ + if(fBase.fFinite){ + this.fFinite = true; + } + else {// (!fBase.fFinite) + if ( ((this.fFacetsDefined & FACET_LENGTH) != 0 ) || ((this.fFacetsDefined & FACET_MAXLENGTH) != 0 ) + || ((this.fFacetsDefined & FACET_TOTALDIGITS) != 0 ) ){ + this.fFinite = true; + } + else if( (((this.fFacetsDefined & FACET_MININCLUSIVE) != 0 ) || ((this.fFacetsDefined & FACET_MINEXCLUSIVE) != 0 )) + && (((this.fFacetsDefined & FACET_MAXINCLUSIVE) != 0 ) || ((this.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0 )) ){ + if( ((this.fFacetsDefined & FACET_FRACTIONDIGITS) != 0 ) || specialCardinalityCheck()){ + this.fFinite = true; + } + else{ + this.fFinite = false; + } + } + else{ + this.fFinite = false; + } + } + } + else if(fVariety == VARIETY_LIST){ + if( ((this.fFacetsDefined & FACET_LENGTH) != 0 ) || ( ((this.fFacetsDefined & FACET_MINLENGTH) != 0 ) + && ((this.fFacetsDefined & FACET_MAXLENGTH) != 0 )) ){ + this.fFinite = true; + } + else{ + this.fFinite = false; + } + + } + else if(fVariety == VARIETY_UNION){ + XSSimpleType [] memberTypes = fMemberTypes; + for(int i = 0 ; i < memberTypes.length ; i++){ + if(!(memberTypes[i].getFinite()) ){ + this.fFinite = false; + return; + } + } + this.fFinite = true; + } + + }//setCardinality + + private short getPrimitiveDV(short validationDV){ + + if (validationDV == DV_ID || validationDV == DV_IDREF || validationDV == DV_ENTITY){ + return DV_STRING; + } + else if (validationDV == DV_INTEGER) { + return DV_DECIMAL; + } + else if (Constants.SCHEMA_1_1_SUPPORT && (validationDV == DV_YEARMONTHDURATION || validationDV == DV_DAYTIMEDURATION)) { + return DV_DURATION; + } + else { + return validationDV; + } + + }//getPrimitiveDV() + + public boolean derivedFromType(XSTypeDefinition ancestor, short derivation) { + // REVISIT: implement according to derivation + + // ancestor is null, return false + if (ancestor == null) { + return false; + } + // extract the actual XSTypeDefinition if the given ancestor is a delegate. + while (ancestor instanceof XSSimpleTypeDelegate) { + ancestor = ((XSSimpleTypeDelegate) ancestor).type; + } + // ancestor is anyType, return true + // anyType is the only type whose base type is itself + if (ancestor.getBaseType() == ancestor) { + return true; + } + // recursively get base, and compare it with ancestor + XSTypeDefinition type = this; + while (type != ancestor && // compare with ancestor + type != fAnySimpleType) { // reached anySimpleType + type = type.getBaseType(); + } + return type == ancestor; + } + + public boolean derivedFrom(String ancestorNS, String ancestorName, short derivation) { + // REVISIT: implement according to derivation + + // ancestor is null, retur false + if (ancestorName == null) + return false; + // ancestor is anyType, return true + if (URI_SCHEMAFORSCHEMA.equals(ancestorNS) && + ANY_TYPE.equals(ancestorName)) { + return true; + } + + // recursively get base, and compare it with ancestor + XSTypeDefinition type = this; + while (!(ancestorName.equals(type.getName()) && + ((ancestorNS == null && type.getNamespace() == null) || + (ancestorNS != null && ancestorNS.equals(type.getNamespace())))) && // compare with ancestor + type != fAnySimpleType) { // reached anySimpleType + type = (XSTypeDefinition)type.getBaseType(); + } + + return type != fAnySimpleType; + } + + /** + * Checks if a type is derived from another by restriction, given the name + * and namespace. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param derivationMethod + * The derivation method + * + * @return boolean True if the ancestor type is derived from the reference type by the specifiied derivation method. + */ + public boolean isDOMDerivedFrom(String ancestorNS, String ancestorName, int derivationMethod) { + + // ancestor is null, return false + if (ancestorName == null) + return false; + + // ancestor is anyType, return true + if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(ancestorNS) + && SchemaSymbols.ATTVAL_ANYTYPE.equals(ancestorName) + && (((derivationMethod & DERIVATION_RESTRICTION) != 0) + || (derivationMethod == DERIVATION_ANY))) { + return true; + } + + // restriction + if ((derivationMethod & DERIVATION_RESTRICTION) != 0) { + if (isDerivedByRestriction(ancestorNS, ancestorName, this)) { + return true; + } + } + + // list + if ((derivationMethod & DERIVATION_LIST) != 0) { + if (isDerivedByList(ancestorNS, ancestorName, this)) { + return true; + } + } + + // union + if ((derivationMethod & DERIVATION_UNION) != 0) { + if (isDerivedByUnion(ancestorNS, ancestorName, this)) { + return true; + } + } + + // extension + if (((derivationMethod & DERIVATION_EXTENSION) != 0) + && (((derivationMethod & DERIVATION_RESTRICTION) == 0) + && ((derivationMethod & DERIVATION_LIST) == 0) + && ((derivationMethod & DERIVATION_UNION) == 0))) { + return false; + } + + // If the value of the parameter is 0 i.e. no bit (corresponding to + // restriction, list, extension or union) is set to 1 for the + // derivationMethod parameter. + if (((derivationMethod & DERIVATION_EXTENSION) == 0) + && (((derivationMethod & DERIVATION_RESTRICTION) == 0) + && ((derivationMethod & DERIVATION_LIST) == 0) + && ((derivationMethod & DERIVATION_UNION) == 0))) { + return isDerivedByAny(ancestorNS, ancestorName, this); + } + + return false; + } + + + /** + * Checks if a type is derived from another by any combination of restriction, list ir union. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param type + * The reference type definition + * + * @return boolean True if the type is derived by restriciton for the reference type + */ + private boolean isDerivedByAny(String ancestorNS, String ancestorName, + XSTypeDefinition type) { + + boolean derivedFrom = false; + XSTypeDefinition oldType = null; + // for each base, item or member type + while (type != null && type != oldType) { + + // If the ancestor type is reached or is the same as this type. + if ((ancestorName.equals(type.getName())) + && ((ancestorNS == null && type.getNamespace() == null) + || (ancestorNS != null && ancestorNS.equals(type.getNamespace())))) { + derivedFrom = true; + break; + } + + // check if derived by restriction or list or union + if (isDerivedByRestriction(ancestorNS, ancestorName, type)) { + return true; + } else if (isDerivedByList(ancestorNS, ancestorName, type)) { + return true; + } else if (isDerivedByUnion(ancestorNS, ancestorName, type)) { + return true; + } + oldType = type; + // get the base, item or member type depending on the variety + if (((XSSimpleTypeDecl) type).getVariety() == VARIETY_ABSENT + || ((XSSimpleTypeDecl) type).getVariety() == VARIETY_ATOMIC) { + type = type.getBaseType(); + } else if (((XSSimpleTypeDecl) type).getVariety() == VARIETY_UNION) { + for (int i = 0; i < ((XSSimpleTypeDecl) type).getMemberTypes().getLength(); i++) { + return isDerivedByAny(ancestorNS, ancestorName, + (XSTypeDefinition) ((XSSimpleTypeDecl) type) + .getMemberTypes().item(i)); + } + } else if (((XSSimpleTypeDecl) type).getVariety() == VARIETY_LIST) { + type = ((XSSimpleTypeDecl) type).getItemType(); + } + } + + return derivedFrom; + } + + /** + * DOM Level 3 + * Checks if a type is derived from another by restriction. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param type + * The reference type definition + * + * @return boolean True if the type is derived by restriciton for the + * reference type + */ + private boolean isDerivedByRestriction (String ancestorNS, String ancestorName, XSTypeDefinition type) { + XSTypeDefinition oldType = null; + while (type != null && type != oldType) { + if ((ancestorName.equals(type.getName())) + && ((ancestorNS != null && ancestorNS.equals(type.getNamespace())) + || (type.getNamespace() == null && ancestorNS == null))) { + + return true; + } + oldType = type; + type = type.getBaseType(); + } + + return false; + } + + /** + * Checks if a type is derived from another by list. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param type + * The reference type definition + * + * @return boolean True if the type is derived by list for the reference type + */ + private boolean isDerivedByList (String ancestorNS, String ancestorName, XSTypeDefinition type) { + // If the variety is union + if (type !=null && ((XSSimpleTypeDefinition)type).getVariety() == VARIETY_LIST) { + + // get the {item type} + XSTypeDefinition itemType = ((XSSimpleTypeDefinition)type).getItemType(); + + // T2 is the {item type definition} + if (itemType != null) { + + // T2 is derived from the other type definition by DERIVATION_RESTRICTION + if (isDerivedByRestriction(ancestorNS, ancestorName, itemType)) { + return true; + } + } + } + return false; + } + + /** + * Checks if a type is derived from another by union. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param type + * The reference type definition + * + * @return boolean True if the type is derived by union for the reference type + */ + private boolean isDerivedByUnion (String ancestorNS, String ancestorName, XSTypeDefinition type) { + + // If the variety is union + if (type !=null && ((XSSimpleTypeDefinition)type).getVariety() == VARIETY_UNION) { + + // get member types + XSObjectList memberTypes = ((XSSimpleTypeDefinition)type).getMemberTypes(); + + for (int i = 0; i < memberTypes.getLength(); i++) { + // One of the {member type definitions} is T2. + if (memberTypes.item(i) != null) { + // T2 is derived from the other type definition by DERIVATION_RESTRICTION + if (isDerivedByRestriction(ancestorNS, ancestorName,(XSSimpleTypeDefinition)memberTypes.item(i))) { + return true; + } + } + } + } + return false; + } + + + static final XSSimpleTypeDecl fAnySimpleType = new XSSimpleTypeDecl(null, "anySimpleType", DV_ANYSIMPLETYPE, ORDERED_FALSE, false, true, false, true, XSConstants.ANYSIMPLETYPE_DT); + + static final XSSimpleTypeDecl fAnyAtomicType = new XSSimpleTypeDecl(fAnySimpleType, "anyAtomicType", DV_ANYATOMICTYPE, ORDERED_FALSE, false, true, false, true, XSSimpleTypeDecl.ANYATOMICTYPE_DT); + + /** + * Validation context used to validate facet values. + */ + static final ValidationContext fDummyContext = new ValidationContext() { + public boolean needFacetChecking() { + return true; + } + + public boolean needExtraChecking() { + return false; + } + public boolean needToNormalize() { + return false; + } + public boolean useNamespaces() { + return true; + } + + public boolean isEntityDeclared(String name) { + return false; + } + + public boolean isEntityUnparsed(String name) { + return false; + } + + public boolean isIdDeclared(String name) { + return false; + } + + public void addId(String name) { + } + + public void addIdRef(String name) { + } + + public String getSymbol (String symbol) { + return symbol.intern(); + } + + public String getURI(String prefix) { + return null; + } + + public Locale getLocale() { + return Locale.getDefault(); + } + }; + + private boolean fAnonymous = false; + + /** + * A wrapper of ValidationContext, to provide a way of switching to a + * different Namespace declaration context. + */ + static final class ValidationContextImpl implements ValidationContext { + + final ValidationContext fExternal; + + ValidationContextImpl(ValidationContext external) { + fExternal = external; + } + + NamespaceContext fNSContext; + void setNSContext(NamespaceContext nsContext) { + fNSContext = nsContext; + } + + public boolean needFacetChecking() { + return fExternal.needFacetChecking(); + } + + public boolean needExtraChecking() { + return fExternal.needExtraChecking(); + } + public boolean needToNormalize() { + return fExternal.needToNormalize(); + } + // schema validation is predicated upon namespaces + public boolean useNamespaces() { + return true; + } + + public boolean isEntityDeclared (String name) { + return fExternal.isEntityDeclared(name); + } + + public boolean isEntityUnparsed (String name) { + return fExternal.isEntityUnparsed(name); + } + + public boolean isIdDeclared (String name) { + return fExternal.isIdDeclared(name); + } + + public void addId(String name) { + fExternal.addId(name); + } + + public void addIdRef(String name) { + fExternal.addIdRef(name); + } + + public String getSymbol (String symbol) { + return fExternal.getSymbol(symbol); + } + + public String getURI(String prefix) { + if (fNSContext == null) { + return fExternal.getURI(prefix); + } + else { + return fNSContext.getURI(prefix); + } + } + + public Locale getLocale() { + return fExternal.getLocale(); + } + } + + public void reset(){ + + // if it's immutable, can't be reset: + if (fIsImmutable) return; + fItemType = null; + fMemberTypes = null; + + fTypeName = null; + fTargetNamespace = null; + fFinalSet = 0; + fBase = null; + fVariety = -1; + fValidationDV = -1; + + fFacetsDefined = 0; + fFixedFacet = 0; + + //for constraining facets + fWhiteSpace = 0; + fLength = -1; + fMinLength = -1; + fMaxLength = -1; + fTotalDigits = -1; + fFractionDigits = -1; + fPattern = null; + fPatternStr = null; + fEnumeration = null; + fLexicalPattern = null; + fLexicalEnumeration = null; + fActualEnumeration = null; + fEnumerationTypeList = null; + fEnumerationItemTypeList = null; + fMaxInclusive = null; + fMaxExclusive = null; + fMinExclusive = null; + fMinInclusive = null; + lengthAnnotation = null; + minLengthAnnotation = null; + maxLengthAnnotation = null; + whiteSpaceAnnotation = null; + totalDigitsAnnotation = null; + fractionDigitsAnnotation = null; + patternAnnotations = null; + enumerationAnnotations = null; + maxInclusiveAnnotation = null; + maxExclusiveAnnotation = null; + minInclusiveAnnotation = null; + minExclusiveAnnotation = null; + + fPatternType = SPECIAL_PATTERN_NONE; + fAnnotations = null; + fFacets = null; + + // REVISIT: reset for fundamental facets + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return fNamespaceItem; + } + + public void setNamespaceItem(XSNamespaceItem namespaceItem) { + fNamespaceItem = namespaceItem; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + return this.fTargetNamespace+"," +this.fTypeName; + } + + /** + * A list of constraining facets if it exists, otherwise an empty + * XSObjectList. Note: This method must not be used to + * retrieve values for enumeration and pattern + * facets. + */ + public XSObjectList getFacets() { + if (fFacets == null && + (fFacetsDefined != 0 || fValidationDV == DV_INTEGER)) { + + XSFacetImpl[] facets = new XSFacetImpl[10]; + int count = 0; + if ((fFacetsDefined & FACET_WHITESPACE) != 0 && + fValidationDV != DV_ANYSIMPLETYPE && + fValidationDV != DV_ANYATOMICTYPE) { + facets[count] = + new XSFacetImpl( + FACET_WHITESPACE, + WS_FACET_STRING[fWhiteSpace], + 0, + null, + (fFixedFacet & FACET_WHITESPACE) != 0, + whiteSpaceAnnotation); + count++; + } + if (fLength != -1) { + facets[count] = + new XSFacetImpl( + FACET_LENGTH, + Integer.toString(fLength), + fLength, + null, + (fFixedFacet & FACET_LENGTH) != 0, + lengthAnnotation); + count++; + } + if (fMinLength != -1) { + facets[count] = + new XSFacetImpl( + FACET_MINLENGTH, + Integer.toString(fMinLength), + fMinLength, + null, + (fFixedFacet & FACET_MINLENGTH) != 0, + minLengthAnnotation); + count++; + } + if (fMaxLength != -1) { + facets[count] = + new XSFacetImpl( + FACET_MAXLENGTH, + Integer.toString(fMaxLength), + fMaxLength, + null, + (fFixedFacet & FACET_MAXLENGTH) != 0, + maxLengthAnnotation); + count++; + } + if (fTotalDigits != -1) { + facets[count] = + new XSFacetImpl( + FACET_TOTALDIGITS, + Integer.toString(fTotalDigits), + fTotalDigits, + null, + (fFixedFacet & FACET_TOTALDIGITS) != 0, + totalDigitsAnnotation); + count++; + } + if (fValidationDV == DV_INTEGER) { + facets[count] = + new XSFacetImpl( + FACET_FRACTIONDIGITS, + "0", + 0, + null, + true, + fractionDigitsAnnotation); + count++; + } + else if (fFractionDigits != -1) { + facets[count] = + new XSFacetImpl( + FACET_FRACTIONDIGITS, + Integer.toString(fFractionDigits), + fFractionDigits, + null, + (fFixedFacet & FACET_FRACTIONDIGITS) != 0, + fractionDigitsAnnotation); + count++; + } + if (fMaxInclusive != null) { + facets[count] = + new XSFacetImpl( + FACET_MAXINCLUSIVE, + fMaxInclusive.toString(), + 0, + fMaxInclusive, + (fFixedFacet & FACET_MAXINCLUSIVE) != 0, + maxInclusiveAnnotation); + count++; + } + if (fMaxExclusive != null) { + facets[count] = + new XSFacetImpl( + FACET_MAXEXCLUSIVE, + fMaxExclusive.toString(), + 0, + fMaxExclusive, + (fFixedFacet & FACET_MAXEXCLUSIVE) != 0, + maxExclusiveAnnotation); + count++; + } + if (fMinExclusive != null) { + facets[count] = + new XSFacetImpl( + FACET_MINEXCLUSIVE, + fMinExclusive.toString(), + 0, + fMinExclusive, + (fFixedFacet & FACET_MINEXCLUSIVE) != 0, + minExclusiveAnnotation); + count++; + } + if (fMinInclusive != null) { + facets[count] = + new XSFacetImpl( + FACET_MININCLUSIVE, + fMinInclusive.toString(), + 0, + fMinInclusive, + (fFixedFacet & FACET_MININCLUSIVE) != 0, + minInclusiveAnnotation); + count++; + } + fFacets = (count > 0) ? new XSObjectListImpl(facets, count) : XSObjectListImpl.EMPTY_LIST; + } + return (fFacets != null) ? fFacets : XSObjectListImpl.EMPTY_LIST; + } + + public XSObject getFacet(int facetType) { + if (facetType == FACET_ENUMERATION || facetType == FACET_PATTERN) { + XSObjectList list = getMultiValueFacets(); + for (int i = 0; i < list.getLength(); i++) { + XSMultiValueFacet f = (XSMultiValueFacet)list.item(i); + if (f.getFacetKind() == facetType) { + return f; + } + } + } + else { + XSObjectList list = getFacets(); + for (int i = 0; i < list.getLength(); i++) { + XSFacet f = (XSFacet)list.item(i); + if (f.getFacetKind() == facetType) { + return f; + } + } + } + return null; + } + + /** + * A list of enumeration and pattern constraining facets if it exists, + * otherwise an empty XSObjectList. + */ + public XSObjectList getMultiValueFacets() { + if (fMultiValueFacets == null && + ((fFacetsDefined & FACET_ENUMERATION) != 0 || + (fFacetsDefined & FACET_PATTERN) != 0 || + fPatternType != SPECIAL_PATTERN_NONE || + fValidationDV == DV_INTEGER)) { + + XSMVFacetImpl[] facets = new XSMVFacetImpl[2]; + int count = 0; + if ((fFacetsDefined & FACET_PATTERN) != 0 || + fPatternType != SPECIAL_PATTERN_NONE || + fValidationDV == DV_INTEGER) { + facets[count] = + new XSMVFacetImpl( + FACET_PATTERN, + this.getLexicalPattern(), + null, + patternAnnotations); + count++; + } + if (fEnumeration != null) { + facets[count] = + new XSMVFacetImpl( + FACET_ENUMERATION, + this.getLexicalEnumeration(), + new ObjectListImpl(fEnumeration, fEnumerationSize), + enumerationAnnotations); + count++; + } + fMultiValueFacets = new XSObjectListImpl(facets, count); + } + return (fMultiValueFacets != null) ? + fMultiValueFacets : XSObjectListImpl.EMPTY_LIST; + } + + public Object getMinInclusiveValue() { + return fMinInclusive; + } + + public Object getMinExclusiveValue() { + return fMinExclusive; + } + + public Object getMaxInclusiveValue() { + return fMaxInclusive; + } + + public Object getMaxExclusiveValue() { + return fMaxExclusive; + } + + public void setAnonymous(boolean anon) { + fAnonymous = anon; + } + + private static final class XSFacetImpl implements XSFacet { + final short kind; + final String svalue; + final int ivalue; + Object avalue; + final boolean fixed; + final XSObjectList annotations; + + public XSFacetImpl(short kind, String svalue, int ivalue, Object avalue, boolean fixed, XSAnnotation annotation) { + this.kind = kind; + this.svalue = svalue; + this.ivalue = ivalue; + this.avalue = avalue; + this.fixed = fixed; + + if (annotation != null) { + this.annotations = new XSObjectListImpl(); + ((XSObjectListImpl)this.annotations).addXSObject(annotation); + } + else { + this.annotations = XSObjectListImpl.EMPTY_LIST; + } + } + + /* + * (non-Javadoc) + * + * @see org.apache.xerces.xs.XSFacet#getAnnotation() + */ + /** + * Optional. Annotation. + */ + public XSAnnotation getAnnotation() { + return (XSAnnotation) annotations.item(0); + } + + /* + * (non-Javadoc) + * + * @see org.apache.xerces.xs.XSFacet#getAnnotations() + */ + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return annotations; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSFacet#getFacetKind() + */ + public short getFacetKind() { + return kind; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSFacet#getLexicalFacetValue() + */ + public String getLexicalFacetValue() { + return svalue; + } + + public Object getActualFacetValue() { + if (avalue == null) { + if (kind == FACET_WHITESPACE) { + avalue = svalue; + } + else { + // Must a facet with an integer value. Use BigInteger. + avalue = BigInteger.valueOf(ivalue); + } + } + return avalue; + } + + public int getIntFacetValue() { + return ivalue; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSFacet#isFixed() + */ + public boolean getFixed() { + return fixed; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSObject#getName() + */ + public String getName() { + return null; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSObject#getNamespace() + */ + public String getNamespace() { + return null; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + // REVISIT: implement + return null; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSObject#getType() + */ + public short getType() { + return XSConstants.FACET; + } + + } + + private static final class XSMVFacetImpl implements XSMultiValueFacet { + final short kind; + final XSObjectList annotations; + final StringList svalues; + final ObjectList avalues; + + public XSMVFacetImpl(short kind, StringList svalues, ObjectList avalues, XSObjectList annotations) { + this.kind = kind; + this.svalues = svalues; + this.avalues = avalues; + this.annotations = (annotations != null) ? annotations : XSObjectListImpl.EMPTY_LIST; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSFacet#getFacetKind() + */ + public short getFacetKind() { + return kind; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSMultiValueFacet#getAnnotations() + */ + public XSObjectList getAnnotations() { + return annotations; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSMultiValueFacet#getLexicalFacetValues() + */ + public StringList getLexicalFacetValues() { + return svalues; + } + + public ObjectList getEnumerationValues() { + return avalues; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSObject#getName() + */ + public String getName() { + return null; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSObject#getNamespace() + */ + public String getNamespace() { + return null; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + // REVISIT: implement + return null; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSObject#getType() + */ + public short getType() { + return XSConstants.MULTIVALUE_FACET; + } + } + + private static abstract class AbstractObjectList extends AbstractList implements ObjectList { + public Object get(int index) { + if (index >= 0 && index < getLength()) { + return item(index); + } + throw new IndexOutOfBoundsException("Index: " + index); + } + public int size() { + return getLength(); + } + } + + public String getTypeNamespace() { + return getNamespace(); + } + + public boolean isDerivedFrom(String typeNamespaceArg, String typeNameArg, int derivationMethod) { + return isDOMDerivedFrom(typeNamespaceArg, typeNameArg, derivationMethod); + } + + private short convertToPrimitiveKind(short valueType) { + /** Primitive datatypes. */ + if (valueType <= XSConstants.NOTATION_DT) { + return valueType; + } + /** Types derived from string. */ + if (valueType <= XSConstants.ENTITY_DT) { + return XSConstants.STRING_DT; + } + /** Types derived from decimal. */ + if (valueType <= XSConstants.POSITIVEINTEGER_DT) { + return XSConstants.DECIMAL_DT; + } + /** Other types. */ + return valueType; + } + + private void appendEnumString(StringBuffer sb) { + sb.append('['); + for (int i = 0; i < fEnumerationSize; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(fEnumeration[i].actualValue); + } + sb.append(']'); + } +} // class XSSimpleTypeDecl + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/XSSimpleTypeDelegate.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/XSSimpleTypeDelegate.java new file mode 100644 index 0000000..d720dc0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/XSSimpleTypeDelegate.java @@ -0,0 +1,220 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import org.apache.xerces.impl.dv.DatatypeException; +import org.apache.xerces.impl.dv.InvalidDatatypeFacetException; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.impl.dv.XSFacets; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObject; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * Base class for XSSimpleType wrapper implementations. + * + * @xerces.internal + * + * @version $Id$ + */ +public class XSSimpleTypeDelegate + implements XSSimpleType { + + protected final XSSimpleType type; + + public XSSimpleTypeDelegate(XSSimpleType type) { + if (type == null) { + throw new NullPointerException(); + } + this.type = type; + } + + public XSSimpleType getWrappedXSSimpleType() { + return type; + } + + public XSObjectList getAnnotations() { + return type.getAnnotations(); + } + + public boolean getBounded() { + return type.getBounded(); + } + + public short getBuiltInKind() { + return type.getBuiltInKind(); + } + + public short getDefinedFacets() { + return type.getDefinedFacets(); + } + + public XSObjectList getFacets() { + return type.getFacets(); + } + + public XSObject getFacet(int facetType) { + return type.getFacet(facetType); + } + + public boolean getFinite() { + return type.getFinite(); + } + + public short getFixedFacets() { + return type.getFixedFacets(); + } + + public XSSimpleTypeDefinition getItemType() { + return type.getItemType(); + } + + public StringList getLexicalEnumeration() { + return type.getLexicalEnumeration(); + } + + public String getLexicalFacetValue(short facetName) { + return type.getLexicalFacetValue(facetName); + } + + public StringList getLexicalPattern() { + return type.getLexicalPattern(); + } + + public XSObjectList getMemberTypes() { + return type.getMemberTypes(); + } + + public XSObjectList getMultiValueFacets() { + return type.getMultiValueFacets(); + } + + public boolean getNumeric() { + return type.getNumeric(); + } + + public short getOrdered() { + return type.getOrdered(); + } + + public XSSimpleTypeDefinition getPrimitiveType() { + return type.getPrimitiveType(); + } + + public short getVariety() { + return type.getVariety(); + } + + public boolean isDefinedFacet(short facetName) { + return type.isDefinedFacet(facetName); + } + + public boolean isFixedFacet(short facetName) { + return type.isFixedFacet(facetName); + } + + public boolean derivedFrom(String namespace, String name, short derivationMethod) { + return type.derivedFrom(namespace, name, derivationMethod); + } + + public boolean derivedFromType(XSTypeDefinition ancestorType, short derivationMethod) { + return type.derivedFromType(ancestorType, derivationMethod); + } + + public boolean getAnonymous() { + return type.getAnonymous(); + } + + public XSTypeDefinition getBaseType() { + return type.getBaseType(); + } + + public short getFinal() { + return type.getFinal(); + } + + public short getTypeCategory() { + return type.getTypeCategory(); + } + + public boolean isFinal(short restriction) { + return type.isFinal(restriction); + } + + public String getName() { + return type.getName(); + } + + public String getNamespace() { + return type.getNamespace(); + } + + public XSNamespaceItem getNamespaceItem() { + return type.getNamespaceItem(); + } + + public short getType() { + return type.getType(); + } + + public void applyFacets(XSFacets facets, short presentFacet, short fixedFacet, ValidationContext context) + throws InvalidDatatypeFacetException { + type.applyFacets(facets, presentFacet, fixedFacet, context); + } + + public short getPrimitiveKind() { + return type.getPrimitiveKind(); + } + + public short getWhitespace() throws DatatypeException { + return type.getWhitespace(); + } + + public boolean isEqual(Object value1, Object value2) { + return type.isEqual(value1, value2); + } + + public boolean isIDType() { + return type.isIDType(); + } + + public void validate(ValidationContext context, ValidatedInfo validatedInfo) + throws InvalidDatatypeValueException { + type.validate(context, validatedInfo); + } + + public Object validate(String content, ValidationContext context, ValidatedInfo validatedInfo) + throws InvalidDatatypeValueException { + return type.validate(content, context, validatedInfo); + } + + public Object validate(Object content, ValidationContext context, ValidatedInfo validatedInfo) + throws InvalidDatatypeValueException { + return type.validate(content, context, validatedInfo); + } + + public String toString() { + return type.toString(); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearDV.java new file mode 100644 index 0000000..d172f2d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearDV.java @@ -0,0 +1,126 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Validator for <gYear> datatype (W3C Schema Datatypes) + * + * @xerces.internal + * + * @author Elena Litani + * @author Gopal Sharma, SUN Microsystem Inc. + * + * @version $Id$ + */ + +public class YearDV extends AbstractDateTimeDV { + + /** + * Convert a string to a compiled form + * + * @param content The lexical representation of time + * @return a valid and normalized time object + */ + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{ + try{ + return parse(content); + } catch(Exception ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "gYear"}); + } + } + + /** + * Parses, validates and computes normalized version of gYear object + * + * @param str The lexical representation of year object CCYY + * with possible time zone Z or (-),(+)hh:mm + * @return normalized date representation + * @exception SchemaDateTimeException Invalid lexical representation + */ + protected DateTimeData parse(String str) throws SchemaDateTimeException{ + DateTimeData date = new DateTimeData(str, this); + int len = str.length(); + + // check for preceding '-' sign + int start = 0; + if (str.charAt(0)=='-') { + start = 1; + } + int sign = findUTCSign(str, start, len); + + final int length = ((sign == -1) ? len : sign) - start; + if (length < 4) { + throw new RuntimeException("Year must have 'CCYY' format"); + } + else if (length > 4 && str.charAt(start) == '0') { + throw new RuntimeException("Leading zeros are required if the year value would otherwise have fewer than four digits; otherwise they are forbidden"); + } + + if (sign == -1) { + date.year=parseIntYear(str, len); + } + else { + date.year=parseIntYear(str, sign); + getTimeZone (str, date, sign, len); + } + + //initialize values + date.month=MONTH; + date.day=1; + + //validate and normalize + validateDateTime(date); + + //save unnormalized values + saveUnnormalized(date); + + if ( date.utc!=0 && date.utc!='Z' ) { + normalize(date); + } + date.position = 0; + return date; + } + + /** + * Converts year object representation to String + * + * @param date year object + * @return lexical representation of month: CCYY with optional time zone sign + */ + protected String dateToString(DateTimeData date) { + StringBuffer message = new StringBuffer(5); + append(message, date.year, 4); + append(message, (char)date.utc, 0); + return message.toString(); + } + + protected XMLGregorianCalendar getXMLGregorianCalendar(DateTimeData date) { + return datatypeFactory.newXMLGregorianCalendar(date.unNormYear, DatatypeConstants.FIELD_UNDEFINED, + DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, + DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, + date.hasTimeZone() ? date.timezoneHr * 60 + date.timezoneMin : DatatypeConstants.FIELD_UNDEFINED); + } +} + + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearMonthDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearMonthDV.java new file mode 100644 index 0000000..acf064f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearMonthDV.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Validator for <gYearMonth> datatype (W3C Schema Datatypes) + * + * @xerces.internal + * + * @author Elena Litani + * @author Gopal Sharma, SUN Microsystem Inc. + * + * @version $Id$ + */ +public class YearMonthDV extends AbstractDateTimeDV{ + + /** + * Convert a string to a compiled form + * + * @param content The lexical representation of gYearMonth + * @return a valid and normalized gYearMonth object + */ + public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException{ + try{ + return parse(content); + } catch(Exception ex){ + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "gYearMonth"}); + } + } + + /** + * Parses, validates and computes normalized version of gYearMonth object + * + * @param str The lexical representation of gYearMonth object CCYY-MM + * with possible time zone Z or (-),(+)hh:mm + * @return normalized date representation + * @exception SchemaDateTimeException Invalid lexical representation + */ + protected DateTimeData parse(String str) throws SchemaDateTimeException{ + DateTimeData date = new DateTimeData(str, this); + int len = str.length(); + + // get date + int end = getYearMonth(str, 0, len, date); + date.day = DAY; + parseTimeZone (str, end, len, date); + + //validate and normalize + + validateDateTime(date); + + //save unnormalized values + saveUnnormalized(date); + + if ( date.utc!=0 && date.utc!='Z' ) { + normalize(date); + } + date.position = 0; + return date; + } + + protected String dateToString(DateTimeData date) { + StringBuffer message = new StringBuffer(25); + append(message, date.year, 4); + message.append('-'); + append(message, date.month, 2); + append(message, (char)date.utc, 0); + return message.toString(); + } + + protected XMLGregorianCalendar getXMLGregorianCalendar(DateTimeData date) { + return datatypeFactory.newXMLGregorianCalendar(date.unNormYear, date.unNormMonth, DatatypeConstants.FIELD_UNDEFINED, + DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, + DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, + date.hasTimeZone() ? date.timezoneHr * 60 + date.timezoneMin : DatatypeConstants.FIELD_UNDEFINED); + } +} + + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearMonthDurationDV.java b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearMonthDurationDV.java new file mode 100644 index 0000000..970d6df --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/dv/xs/YearMonthDurationDV.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.dv.xs; + +import java.math.BigInteger; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.Duration; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidationContext; + +/** + * Used to validate the type + * + * @xerces.internal + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +class YearMonthDurationDV extends DurationDV { + + public Object getActualValue(String content, ValidationContext context) + throws InvalidDatatypeValueException { + try { + return parse(content, DurationDV.YEARMONTHDURATION_TYPE); + } + catch (Exception ex) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "yearMonthDuration"}); + } + } + + protected Duration getDuration(DateTimeData date) { + int sign = 1; + if ( date.year<0 || date.month<0) { + sign = -1; + } + return datatypeFactory.newDuration(sign == 1, + date.year != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.year):null, + date.month != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.month):null, + null, + null, + null, + null); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/io/ASCIIReader.java b/resources/xerces2-j-src/org/apache/xerces/impl/io/ASCIIReader.java new file mode 100644 index 0000000..6aa7ff5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/io/ASCIIReader.java @@ -0,0 +1,249 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.Locale; + +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.MessageFormatter; + +/** + * A simple ASCII byte reader. This is an optimized reader for reading + * byte streams that only contain 7-bit ASCII characters. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public final class ASCIIReader + extends Reader { + + // + // Constants + // + + /** Default byte buffer size (2048). */ + public static final int DEFAULT_BUFFER_SIZE = 2048; + + // + // Data + // + + /** Input stream. */ + protected final InputStream fInputStream; + + /** Byte buffer. */ + protected final byte[] fBuffer; + + // message formatter; used to produce localized + // exception messages + private final MessageFormatter fFormatter; + + //Locale to use for messages + private final Locale fLocale; + + // + // Constructors + // + + /** + * Constructs an ASCII reader from the specified input stream + * using the default buffer size. + * + * @param inputStream The input stream. + * @param messageFormatter the MessageFormatter to use to message reporting. + * @param locale the Locale for which messages are to be reported + */ + public ASCIIReader(InputStream inputStream, MessageFormatter messageFormatter, + Locale locale) { + this(inputStream, DEFAULT_BUFFER_SIZE, messageFormatter, locale); + } // (InputStream, MessageFormatter, Locale) + + /** + * Constructs an ASCII reader from the specified input stream + * and buffer size. + * + * @param inputStream The input stream. + * @param size The initial buffer size. + * @param messageFormatter the MessageFormatter to use to message reporting. + * @param locale the Locale for which messages are to be reported + */ + public ASCIIReader(InputStream inputStream, int size, + MessageFormatter messageFormatter, Locale locale) { + this(inputStream, new byte[size], messageFormatter, locale); + } // (InputStream, int, MessageFormatter, Locale) + + /** + * Constructs an ASCII reader from the specified input stream and buffer. + * + * @param inputStream The input stream. + * @param buffer The byte buffer. + * @param messageFormatter the MessageFormatter to use to message reporting. + * @param locale the Locale for which messages are to be reported + */ + public ASCIIReader(InputStream inputStream, byte [] buffer, + MessageFormatter messageFormatter, Locale locale) { + fInputStream = inputStream; + fBuffer = buffer; + fFormatter = messageFormatter; + fLocale = locale; + } // (InputStream, byte[], MessageFormatter, Locale) + + // + // Reader methods + // + + /** + * Read a single character. This method will block until a character is + * available, an I/O error occurs, or the end of the stream is reached. + * + *

Subclasses that intend to support efficient single-character input + * should override this method. + * + * @return The character read, as an integer in the range 0 to 127 + * (0x00-0x7f), or -1 if the end of the stream has + * been reached + * + * @exception IOException If an I/O error occurs + */ + public int read() throws IOException { + int b0 = fInputStream.read(); + if (b0 >= 0x80) { + throw new MalformedByteSequenceException(fFormatter, + fLocale, XMLMessageFormatter.XML_DOMAIN, + "InvalidASCII", new Object [] {Integer.toString(b0)}); + } + return b0; + } // read():int + + /** + * Read characters into a portion of an array. This method will block + * until some input is available, an I/O error occurs, or the end of the + * stream is reached. + * + * @param ch Destination buffer + * @param offset Offset at which to start storing characters + * @param length Maximum number of characters to read + * + * @return The number of characters read, or -1 if the end of the + * stream has been reached + * + * @exception IOException If an I/O error occurs + */ + public int read(char ch[], int offset, int length) throws IOException { + if (length > fBuffer.length) { + length = fBuffer.length; + } + int count = fInputStream.read(fBuffer, 0, length); + for (int i = 0; i < count; i++) { + int b0 = fBuffer[i]; + if (b0 < 0) { + throw new MalformedByteSequenceException(fFormatter, + fLocale, XMLMessageFormatter.XML_DOMAIN, + "InvalidASCII", new Object [] {Integer.toString(b0 & 0x0FF)}); + } + ch[offset + i] = (char)b0; + } + return count; + } // read(char[],int,int) + + /** + * Skip characters. This method will block until some characters are + * available, an I/O error occurs, or the end of the stream is reached. + * + * @param n The number of characters to skip + * + * @return The number of characters actually skipped + * + * @exception IOException If an I/O error occurs + */ + public long skip(long n) throws IOException { + return fInputStream.skip(n); + } // skip(long):long + + /** + * Tell whether this stream is ready to be read. + * + * @return True if the next read() is guaranteed not to block for input, + * false otherwise. Note that returning false does not guarantee that the + * next read will block. + * + * @exception IOException If an I/O error occurs + */ + public boolean ready() throws IOException { + return false; + } // ready() + + /** + * Tell whether this stream supports the mark() operation. + */ + public boolean markSupported() { + return fInputStream.markSupported(); + } // markSupported() + + /** + * Mark the present position in the stream. Subsequent calls to reset() + * will attempt to reposition the stream to this point. Not all + * character-input streams support the mark() operation. + * + * @param readAheadLimit Limit on the number of characters that may be + * read while still preserving the mark. After + * reading this many characters, attempting to + * reset the stream may fail. + * + * @exception IOException If the stream does not support mark(), + * or if some other I/O error occurs + */ + public void mark(int readAheadLimit) throws IOException { + fInputStream.mark(readAheadLimit); + } // mark(int) + + /** + * Reset the stream. If the stream has been marked, then attempt to + * reposition it at the mark. If the stream has not been marked, then + * attempt to reset it in some way appropriate to the particular stream, + * for example by repositioning it to its starting point. Not all + * character-input streams support the reset() operation, and some support + * reset() without supporting mark(). + * + * @exception IOException If the stream has not been marked, + * or if the mark has been invalidated, + * or if the stream does not support reset(), + * or if some other I/O error occurs + */ + public void reset() throws IOException { + fInputStream.reset(); + } // reset() + + /** + * Close the stream. Once a stream has been closed, further read(), + * ready(), mark(), or reset() invocations will throw an IOException. + * Closing a previously-closed stream, however, has no effect. + * + * @exception IOException If an I/O error occurs + */ + public void close() throws IOException { + fInputStream.close(); + } // close() + +} // class ASCIIReader diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/io/Latin1Reader.java b/resources/xerces2-j-src/org/apache/xerces/impl/io/Latin1Reader.java new file mode 100644 index 0000000..2c94202 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/io/Latin1Reader.java @@ -0,0 +1,214 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +/** + *

Reader for the ISO-8859-1 encoding.

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class Latin1Reader + extends Reader { + + // + // Constants + // + + /** Default byte buffer size (2048). */ + public static final int DEFAULT_BUFFER_SIZE = 2048; + + // + // Data + // + + /** Input stream. */ + protected final InputStream fInputStream; + + /** Byte buffer. */ + protected final byte[] fBuffer; + + // + // Constructors + // + + /** + * Constructs an ISO-8859-1 reader from the specified input stream + * using the default buffer size. + * + * @param inputStream The input stream. + */ + public Latin1Reader(InputStream inputStream) { + this(inputStream, DEFAULT_BUFFER_SIZE); + } // (InputStream) + + /** + * Constructs an ISO-8859-1 reader from the specified input stream + * and buffer size. + * + * @param inputStream The input stream. + * @param size The initial buffer size. + */ + public Latin1Reader(InputStream inputStream, int size) { + this(inputStream, new byte[size]); + } // (InputStream, int) + + /** + * Constructs an ISO-8859-1 reader from the specified input stream and buffer. + * + * @param inputStream The input stream. + * @param buffer The byte buffer. + */ + public Latin1Reader(InputStream inputStream, byte [] buffer) { + fInputStream = inputStream; + fBuffer = buffer; + } // (InputStream, byte[]) + + // + // Reader methods + // + + /** + * Read a single character. This method will block until a character is + * available, an I/O error occurs, or the end of the stream is reached. + * + *

Subclasses that intend to support efficient single-character input + * should override this method. + * + * @return The character read, as an integer in the range 0 to 255 + * (0x00-0xff), or -1 if the end of the stream has + * been reached + * + * @exception IOException If an I/O error occurs + */ + public int read() throws IOException { + return fInputStream.read(); + } // read():int + + /** + * Read characters into a portion of an array. This method will block + * until some input is available, an I/O error occurs, or the end of the + * stream is reached. + * + * @param ch Destination buffer + * @param offset Offset at which to start storing characters + * @param length Maximum number of characters to read + * + * @return The number of characters read, or -1 if the end of the + * stream has been reached + * + * @exception IOException If an I/O error occurs + */ + public int read(char ch[], int offset, int length) throws IOException { + if (length > fBuffer.length) { + length = fBuffer.length; + } + int count = fInputStream.read(fBuffer, 0, length); + for (int i = 0; i < count; ++i) { + ch[offset + i] = (char) (fBuffer[i] & 0xff); + } + return count; + } // read(char[],int,int) + + /** + * Skip characters. This method will block until some characters are + * available, an I/O error occurs, or the end of the stream is reached. + * + * @param n The number of characters to skip + * + * @return The number of characters actually skipped + * + * @exception IOException If an I/O error occurs + */ + public long skip(long n) throws IOException { + return fInputStream.skip(n); + } // skip(long):long + + /** + * Tell whether this stream is ready to be read. + * + * @return True if the next read() is guaranteed not to block for input, + * false otherwise. Note that returning false does not guarantee that the + * next read will block. + * + * @exception IOException If an I/O error occurs + */ + public boolean ready() throws IOException { + return false; + } // ready() + + /** + * Tell whether this stream supports the mark() operation. + */ + public boolean markSupported() { + return fInputStream.markSupported(); + } // markSupported() + + /** + * Mark the present position in the stream. Subsequent calls to reset() + * will attempt to reposition the stream to this point. Not all + * character-input streams support the mark() operation. + * + * @param readAheadLimit Limit on the number of characters that may be + * read while still preserving the mark. After + * reading this many characters, attempting to + * reset the stream may fail. + * + * @exception IOException If the stream does not support mark(), + * or if some other I/O error occurs + */ + public void mark(int readAheadLimit) throws IOException { + fInputStream.mark(readAheadLimit); + } // mark(int) + + /** + * Reset the stream. If the stream has been marked, then attempt to + * reposition it at the mark. If the stream has not been marked, then + * attempt to reset it in some way appropriate to the particular stream, + * for example by repositioning it to its starting point. Not all + * character-input streams support the reset() operation, and some support + * reset() without supporting mark(). + * + * @exception IOException If the stream has not been marked, + * or if the mark has been invalidated, + * or if the stream does not support reset(), + * or if some other I/O error occurs + */ + public void reset() throws IOException { + fInputStream.reset(); + } // reset() + + /** + * Close the stream. Once a stream has been closed, further read(), + * ready(), mark(), or reset() invocations will throw an IOException. + * Closing a previously-closed stream, however, has no effect. + * + * @exception IOException If an I/O error occurs + */ + public void close() throws IOException { + fInputStream.close(); + } // close() + +} // class Latin1Reader diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/io/MalformedByteSequenceException.java b/resources/xerces2-j-src/org/apache/xerces/impl/io/MalformedByteSequenceException.java new file mode 100644 index 0000000..15a406b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/io/MalformedByteSequenceException.java @@ -0,0 +1,138 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.io; + +import java.io.CharConversionException; +import java.util.Locale; + +import org.apache.xerces.util.MessageFormatter; + +/** + *

Signals that a malformed byte sequence was detected + * by a java.io.Reader that decodes bytes + * of a given encoding into characters.

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class MalformedByteSequenceException extends CharConversionException { + + /** Serialization version. */ + static final long serialVersionUID = 8436382245048328739L; + + // + // Data + // + + /** message formatter **/ + private MessageFormatter fFormatter; + + /** locale for error message **/ + private Locale fLocale; + + /** error domain **/ + private String fDomain; + + /** key for the error message **/ + private String fKey; + + /** replacement arguements for the error message **/ + private Object[] fArguments; + + /** message text for this message, initially null **/ + private String fMessage; + + // + // Constructors + // + + /** + * Constructs a MalformedByteSequenceException with the given + * parameters which may be passed to an error reporter to + * generate a localized string for this exception. + * + * @param formatter The MessageFormatter used for building the + * message text for this exception. + * @param locale The Locale for which messages are to be reported. + * @param domain The error domain. + * @param key The key of the error message. + * @param arguments The replacement arguments for the error message, + * if needed. + */ + public MalformedByteSequenceException(MessageFormatter formatter, + Locale locale, String domain, String key, Object[] arguments) { + fFormatter = formatter; + fLocale = locale; + fDomain = domain; + fKey = key; + fArguments = arguments; + } // (MessageFormatter, Locale, String, String, Object[]) + + // + // Public methods + // + + /** + *

Returns the error domain of the error message.

+ * + * @return the error domain + */ + public String getDomain () { + return fDomain; + } // getDomain + + /** + *

Returns the key of the error message.

+ * + * @return the error key of the error message + */ + public String getKey () { + return fKey; + } // getKey() + + /** + *

Returns the replacement arguments for the error + * message or null if none exist.

+ * + * @return the replacement arguments for the error message + * or null if none exist + */ + public Object[] getArguments () { + return fArguments; + } // getArguments(); + + /** + *

Returns the localized message for this exception.

+ * + * @return the localized message for this exception. + */ + public synchronized String getMessage() { + if (fMessage == null) { + fMessage = fFormatter.formatMessage(fLocale, fKey, fArguments); + // The references to the message formatter and locale + // aren't needed anymore so null them. + fFormatter = null; + fLocale = null; + } + return fMessage; + } // getMessage() + +} // MalformedByteSequenceException diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/io/UCSReader.java b/resources/xerces2-j-src/org/apache/xerces/impl/io/UCSReader.java new file mode 100644 index 0000000..188387b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/io/UCSReader.java @@ -0,0 +1,325 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +/** + * Reader for UCS-2 and UCS-4 encodings. + * (i.e., encodings from ISO-10646-UCS-(2|4)). + * + * @xerces.internal + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public final class UCSReader extends Reader { + + // + // Constants + // + + /** + * Default byte buffer size (8192, larger than that of ASCIIReader + * since it's reasonable to surmise that the average UCS-4-encoded + * file should be 4 times as large as the average ASCII-encoded file). + */ + public static final int DEFAULT_BUFFER_SIZE = 8192; + + public static final short UCS2LE = 1; + public static final short UCS2BE = 2; + public static final short UCS4LE = 4; + public static final short UCS4BE = 8; + + // + // Data + // + + /** Input stream. */ + protected final InputStream fInputStream; + + /** Byte buffer. */ + protected final byte[] fBuffer; + + // what kind of data we're dealing with + protected final short fEncoding; + + // + // Constructors + // + + /** + * Constructs a UCS reader from the specified input stream + * using the default buffer size. The Endian-ness and whether this is + * UCS-2 or UCS-4 needs also to be known in advance. + * + * @param inputStream The input stream. + * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE. + */ + public UCSReader(InputStream inputStream, short encoding) { + this(inputStream, DEFAULT_BUFFER_SIZE, encoding); + } // (InputStream, short) + + /** + * Constructs a UCS reader from the specified input stream + * and buffer size. The Endian-ness and whether this is + * UCS-2 or UCS-4 needs also to be known in advance. + * + * @param inputStream The input stream. + * @param size The initial buffer size. + * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE. + */ + public UCSReader(InputStream inputStream, int size, short encoding) { + this(inputStream, new byte[size], encoding); + } // (InputStream,int,short) + + /** + * Constructs a UCS reader from the specified input stream + * and buffer. The Endian-ness and whether this is + * UCS-2 or UCS-4 needs also to be known in advance. + * + * @param inputStream The input stream. + * @param buffer The byte buffer. + * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE. + */ + public UCSReader(InputStream inputStream, byte [] buffer, short encoding) { + fInputStream = inputStream; + fBuffer = buffer; + fEncoding = encoding; + } // (InputStream,int,short) + + // + // Reader methods + // + + /** + * Read a single character. This method will block until a character is + * available, an I/O error occurs, or the end of the stream is reached. + * + *

Subclasses that intend to support efficient single-character input + * should override this method. + * + * @return The character read, as an integer in the range 0 to 127 + * (0x00-0x7f), or -1 if the end of the stream has + * been reached + * + * @exception IOException If an I/O error occurs + */ + public int read() throws IOException { + int b0 = fInputStream.read() & 0xff; + if (b0 == 0xff) { + return -1; + } + int b1 = fInputStream.read() & 0xff; + if (b1 == 0xff) { + return -1; + } + // UCS-4 + if (fEncoding >= 4) { + int b2 = fInputStream.read() & 0xff; + if (b2 == 0xff) { + return -1; + } + int b3 = fInputStream.read() & 0xff; + if (b3 == 0xff) { + return -1; + } + if (fEncoding == UCS4BE) { + return (b0<<24)+(b1<<16)+(b2<<8)+b3; + } + return (b3<<24)+(b2<<16)+(b1<<8)+b0; + } + // UCS-2 + if (fEncoding == UCS2BE) { + return (b0<<8)+b1; + } + return (b1<<8)+b0; + } // read():int + + /** + * Read characters into a portion of an array. This method will block + * until some input is available, an I/O error occurs, or the end of the + * stream is reached. + * + * @param ch Destination buffer + * @param offset Offset at which to start storing characters + * @param length Maximum number of characters to read + * + * @return The number of characters read, or -1 if the end of the + * stream has been reached + * + * @exception IOException If an I/O error occurs + */ + public int read(char ch[], int offset, int length) throws IOException { + int byteLength = length << ((fEncoding >= 4)?2:1); + if (byteLength > fBuffer.length) { + byteLength = fBuffer.length; + } + int count = fInputStream.read(fBuffer, 0, byteLength); + if (count == -1) return -1; + // try and make count be a multiple of the number of bytes we're looking for + if (fEncoding >= 4) { // BigEndian + // this looks ugly, but it avoids an if at any rate... + int numToRead = (4 - (count & 3) & 3); + for (int i = 0; i < numToRead; i++) { + int charRead = fInputStream.read(); + if (charRead == -1) { // end of input; something likely went wrong!A Pad buffer with nulls. + for (int j = i; j < numToRead; j++) { + fBuffer[count+j] = 0; + } + break; + } + fBuffer[count+i] = (byte)charRead; + } + count += numToRead; + } + else { + int numToRead = count & 1; + if (numToRead != 0) { + count++; + int charRead = fInputStream.read(); + if (charRead == -1) { // end of input; something likely went wrong!A Pad buffer with nulls. + fBuffer[count] = 0; + } + else { + fBuffer[count] = (byte)charRead; + } + } + } + + // now count is a multiple of the right number of bytes + int numChars = count >> ((fEncoding >= 4)?2:1); + int curPos = 0; + for (int i = 0; i < numChars; i++) { + int b0 = fBuffer[curPos++] & 0xff; + int b1 = fBuffer[curPos++] & 0xff; + // UCS-4 + if (fEncoding >= 4) { + int b2 = fBuffer[curPos++] & 0xff; + int b3 = fBuffer[curPos++] & 0xff; + if (fEncoding == UCS4BE) { + ch[offset+i] = (char)((b0<<24)+(b1<<16)+(b2<<8)+b3); + } + else { + ch[offset+i] = (char)((b3<<24)+(b2<<16)+(b1<<8)+b0); + } + } + else { // UCS-2 + if (fEncoding == UCS2BE) { + ch[offset+i] = (char)((b0<<8)+b1); + } + else { + ch[offset+i] = (char)((b1<<8)+b0); + } + } + } + return numChars; + } // read(char[],int,int) + + /** + * Skip characters. This method will block until some characters are + * available, an I/O error occurs, or the end of the stream is reached. + * + * @param n The number of characters to skip + * + * @return The number of characters actually skipped + * + * @exception IOException If an I/O error occurs + */ + public long skip(long n) throws IOException { + // charWidth will represent the number of bits to move + // n leftward to get num of bytes to skip, and then move the result rightward + // to get num of chars effectively skipped. + // The trick with &'ing, as with elsewhere in this dcode, is + // intended to avoid an expensive use of / that might not be optimized + // away. + int charWidth = (fEncoding >=4)?2:1; + long bytesSkipped = fInputStream.skip(n<> charWidth; + return (bytesSkipped >> charWidth) + 1; + } // skip(long):long + + /** + * Tell whether this stream is ready to be read. + * + * @return True if the next read() is guaranteed not to block for input, + * false otherwise. Note that returning false does not guarantee that the + * next read will block. + * + * @exception IOException If an I/O error occurs + */ + public boolean ready() throws IOException { + return false; + } // ready() + + /** + * Tell whether this stream supports the mark() operation. + */ + public boolean markSupported() { + return fInputStream.markSupported(); + } // markSupported() + + /** + * Mark the present position in the stream. Subsequent calls to reset() + * will attempt to reposition the stream to this point. Not all + * character-input streams support the mark() operation. + * + * @param readAheadLimit Limit on the number of characters that may be + * read while still preserving the mark. After + * reading this many characters, attempting to + * reset the stream may fail. + * + * @exception IOException If the stream does not support mark(), + * or if some other I/O error occurs + */ + public void mark(int readAheadLimit) throws IOException { + fInputStream.mark(readAheadLimit); + } // mark(int) + + /** + * Reset the stream. If the stream has been marked, then attempt to + * reposition it at the mark. If the stream has not been marked, then + * attempt to reset it in some way appropriate to the particular stream, + * for example by repositioning it to its starting point. Not all + * character-input streams support the reset() operation, and some support + * reset() without supporting mark(). + * + * @exception IOException If the stream has not been marked, + * or if the mark has been invalidated, + * or if the stream does not support reset(), + * or if some other I/O error occurs + */ + public void reset() throws IOException { + fInputStream.reset(); + } // reset() + + /** + * Close the stream. Once a stream has been closed, further read(), + * ready(), mark(), or reset() invocations will throw an IOException. + * Closing a previously-closed stream, however, has no effect. + * + * @exception IOException If an I/O error occurs + */ + public void close() throws IOException { + fInputStream.close(); + } // close() + +} // class UCSReader diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/io/UTF16Reader.java b/resources/xerces2-j-src/org/apache/xerces/impl/io/UTF16Reader.java new file mode 100644 index 0000000..3318438 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/io/UTF16Reader.java @@ -0,0 +1,323 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.Locale; + +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.MessageFormatter; + +/** + *

A UTF-16 reader. Can also be used for UCS-2 (i.e. ISO-10646-UCS-2).

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class UTF16Reader + extends Reader { + + // + // Constants + // + + /** Default byte buffer size (4096). */ + public static final int DEFAULT_BUFFER_SIZE = 4096; + + // + // Data + // + + /** Input stream. */ + protected final InputStream fInputStream; + + /** Byte buffer. */ + protected final byte[] fBuffer; + + /** Endianness. */ + protected final boolean fIsBigEndian; + + // message formatter; used to produce localized exception messages + private final MessageFormatter fFormatter; + + // Locale to use for messages + private final Locale fLocale; + + // + // Constructors + // + + /** + * Constructs a UTF-16 reader from the specified input stream + * using the default buffer size. Primarily for testing. + * + * @param inputStream The input stream. + * @param isBigEndian The byte order. + */ + public UTF16Reader(InputStream inputStream, boolean isBigEndian) { + this(inputStream, DEFAULT_BUFFER_SIZE, isBigEndian, + new XMLMessageFormatter(), Locale.getDefault()); + } // (InputStream, boolean) + + /** + * Constructs a UTF-16 reader from the specified input stream + * using the default buffer size and the given MessageFormatter. + * + * @param inputStream The input stream. + * @param isBigEndian The byte order. + */ + public UTF16Reader(InputStream inputStream, boolean isBigEndian, + MessageFormatter messageFormatter, Locale locale) { + this(inputStream, DEFAULT_BUFFER_SIZE, isBigEndian, messageFormatter, locale); + } // (InputStream, boolean, MessageFormatter, Locale) + + /** + * Constructs a UTF-16 reader from the specified input stream + * and buffer size and given MessageFormatter. + * + * @param inputStream The input stream. + * @param size The initial buffer size. + * @param isBigEndian The byte order. + * @param messageFormatter Given MessageFormatter + * @param locale Locale to use for messages + */ + public UTF16Reader(InputStream inputStream, int size, boolean isBigEndian, + MessageFormatter messageFormatter, Locale locale) { + this(inputStream, new byte[size], isBigEndian, messageFormatter, locale); + } // (InputStream, int, boolean, MessageFormatter, Locale) + + /** + * Constructs a UTF-16 reader from the specified input stream, + * buffer and MessageFormatter. + * + * @param inputStream The input stream. + * @param buffer The byte buffer. + * @param isBigEndian The byte order. + * @param messageFormatter Given MessageFormatter + * @param locale Locale to use for messages + */ + public UTF16Reader(InputStream inputStream, byte [] buffer, boolean isBigEndian, + MessageFormatter messageFormatter, Locale locale) { + fInputStream = inputStream; + fBuffer = buffer; + fIsBigEndian = isBigEndian; + fFormatter = messageFormatter; + fLocale = locale; + } // (InputStream, byte[], boolean, MessageFormatter, Locale) + + // + // Reader methods + // + + /** + * Read a single character. This method will block until a character is + * available, an I/O error occurs, or the end of the stream is reached. + * + *

Subclasses that intend to support efficient single-character input + * should override this method. + * + * @return The character read, as an integer in the range 0 to 65535 + * (0x00-0xffff), or -1 if the end of the stream has + * been reached + * + * @exception IOException If an I/O error occurs + */ + public int read() throws IOException { + final int b0 = fInputStream.read(); + if (b0 == -1) { + return -1; + } + final int b1 = fInputStream.read(); + if (b1 == -1) { + expectedTwoBytes(); + } + // UTF-16BE + if (fIsBigEndian) { + return (b0 << 8) | b1; + } + // UTF-16LE + return (b1 << 8) | b0; + } // read():int + + /** + * Read characters into a portion of an array. This method will block + * until some input is available, an I/O error occurs, or the end of the + * stream is reached. + * + * @param ch Destination buffer + * @param offset Offset at which to start storing characters + * @param length Maximum number of characters to read + * + * @return The number of characters read, or -1 if the end of the + * stream has been reached + * + * @exception IOException If an I/O error occurs + */ + public int read(char ch[], int offset, int length) throws IOException { + int byteLength = length << 1; + if (byteLength > fBuffer.length) { + byteLength = fBuffer.length; + } + int byteCount = fInputStream.read(fBuffer, 0, byteLength); + if (byteCount == -1) { + return -1; + } + // If an odd number of bytes were read, we still need to read one more. + if ((byteCount & 1) != 0) { + int b = fInputStream.read(); + if (b == -1) { + expectedTwoBytes(); + } + fBuffer[byteCount++] = (byte) b; + } + final int charCount = byteCount >> 1; + if (fIsBigEndian) { + processBE(ch, offset, charCount); + } + else { + processLE(ch, offset, charCount); + } + return charCount; + } // read(char[],int,int) + + /** + * Skip characters. This method will block until some characters are + * available, an I/O error occurs, or the end of the stream is reached. + * + * @param n The number of characters to skip + * + * @return The number of characters actually skipped + * + * @exception IOException If an I/O error occurs + */ + public long skip(long n) throws IOException { + long bytesSkipped = fInputStream.skip(n << 1); + if ((bytesSkipped & 1) != 0) { + int b = fInputStream.read(); + if (b == -1) { + expectedTwoBytes(); + } + ++bytesSkipped; + } + return bytesSkipped >> 1; + } // skip(long):long + + /** + * Tell whether this stream is ready to be read. + * + * @return True if the next read() is guaranteed not to block for input, + * false otherwise. Note that returning false does not guarantee that the + * next read will block. + * + * @exception IOException If an I/O error occurs + */ + public boolean ready() throws IOException { + return false; + } // ready() + + /** + * Tell whether this stream supports the mark() operation. + */ + public boolean markSupported() { + return false; + } // markSupported() + + /** + * Mark the present position in the stream. Subsequent calls to reset() + * will attempt to reposition the stream to this point. Not all + * character-input streams support the mark() operation. + * + * @param readAheadLimit Limit on the number of characters that may be + * read while still preserving the mark. After + * reading this many characters, attempting to + * reset the stream may fail. + * + * @exception IOException If the stream does not support mark(), + * or if some other I/O error occurs + */ + public void mark(int readAheadLimit) throws IOException { + throw new IOException(fFormatter.formatMessage(fLocale, "OperationNotSupported", new Object[]{"mark()", "UTF-16"})); + } // mark(int) + + /** + * Reset the stream. If the stream has been marked, then attempt to + * reposition it at the mark. If the stream has not been marked, then + * attempt to reset it in some way appropriate to the particular stream, + * for example by repositioning it to its starting point. Not all + * character-input streams support the reset() operation, and some support + * reset() without supporting mark(). + * + * @exception IOException If the stream has not been marked, + * or if the mark has been invalidated, + * or if the stream does not support reset(), + * or if some other I/O error occurs + */ + public void reset() throws IOException { + } // reset() + + /** + * Close the stream. Once a stream has been closed, further read(), + * ready(), mark(), or reset() invocations will throw an IOException. + * Closing a previously-closed stream, however, has no effect. + * + * @exception IOException If an I/O error occurs + */ + public void close() throws IOException { + fInputStream.close(); + } // close() + + // + // Private methods + // + + /** Decodes UTF-16BE **/ + private void processBE(final char ch[], int offset, final int count) { + int curPos = 0; + for (int i = 0; i < count; ++i) { + final int b0 = fBuffer[curPos++] & 0xff; + final int b1 = fBuffer[curPos++] & 0xff; + ch[offset++] = (char) ((b0 << 8) | b1); + } + } // processBE(char[],int,int) + + /** Decodes UTF-16LE **/ + private void processLE(final char ch[], int offset, final int count) { + int curPos = 0; + for (int i = 0; i < count; ++i) { + final int b0 = fBuffer[curPos++] & 0xff; + final int b1 = fBuffer[curPos++] & 0xff; + ch[offset++] = (char) ((b1 << 8) | b0); + } + } // processLE(char[],int,int) + + /** Throws an exception for expected byte. */ + private void expectedTwoBytes() + throws MalformedByteSequenceException { + throw new MalformedByteSequenceException(fFormatter, + fLocale, + XMLMessageFormatter.XML_DOMAIN, + "ExpectedByte", + new Object[] {"2", "2"}); + } // expectedTwoBytes() + +} // class UTF16Reader diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/io/UTF8Reader.java b/resources/xerces2-j-src/org/apache/xerces/impl/io/UTF8Reader.java new file mode 100644 index 0000000..dc46e7a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/io/UTF8Reader.java @@ -0,0 +1,713 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.Locale; + +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.MessageFormatter; + +/** + *

A UTF-8 reader.

+ * + * @xerces.internal + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public final class UTF8Reader + extends Reader { + + // + // Constants + // + + /** Default byte buffer size (2048). */ + public static final int DEFAULT_BUFFER_SIZE = 2048; + + // debugging + + /** Debug read. */ + private static final boolean DEBUG_READ = false; + + // + // Data + // + + /** Input stream. */ + protected final InputStream fInputStream; + + /** Byte buffer. */ + protected final byte[] fBuffer; + + /** Offset into buffer. */ + protected int fOffset; + + /** Surrogate character. */ + private int fSurrogate = -1; + + // message formatter; used to produce localized + // exception messages + private final MessageFormatter fFormatter; + + //Locale to use for messages + private final Locale fLocale; + + // + // Constructors + // + + /** + * Constructs a UTF-8 reader from the specified input stream + * using the default buffer size. Primarily for testing. + * + * @param inputStream The input stream. + */ + public UTF8Reader(InputStream inputStream) { + this(inputStream, DEFAULT_BUFFER_SIZE, new XMLMessageFormatter(), Locale.getDefault()); + } // (InputStream, MessageFormatter) + + /** + * Constructs a UTF-8 reader from the specified input stream + * using the default buffer size and the given MessageFormatter. + * + * @param inputStream The input stream. + * @param messageFormatter given MessageFormatter + * @param locale Locale to use for messages + */ + public UTF8Reader(InputStream inputStream, MessageFormatter messageFormatter, + Locale locale) { + this(inputStream, DEFAULT_BUFFER_SIZE, messageFormatter, locale); + } // (InputStream, MessageFormatter, Locale) + + /** + * Constructs a UTF-8 reader from the specified input stream, + * buffer size and MessageFormatter. + * + * @param inputStream The input stream. + * @param size The initial buffer size. + * @param messageFormatter the formatter for localizing/formatting errors. + * @param locale the Locale to use for messages + */ + public UTF8Reader(InputStream inputStream, int size, + MessageFormatter messageFormatter, Locale locale) { + this(inputStream, new byte[size], messageFormatter, locale); + } // (InputStream, int, MessageFormatter, Locale) + + /** + * Constructs a UTF-8 reader from the specified input stream, + * buffer and MessageFormatter. + * + * @param inputStream The input stream. + * @param buffer The byte buffer. + * @param messageFormatter the formatter for localizing/formatting errors. + * @param locale the Locale to use for messages + */ + public UTF8Reader(InputStream inputStream, byte [] buffer, + MessageFormatter messageFormatter, Locale locale) { + fInputStream = inputStream; + fBuffer = buffer; + fFormatter = messageFormatter; + fLocale = locale; + } // (InputStream, byte[], MessageFormatter, Locale) + + // + // Reader methods + // + + /** + * Read a single character. This method will block until a character is + * available, an I/O error occurs, or the end of the stream is reached. + * + *

Subclasses that intend to support efficient single-character input + * should override this method. + * + * @return The character read, as an integer in the range 0 to 16383 + * (0x00-0xffff), or -1 if the end of the stream has + * been reached + * + * @exception IOException If an I/O error occurs + */ + public int read() throws IOException { + + // decode character + int c = fSurrogate; + if (fSurrogate == -1) { + // NOTE: We use the index into the buffer if there are remaining + // bytes from the last block read. -Ac + int index = 0; + + // get first byte + int b0 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b0 == -1) { + return -1; + } + + // UTF-8: [0xxx xxxx] + // Unicode: [0000 0000] [0xxx xxxx] + if (b0 < 0x80) { + c = (char)b0; + } + + // UTF-8: [110y yyyy] [10xx xxxx] + // Unicode: [0000 0yyy] [yyxx xxxx] + else if ((b0 & 0xE0) == 0xC0 && (b0 & 0x1E) != 0) { + int b1 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b1 == -1) { + expectedByte(2, 2); + } + if ((b1 & 0xC0) != 0x80) { + invalidByte(2, 2, b1); + } + c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F); + } + + // UTF-8: [1110 zzzz] [10yy yyyy] [10xx xxxx] + // Unicode: [zzzz yyyy] [yyxx xxxx] + else if ((b0 & 0xF0) == 0xE0) { + int b1 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b1 == -1) { + expectedByte(2, 3); + } + if ((b1 & 0xC0) != 0x80 + || (b0 == 0xED && b1 >= 0xA0) + || ((b0 & 0x0F) == 0 && (b1 & 0x20) == 0)) { + invalidByte(2, 3, b1); + } + int b2 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b2 == -1) { + expectedByte(3, 3); + } + if ((b2 & 0xC0) != 0x80) { + invalidByte(3, 3, b2); + } + c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) | + (b2 & 0x003F); + } + + // UTF-8: [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]* + // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate) + // [1101 11yy] [yyxx xxxx] (low surrogate) + // * uuuuu = wwww + 1 + else if ((b0 & 0xF8) == 0xF0) { + int b1 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b1 == -1) { + expectedByte(2, 4); + } + if ((b1 & 0xC0) != 0x80 + || ((b1 & 0x30) == 0 && (b0 & 0x07) == 0)) { + invalidByte(2, 3, b1); + } + int b2 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b2 == -1) { + expectedByte(3, 4); + } + if ((b2 & 0xC0) != 0x80) { + invalidByte(3, 3, b2); + } + int b3 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b3 == -1) { + expectedByte(4, 4); + } + if ((b3 & 0xC0) != 0x80) { + invalidByte(4, 4, b3); + } + int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003); + if (uuuuu > 0x10) { + invalidSurrogate(uuuuu); + } + int wwww = uuuuu - 1; + int hs = 0xD800 | + ((wwww << 6) & 0x03C0) | ((b1 << 2) & 0x003C) | + ((b2 >> 4) & 0x0003); + int ls = 0xDC00 | ((b2 << 6) & 0x03C0) | (b3 & 0x003F); + c = hs; + fSurrogate = ls; + } + + // error + else { + invalidByte(1, 1, b0); + } + } + + // use surrogate + else { + fSurrogate = -1; + } + + // return character + if (DEBUG_READ) { + System.out.println("read(): 0x"+Integer.toHexString(c)); + } + return c; + + } // read():int + + /** + * Read characters into a portion of an array. This method will block + * until some input is available, an I/O error occurs, or the end of the + * stream is reached. + * + * @param ch Destination buffer + * @param offset Offset at which to start storing characters + * @param length Maximum number of characters to read + * + * @return The number of characters read, or -1 if the end of the + * stream has been reached + * + * @exception IOException If an I/O error occurs + */ + public int read(char ch[], int offset, int length) throws IOException { + + // read bytes + int out = offset; + int count = 0; + if (fOffset == 0) { + // adjust length to read + if (length > fBuffer.length) { + length = fBuffer.length; + } + + // handle surrogate + if (fSurrogate != -1) { + ch[out++] = (char)fSurrogate; + fSurrogate = -1; + length--; + } + + // perform read operation + count = fInputStream.read(fBuffer, 0, length); + if (count == -1) { + return -1; + } + count += out - offset; + } + + // skip read; last character was in error + // NOTE: Having an offset value other than zero means that there was + // an error in the last character read. In this case, we have + // skipped the read so we don't consume any bytes past the + // error. By signalling the error on the next block read we + // allow the method to return the most valid characters that + // it can on the previous block read. -Ac + else { + count = fOffset; + fOffset = 0; + } + + // convert bytes to characters + final int total = count; + int in; + byte byte1; + final byte byte0 = 0; + for (in = 0; in < total; in++) { + byte1 = fBuffer[in]; + if (byte1 >= byte0) { + ch[out++] = (char)byte1; + } + else { + break; + } + } + for ( ; in < total; in++) { + byte1 = fBuffer[in]; + + // UTF-8: [0xxx xxxx] + // Unicode: [0000 0000] [0xxx xxxx] + if (byte1 >= byte0) { + ch[out++] = (char)byte1; + continue; + } + + // UTF-8: [110y yyyy] [10xx xxxx] + // Unicode: [0000 0yyy] [yyxx xxxx] + int b0 = byte1 & 0x0FF; + if ((b0 & 0xE0) == 0xC0 && (b0 & 0x1E) != 0) { + int b1 = -1; + if (++in < total) { + b1 = fBuffer[in] & 0x00FF; + } + else { + b1 = fInputStream.read(); + if (b1 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fOffset = 1; + return out - offset; + } + expectedByte(2, 2); + } + count++; + } + if ((b1 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + invalidByte(2, 2, b1); + } + int c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F); + ch[out++] = (char)c; + count -= 1; + continue; + } + + // UTF-8: [1110 zzzz] [10yy yyyy] [10xx xxxx] + // Unicode: [zzzz yyyy] [yyxx xxxx] + if ((b0 & 0xF0) == 0xE0) { + int b1 = -1; + if (++in < total) { + b1 = fBuffer[in] & 0x00FF; + } + else { + b1 = fInputStream.read(); + if (b1 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fOffset = 1; + return out - offset; + } + expectedByte(2, 3); + } + count++; + } + if ((b1 & 0xC0) != 0x80 + || (b0 == 0xED && b1 >= 0xA0) + || ((b0 & 0x0F) == 0 && (b1 & 0x20) == 0)) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + invalidByte(2, 3, b1); + } + int b2 = -1; + if (++in < total) { + b2 = fBuffer[in] & 0x00FF; + } + else { + b2 = fInputStream.read(); + if (b2 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + expectedByte(3, 3); + } + count++; + } + if ((b2 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fBuffer[2] = (byte)b2; + fOffset = 3; + return out - offset; + } + invalidByte(3, 3, b2); + } + int c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) | + (b2 & 0x003F); + ch[out++] = (char)c; + count -= 2; + continue; + } + + // UTF-8: [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]* + // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate) + // [1101 11yy] [yyxx xxxx] (low surrogate) + // * uuuuu = wwww + 1 + if ((b0 & 0xF8) == 0xF0) { + int b1 = -1; + if (++in < total) { + b1 = fBuffer[in] & 0x00FF; + } + else { + b1 = fInputStream.read(); + if (b1 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fOffset = 1; + return out - offset; + } + expectedByte(2, 4); + } + count++; + } + if ((b1 & 0xC0) != 0x80 + || ((b1 & 0x30) == 0 && (b0 & 0x07) == 0)) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + invalidByte(2, 4, b1); + } + int b2 = -1; + if (++in < total) { + b2 = fBuffer[in] & 0x00FF; + } + else { + b2 = fInputStream.read(); + if (b2 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + expectedByte(3, 4); + } + count++; + } + if ((b2 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fBuffer[2] = (byte)b2; + fOffset = 3; + return out - offset; + } + invalidByte(3, 4, b2); + } + int b3 = -1; + if (++in < total) { + b3 = fBuffer[in] & 0x00FF; + } + else { + b3 = fInputStream.read(); + if (b3 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fBuffer[2] = (byte)b2; + fOffset = 3; + return out - offset; + } + expectedByte(4, 4); + } + count++; + } + if ((b3 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fBuffer[2] = (byte)b2; + fBuffer[3] = (byte)b3; + fOffset = 4; + return out - offset; + } + invalidByte(4, 4, b2); + } + + // decode bytes into surrogate characters + int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003); + if (uuuuu > 0x10) { + invalidSurrogate(uuuuu); + } + int wwww = uuuuu - 1; + int zzzz = b1 & 0x000F; + int yyyyyy = b2 & 0x003F; + int xxxxxx = b3 & 0x003F; + int hs = 0xD800 | ((wwww << 6) & 0x03C0) | (zzzz << 2) | (yyyyyy >> 4); + int ls = 0xDC00 | ((yyyyyy << 6) & 0x03C0) | xxxxxx; + + // set characters + ch[out++] = (char)hs; + if ((count -= 2) <= length) { + ch[out++] = (char)ls; + } + // reached the end of the char buffer; save low surrogate for the next read + else { + fSurrogate = ls; + --count; + } + continue; + } + + // error + if (out > offset) { + fBuffer[0] = (byte)b0; + fOffset = 1; + return out - offset; + } + invalidByte(1, 1, b0); + } + + // return number of characters converted + if (DEBUG_READ) { + System.out.println("read(char[],"+offset+','+length+"): count="+count); + } + return count; + + } // read(char[],int,int) + + /** + * Skip characters. This method will block until some characters are + * available, an I/O error occurs, or the end of the stream is reached. + * + * @param n The number of characters to skip + * + * @return The number of characters actually skipped + * + * @exception IOException If an I/O error occurs + */ + public long skip(long n) throws IOException { + + long remaining = n; + final char[] ch = new char[fBuffer.length]; + do { + int length = ch.length < remaining ? ch.length : (int)remaining; + int count = read(ch, 0, length); + if (count > 0) { + remaining -= count; + } + else { + break; + } + } while (remaining > 0); + + long skipped = n - remaining; + return skipped; + + } // skip(long):long + + /** + * Tell whether this stream is ready to be read. + * + * @return True if the next read() is guaranteed not to block for input, + * false otherwise. Note that returning false does not guarantee that the + * next read will block. + * + * @exception IOException If an I/O error occurs + */ + public boolean ready() throws IOException { + return false; + } // ready() + + /** + * Tell whether this stream supports the mark() operation. + */ + public boolean markSupported() { + return false; + } // markSupported() + + /** + * Mark the present position in the stream. Subsequent calls to reset() + * will attempt to reposition the stream to this point. Not all + * character-input streams support the mark() operation. + * + * @param readAheadLimit Limit on the number of characters that may be + * read while still preserving the mark. After + * reading this many characters, attempting to + * reset the stream may fail. + * + * @exception IOException If the stream does not support mark(), + * or if some other I/O error occurs + */ + public void mark(int readAheadLimit) throws IOException { + throw new IOException(fFormatter.formatMessage(fLocale, "OperationNotSupported", new Object[]{"mark()", "UTF-8"})); + } // mark(int) + + /** + * Reset the stream. If the stream has been marked, then attempt to + * reposition it at the mark. If the stream has not been marked, then + * attempt to reset it in some way appropriate to the particular stream, + * for example by repositioning it to its starting point. Not all + * character-input streams support the reset() operation, and some support + * reset() without supporting mark(). + * + * @exception IOException If the stream has not been marked, + * or if the mark has been invalidated, + * or if the stream does not support reset(), + * or if some other I/O error occurs + */ + public void reset() throws IOException { + fOffset = 0; + fSurrogate = -1; + } // reset() + + /** + * Close the stream. Once a stream has been closed, further read(), + * ready(), mark(), or reset() invocations will throw an IOException. + * Closing a previously-closed stream, however, has no effect. + * + * @exception IOException If an I/O error occurs + */ + public void close() throws IOException { + fInputStream.close(); + } // close() + + // + // Private methods + // + + /** Throws an exception for expected byte. */ + private void expectedByte(int position, int count) + throws MalformedByteSequenceException { + + throw new MalformedByteSequenceException(fFormatter, + fLocale, + XMLMessageFormatter.XML_DOMAIN, + "ExpectedByte", + new Object[] {Integer.toString(position), Integer.toString(count)}); + + } // expectedByte(int,int) + + /** Throws an exception for invalid byte. */ + private void invalidByte(int position, int count, int c) + throws MalformedByteSequenceException { + + throw new MalformedByteSequenceException(fFormatter, + fLocale, + XMLMessageFormatter.XML_DOMAIN, + "InvalidByte", + new Object [] {Integer.toString(position), Integer.toString(count)}); + + } // invalidByte(int,int,int) + + /** Throws an exception for invalid surrogate bits. */ + private void invalidSurrogate(int uuuuu) throws MalformedByteSequenceException { + + throw new MalformedByteSequenceException(fFormatter, + fLocale, + XMLMessageFormatter.XML_DOMAIN, + "InvalidHighSurrogate", + new Object[] {Integer.toHexString(uuuuu)}); + + } // invalidSurrogate(int) + +} // class UTF8Reader diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/DOMMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/DOMMessages.properties new file mode 100644 index 0000000..7ad6e8d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/DOMMessages.properties @@ -0,0 +1,83 @@ +# +# 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. +# + +# This file stores localized messages for the Xerces +# DOM implementation. +# +# The messages are arranged in key and value tuples in a ListResourceBundle. +# +# @version $Id$ + + BadMessageKey = The error message corresponding to the message key can not be found. + FormatFailed = An internal error occurred while formatting the following message:\n + +# DOM Core + +# exception codes +DOMSTRING_SIZE_ERR = The specified range of text does not fit into a DOMString. +HIERARCHY_REQUEST_ERR = An attempt was made to insert a node where it is not permitted. +INDEX_SIZE_ERR = The index or size is negative, or greater than the allowed value. +INUSE_ATTRIBUTE_ERR = An attempt is made to add an attribute that is already in use elsewhere. +INVALID_ACCESS_ERR = A parameter or an operation is not supported by the underlying object. +INVALID_CHARACTER_ERR = An invalid or illegal XML character is specified. +INVALID_MODIFICATION_ERR = An attempt is made to modify the type of the underlying object. +INVALID_STATE_ERR = An attempt is made to use an object that is not, or is no longer, usable. +NAMESPACE_ERR = An attempt is made to create or change an object in a way which is incorrect with regard to namespaces. +NOT_FOUND_ERR = An attempt is made to reference a node in a context where it does not exist. +NOT_SUPPORTED_ERR = The implementation does not support the requested type of object or operation. +NO_DATA_ALLOWED_ERR = Data is specified for a node which does not support data. +NO_MODIFICATION_ALLOWED_ERR = An attempt is made to modify an object where modifications are not allowed. +SYNTAX_ERR = An invalid or illegal string is specified. +VALIDATION_ERR = A call to a method such as insertBefore or removeChild would make the Node invalid with respect to document grammar. +WRONG_DOCUMENT_ERR = A node is used in a different document than the one that created it. +TYPE_MISMATCH_ERR = The value type for this parameter name is incompatible with the expected value type. + +#error messages or exceptions +FEATURE_NOT_SUPPORTED = The parameter {0} is recognized but the requested value cannot be set. +FEATURE_NOT_FOUND = The parameter {0} is not recognized. +STRING_TOO_LONG = The resulting string is too long to fit in a DOMString: ''{0}''. + +#DOM Level 3 DOMError codes +wf-invalid-character = The text {0} of the {1} node contains invalid XML characters. +wf-invalid-character-in-node-name = The {0} node named {1} contains invalid XML characters. +cdata-sections-splitted = CDATA sections containing the CDATA section termination marker \"]]>\" +doctype-not-allowed = DOCTYPE declaration is not allowed. +unsupported-encoding = The encoding {0} is not supported. + +#Error codes used in DOM Normalizer +InvalidXMLCharInDOM = An invalid XML character (Unicode: 0x{0}) was found in the DOM during normalization. +UndeclaredEntRefInAttrValue = The attribute \"{0}\" value \"{1}\" referenced an entity that was not declared. +NullLocalElementName = A null local name was encountered during namespace normalization of element {0}. +NullLocalAttrName = A null local name was encountered during namespace normalization of attribute {0}. + +#Error codes used in DOMParser +InvalidDocumentClassName = The class name of the document factory \"{0}\" used to construct the DOM tree is not of type org.w3c.dom.Document. +MissingDocumentClassName = The class name of the document factory \"{0}\" used to construct the DOM tree could not be found. +CannotCreateDocumentClass = The class named \"{0}\" could not be constructed as a org.w3c.dom.Document. +CannotQueryDeferredNode = Current element node cannot be queried when node expansion is deferred. + +# Error codes used by JAXP DocumentBuilder +jaxp-order-not-supported = Property ''{0}'' must be set before setting property ''{1}''. +jaxp-null-input-source = The source specified cannot be null. + +#Ranges +BAD_BOUNDARYPOINTS_ERR = The boundary-points of a Range do not meet specific requirements. +INVALID_NODE_TYPE_ERR = The container of a boundary-point of a Range is being set to either a node of an invalid type or a node with an ancestor of an invalid type. + +#Events +UNSPECIFIED_EVENT_TYPE_ERR = The Event's type was not specified by initializing the event before the method was called. + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/DatatypeMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/DatatypeMessages.properties new file mode 100644 index 0000000..4743d56 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/DatatypeMessages.properties @@ -0,0 +1,47 @@ +# +# 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. +# + +# This file stores localized messages for the Xerces JAXP Datatype API implementation. +# +# The messages are arranged in key and value tuples in a ListResourceBundle. +# +# @version $Id$ + +BadMessageKey = The error message corresponding to the message key can not be found. +FormatFailed = An internal error occurred while formatting the following message:\n + +FieldCannotBeNull={0} cannot be called with 'null' parameter. +UnknownField={0} called with an unknown field\:{1} +#There are two similar keys 'InvalidXMLGreogorianCalendarValue' . Suffix (year, month) has been added and are used as per the context. +InvalidXGCValue-milli=Year \= {0}, Month \= {1}, Day \= {2}, Hour \= {3}, Minute \= {4}, Second \= {5}, fractionalSecond \= {6}, Timezone \= {7} , is not a valid representation of an XML Gregorian Calendar value. +#There are two similar keys 'InvalidXMLGreogorianCalendarValue' . Suffix (year, month) has been added and are used as per the context. +InvalidXGCValue-fractional=Year \= {0}, Month \= {1}, Day \= {2}, Hour \= {3}, Minute \= {4}, Second \= {5}, fractionalSecond \= {6}, Timezone \= {7} , is not a valid representation of an XML Gregorian Calendar value. + +InvalidXGCFields=Invalid set of fields set for XMLGregorianCalendar + +InvalidFractional=Invalid value {0} for fractional second. + +#XGC stands for XML Gregorian Calendar +InvalidXGCRepresentation="{0}" is not a valid representation of an XML Gregorian Calendar value. + +InvalidFieldValue=Invalid value {0} for {1} field. + +NegativeField= {0} field is negative + +AllFieldsNull=All the fields (javax.xml.datatype.DatatypeConstants.Field) are null. + +TooLarge={0} value "{1}" too large to be supported by this implementation diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/JAXPValidationMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/JAXPValidationMessages.properties new file mode 100644 index 0000000..0725796 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/JAXPValidationMessages.properties @@ -0,0 +1,50 @@ +# +# 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. +# + +# This file stores localized messages for the Xerces JAXP Validation API implementation. +# +# The messages are arranged in key and value tuples in a ListResourceBundle. +# +# @version $Id$ + +# Messages for message reporting +BadMessageKey = The error message corresponding to the message key can not be found. +FormatFailed = An internal error occurred while formatting the following message:\n + +# SchemaFactory error messages +SchemaLanguageNull = The schema language specified cannot be null. +SchemaLanguageLengthZero = The schema language specified cannot have a length of zero characters. +SchemaSourceArrayNull = The Source array parameter cannot be null. +SchemaSourceArrayMemberNull = The Source array parameter cannot contain any items that are null. +SchemaFactorySourceUnrecognized = Source parameter of type ''{0}'' is not recognized by this SchemaFactory. +SAXSourceNullInputSource = The SAXSource specified contains no InputSource. + +# Validator error messages +SourceParameterNull = Source parameter cannot be null. +SourceNotAccepted = Source parameter of type ''{0}'' is not accepted by this validator. +SourceResultMismatch = Source parameter of type ''{0}'' is not compatible with result parameter of type ''{1}''. +StAXIllegalInitialState = Expecting the initial state to be start document or start element. +StreamResultNotInitialized = The StreamResult contains no OutputStream, Writer, or system ID. + +# TypeInfoProvider error messages +TypeInfoProviderIllegalStateElement = Element type information cannot be queried from a TypeInfoProvider outside of a startElement or endElement callback. +TypeInfoProviderIllegalStateAttribute = Attribute type information cannot be queried from a TypeInfoProvider outside of a startElement callback. + +# General error messages +FeatureNameNull = The feature name cannot be null. +ProperyNameNull = The property name cannot be null. + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/SAXMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/SAXMessages.properties new file mode 100644 index 0000000..49dbc2b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/SAXMessages.properties @@ -0,0 +1,46 @@ +# +# 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. +# + +# This file stores localized messages for the Xerces +# SAX implementation. +# +# The messages are arranged in key and value tuples in a ListResourceBundle. +# +# @version $Id$ + +BadMessageKey = The error message corresponding to the message key can not be found. +FormatFailed = An internal error occurred while formatting the following message:\n + +# JAXP messages +schema-not-supported = The specified schema language is not supported. +jaxp-order-not-supported = Property ''{0}'' must be set before setting property ''{1}''. +schema-already-specified = Property ''{0}'' cannot be set when a non-null Schema object has already been specified. + +# feature messages +feature-not-supported = Feature ''{0}'' is not supported. +feature-not-recognized = Feature ''{0}'' is not recognized. +true-not-supported = True state for feature ''{0}'' is not supported. +false-not-supported = False state for feature ''{0}'' is not supported. +feature-read-only = Feature ''{0}'' is read only. + +# property messages +property-not-supported = Property ''{0}'' is not supported. +property-not-recognized = Property ''{0}'' is not recognized. +property-read-only = Property ''{0}'' is read only. +property-not-parsing-supported = Property ''{0}'' is not supported while parsing. +dom-node-read-not-supported = Cannot read DOM node property. No DOM tree exists. +incompatible-class = The value specified for property ''{0}'' cannot be casted to {1}. diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/XIncludeMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XIncludeMessages.properties new file mode 100644 index 0000000..c2af19f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XIncludeMessages.properties @@ -0,0 +1,56 @@ +# +# 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. +# + +# This file stores localized messages for the Xerces XInclude implementation. +# +# The messages are arranged in key and value tuples in a ListResourceBundle. +# +# @version $Id$ + +# Messages for message reporting +BadMessageKey = The error message corresponding to the message key can not be found. +FormatFailed = An internal error occurred while formatting the following message:\n + +# Messages for erroneous input +NoFallback = An 'include' failed, and no 'fallback' element was found. +MultipleFallbacks = The [children] of an 'include' element cannot contain more than one 'fallback' element. +FallbackParent = A 'fallback' element was found that did not have 'include' as the parent. +IncludeChild = Elements from namespace ''http://www.w3.org/2001/XInclude'', other than ''fallback'', are not allowed to be children of ''include'' elements. However, ''{0}'' was found. +FallbackChild = Elements from namespace ''http://www.w3.org/2001/XInclude'', other than ''include'', are not allowed to be children of ''fallback'' elements. However, ''{0}'' was found. +HrefMissing = The 'href' attribute of an 'include' element is missing. +RecursiveInclude = Recursive include detected. Document ''{0}'' was already processed. +InvalidParseValue = Invalid value for ''parse'' attribute on ''include'' element: ''{0}''. +XMLParseError = Error attempting to parse XML file (href=''{0}''). +XMLResourceError = Include operation failed, reverting to fallback. Resource error reading file as XML (href=''{0}''). Reason: {1} +TextResourceError = Include operation failed, reverting to fallback. Resource error reading file as text (href=''{0}''). Reason: {1} +NonDuplicateNotation = Multiple notations were used which had the name ''{0}'', but which were not determined to be duplicates. +NonDuplicateUnparsedEntity = Multiple unparsed entities were used which had the name ''{0}'', but which were not determined to be duplicates. +XpointerMissing = xpointer attribute must be present when href attribute is absent. +AcceptMalformed = Characters outside the range #x20 through #x7E are not allowed in the value of the 'accept' attribute of an 'include' element. +AcceptLanguageMalformed = Characters outside the range #x20 through #x7E are not allowed in the value of the 'accept-language' attribute of an 'include' element. +RootElementRequired = A well-formed document requires a root element. +MultipleRootElements = A well-formed document must not contain multiple root elements. +ContentIllegalAtTopLevel = The replacement of an 'include' element appearing as the document element in the top-level source infoset cannot contain characters. +UnexpandedEntityReferenceIllegal = The replacement of an 'include' element appearing as the document element in the top-level source infoset cannot contain unexpanded entity references. +HrefFragmentIdentifierIllegal = Fragment identifiers must not be used. The ''href'' attribute value ''{0}'' is not permitted. +HrefSyntacticallyInvalid = ''href'' attribute value ''{0}'' is syntactically invalid. After applying escaping rules the value is neither a syntactically correct URI or IRI. +XPointerStreamability = An xpointer was specified that points to a location in the source infoset. This location cannot be accessed due to the streaming nature of the processor. +XPointerResolutionUnsuccessful = XPointer resolution unsuccessful. + +# Messages from erroneous set-up +IncompatibleNamespaceContext = The type of the NamespaceContext is incompatible with using XInclude; it must be an instance of XIncludeNamespaceSupport +ExpandedSystemId = Could not expand system id of included resource diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLMessageFormatter.java b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLMessageFormatter.java new file mode 100644 index 0000000..a570b5b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLMessageFormatter.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.msg; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.xerces.util.MessageFormatter; + +/** + * XMLMessageFormatter provides error messages for the XML 1.0 Recommendation and for + * the Namespaces Recommendation + * + * @xerces.internal + * + * @author Eric Ye, IBM + * @version $Id$ + * + */ +public class XMLMessageFormatter implements MessageFormatter { + /** + * The domain of messages concerning the XML 1.0 specification. + */ + public static final String XML_DOMAIN = "http://www.w3.org/TR/1998/REC-xml-19980210"; + public static final String XMLNS_DOMAIN = "http://www.w3.org/TR/1999/REC-xml-names-19990114"; + + // private objects to cache the locale and resource bundle + private Locale fLocale = null; + private ResourceBundle fResourceBundle = null; + + // + // MessageFormatter methods + // + + /** + * Formats a message with the specified arguments using the given + * locale information. + * + * @param locale The locale of the message. + * @param key The message key. + * @param arguments The message replacement text arguments. The order + * of the arguments must match that of the placeholders + * in the actual message. + * + * @return Returns the formatted message. + * + * @throws MissingResourceException Thrown if the message with the + * specified key cannot be found. + */ + public String formatMessage(Locale locale, String key, Object[] arguments) + throws MissingResourceException { + + if (locale == null) { + locale = Locale.getDefault(); + } + if (locale != fLocale) { + fResourceBundle = ResourceBundle.getBundle("org.apache.xerces.impl.msg.XMLMessages", locale); + // memorize the most-recent locale + fLocale = locale; + } + + // format message + String msg; + try { + msg = fResourceBundle.getString(key); + if (arguments != null) { + try { + msg = java.text.MessageFormat.format(msg, arguments); + } + catch (Exception e) { + msg = fResourceBundle.getString("FormatFailed"); + msg += " " + fResourceBundle.getString(key); + } + } + } + + // error + catch (MissingResourceException e) { + msg = fResourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(key, msg, key); + } + + // no message + if (msg == null) { + msg = key; + if (arguments.length > 0) { + StringBuffer str = new StringBuffer(msg); + str.append('?'); + for (int i = 0; i < arguments.length; i++) { + if (i > 0) { + str.append('&'); + } + str.append(String.valueOf(arguments[i])); + } + } + } + + return msg; + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLMessages.properties new file mode 100644 index 0000000..c0f1afb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLMessages.properties @@ -0,0 +1,313 @@ +# +# 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. +# + +# This file contains error and warning messages related to XML +# The messages are arranged in key and value tuples in a ListResourceBundle. +# +# @version $Id$ + + BadMessageKey = The error message corresponding to the message key can not be found. + FormatFailed = An internal error occurred while formatting the following message:\n + +# Document messages + PrematureEOF=Premature end of file. +# 2.1 Well-Formed XML Documents + RootElementRequired = The root element is required in a well-formed document. +# 2.2 Characters + InvalidCharInCDSect = An invalid XML character (Unicode: 0x{0}) was found in the CDATA section. + InvalidCharInContent = An invalid XML character (Unicode: 0x{0}) was found in the element content of the document. + TwoColonsInQName = An invalid second ':' was found in the element type or attribute name. + ColonNotLegalWithNS = A colon is not allowed in the name ''{0}'' when namespaces are enabled. + InvalidCharInMisc = An invalid XML character (Unicode: 0x{0}) was found in markup after the end of the element content. + InvalidCharInProlog = An invalid XML character (Unicode: 0x{0}) was found in the prolog of the document. + InvalidCharInXMLDecl = An invalid XML character (Unicode: 0x{0}) was found in the XML declaration. +# 2.4 Character Data and Markup + CDEndInContent = The character sequence \"]]>\" must not appear in content unless used to mark the end of a CDATA section. +# 2.7 CDATA Sections + CDSectUnterminated = The CDATA section must end with \"]]>\". +# 2.8 Prolog and Document Type Declaration + XMLDeclMustBeFirst = The XML declaration may only appear at the very beginning of the document. + EqRequiredInXMLDecl = The '' = '' character must follow \"{0}\" in the XML declaration. + QuoteRequiredInXMLDecl = The value following \"{0}\" in the XML declaration must be a quoted string. + XMLDeclUnterminated = The XML declaration must end with \"?>\". + VersionInfoRequired = The version is required in the XML declaration. + SpaceRequiredBeforeVersionInXMLDecl = White space is required before the version pseudo attribute in the XML declaration. + SpaceRequiredBeforeEncodingInXMLDecl = White space is required before the encoding pseudo attribute in the XML declaration. + SpaceRequiredBeforeStandalone = White space is required before the encoding pseudo attribute in the XML declaration. + MarkupNotRecognizedInProlog = The markup in the document preceding the root element must be well-formed. + MarkupNotRecognizedInMisc = The markup in the document following the root element must be well-formed. + AlreadySeenDoctype = Already seen doctype. + DoctypeNotAllowed = DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true. + ContentIllegalInProlog = Content is not allowed in prolog. + ReferenceIllegalInProlog = Reference is not allowed in prolog. +# Trailing Misc + ContentIllegalInTrailingMisc=Content is not allowed in trailing section. + ReferenceIllegalInTrailingMisc=Reference is not allowed in trailing section. + +# 2.9 Standalone Document Declaration + SDDeclInvalid = The standalone document declaration value must be \"yes\" or \"no\", not \"{0}\". +# 2.12 Language Identification + XMLLangInvalid = The xml:lang attribute value \"{0}\" is an invalid language identifier. +# 3. Logical Structures + ETagRequired = The element type \"{0}\" must be terminated by the matching end-tag \"\". +# 3.1 Start-Tags, End-Tags, and Empty-Element Tags + ElementUnterminated = Element type \"{0}\" must be followed by either attribute specifications, \">\" or \"/>\". + EqRequiredInAttribute = Attribute name \"{1}\" associated with an element type \"{0}\" must be followed by the '' = '' character. + OpenQuoteExpected = Open quote is expected for attribute \"{1}\" associated with an element type \"{0}\". + CloseQuoteExpected = Close quote is expected for attribute \"{1}\" associated with an element type \"{0}\". + AttributeNotUnique = Attribute \"{1}\" was already specified for element \"{0}\". + AttributeNSNotUnique = Attribute \"{1}\" bound to namespace \"{2}\" was already specified for element \"{0}\". + ETagUnterminated = The end-tag for element type \"{0}\" must end with a ''>'' delimiter. + MarkupNotRecognizedInContent = The content of elements must consist of well-formed character data or markup. + DoctypeIllegalInContent = A DOCTYPE is not allowed in content. +# 4.1 Character and Entity References + ReferenceUnterminated = The reference must be terminated by a ';' delimiter. +# 4.3.2 Well-Formed Parsed Entities + ReferenceNotInOneEntity = The reference must be entirely contained within the same parsed entity. + ElementEntityMismatch = The element \"{0}\" must start and end within the same entity. + MarkupEntityMismatch=XML document structures must start and end within the same entity. + +# Messages common to Document and DTD +# 2.2 Characters + InvalidCharInAttValue = An invalid XML character (Unicode: 0x{2}) was found in the value of attribute \"{1}\" and element is \"{0}\". + InvalidCharInComment = An invalid XML character (Unicode: 0x{0}) was found in the comment. + InvalidCharInPI = An invalid XML character (Unicode: 0x{0}) was found in the processing instruction. + InvalidCharInInternalSubset = An invalid XML character (Unicode: 0x{0}) was found in the internal subset of the DTD. + InvalidCharInTextDecl = An invalid XML character (Unicode: 0x{0}) was found in the text declaration. +# 2.3 Common Syntactic Constructs + QuoteRequiredInAttValue = The value of attribute \"{1}\" must begin with either a single or double quote character. + LessthanInAttValue = The value of attribute \"{1}\" associated with an element type \"{0}\" must not contain the ''<'' character. + AttributeValueUnterminated = The value for attribute \"{1}\" must end with the matching quote character. +# 2.5 Comments + InvalidCommentStart = Comment must start with \"\". + COMMENT_NOT_IN_ONE_ENTITY = The comment is not enclosed in the same entity. +# 2.6 Processing Instructions + PITargetRequired = The processing instruction must begin with the name of the target. + SpaceRequiredInPI = White space is required between the processing instruction target and data. + PIUnterminated = The processing instruction must end with \"?>\". + ReservedPITarget = The processing instruction target matching \"[xX][mM][lL]\" is not allowed. + PI_NOT_IN_ONE_ENTITY = The processing instruction is not enclosed in the same entity. +# 2.8 Prolog and Document Type Declaration + VersionInfoInvalid = Invalid version \"{0}\". + VersionNotSupported = XML version \"{0}\" is not supported, only XML 1.0 is supported. + VersionNotSupported11 = XML version \"{0}\" is not supported, only XML 1.0 and XML 1.1 are supported. +# 4.1 Character and Entity References + DigitRequiredInCharRef = A decimal representation must immediately follow the \"&#\" in a character reference. + HexdigitRequiredInCharRef = A hexadecimal representation must immediately follow the \"&#x\" in a character reference. + SemicolonRequiredInCharRef = The character reference must end with the ';' delimiter. + InvalidCharRef = Character reference \"&#{0}\" is an invalid XML character. + NameRequiredInReference = The entity name must immediately follow the '&' in the entity reference. + SemicolonRequiredInReference = The reference to entity \"{0}\" must end with the '';'' delimiter. +# 4.3.1 The Text Declaration + TextDeclMustBeFirst = The text declaration may only appear at the very beginning of the external parsed entity. + EqRequiredInTextDecl = The '' = '' character must follow \"{0}\" in the text declaration. + QuoteRequiredInTextDecl = The value following \"{0}\" in the text declaration must be a quoted string. + CloseQuoteMissingInTextDecl = closing quote in the value following \"{0}\" in the text declaration is missing. + SpaceRequiredBeforeVersionInTextDecl = White space is required before the version pseudo attribute in the text declaration. + SpaceRequiredBeforeEncodingInTextDecl = White space is required before the encoding pseudo attribute in the text declaration. + TextDeclUnterminated = The text declaration must end with \"?>\". + EncodingDeclRequired = The encoding declaration is required in the text declaration. + NoMorePseudoAttributes = No more pseudo attributes are allowed. + MorePseudoAttributes = More pseudo attributes are expected. + PseudoAttrNameExpected = A pseudo attribute name is expected. +# 4.3.2 Well-Formed Parsed Entities + CommentNotInOneEntity = The comment must be entirely contained within the same parsed entity. + PINotInOneEntity = The processing instruction must be entirely contained within the same parsed entity. +# 4.3.3 Character Encoding in Entities + EncodingDeclInvalid = Invalid encoding name \"{0}\". + EncodingByteOrderUnsupported = Given byte order for encoding \"{0}\" is not supported. + InvalidByte = Invalid byte {0} of {1}-byte UTF-8 sequence. + ExpectedByte = Expected byte {0} of {1}-byte UTF-8 sequence. + InvalidHighSurrogate = High surrogate bits in UTF-8 sequence must not exceed 0x10 but found 0x{0}. + OperationNotSupported = Operation \"{0}\" not supported by {1} reader. + InvalidASCII = Byte \"{0}\" is not a member of the (7-bit) ASCII character set. + CharConversionFailure = An entity determined to be in a certain encoding must not contain sequences illegal in that encoding. + +# DTD Messages +# 2.2 Characters + InvalidCharInEntityValue = An invalid XML character (Unicode: 0x{0}) was found in the literal entity value. + InvalidCharInExternalSubset = An invalid XML character (Unicode: 0x{0}) was found in the external subset of the DTD. + InvalidCharInIgnoreSect = An invalid XML character (Unicode: 0x{0}) was found in the excluded conditional section. + InvalidCharInPublicID = An invalid XML character (Unicode: 0x{0}) was found in the public identifier. + InvalidCharInSystemID = An invalid XML character (Unicode: 0x{0}) was found in the system identifier. +# 2.3 Common Syntactic Constructs + SpaceRequiredAfterSYSTEM = White space is required after keyword SYSTEM in DOCTYPE decl. + QuoteRequiredInSystemID = The system identifier must begin with either a single or double quote character. + SystemIDUnterminated = The system identifier must end with the matching quote character. + SpaceRequiredAfterPUBLIC = White spaces are required after keyword PUBLIC in DOCTYPE decl. + QuoteRequiredInPublicID = The public identifier must begin with either a single or double quote character. + PublicIDUnterminated = The public identifier must end with the matching quote character. + PubidCharIllegal = The character (Unicode: 0x{0}) is not permitted in the public identifier. + SpaceRequiredBetweenPublicAndSystem = White spaces are required between publicId and systemId. +# 2.8 Prolog and Document Type Declaration + MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL = White space is required after \"''. + PEReferenceWithinMarkup = The parameter entity reference \"%{0};\" cannot occur within markup in the internal subset of the DTD. + MSG_MARKUP_NOT_RECOGNIZED_IN_DTD = The markup declarations contained or pointed to by the document type declaration must be well-formed. +# 2.10 White Space Handling + MSG_XML_SPACE_DECLARATION_ILLEGAL = The attribute declaration for \"xml:space\" must be given as an enumerated type whose only possible values are \"default\" and \"preserve\". +# 3.2 Element Type Declarations + MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL = White space is required after \"''. +# 3.2.1 Element Content + MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN = A ''('' character or an element type is required in the declaration of element type \"{0}\". + MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN = A '')'' is required in the declaration of element type \"{0}\". +# 3.2.2 Mixed Content + MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT = An element type is required in the declaration of element type \"{0}\". + MSG_CLOSE_PAREN_REQUIRED_IN_MIXED = A '')'' is required in the declaration of element type \"{0}\". + MixedContentUnterminated = The mixed content model \"{0}\" must end with \")*\" when the types of child elements are constrained. +# 3.3 Attribute-List Declarations + MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL = White space is required after \"\". + IgnoreSectUnterminated = The excluded conditional section must end with \"]]>\". +# 4.1 Character and Entity References + NameRequiredInPEReference = The entity name must immediately follow the '%' in the parameter entity reference. + SemicolonRequiredInPEReference = The parameter entity reference \"%{0};\" must end with the '';'' delimiter. +# 4.2 Entity Declarations + MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL = White space is required after \"''. + MSG_DUPLICATE_ENTITY_DEFINITION = Entity \"{0}\" is declared more than once. +# 4.2.2 External Entities + ExternalIDRequired = The external entity declaration must begin with either \"SYSTEM\" or \"PUBLIC\". + MSG_SPACE_REQUIRED_BEFORE_PUBIDLITERAL_IN_EXTERNALID = White space is required between \"PUBLIC\" and the public identifier. + MSG_SPACE_REQUIRED_AFTER_PUBIDLITERAL_IN_EXTERNALID = White space is required between the public identifier and the system identifier. + MSG_SPACE_REQUIRED_BEFORE_SYSTEMLITERAL_IN_EXTERNALID = White space is required between \"SYSTEM\" and the system identifier. + MSG_URI_FRAGMENT_IN_SYSTEMID = The fragment identifier should not be specified as part of the system identifier \"{0}\". +# 4.7 Notation Declarations + MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL = White space is required after \"''. + +# Validation messages + DuplicateTypeInMixedContent = The element type \"{1}\" was already specified in the content model of the element decl \"{0}\". + ENTITIESInvalid = Attribute value \"{1}\" of type ENTITIES must be the names of one or more unparsed entities. + ENTITYInvalid = Attribute value \"{1}\" of type ENTITY must be the name of an unparsed entity. + IDDefaultTypeInvalid = The ID attribute \"{0}\" must have a declared default of \"#IMPLIED\" or \"#REQUIRED\". + IDInvalid = Attribute value \"{0}\" of type ID must be a name. + IDInvalidWithNamespaces = Attribute value \"{0}\" of type ID must be an NCName when namespaces are enabled. + IDNotUnique = Attribute value \"{0}\" of type ID must be unique within the document. + IDREFInvalid = Attribute value \"{0}\" of type IDREF must be a name. + IDREFInvalidWithNamespaces = Attribute value \"{0}\" of type IDREF must be an NCName when namespaces are enabled. + IDREFSInvalid = Attribute value \"{0}\" of type IDREFS must be one or more names. + ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL = The replacement text of parameter entity \"{0}\" must include properly nested declarations when the entity reference is used as a complete declaration. + ImproperDeclarationNesting = The replacement text of parameter entity \"{0}\" must include properly nested declarations. + ImproperGroupNesting = The replacement text of parameter entity \"{0}\" must include properly nested pairs of parentheses. + INVALID_PE_IN_CONDITIONAL = The replacement text of parameter entity \"{0}\" must include the entire conditional section or just INCLUDE or IGNORE. + MSG_ATTRIBUTE_NOT_DECLARED = Attribute \"{1}\" must be declared for element type \"{0}\". + MSG_ATTRIBUTE_VALUE_NOT_IN_LIST = Attribute \"{0}\" with value \"{1}\" must have a value from the list \"{2}\". + MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE = The value \"{1}\" of attribute \"{0}\" must not be changed by normalization (to \"{2}\") in a standalone document. + MSG_CONTENT_INCOMPLETE = The content of element type \"{0}\" is incomplete, it must match \"{1}\". + MSG_CONTENT_INVALID = The content of element type \"{0}\" must match \"{1}\". + MSG_CONTENT_INVALID_SPECIFIED = The content of element type \"{0}\" must match \"{1}\". Children of type \"{2}\" are not allowed. + MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED = Attribute \"{1}\" for element type \"{0}\" has a default value and must be specified in a standalone document. + MSG_DUPLICATE_ATTDEF = Attribute \"{1}\" is already declared for element type \"{0}\". + MSG_ELEMENT_ALREADY_DECLARED = Element type \"{0}\" must not be declared more than once. + MSG_ELEMENT_NOT_DECLARED = Element type \"{0}\" must be declared. + MSG_GRAMMAR_NOT_FOUND = Document is invalid: no grammar found. + MSG_ELEMENT_WITH_ID_REQUIRED = An element with the identifier \"{0}\" must appear in the document. + MSG_EXTERNAL_ENTITY_NOT_PERMITTED = The reference to external entity \"{0}\" is not permitted in a standalone document. + MSG_FIXED_ATTVALUE_INVALID = Attribute \"{1}\" with value \"{2}\" must have a value of \"{3}\". + MSG_MORE_THAN_ONE_ID_ATTRIBUTE = Element type \"{0}\" already has attribute \"{1}\" of type ID, a second attribute \"{2}\" of type ID is not permitted. + MSG_MORE_THAN_ONE_NOTATION_ATTRIBUTE = Element type \"{0}\" already has attribute \"{1}\" of type NOTATION, a second attribute \"{2}\" of type NOTATION is not permitted. + MSG_NOTATION_NOT_DECLARED_FOR_NOTATIONTYPE_ATTRIBUTE = The notation \"{1}\" must be declared when referenced in the notation type list for attribute \"{0}\". + MSG_NOTATION_NOT_DECLARED_FOR_UNPARSED_ENTITYDECL = The notation \"{1}\" must be declared when referenced in the unparsed entity declaration for \"{0}\". + MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE = The reference to entity \"{0}\" declared in the external subset of the DTD or in a parameter entity is not permitted in a standalone document. + MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED = Attribute \"{1}\" is required and must be specified for element type \"{0}\". + MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE = In a standalone document white space must not occur between elements with element content which are declared in the external subset of the DTD or in a parameter entity. + NMTOKENInvalid = Attribute value \"{0}\" of type NMTOKEN must be a name token. + NMTOKENSInvalid = Attribute value \"{0}\" of type NMTOKENS must be one or more name tokens. + NoNotationOnEmptyElement = Element type \"{0}\" which was declared EMPTY cannot declare attribute \"{1}\" of type NOTATION. + RootElementTypeMustMatchDoctypedecl = Document root element \"{1}\", must match DOCTYPE root \"{0}\". + UndeclaredElementInContentSpec = The content model of element \"{0}\" refers to the undeclared element \"{1}\". + UniqueNotationName = The declaration for the notation \"{0}\" is not unique. A given Name must not be declared in more than one notation declaration. + ENTITYFailedInitializeGrammar = ENTITYDatatype Validator: Failed Need to call initialize method with a valid Grammar reference. + ENTITYNotUnparsed = ENTITY \"{0}\" is not unparsed. + ENTITYNotValid = ENTITY \"{0}\" is not valid. + EmptyList = Value of type ENTITIES, IDREFS, and NMTOKENS cannot be empty list. + +# Entity related messages +# 3.1 Start-Tags, End-Tags, and Empty-Element Tags + ReferenceToExternalEntity = The external entity reference \"&{0};\" is not permitted in an attribute value. +# 4.1 Character and Entity References + EntityNotDeclared = The entity \"{0}\" was referenced, but not declared. + ReferenceToUnparsedEntity = The unparsed entity reference \"&{0};\" is not permitted. + RecursiveReference = Recursive entity reference \"{0}\". (Reference path: {1}), + RecursiveGeneralReference = Recursive general entity reference \"&{0};\". (Reference path: {1}), + RecursivePEReference = Recursive parameter entity reference \"%{0};\". (Reference path: {1}), +# 4.3.3 Character Encoding in Entities + EncodingNotSupported = The encoding \"{0}\" is not supported. + EncodingRequired = A parsed entity not encoded in either UTF-8 or UTF-16 must contain an encoding declaration. + +# Namespaces support +# 4. Using Qualified Names + IllegalQName = Element or attribute do not match QName production: QName::=(NCName':')?NCName. + ElementXMLNSPrefix = Element \"{0}\" cannot have \"xmlns\" as its prefix. + ElementPrefixUnbound = The prefix \"{0}\" for element \"{1}\" is not bound. + AttributePrefixUnbound = The prefix \"{2}\" for attribute \"{1}\" associated with an element type \"{0}\" is not bound. + EmptyPrefixedAttName = The value of the attribute \"{0}\" is invalid. Prefixed namespace bindings may not be empty. + PrefixDeclared = The namespace prefix \"{0}\" was not declared. + CantBindXMLNS = The prefix "xmlns" cannot be bound to any namespace explicitly; neither can the namespace for "xmlns" be bound to any prefix explicitly. + CantBindXML = The prefix "xml" cannot be bound to any namespace other than its usual namespace; neither can the namespace for "xml" be bound to any prefix other than "xml". + MSG_ATT_DEFAULT_INVALID = The defaultValue \"{1}\" of attribute \"{0}\" is not legal as for the lexical constraints of this attribute type. + +# REVISIT: These need messages + MSG_SPACE_REQUIRED_AFTER_SYSTEMLITERAL_IN_EXTERNALID=MSG_SPACE_REQUIRED_AFTER_SYSTEMLITERAL_IN_EXTERNALID + OpenQuoteMissingInDecl=OpenQuoteMissingInDecl + InvalidCharInLiteral=InvalidCharInLiteral + + +#Application can set the limit of number of entities that should be expanded by the parser. +EntityExpansionLimitExceeded=The parser has encountered more than \"{0}\" entity expansions in this document; this is the limit imposed by the application. + +#Application can set limits on the size of entities that should be processed by the parser. +TotalEntitySizeLimitExceeded=The parser has encountered more than \"{0}\" bytes or characters within entities declared and referenced by this document; this is the limit imposed by the application. +MaxGeneralEntitySizeLimitExceeded=The parser has encountered more than \"{0}\" bytes or characters within a general entity; this is the limit imposed by the application. +MaxParameterEntitySizeLimitExceeded=The parser has encountered more than \"{0}\" bytes or characters within a parameter entity; this is the limit imposed by the application. diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLSchemaMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLSchemaMessages.properties new file mode 100644 index 0000000..7957716 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLSchemaMessages.properties @@ -0,0 +1,321 @@ +# +# 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. +# + +# This file contains error and warning messages related to XML Schema +# The messages are arranged in key and value tuples in a ListResourceBundle. +# +# @version $Id$ + + BadMessageKey = The error message corresponding to the message key can not be found. + FormatFailed = An internal error occurred while formatting the following message:\n + +# For internal use + + Internal-Error = Internal error: {0}. + dt-whitespace = Whitespace facet value is not available for the union simpleType ''{0}'' + GrammarConflict = One of the grammar(s) returned from the user's grammar pool is in conflict with another grammar. + +# Identity constraints + + AbsentKeyValue = cvc-identity-constraint.4.2.1.a: Element \"{0}\" has no value for the key \"{1}\". + DuplicateField = Duplicate match in scope for field \"{0}\". + DuplicateKey = cvc-identity-constraint.4.2.2: Duplicate key value [{0}] declared for identity constraint \"{2}\" of element \"{1}\". + DuplicateUnique = cvc-identity-constraint.4.1: Duplicate unique value [{0}] declared for identity constraint \"{2}\" of element \"{1}\". + FieldMultipleMatch = cvc-identity-constraint.3: Field \"{0}\" of identity constraint \"{1}\" matches more than one value within the scope of its selector; fields must match unique values. + FixedDiffersFromActual = The content of this element is not equivalent to the value of the \"fixed\" attribute in the element's declaration in the schema. + KeyMatchesNillable = cvc-identity-constraint.4.2.3: Element \"{0}\" has the key \"{1}\" which matches an element which has nillable set to true. + KeyNotEnoughValues = cvc-identity-constraint.4.2.1.b: Not enough values specified for identity constraint specified for element \"{0}\". + KeyNotFound = cvc-identity-constraint.4.3: Key ''{0}'' with value ''{1}'' not found for identity constraint of element ''{2}''. + KeyRefOutOfScope = Identity Constraint error: identity constraint \"{0}\" has a keyref which refers to a key or unique that is out of scope. + KeyRefReferNotFound = Key reference declaration \"{0}\" refers to unknown key with name \"{1}\". + UnknownField = Internal identity constraint error; unknown field \"{0}\" for identity constraint \"{2}\" specified for element \"{1}\". + +# Ideally, we should only use the following error keys, not the ones under +# "Identity constraints". And we should cover all of the following errors. + +#validation (3.X.4) + + cvc-attribute.3 = cvc-attribute.3: The value ''{2}'' of attribute ''{1}'' on element ''{0}'' is not valid with respect to its type, ''{3}''. + cvc-attribute.4 = cvc-attribute.4: The value ''{2}'' of attribute ''{1}'' on element ''{0}'' is not valid with respect to its fixed '{'value constraint'}'. The attribute must have a value of ''{3}''. + cvc-complex-type.2.1 = cvc-complex-type.2.1: Element ''{0}'' must have no character or element information item [children], because the type''s content type is empty. + cvc-complex-type.2.2 = cvc-complex-type.2.2: Element ''{0}'' must have no element [children], and the value must be valid. + cvc-complex-type.2.3 = cvc-complex-type.2.3: Element ''{0}'' cannot have character [children], because the type''s content type is element-only. + cvc-complex-type.2.4.a = cvc-complex-type.2.4.a: Invalid content was found starting with element ''{0}''. One of ''{1}'' is expected. + cvc-complex-type.2.4.b = cvc-complex-type.2.4.b: The content of element ''{0}'' is not complete. One of ''{1}'' is expected. + cvc-complex-type.2.4.c = cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element ''{0}''. + cvc-complex-type.2.4.d = cvc-complex-type.2.4.d: Invalid content was found starting with element ''{0}''. No child element is expected at this point. + cvc-complex-type.2.4.e = cvc-complex-type.2.4.e: ''{0}'' can occur a maximum of ''{2}'' times in the current sequence. This limit was exceeded. At this point one of ''{1}'' is expected. + cvc-complex-type.2.4.f = cvc-complex-type.2.4.f: ''{0}'' can occur a maximum of ''{1}'' times in the current sequence. This limit was exceeded. No child element is expected at this point. + cvc-complex-type.2.4.g = cvc-complex-type.2.4.g: Invalid content was found starting with element ''{0}''. ''{1}'' is expected to occur a minimum of ''{2}'' times in the current sequence. One more instance is required to satisfy this constraint. + cvc-complex-type.2.4.h = cvc-complex-type.2.4.h: Invalid content was found starting with element ''{0}''. ''{1}'' is expected to occur a minimum of ''{2}'' times in the current sequence. ''{3}'' more instances are required to satisfy this constraint. + cvc-complex-type.2.4.i = cvc-complex-type.2.4.i: The content of element ''{0}'' is not complete. ''{1}'' is expected to occur a minimum of ''{2}'' times. One more instance is required to satisfy this constraint. + cvc-complex-type.2.4.j = cvc-complex-type.2.4.j: The content of element ''{0}'' is not complete. ''{1}'' is expected to occur a minimum of ''{2}'' times. ''{3}'' more instances are required to satisfy this constraint. + cvc-complex-type.3.1 = cvc-complex-type.3.1: Value ''{2}'' of attribute ''{1}'' of element ''{0}'' is not valid with respect to the corresponding attribute use. Attribute ''{1}'' has a fixed value of ''{3}''. + cvc-complex-type.3.2.1 = cvc-complex-type.3.2.1: Element ''{0}'' does not have an attribute wildcard for attribute ''{1}''. + cvc-complex-type.3.2.2 = cvc-complex-type.3.2.2: Attribute ''{1}'' is not allowed to appear in element ''{0}''. + cvc-complex-type.4 = cvc-complex-type.4: Attribute ''{1}'' must appear on element ''{0}''. + cvc-complex-type.5.1 = cvc-complex-type.5.1: In element ''{0}'', attribute ''{1}'' is a Wild ID. But there is already a Wild ID ''{2}''. There can be only one. + cvc-complex-type.5.2 = cvc-complex-type.5.2: In element ''{0}'', attribute ''{1}'' is a Wild ID. But there is already an attribute ''{2}'' derived from ID among the '{'attribute uses'}'. + cvc-datatype-valid.1.2.1 = cvc-datatype-valid.1.2.1: ''{0}'' is not a valid value for ''{1}''. + cvc-datatype-valid.1.2.2 = cvc-datatype-valid.1.2.2: ''{0}'' is not a valid value of list type ''{1}''. + cvc-datatype-valid.1.2.3 = cvc-datatype-valid.1.2.3: ''{0}'' is not a valid value of union type ''{1}''. + cvc-elt.1.a = cvc-elt.1.a: Cannot find the declaration of element ''{0}''. + cvc-elt.1.b = cvc-elt.1.b: The name of the element does not match the name of the element declaration. Saw ''{0}''. Expected ''{1}''. + cvc-elt.2 = cvc-elt.2: The value of '{'abstract'}' in the element declaration for ''{0}'' must be false. + cvc-elt.3.1 = cvc-elt.3.1: Attribute ''{1}'' must not appear on element ''{0}'', because the '{'nillable'}' property of ''{0}'' is false. + cvc-elt.3.2.1 = cvc-elt.3.2.1: Element ''{0}'' cannot have character or element information [children], because ''{1}'' is specified. + cvc-elt.3.2.2 = cvc-elt.3.2.2: There must be no fixed '{'value constraint'}' for element ''{0}'', because ''{1}'' is specified. + cvc-elt.4.1 = cvc-elt.4.1: The value ''{2}'' of attribute ''{1}'' of element ''{0}'' is not a valid QName. + cvc-elt.4.2 = cvc-elt.4.2: Cannot resolve ''{1}'' to a type definition for element ''{0}''. + cvc-elt.4.3 = cvc-elt.4.3: Type ''{1}'' is not validly derived from the type definition, ''{2}'', of element ''{0}''. + cvc-elt.5.1.1 = cvc-elt.5.1.1: '{'value constraint'}' ''{2}'' of element ''{0}'' is not a valid default value for type ''{1}''. + cvc-elt.5.2.2.1 = cvc-elt.5.2.2.1: Element ''{0}'' must have no element information item [children]. + cvc-elt.5.2.2.2.1 = cvc-elt.5.2.2.2.1: The value ''{1}'' of element ''{0}'' does not match the fixed '{'value constraint'}' value ''{2}''. + cvc-elt.5.2.2.2.2 = cvc-elt.5.2.2.2.2: The value ''{1}'' of element ''{0}'' does not match the '{'value constraint'}' value ''{2}''. + cvc-enumeration-valid = cvc-enumeration-valid: Value ''{0}'' is not facet-valid with respect to enumeration ''{1}''. It must be a value from the enumeration. + cvc-fractionDigits-valid = cvc-fractionDigits-valid: Value ''{0}'' has {1} fraction digits, but the number of fraction digits has been limited to {2}. + cvc-id.1 = cvc-id.1: There is no ID/IDREF binding for IDREF ''{0}''. + cvc-id.2 = cvc-id.2: There are multiple occurrences of ID value ''{0}''. + cvc-id.3 = cvc-id.3: A field of identity constraint ''{0}'' matched element ''{1}'', but this element does not have a simple type. + cvc-length-valid = cvc-length-valid: Value ''{0}'' with length = ''{1}'' is not facet-valid with respect to length ''{2}'' for type ''{3}''. + cvc-maxExclusive-valid = cvc-maxExclusive-valid: Value ''{0}'' is not facet-valid with respect to maxExclusive ''{1}'' for type ''{2}''. + cvc-maxInclusive-valid = cvc-maxInclusive-valid: Value ''{0}'' is not facet-valid with respect to maxInclusive ''{1}'' for type ''{2}''. + cvc-maxLength-valid = cvc-maxLength-valid: Value ''{0}'' with length = ''{1}'' is not facet-valid with respect to maxLength ''{2}'' for type ''{3}''. + cvc-minExclusive-valid = cvc-minExclusive-valid: Value ''{0}'' is not facet-valid with respect to minExclusive ''{1}'' for type ''{2}''. + cvc-minInclusive-valid = cvc-minInclusive-valid: Value ''{0}'' is not facet-valid with respect to minInclusive ''{1}'' for type ''{2}''. + cvc-minLength-valid = cvc-minLength-valid: Value ''{0}'' with length = ''{1}'' is not facet-valid with respect to minLength ''{2}'' for type ''{3}''. + cvc-pattern-valid = cvc-pattern-valid: Value ''{0}'' is not facet-valid with respect to pattern ''{1}'' for type ''{2}''. + cvc-totalDigits-valid = cvc-totalDigits-valid: Value ''{0}'' has {1} total digits, but the number of total digits has been limited to {2}. + cvc-type.1 = cvc-type.1: The type definition ''{0}'' was not found. + cvc-type.2 = cvc-type.2: The type definition cannot be abstract for element {0}. + cvc-type.3.1.1 = cvc-type.3.1.1: Element ''{0}'' is a simple type, so it cannot have attributes, excepting those whose namespace name is identical to ''http://www.w3.org/2001/XMLSchema-instance'' and whose [local name] is one of ''type'', ''nil'', ''schemaLocation'' or ''noNamespaceSchemaLocation''. However, the attribute, ''{1}'' was found. + cvc-type.3.1.2 = cvc-type.3.1.2: Element ''{0}'' is a simple type, so it must have no element information item [children]. + cvc-type.3.1.3 = cvc-type.3.1.3: The value ''{1}'' of element ''{0}'' is not valid. + +#schema valid (3.X.3) + + schema_reference.4 = schema_reference.4: Failed to read schema document ''{0}'', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not . + src-annotation = src-annotation: elements can only contain and elements, but ''{0}'' was found. + src-attribute.1 = src-attribute.1: The properties ''default'' and ''fixed'' cannot both be present in attribute declaration ''{0}''. Use only one of them. + src-attribute.2 = src-attribute.2: : The property ''default'' is present in attribute ''{0}'', so the value of ''use'' must be ''optional''. + src-attribute.3.1 = src-attribute.3.1: One of 'ref' or 'name' must be present in a local attribute declaration. + src-attribute.3.2 = src-attribute.3.2: The content must match (annotation?) for the attribute reference ''{0}''. + src-attribute.4 = src-attribute.4: Attribute ''{0}'' has both a ''type'' attribute and an anonymous ''simpleType'' child. Only one of these is allowed for an attribute. + src-attribute_group.2 = src-attribute_group.2: The intersection of wildcards is not expressible for attribute group ''{0}''. + src-attribute_group.3 = src-attribute_group.3: Circular definitions detected for attribute group ''{0}''. Recursively following attribute group references eventually leads back to itself. + src-ct.1 = src-ct.1: Complex Type Definition Representation Error for type ''{0}''. When is used, the base type must be a complexType. ''{1}'' is a simpleType. + src-ct.2.1 = src-ct.2.1: Complex Type Definition Representation Error for type ''{0}''. When is used, the base type must be a complexType whose content type is simple, or, only if restriction is specified, a complex type with mixed content and emptiable particle, or, only if extension is specified, a simple type. ''{1}'' satisfies none of these conditions. + src-ct.2.2 = src-ct.2.2: Complex Type Definition Representation Error for type ''{0}''. When a complexType with simpleContent restricts a complexType with mixed content and emptiable particle, then there must be a among the children of . + src-ct.4 = src-ct.4: Complex Type Definition Representation Error for type ''{0}''. The intersection of wildcards is not expressible. + src-ct.5 = src-ct.5: Complex Type Definition Representation Error for type ''{0}''. The union of wildcards is not expressible. + src-element.1 = src-element.1: The properties ''default'' and ''fixed'' cannot both be present in element declaration ''{0}''. Use only one of them. + src-element.2.1 = src-element.2.1: : One of 'ref' or 'name' must be present in a local element declaration. + src-element.2.2 = src-element.2.2: Since ''{0}'' contains the ''ref'' attribute, its content must match (annotation?). However, ''{1}'' was found. + src-element.3 = src-element.3: Element ''{0}'' has both a ''type'' attribute and a ''anonymous type'' child. Only one of these is allowed for an element. + src-import.1.1 = src-import.1.1: The namespace attribute ''{0}'' of an element information item must not be the same as the targetNamespace of the schema it exists in. + src-import.1.2 = src-import.1.2: If the namespace attribute is not present on an element information item then the enclosing schema must have a targetNamespace. + src-import.2 = src-import.2: The root element of document ''{0}'' has to have the namespace name ''http://www.w3.org/2001/XMLSchema'' and the local name ''schema''. + src-import.3.1 = src-import.3.1: The namespace attribute, ''{0}'', of an element information item must be identical to the targetNamespace attribute, ''{1}'', of the imported document. + src-import.3.2 = src-import.3.2: An element information item that had no namespace attribute was found, so the imported document cannot have a targetNamespace attribute. However, the targetNamespace ''{1}'' was found in the imported document. + src-include.1 = src-include.1: The root element of document ''{0}'' has to have the namespace name ''http://www.w3.org/2001/XMLSchema'' and the local name ''schema''. + src-include.2.1 = src-include.2.1: The targetNamespace of the referenced schema, currently ''{1}'', must be identical to that of the including schema, currently ''{0}''. + src-redefine.2 = src-redefine.2: The root element of document ''{0}'' has to have the namespace name ''http://www.w3.org/2001/XMLSchema'' and the local name ''schema''. + src-redefine.3.1 = src-redefine.3.1: The targetNamespace of the referenced schema, currently ''{1}'', must be identical to that of the redefining schema, currently ''{0}''. + src-redefine.5.a.a = src-redefine.5.a.a: No non-annotation children of were found. children of elements must have descendants, with 'base' attributes that refer to themselves. + src-redefine.5.a.b = src-redefine.5.a.b: ''{0}'' is not a valid child element. children of elements must have descendants, with ''base'' attributes that refer to themselves. + src-redefine.5.a.c = src-redefine.5.a.c: ''{0}'' does not have a ''base'' attribute that refers to the redefined element, ''{1}''. children of elements must have descendants, with ''base'' attributes that refer to themselves. + src-redefine.5.b.a = src-redefine.5.b.a: No non-annotation children of were found. children of elements must have or descendants, with 'base' attributes that refer to themselves. + src-redefine.5.b.b = src-redefine.5.b.b: No non-annotation grandchildren of were found. children of elements must have or descendants, with 'base' attributes that refer to themselves. + src-redefine.5.b.c = src-redefine.5.b.c: ''{0}'' is not a valid grandchild element. children of elements must have or descendants, with ''base'' attributes that refer to themselves. + src-redefine.5.b.d = src-redefine.5.b.d: ''{0}'' does not have a ''base'' attribute that refers to the redefined element, ''{1}''. children of elements must have or descendants, with ''base'' attributes that refer to themselves. + src-redefine.6.1.1 = src-redefine.6.1.1: If a group child of a element contains a group referring itself, it must have exactly 1; this one has ''{0}''. + src-redefine.6.1.2 = src-redefine.6.1.2: The group ''{0}'', which contains a reference to a group being redefined, must have ''minOccurs'' = ''maxOccurs'' = 1. + src-redefine.6.2.1 = src-redefine.6.2.1: No group in the redefined schema has a name matching ''{0}''. + src-redefine.6.2.2 = src-redefine.6.2.2: Group ''{0}'' does not properly restrict the group it redefines; constraint violated: ''{1}''. + src-redefine.7.1 = src-redefine.7.1: If an attributeGroup child of a element contains an attributeGroup referring itself, it must have exactly 1; this one has {0}. + src-redefine.7.2.1 = src-redefine.7.2.1: No attributeGroup in the redefined schema has a name matching ''{0}''. + src-redefine.7.2.2 = src-redefine.7.2.2: AttributeGroup ''{0}'' does not properly restrict the attributeGroup it redefines; constraint violated: ''{1}''. + src-resolve = src-resolve: Cannot resolve the name ''{0}'' to a(n) ''{1}'' component. + src-resolve.4.1 = src-resolve.4.1: Error resolving component ''{2}''. It was detected that ''{2}'' has no namespace, but components with no target namespace are not referenceable from schema document ''{0}''. If ''{2}'' is intended to have a namespace, perhaps a prefix needs to be provided. If it is intended that ''{2}'' has no namespace, then an ''import'' without a "namespace" attribute should be added to ''{0}''. + src-resolve.4.2 = src-resolve.4.2: Error resolving component ''{2}''. It was detected that ''{2}'' is in namespace ''{1}'', but components from this namespace are not referenceable from schema document ''{0}''. If this is the incorrect namespace, perhaps the prefix of ''{2}'' needs to be changed. If this is the correct namespace, then an appropriate ''import'' tag should be added to ''{0}''. + src-simple-type.2.a = src-simple-type.2.a: A element was found that has both a base [attribute] and a element among its [children]. Only one is allowed. + src-simple-type.2.b = src-simple-type.2.b: A element was found that has neither a base [attribute] nor a element among its [children]. One is required. + src-simple-type.3.a = src-simple-type.3.a: A element was found that has both an itemType [attribute] and a element among its [children]. Only one is allowed. + src-simple-type.3.b = src-simple-type.3.b: A element was found that has neither an itemType [attribute] nor a element among its [children]. One is required. + src-single-facet-value = src-single-facet-value: The facet ''{0}'' is defined more than once. + src-union-memberTypes-or-simpleTypes = src-union-memberTypes-or-simpleTypes: A element must have either a non-empty memberTypes [attribute] or at least one element among its [children]. + +#constraint valid (3.X.6) + + ag-props-correct.2 = ag-props-correct.2: Error for attribute group ''{0}''. Duplicate attribute uses with the same name and target namespace are specified. Name of duplicate attribute use is ''{1}''. + ag-props-correct.3 = ag-props-correct.3: Error for attribute group ''{0}''. Two attribute declarations, ''{1}'' and ''{2}'' have types which are derived from ID. + a-props-correct.2 = a-props-correct.2: Invalid value constraint value ''{1}'' in attribute ''{0}''. + a-props-correct.3 = a-props-correct.3: Attribute ''{0}'' cannot use ''fixed'' or ''default'', because the attribute''s '{'type definition'}' is ID, or is derived from ID. + au-props-correct.2 = au-props-correct.2: In the attribute declaration of ''{0}'', a fixed value of ''{1}'' was specified. So if the attribute use referring to ''{0}'' also has a '{'value constraint'}', it must be fixed and its value must be ''{1}''. + cos-all-limited.1.2 = cos-all-limited.1.2: An 'all' model group must appear in a particle with '{'min occurs'}' = '{'max occurs'}' = 1, and that particle must be part of a pair which constitutes the '{'content type'}' of a complex type definition. + cos-all-limited.2 = cos-all-limited.2: The '{'max occurs'}' of an element in an ''all'' model group must be 0 or 1. The value ''{0}'' for element ''{1}'' is invalid. + cos-applicable-facets = cos-applicable-facets: Facet ''{0}'' is not allowed by type {1}. + cos-ct-extends.1.1 = cos-ct-extends.1.1: Type ''{0}'' was derived by extension from type ''{1}''. However, the ''final'' attribute of ''{1}'' forbids derivation by extension. + cos-ct-extends.1.4.3.2.2.1.a = cos-ct-extends.1.4.3.2.2.1.a: The content type of a derived type and that of its base must both be mixed or both be element-only. Type ''{0}'' is element only, but its base type is not. + cos-ct-extends.1.4.3.2.2.1.b = cos-ct-extends.1.4.3.2.2.1.b: The content type of a derived type and that of its base must both be mixed or both be element-only. Type ''{0}'' is mixed, but its base type is not. + cos-element-consistent = cos-element-consistent: Error for type ''{0}''. Multiple elements with name ''{1}'', with different types, appear in the model group. + cos-list-of-atomic = cos-list-of-atomic: In the definition of list type ''{0}'', type ''{1}'' is an invalid list element type because it is not atomic (''{1}'' is either a list type, or a union type which contains a list). + cos-nonambig = cos-nonambig: {0} and {1} (or elements from their substitution group) violate \"Unique Particle Attribution\". During validation against this schema, ambiguity would be created for those two particles. + cos-particle-restrict.a = cos-particle-restrict.a: Derived particle is empty, and base is not emptiable. + cos-particle-restrict.b = cos-particle-restrict.b: Base particle is empty, but derived particle is not. + cos-particle-restrict.2 = cos-particle-restrict.2: Forbidden particle restriction: ''{0}''. + cos-st-restricts.1.1 = cos-st-restricts.1.1: The type ''{1}'' is atomic, so its '{'base type definition'}', ''{0}'', must be an atomic simple type definition or a built-in primitive datatype. + cos-st-restricts.2.1 = cos-st-restricts.2.1: In the definition of list type ''{0}'', type ''{1}'' is an invalid item type because it is either a list type, or a union type that contains a list. + cos-st-restricts.2.3.1.1 = cos-st-restricts.2.3.1.1: The '{'final'}' component of the '{'item type definition'}', ''{0}'', contains ''list''. This means that ''{0}'' cannot be used as an item type for list type ''{1}''. + cos-st-restricts.3.3.1.1 = cos-st-restricts.3.3.1.1: The '{'final'}' component of the '{'member type definitions'}', ''{0}'', contains ''union''. This means that ''{0}'' cannot be used as an member type for union type ''{1}''. + cos-valid-default.2.1 = cos-valid-default.2.1: Element ''{0}'' has a value constraint and must have a mixed or simple content model. + cos-valid-default.2.2.2 = cos-valid-default.2.2.2: Since element ''{0}'' has a '{'value constraint'}' and its type definition has mixed '{'content type'}', then the particle of the '{'content type'}' must be emptiable. + c-props-correct.2 = c-props-correct.2: Cardinality of Fields for keyref ''{0}'' and key ''{1}'' must match each other. + ct-props-correct.3 = ct-props-correct.3: Circular definitions detected for complex type ''{0}''. This means that ''{0}'' is contained in its own type hierarchy, which is an error. + ct-props-correct.4 = ct-props-correct.4: Error for type ''{0}''. Duplicate attribute uses with the same name and target namespace are specified. Name of duplicate attribute use is ''{1}''. + ct-props-correct.5 = ct-props-correct.5: Error for type ''{0}''. Two attribute declarations, ''{1}'' and ''{2}'' have types which are derived from ID. + derivation-ok-restriction.1 = derivation-ok-restriction.1: Type ''{0}'' was derived by restriction from type ''{1}''. However, ''{1}'' has a '{'final'}' property that forbids derivation by restriction. + derivation-ok-restriction.2.1.1 = derivation-ok-restriction.2.1.1: Error for type ''{0}''. The attribute use ''{1}'' in this type has a ''use'' value of ''{2}'', which is inconsistent with the value of ''required'' in a matching attribute use in the base type. + derivation-ok-restriction.2.1.2 = derivation-ok-restriction.2.1.2: Error for type ''{0}''. The attribute use ''{1}'' in this type has type ''{2}'', which is not validly derived from ''{3}'', the type of the matching attribute use in the base type. + derivation-ok-restriction.2.1.3.a = derivation-ok-restriction.2.1.3.a: Error for type ''{0}''. The attribute use ''{1}'' in this type has an effective value constraint which is not fixed, and the effective value constraint of the matching attribute use in the base type is fixed. + derivation-ok-restriction.2.1.3.b = derivation-ok-restriction.2.1.3.b: Error for type ''{0}''. The attribute use ''{1}'' in this type has an effective value constraint fixed with a value of ''{2}'', which is not consistent with the value of ''{3}'' for the fixed effective value constraint of the matching attribute use in the base type. + derivation-ok-restriction.2.2.a = derivation-ok-restriction.2.2.a: Error for type ''{0}''. The attribute use ''{1}'' in this type does not have a matching attribute use in the base, and the base type does not have a wildcard attribute. + derivation-ok-restriction.2.2.b = derivation-ok-restriction.2.2.b: Error for type ''{0}''. The attribute use ''{1}'' in this type does not have a matching attribute use in the base, and the wildcard in the base type does not allow the namespace ''{2}'' of this attribute use. + derivation-ok-restriction.3 = derivation-ok-restriction.3: Error for type ''{0}''. The attribute use ''{1}'' in the base type has REQUIRED as true, but there is no matching attribute use in the derived type. + derivation-ok-restriction.4.1 = derivation-ok-restriction.4.1: Error for type ''{0}''. The derivation has an attribute wildcard, but the base does not have one. + derivation-ok-restriction.4.2 = derivation-ok-restriction.4.2: Error for type ''{0}''. The wildcard in the derivation is not a valid wildcard subset of the one in the base. + derivation-ok-restriction.4.3 = derivation-ok-restriction.4.3: Error for type ''{0}''. The process contents of the wildcard in the derivation ({1}) is weaker than that in the base ({2}). + derivation-ok-restriction.5.2.2.1 = derivation-ok-restriction.5.2.2.1: Error for type ''{0}''. The simple content type of this type, ''{1}'', is not a valid restriction of the simple content type of the base, ''{2}''. + derivation-ok-restriction.5.3.2 = derivation-ok-restriction.5.3.2: Error for type ''{0}''. The content type of this type is empty, but the content type of the base, ''{1}'', is not empty or emptiable. + derivation-ok-restriction.5.4.1.2 = derivation-ok-restriction.5.4.1.2: Error for type ''{0}''. The content type of this type is mixed, but the content type of the base, ''{1}'', is not. + derivation-ok-restriction.5.4.2 = derivation-ok-restriction.5.4.2: Error for type ''{0}''. The particle of the type is not a valid restriction of the particle of the base. + enumeration-required-notation = enumeration-required-notation: The NOTATION type, ''{0}'' used by {2} ''{1}'', must have an enumeration facet value which specifies the notation elements used by this type. + enumeration-valid-restriction = enumeration-valid-restriction: Enumeration value ''{0}'' is not in the value space of the base type, {1}. + e-props-correct.2 = e-props-correct.2: Invalid value constraint value ''{1}'' in element ''{0}''. + e-props-correct.4 = e-props-correct.4: The '{'type definition'}' of element ''{0}'' is not validly derived from the '{'type definition'}' of the substitutionHead ''{1}'', or the '{'substitution group exclusions'}' property of ''{1}'' does not allow this derivation. + e-props-correct.5 = e-props-correct.5: A '{'value constraint'}' must not be present on element ''{0}'', because the element''s '{'type definition'}' or '{'type definition'}'''s '{'content type'}' is ID, or is derived from ID. + e-props-correct.6 = e-props-correct.6: Circular substitution group detected for element ''{0}''. + fractionDigits-valid-restriction = fractionDigits-valid-restriction: In the definition of {2}, the value ''{0}'' for the facet ''fractionDigits'' is invalid, because it must be <= the value for ''fractionDigits'' which was set to ''{1}'' in one of the ancestor types. + fractionDigits-totalDigits = fractionDigits-totalDigits: In the definition of {2}, the value ''{0}'' for the facet ''fractionDigits'' is invalid, because the value must be <= the value for ''totalDigits'' which is ''{1}''. + length-minLength-maxLength.1.1 = length-minLength-maxLength.1.1: For type {0}, it is an error for the value of length ''{1}'' to be less than the value of minLength ''{2}''. + length-minLength-maxLength.1.2.a = length-minLength-maxLength.1.2.a: For type {0}, it is an error for the base to not have a minLength facet if the current restriction has the minLength facet and the current restriction or base has the length facet. + length-minLength-maxLength.1.2.b = length-minLength-maxLength.1.2.b: For type {0}, it is an error for the current minLength ''{1}'' to not equal the base minLength ''{2}''. + length-minLength-maxLength.2.1 = length-minLength-maxLength.2.1: For type {0}, it is an error for the value of length ''{1}'' to be greater than the value of maxLength ''{2}''. + length-minLength-maxLength.2.2.a = length-minLength-maxLength.2.2.a: For type {0}, it is an error for the base to not have a maxLength facet if the current restriction has the maxLength facet and the current restriction or base has the length facet. + length-minLength-maxLength.2.2.b = length-minLength-maxLength.2.2.b: For type {0}, it is an error for the current maxLength ''{1}'' to not equal the base maxLength ''{2}''. + length-valid-restriction = length-valid-restriction: Error for type ''{2}''. The value of length = ''{0}'' must be = the value of that of the base type ''{1}''. + maxExclusive-valid-restriction.1 = maxExclusive-valid-restriction.1: Error for type ''{2}''. The maxExclusive value =''{0}'' must be <= maxExclusive of the base type ''{1}''. + maxExclusive-valid-restriction.2 = maxExclusive-valid-restriction.2: Error for type ''{2}''. The maxExclusive value =''{0}'' must be <= maxInclusive of the base type ''{1}''. + maxExclusive-valid-restriction.3 = maxExclusive-valid-restriction.3: Error for type ''{2}''. The maxExclusive value =''{0}'' must be > minInclusive of the base type ''{1}''. + maxExclusive-valid-restriction.4 = maxExclusive-valid-restriction.4: Error for type ''{2}''. The maxExclusive value =''{0}'' must be > minExclusive of the base type ''{1}''. + maxInclusive-maxExclusive = maxInclusive-maxExclusive: It is an error for both maxInclusive and maxExclusive to be specified for the same datatype. In {2}, maxInclusive = ''{0}'' and maxExclusive = ''{1}''. + maxInclusive-valid-restriction.1 = maxInclusive-valid-restriction.1: Error for type ''{2}''. The maxInclusive value =''{0}'' must be <= maxInclusive of the base type ''{1}''. + maxInclusive-valid-restriction.2 = maxInclusive-valid-restriction.2: Error for type ''{2}''. The maxInclusive value =''{0}'' must be < maxExclusive of the base type ''{1}''. + maxInclusive-valid-restriction.3 = maxInclusive-valid-restriction.3: Error for type ''{2}''. The maxInclusive value =''{0}'' must be >= minInclusive of the base type ''{1}''. + maxInclusive-valid-restriction.4 = maxInclusive-valid-restriction.4: Error for type ''{2}''. The maxInclusive value =''{0}'' must be > minExclusive of the base type ''{1}''. + maxLength-valid-restriction = maxLength-valid-restriction: In the definition of {2}, maxLength value = ''{0}'' must be <= that of the base type ''{1}''. + mg-props-correct.2 = mg-props-correct.2: Circular definitions detected for group ''{0}''. Recursively following the '{'term'}' values of the particles leads to a particle whose '{'term'}' is the group itself. + minExclusive-less-than-equal-to-maxExclusive = minExclusive-less-than-equal-to-maxExclusive: In the definition of {2}, minExclusive value = ''{0}'' must be <= maxExclusive value = ''{1}''. + minExclusive-less-than-maxInclusive = minExclusive-less-than-maxInclusive: In the definition of {2}, minExclusive value = ''{0}'' must be < maxInclusive value = ''{1}''. + minExclusive-valid-restriction.1 = minExclusive-valid-restriction.1: Error for type ''{2}''. The minExclusive value =''{0}'' must be >= minExclusive of the base type ''{1}''. + minExclusive-valid-restriction.2 = minExclusive-valid-restriction.2: Error for type ''{2}''. The minExclusive value =''{0}'' must be <= maxInclusive of the base type ''{1}''. + minExclusive-valid-restriction.3 = minExclusive-valid-restriction.3: Error for type ''{2}''. The minExclusive value =''{0}'' must be >= minInclusive of the base type ''{1}''. + minExclusive-valid-restriction.4 = minExclusive-valid-restriction.4: Error for type ''{2}''. The minExclusive value =''{0}'' must be < maxExclusive of the base type ''{1}''. + minInclusive-less-than-equal-to-maxInclusive = minInclusive-less-than-equal-to-maxInclusive: In the definition of {2}, minInclusive value = ''{0}'' must be <= maxInclusive value = ''{1}''. + minInclusive-less-than-maxExclusive = minInclusive-less-than-maxExclusive: In the definition of {2}, minInclusive value = ''{0}'' must be < maxExclusive value = ''{1}''. + minInclusive-minExclusive = minInclusive-minExclusive: It is an error for both minInclusive and minExclusive to be specified for the same datatype. In {2}, minInclusive = ''{0}'' and minExclusive = ''{1}''. + minInclusive-valid-restriction.1 = minInclusive-valid-restriction.1: Error for type ''{2}''. The minInclusive value =''{0}'' must be >= minInclusive of the base type ''{1}''. + minInclusive-valid-restriction.2 = minInclusive-valid-restriction.2: Error for type ''{2}''. The minInclusive value =''{0}'' must be <= maxInclusive of the base type ''{1}''. + minInclusive-valid-restriction.3 = minInclusive-valid-restriction.3: Error for type ''{2}''. The minInclusive value =''{0}'' must be > minExclusive of the base type ''{1}''. + minInclusive-valid-restriction.4 = minInclusive-valid-restriction.4: Error for type ''{2}''. The minInclusive value =''{0}'' must be < maxExclusive of the base type ''{1}''. + minLength-less-than-equal-to-maxLength = minLength-less-than-equal-to-maxLength: In the definition of {2}, value of minLength = ''{0}'' must be < value of maxLength = ''{1}''. + minLength-valid-restriction = minLength-valid-restriction: In the definition of {2}, minLength = ''{0}'' must be >= than that of the base type, ''{1}''. + no-xmlns = no-xmlns: The {name} of an attribute declaration must not match 'xmlns'. + no-xsi = no-xsi: The '{'target namespace'}' of an attribute declaration must not match ''{0}''. + p-props-correct.2.1 = p-props-correct.2.1: In the declaration of ''{0}'', the value of ''minOccurs'' is ''{1}'', but it must not be greater than the value of ''maxOccurs'', which is ''{2}''. + rcase-MapAndSum.1 = rcase-MapAndSum.1: There is not a complete functional mapping between the particles. + rcase-MapAndSum.2 = rcase-MapAndSum.2: Group''s occurrence range, ({0},{1}), is not a valid restriction of base group''s occurrence range, ({2},{3}). + rcase-NameAndTypeOK.1 = rcase-NameAndTypeOK.1: Elements have names and target namespaces which are not the same: Element ''{0}'' in namespace ''{1}'' and element ''{2}'' in namespace ''{3}''. + rcase-NameAndTypeOK.2 = rcase-NameAndTypeOK.2: Error for the particle whose '{'term'}' is the element declaration ''{0}''. The element declaration''s '{'nillable'}' is true, but the corresponding particle in the base type has an element declaration whose '{'nillable'}' is false. + rcase-NameAndTypeOK.3 = rcase-NameAndTypeOK.3: Error for the particle whose '{'term'}' is the element declaration ''{0}''. Its occurrence range, ({1},{2}), is not a valid restriction of the range, ({3},{4}), of the corresponding particle in the base type. + rcase-NameAndTypeOK.4.a = rcase-NameAndTypeOK.4.a: Element ''{0}'' is not fixed, but the corresponding element in the base type is fixed with value ''{1}''. + rcase-NameAndTypeOK.4.b = rcase-NameAndTypeOK.4.b: Element ''{0}'' is fixed with value ''{1}'', but the corresponding element in the base type is fixed with value ''{2}''. + rcase-NameAndTypeOK.5 = rcase-NameAndTypeOK.5: Identity constraints for element ''{0}'' are not a subset of those in base. + rcase-NameAndTypeOK.6 = rcase-NameAndTypeOK.6: The disallowed substitutions for element ''{0}'' are not a superset of those in the base. + rcase-NameAndTypeOK.7 = rcase-NameAndTypeOK.7: The type of element ''{0}'', ''{1}'', is not derived from the type of the base element, ''{2}''. + rcase-NSCompat.1 = rcase-NSCompat.1: Element ''{0}'' has a namespace ''{1}'' which is not allowed by the wildcard in the base. + rcase-NSCompat.2 = rcase-NSCompat.2: Error for the particle whose '{'term'}' is the element declaration ''{0}''. Its occurrence range, ({1},{2}), is not a valid restriction of the range, ({3},{4}), of the corresponding particle in the base type. + rcase-NSRecurseCheckCardinality.1 = rcase-NSRecurseCheckCardinality.1: There is not a complete functional mapping between the particles. + rcase-NSRecurseCheckCardinality.2 = rcase-NSRecurseCheckCardinality.2: Group''s occurrence range, ({0},{1}), is not a valid restriction of base wildcard''s range, ({2},{3}). + rcase-NSSubset.1 = rcase-NSSubset.1: Wildcard is not a subset of corresponding wildcard in base. + rcase-NSSubset.2 = rcase-NSSubset.2: Wildcard''s occurrence range, ({0},{1}), is not a valid restriction of that in the base, ({2},{3}),. + rcase-NSSubset.3 = rcase-NSSubset.3: Wildcard''s process contents, ''{0}'', is weaker than that in the base, ''{1}''. + rcase-Recurse.1 = rcase-Recurse.1: Group''s occurrence range, ({0},{1}), is not a valid restriction of base group''s occurrence range, ({2},{3}). + rcase-Recurse.2 = rcase-Recurse.2: There is not a complete functional mapping between the particles. + rcase-RecurseLax.1 = rcase-RecurseLax.1: Group''s occurrence range, ({0},{1}), is not a valid restriction of base group''s occurrence range, ({2},{3}). + rcase-RecurseLax.2 = rcase-RecurseLax.2: There is not a complete functional mapping between the particles. + rcase-RecurseUnordered.1 = rcase-RecurseUnordered.1: Group''s occurrence range, ({0},{1}), is not a valid restriction of base group''s occurrence range, ({2},{3}). + rcase-RecurseUnordered.2 = rcase-RecurseUnordered.2: There is not a complete functional mapping between the particles. +# We're using sch-props-correct.2 instead of the old src-redefine.1 +# src-redefine.1 = src-redefine.1: The component ''{0}'' is begin redefined, but its corresponding component isn't in the schema document being redefined (with namespace ''{2}''), but in a different document, with namespace ''{1}''. + sch-props-correct.2 = sch-props-correct.2: A schema cannot contain two global components with the same name; this schema contains two occurrences of ''{0}''. + st-props-correct.2 = st-props-correct.2: Circular definitions have been detected for simple type ''{0}''. This means that ''{0}'' is contained in its own type hierarchy, which is an error. + st-props-correct.3 = st-props-correct.3: Error for type ''{0}''. The value of '{'final'}' of the '{'base type definition'}', ''{1}'', forbids derivation by restriction. + totalDigits-valid-restriction = totalDigits-valid-restriction: In the definition of {2}, the value ''{0}'' for the facet ''totalDigits'' is invalid, because it must be <= the value for ''totalDigits'' which was set to ''{1}'' in one of the ancestor types. + whiteSpace-valid-restriction.1 = whiteSpace-valid-restriction.1: In the definition of {0}, the value ''{1}'' for the facet ''whitespace'' is invalid, because the value for ''whitespace'' has been set to ''collapse'' in one of the ancestor types. + whiteSpace-valid-restriction.2 = whiteSpace-valid-restriction.2: In the definition of {0}, the value ''preserve'' for the facet ''whitespace'' is invalid, because the value for ''whitespace'' has been set to ''replace'' in one of the ancestor types. + +#schema for Schemas + + s4s-att-invalid-value = s4s-att-invalid-value: Invalid attribute value for ''{1}'' in element ''{0}''. Recorded reason: {2} + s4s-att-must-appear = s4s-att-must-appear: Attribute ''{1}'' must appear in element ''{0}''. + s4s-att-not-allowed = s4s-att-not-allowed: Attribute ''{1}'' cannot appear in element ''{0}''. + s4s-elt-invalid = s4s-elt-invalid: Element ''{0}'' is not a valid element in a schema document. + s4s-elt-must-match.1 = s4s-elt-must-match.1: The content of ''{0}'' must match {1}. A problem was found starting at: {2}. + s4s-elt-must-match.2 = s4s-elt-must-match.2: The content of ''{0}'' must match {1}. Not enough elements were found. + # the "invalid-content" messages provide less information than the "must-match" counterparts above. They're used for complex types when providing a "match" would be an information dump + s4s-elt-invalid-content.1 = s4s-elt-invalid-content.1: The content of ''{0}'' is invalid. Element ''{1}'' is invalid, misplaced, or occurs too often. + s4s-elt-invalid-content.2 = s4s-elt-invalid-content.2: The content of ''{0}'' is invalid. Element ''{1}'' cannot be empty. + s4s-elt-invalid-content.3 = s4s-elt-invalid-content.3: Elements of type ''{0}'' cannot appear after declarations as children of a element. + s4s-elt-schema-ns = s4s-elt-schema-ns: The namespace of element ''{0}'' must be from the schema namespace, ''http://www.w3.org/2001/XMLSchema''. + s4s-elt-character = s4s-elt-character: Non-whitespace characters are not allowed in schema elements other than ''xs:appinfo'' and ''xs:documentation''. Saw ''{0}''. + +# codes not defined by the spec + + c-fields-xpaths = c-fields-xpaths: The field value = ''{0}'' is not valid. + c-general-xpath = c-general-xpath: The expression ''{0}'' is not valid with respect to the XPath subset supported by XML Schema. + c-general-xpath-ns = c-general-xpath-ns: A namespace prefix in XPath expression ''{0}'' was not bound to a namespace. + c-selector-xpath = c-selector-xpath: The selector value = ''{0}'' is not valid; selector xpaths cannot contain attributes. + EmptyTargetNamespace = EmptyTargetNamespace: In schema document ''{0}'', the value of the ''targetNamespace'' attribute cannot be an empty string. + FacetValueFromBase = FacetValueFromBase: In the declaration of type ''{0}'', value ''{1}'' of facet ''{2}'' must be from the value space of the base type, ''{3}''. + FixedFacetValue = FixedFacetValue: In the definition of {3}, the value ''{1}'' for the facet ''{0}'' is invalid, because the value for ''{0}'' has been set to ''{2}'' in one of the ancestor types, and '{'fixed'}' = true. + InvalidRegex = InvalidRegex: Pattern value ''{0}'' is not a valid regular expression. The reported error was: ''{1}''. + maxOccurLimit = Current configuration of the parser doesn''t allow the expansion of a content model for a complex type to contain more than {0} nodes. + PublicSystemOnNotation = PublicSystemOnNotation: At least one of 'public' and 'system' must appear in element 'notation'. + SchemaLocation = SchemaLocation: schemaLocation value = ''{0}'' must have even number of URI''s. + TargetNamespace.1 = TargetNamespace.1: Expecting namespace ''{0}'', but the target namespace of the schema document is ''{1}''. + TargetNamespace.2 = TargetNamespace.2: Expecting no namespace, but the schema document has a target namespace of ''{1}''. + UndeclaredEntity = UndeclaredEntity: Entity ''{0}'' is not declared. + UndeclaredPrefix = UndeclaredPrefix: Cannot resolve ''{0}'' as a QName: the prefix ''{1}'' is not declared. + FacetsContradict = FacetsContradict: For simpleType definition ''{2}'', the enumeration value ''{0}'' contradicts with value of ''{1}'' facet. + +# JAXP 1.2 schema source property errors + + jaxp12-schema-source-type.1 = The ''http://java.sun.com/xml/jaxp/properties/schemaSource'' property cannot have a value of type ''{0}''. Possible types of the value supported are String, File, InputStream, InputSource or an array of these types. + jaxp12-schema-source-type.2 = The ''http://java.sun.com/xml/jaxp/properties/schemaSource'' property cannot have an array value of type ''{0}''. Possible types of the array supported are Object, String, File, InputStream and InputSource. + jaxp12-schema-source-ns = When using an array of Objects as the value of the 'http://java.sun.com/xml/jaxp/properties/schemaSource' property, it is illegal to have two schemas that share the same target namespace. + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLSerializerMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLSerializerMessages.properties new file mode 100644 index 0000000..e9e26cd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XMLSerializerMessages.properties @@ -0,0 +1,50 @@ +# +# 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. +# + +# This file stores error messages for the Xerces XML +# serializer. Many DOM Load/Save error messages also +# live here, since the serializer largely implements that package. +# +# As usual with properties files, the messages are arranged in +# key/value tuples. +# +# @version $Id$ + + BadMessageKey = The error message corresponding to the message key can not be found. + FormatFailed = An internal error occurred while formatting the following message:\n + + ArgumentIsNull = Argument ''{0}'' is null. + NoWriterSupplied = No writer supplied for serializer. + MethodNotSupported = The method ''{0}'' is not supported by this factory. + ResetInMiddle = The serializer may not be reset in the middle of serialization. + Internal = Internal error: element state is zero. + NoName = There is no rawName and localName is null. + ElementQName = The element name ''{0}'' is not a QName. + ElementPrefix = Element ''{0}'' does not belong to any namespace: prefix could be undeclared or bound to some namespace. + AttributeQName = The attribute name ''{0}'' is not a QName. + AttributePrefix = Attribute ''{0}'' does not belong to any namespace: prefix could be undeclared or bound to some namespace. + InvalidNSDecl = Namespace declaration syntax is incorrect: {0}. + EndingCDATA = The character sequence \"]]>\" must not appear in content unless used to mark the end of a CDATA section. + SplittingCDATA = Splitting a CDATA section containing the CDATA section termination marker \"]]>\". + ResourceNotFound = The resource ''{0}'' could not be found. + ResourceNotLoaded = The resource ''{0}'' could not be loaded. {1} + SerializationStopped = Serialization stopped at user request. + + # DOM Level 3 load and save messages + no-output-specified = no-output-specified: The output destination for data to be written to was null. + unsupported-encoding = unsupported-encoding: An unsupported encoding is encountered. + unable-to-serialize-node = unable-to-serialize-node: The node could not be serialized. diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/msg/XPointerMessages.properties b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XPointerMessages.properties new file mode 100644 index 0000000..038282b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/msg/XPointerMessages.properties @@ -0,0 +1,44 @@ +# +# 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. +# + +# This file stores localized messages for the Xerces XPointer implementation. +# +# The messages are arranged in key and value tuples in a ListResourceBundle. +# +# @version $Id$ + +# Messages for message reporting +BadMessageKey = The error message corresponding to the message key can not be found. +FormatFailed = An internal error occurred while formatting the following message:\n + +# XPointer Framework Error Messages +XPointerProcessingError = XPointerProcessingError: An error occurred while processing the XPointer expression. +InvalidXPointerToken = InvalidXPointerToken: The XPointer expression contains the invalid token ''{0}'' +InvalidXPointerExpression = InvalidXPointerExpression: The XPointer expression ''{0}'' is invalid. +MultipleShortHandPointers = MultipleShortHandPointers: The XPointer expression ''{0}'' is invalid. It has more than one ShortHand Pointer. +SchemeDataNotFollowedByCloseParenthesis = SchemeDataNotFollowedByCloseParenthesis: The XPointer expression ''{0}'' is invalid. The SchemeData was not followed by a '')'' character. +SchemeUnsupported = SchemeUnsupported: The XPointer scheme ''{0}'' is not supported. +InvalidShortHandPointer = InvalidShortHandPointer: The NCName of the ShortHand Pointer ''{0}'' is invalid. +UnbalancedParenthesisInXPointerExpression = UnbalancedParenthesisInXPointerExpression: The XPointer expression ''{0}'' is invalid. The number of open parenthesis ''{1}'' is not equal to the number of close parenthesis ''{2}''. +InvalidSchemeDataInXPointer = InvalidSchemeDataInXPointer: The XPointer expression ''{0}'' contains invalid SchemeData. + +# XPointer Element Scheme Error Messages +InvalidElementSchemeToken = InvalidElementSchemeToken: The element() scheme XPointer expression contains the invalid token ''{0}'' +InvalidElementSchemeXPointer = InvalidElementSchemeXPointer: The Element Scheme XPointer expression ''{0}'' is invalid. +XPointerElementSchemeProcessingError = XPointerElementSchemeProcessingError: An error occurred while processing the XPointer element() Scheme expression. +InvalidNCNameInElementSchemeData = InvalidNCNameInElementSchemeData: The element() Scheme contains a ShortHand Pointer ''{0}'' with an invalid NCName. +InvalidChildSequenceCharacter = InvalidChildSequenceCharacter: The element() Scheme contains an invalid child sequence character ''{0}''. \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/validation/ConfigurableValidationState.java b/resources/xerces2-j-src/org/apache/xerces/impl/validation/ConfigurableValidationState.java new file mode 100644 index 0000000..47c7fa6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/validation/ConfigurableValidationState.java @@ -0,0 +1,127 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.validation; + +import java.util.Iterator; + +/** + *

An extension of ValidationState which can be configured to turn + * off checking for ID/IDREF errors and unparsed entity errors.

+ * + * @xerces.internal + * + * @author Peter McCracken, IBM + * @version $Id$ + */ +public final class ConfigurableValidationState extends ValidationState { + + /** + * Whether to check for ID/IDREF errors + */ + private boolean fIdIdrefChecking; + + /** + * Whether to check for unparsed entity errors + */ + private boolean fUnparsedEntityChecking; + + /** + * Creates a new ConfigurableValidationState. + * By default, error checking for both ID/IDREFs + * and unparsed entities are turned on. + */ + public ConfigurableValidationState() { + super(); + fIdIdrefChecking = true; + fUnparsedEntityChecking = true; + } + + /** + * Turns checking for ID/IDREF errors on and off. + * @param setting true to turn on error checking, + * false to turn off error checking + */ + public void setIdIdrefChecking(boolean setting) { + fIdIdrefChecking = setting; + } + + /** + * Turns checking for unparsed entity errors on and off. + * @param setting true to turn on error checking, + * false to turn off error checking + */ + public void setUnparsedEntityChecking(boolean setting) { + fUnparsedEntityChecking = setting; + } + + /** + * Checks if all IDREFs have a corresponding ID. + * @return null, if ID/IDREF checking is turned off + * otherwise, returns the value of the super implementation + */ + public Iterator checkIDRefID() { + return (fIdIdrefChecking) ? super.checkIDRefID() : null; + } + + /** + * Checks if an ID has already been declared. + * @return false, if ID/IDREF checking is turned off + * otherwise, returns the value of the super implementation + */ + public boolean isIdDeclared(String name) { + return (fIdIdrefChecking) ? super.isIdDeclared(name) : false; + } + + /** + * Checks if an entity is declared. + * @return true, if unparsed entity checking is turned off + * otherwise, returns the value of the super implementation + */ + public boolean isEntityDeclared(String name) { + return (fUnparsedEntityChecking) ? super.isEntityDeclared(name) : true; + } + + /** + * Checks if an entity is unparsed. + * @return true, if unparsed entity checking is turned off + * otherwise, returns the value of the super implementation + */ + public boolean isEntityUnparsed(String name) { + return (fUnparsedEntityChecking) ? super.isEntityUnparsed(name) : true; + } + + /** + * Adds the ID, if ID/IDREF checking is enabled. + * @param name the ID to add + */ + public void addId(String name) { + if (fIdIdrefChecking) { + super.addId(name); + } + } + + /** + * Adds the IDREF, if ID/IDREF checking is enabled. + * @param name the IDREF to add + */ + public void addIdRef(String name) { + if (fIdIdrefChecking) { + super.addIdRef(name); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/validation/EntityState.java b/resources/xerces2-j-src/org/apache/xerces/impl/validation/EntityState.java new file mode 100644 index 0000000..db4a7ac --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/validation/EntityState.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.validation; + + +/** + * The entity state interface defines methods that must be implemented + * by components that store information about entity declarations, as well as by + * entity validator that will need to validate attributes of type entity. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public interface EntityState { + /** + * Query method to check if entity with this name was declared. + * + * @param name + * @return true if name is a declared entity + */ + public boolean isEntityDeclared (String name); + + /** + * Query method to check if entity is unparsed. + * + * @param name + * @return true if name is an unparsed entity + */ + public boolean isEntityUnparsed (String name); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/validation/ValidationManager.java b/resources/xerces2-j-src/org/apache/xerces/impl/validation/ValidationManager.java new file mode 100644 index 0000000..3ca1967 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/validation/ValidationManager.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.validation; + +import java.util.ArrayList; + +/** + * ValidationManager is a coordinator property for validators in the + * pipeline. Each validator must know how to interact with + * this property. Validators are not required to know what kind of + * other validators present in the pipeline, but should understand + * that there are others and that some coordination is required. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public class ValidationManager { + + protected final ArrayList fVSs = new ArrayList(); + protected boolean fGrammarFound = false; + + // used by the DTD validator to tell other components that it has a + // cached DTD in hand so there's no reason to + // scan external subset or entity decls. + protected boolean fCachedDTD = false; + + /** + * Each validator should call this method to add its ValidationState into + * the validation manager. + */ + public final void addValidationState(ValidationState vs) { + fVSs.add(vs); + } + + /** + * Set the information required to validate entity values. + */ + public final void setEntityState(EntityState state) { + for (int i = fVSs.size()-1; i >= 0; i--) { + ((ValidationState)fVSs.get(i)).setEntityState(state); + } + } + + public final void setGrammarFound(boolean grammar){ + fGrammarFound = grammar; + } + + public final boolean isGrammarFound(){ + return fGrammarFound; + } + + public final void setCachedDTD(boolean cachedDTD) { + fCachedDTD = cachedDTD; + } // setCachedDTD(boolean) + + public final boolean isCachedDTD() { + return fCachedDTD; + } // isCachedDTD(): boolean + + + public final void reset () { + fVSs.clear(); + fGrammarFound = false; + fCachedDTD = false; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/validation/ValidationState.java b/resources/xerces2-j-src/org/apache/xerces/impl/validation/ValidationState.java new file mode 100644 index 0000000..9baab0d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/validation/ValidationState.java @@ -0,0 +1,208 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.validation; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; + +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.NamespaceContext; + +/** + * Implementation of the ValidationContext interface. Used to establish an + * environment for simple type validation. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public class ValidationState implements ValidationContext { + + // + // private data + // + private boolean fExtraChecking = true; + private boolean fFacetChecking = true; + private boolean fNormalize = true; + private boolean fNamespaces = true; + + private EntityState fEntityState = null; + private NamespaceContext fNamespaceContext = null; + private SymbolTable fSymbolTable = null; + private Locale fLocale = null; + + //REVISIT: Should replace with a lighter structure. + private final HashMap fIdTable = new HashMap(); + private final HashMap fIdRefTable = new HashMap(); + private final static Object fNullValue = new Object(); + + // + // public methods + // + public void setExtraChecking(boolean newValue) { + fExtraChecking = newValue; + } + + public void setFacetChecking(boolean newValue) { + fFacetChecking = newValue; + } + + public void setNormalizationRequired (boolean newValue) { + fNormalize = newValue; + } + + public void setUsingNamespaces (boolean newValue) { + fNamespaces = newValue; + } + + public void setEntityState(EntityState state) { + fEntityState = state; + } + + public void setNamespaceSupport(NamespaceContext namespace) { + fNamespaceContext = namespace; + } + + public void setSymbolTable(SymbolTable sTable) { + fSymbolTable = sTable; + } + + /** + * return null if all IDREF values have a corresponding ID value; + * otherwise return an iterator for all the IDREF values without + * a matching ID value. + */ + public Iterator checkIDRefID() { + HashSet missingIDs = null; + Iterator iter = fIdRefTable.keySet().iterator(); + String key; + while (iter.hasNext()) { + key = (String) iter.next(); + if (!fIdTable.containsKey(key)) { + if (missingIDs == null) { + missingIDs = new HashSet(); + } + missingIDs.add(key); + } + } + return (missingIDs != null) ? missingIDs.iterator() : null; + } + + public void reset () { + fExtraChecking = true; + fFacetChecking = true; + fNamespaces = true; + fIdTable.clear(); + fIdRefTable.clear(); + fEntityState = null; + fNamespaceContext = null; + fSymbolTable = null; + } + + /** + * The same validation state can be used to validate more than one (schema) + * validation roots. Entity/Namespace/Symbol are shared, but each validation + * root needs its own id/idref tables. So we need this method to reset only + * the two tables. + */ + public void resetIDTables() { + fIdTable.clear(); + fIdRefTable.clear(); + } + + // + // implementation of ValidationContext methods + // + + // whether to do extra id/idref/entity checking + public boolean needExtraChecking() { + return fExtraChecking; + } + + // whether to validate against facets + public boolean needFacetChecking() { + return fFacetChecking; + } + + public boolean needToNormalize (){ + return fNormalize; + } + + public boolean useNamespaces() { + return fNamespaces; + } + + // entity + public boolean isEntityDeclared (String name) { + if (fEntityState !=null) { + return fEntityState.isEntityDeclared(getSymbol(name)); + } + return false; + } + public boolean isEntityUnparsed (String name) { + if (fEntityState !=null) { + return fEntityState.isEntityUnparsed(getSymbol(name)); + } + return false; + } + + // id + public boolean isIdDeclared(String name) { + return fIdTable.containsKey(name); + } + public void addId(String name) { + fIdTable.put(name, fNullValue); + } + + // idref + public void addIdRef(String name) { + fIdRefTable.put(name, fNullValue); + } + // get symbols + + public String getSymbol (String symbol) { + if (fSymbolTable != null) + return fSymbolTable.addSymbol(symbol); + // if there is no symbol table, we return java-internalized string, + // because symbol table strings are also java-internalzied. + // this guarantees that the returned string from this method can be + // compared by reference with other symbol table string. -SG + return symbol.intern(); + } + // qname, notation + public String getURI(String prefix) { + if (fNamespaceContext !=null) { + return fNamespaceContext.getURI(prefix); + } + return null; + } + + // Locale + + public void setLocale(Locale locale) { + fLocale = locale; + } + + public Locale getLocale() { + return fLocale; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/XPath.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/XPath.java new file mode 100644 index 0000000..e1f5835 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/XPath.java @@ -0,0 +1,2023 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath; + +import java.util.ArrayList; +import java.util.Vector; + +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; + +/** + * Bare minimum XPath parser. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @version $Id$ + */ +public class XPath { + + // + // Constants + // + + private static final boolean DEBUG_ALL = false; + + private static final boolean DEBUG_XPATH_PARSE = DEBUG_ALL || false; + + private static final boolean DEBUG_ANY = DEBUG_XPATH_PARSE; + + // + // Data + // + + /** Expression. */ + protected final String fExpression; + + /** Symbol table. */ + protected final SymbolTable fSymbolTable; + + /** Location paths. */ + protected final LocationPath[] fLocationPaths; + + // + // Constructors + // + + /** Constructs an XPath object from the specified expression. */ + public XPath(String xpath, SymbolTable symbolTable, + NamespaceContext context) + throws XPathException { + fExpression = xpath; + fSymbolTable = symbolTable; + fLocationPaths = parseExpression(context); + if (DEBUG_XPATH_PARSE) { + System.out.println(">>> "+fLocationPaths); + } + } // (String,SymbolTable,NamespaceContext) + + // + // Public methods + // + + /** + * Returns a representation of all location paths for this XPath. + * XPath = locationPath ( '|' locationPath) + */ + public LocationPath[] getLocationPaths() { + LocationPath[] ret=new LocationPath[fLocationPaths.length]; + for (int i=0;i0){ + buf.append('|'); + } + buf.append(fLocationPaths[i].toString()); + } + return buf.toString(); + } // toString():String + + // + // Private methods + // + + /** + * Used by the {@link #parseExpression(NamespaceContext)} method + * to verify the assumption. + * + * If b is false, this method throws XPathException + * to report the error. + */ + private static void check( boolean b ) throws XPathException { + if(!b) throw new XPathException("c-general-xpath"); + } + + /** + * Used by the {@link #parseExpression(NamespaceContext)} method + * to build a {@link LocationPath} object from the accumulated + * {@link Step}s. + */ + private LocationPath buildLocationPath( Vector stepsVector ) throws XPathException { + int size = stepsVector.size(); + check(size!=0); + Step[] steps = new Step[size]; + stepsVector.copyInto(steps); + stepsVector.removeAllElements(); + + return new LocationPath(steps); + } + + /** + * This method is implemented by using the XPathExprScanner and + * examining the list of tokens that it returns. + */ + private LocationPath[] parseExpression(final NamespaceContext context) + throws XPathException { + + // tokens + final XPath.Tokens xtokens = new XPath.Tokens(fSymbolTable); + + // scanner + XPath.Scanner scanner = new XPath.Scanner(fSymbolTable) { + protected void addToken(XPath.Tokens tokens, int token) + throws XPathException { + if ( + token == XPath.Tokens.EXPRTOKEN_ATSIGN || + token == XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME || + token == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH || + token == XPath.Tokens.EXPRTOKEN_PERIOD || + token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY || + token == XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE || + token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH || + token == XPath.Tokens.EXPRTOKEN_OPERATOR_UNION || + token == XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD || + token == XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE || + token == XPath.Tokens.EXPRTOKEN_DOUBLE_COLON + // + ) { + super.addToken(tokens, token); + return; + } + throw new XPathException("c-general-xpath"); + } + }; + + int length = fExpression.length(); + + boolean success = scanner.scanExpr(fSymbolTable, + xtokens, fExpression, 0, length); + if(!success) + throw new XPathException("c-general-xpath"); + + //fTokens.dumpTokens(); + Vector stepsVector = new Vector(); + ArrayList locationPathsVector= new ArrayList(); + + // true when the next token should be 'Step' (as defined in + // the production rule [3] of XML Schema P1 section 3.11.6 + // if false, we are expecting either '|' or '/'. + // + // this is to make sure we can detect a token list like + // 'abc' '/' '/' 'def' 'ghi' + boolean expectingStep = true; + + while (xtokens.hasMore()) { + final int token = xtokens.nextToken(); + + switch (token) { + case XPath.Tokens.EXPRTOKEN_OPERATOR_UNION :{ + check(!expectingStep); + locationPathsVector.add(buildLocationPath(stepsVector)); + expectingStep=true; + break; + } + case XPath.Tokens.EXPRTOKEN_ATSIGN: { + check(expectingStep); + Step step = new Step( + new Axis(Axis.ATTRIBUTE), + parseNodeTest(xtokens.nextToken(),xtokens,context)); + stepsVector.addElement(step); + expectingStep=false; + break; + } + case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE: { + check(expectingStep); + // If we got here we're expecting attribute:: + if (xtokens.nextToken() != XPath.Tokens.EXPRTOKEN_DOUBLE_COLON) { + throw new XPathException("c-general-xpath"); + } + Step step = new Step( + new Axis(Axis.ATTRIBUTE), + parseNodeTest(xtokens.nextToken(),xtokens,context)); + stepsVector.addElement(step); + expectingStep = false; + break; + } + case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: + case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE: + case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: { + check(expectingStep); + Step step = new Step( + new Axis(Axis.CHILD), + parseNodeTest(token,xtokens,context)); + stepsVector.addElement(step); + expectingStep=false; + break; + } + case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD: { + check(expectingStep); + // If we got here we're expecting child:: + if (xtokens.nextToken() != XPath.Tokens.EXPRTOKEN_DOUBLE_COLON) { + throw new XPathException("c-general-xpath"); + } + Step step = new Step( + new Axis(Axis.CHILD), + parseNodeTest(xtokens.nextToken(),xtokens,context)); + stepsVector.addElement(step); + expectingStep = false; + break; + } + case XPath.Tokens.EXPRTOKEN_PERIOD: { + check(expectingStep); + expectingStep=false; + + // unless this is the first step in this location path, + // there's really no reason to keep them in LocationPath. + // This amounts to shorten "a/././b/./c" to "a/b/c". + // Also, the matcher fails to work correctly if XPath + // has those redundant dots. + if (stepsVector.size()==0) { + // build step + Axis axis = new Axis(Axis.SELF); + NodeTest nodeTest = new NodeTest(NodeTest.NODE); + Step step = new Step(axis, nodeTest); + stepsVector.addElement(step); + + if( xtokens.hasMore() + && xtokens.peekToken() == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH){ + // consume '//' + xtokens.nextToken(); + + // build step + axis = new Axis(Axis.DESCENDANT); + nodeTest = new NodeTest(NodeTest.NODE); + step = new Step(axis, nodeTest); + stepsVector.addElement(step); + expectingStep=true; + } + } + break; + } + case XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH:{ + // this cannot appear in an arbitrary position. + // it is only allowed right after '.' when + // '.' is the first token of a location path. + throw new XPathException("c-general-xpath"); + } + case XPath.Tokens.EXPRTOKEN_DOUBLE_COLON: { + // :: cannot appear in an arbitrary position. + // We only expect this token if the xpath + // contains child:: or attribute:: + throw new XPathException("c-general-xpath"); + } + case XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH: { + check(!expectingStep); + expectingStep=true; + break; + } + default: + // we should have covered all the tokens that we can possibly see. + throw new InternalError(); + } + } + + check(!expectingStep); + + locationPathsVector.add(buildLocationPath(stepsVector)); + + // return location path + return (LocationPath[])locationPathsVector.toArray(new LocationPath[locationPathsVector.size()]); + + } // parseExpression(SymbolTable,NamespaceContext) + + /** + * Used by {@link #parseExpression} to parse a node test + * from the token list. + */ + private NodeTest parseNodeTest( int typeToken, Tokens xtokens, NamespaceContext context ) + throws XPathException { + switch(typeToken) { + case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: + return new NodeTest(NodeTest.WILDCARD); + + case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE: + case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: + // consume QName token + String prefix = xtokens.nextTokenAsString(); + String uri = null; + if (context != null && prefix != XMLSymbols.EMPTY_STRING) { + uri = context.getURI(prefix); + } + if (prefix != XMLSymbols.EMPTY_STRING && context != null && uri == null) { + throw new XPathException("c-general-xpath-ns"); + } + + if (typeToken==XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE) + return new NodeTest(prefix,uri); + + String localpart = xtokens.nextTokenAsString(); + String rawname = prefix != XMLSymbols.EMPTY_STRING + ? fSymbolTable.addSymbol(prefix+':'+localpart) + : localpart; + + return new NodeTest(new QName(prefix, localpart, rawname, uri)); + + default: + throw new XPathException("c-general-xpath"); + } + } + + + // + // Classes + // + + // location path information + + /** + * A location path representation for an XPath expression. + * + * @xerces.internal + * + * @author Andy Clark, IBM + */ + public static class LocationPath + implements Cloneable { + + // + // Data + // + + /** List of steps. */ + public final Step[] steps; + + // + // Constructors + // + + /** Creates a location path from a series of steps. */ + public LocationPath(Step[] steps) { + this.steps = steps; + } // (Step[]) + + /** Copy constructor. */ + protected LocationPath(LocationPath path) { + steps = new Step[path.steps.length]; + for (int i = 0; i < steps.length; i++) { + steps[i] = (Step)path.steps[i].clone(); + } + } // (LocationPath) + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < steps.length; i++) { + if (i > 0 && (steps[i-1].axis.type!=Axis.DESCENDANT + && steps[i].axis.type!=Axis.DESCENDANT) ){ + str.append('/'); + } + str.append(steps[i].toString()); + } + // DEBUG: This code is just for debugging and should *not* + // be left in because it will mess up hashcodes of + // serialized versions of this object. -Ac + if (false) { + str.append('['); + String s = super.toString(); + str.append(s.substring(s.indexOf('@'))); + str.append(']'); + } + return str.toString(); + } // toString():String + + /** Returns a clone of this object. */ + public Object clone() { + return new LocationPath(this); + } // clone():Object + + } // class locationPath + + /** + * A location path step comprised of an axis and node test. + * + * @xerces.internal + * + * @author Andy Clark, IBM + */ + public static class Step + implements Cloneable { + + // + // Data + // + + /** Axis. */ + public final Axis axis; + + /** Node test. */ + public final NodeTest nodeTest; + + // + // Constructors + // + + /** Constructs a step from an axis and node test. */ + public Step(Axis axis, NodeTest nodeTest) { + this.axis = axis; + this.nodeTest = nodeTest; + } // (Axis,NodeTest) + + /** Copy constructor. */ + protected Step(Step step) { + axis = (Axis)step.axis.clone(); + nodeTest = (NodeTest)step.nodeTest.clone(); + } // (Step) + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + if (axis.type == Axis.SELF) { + return "."; + } + if (axis.type == Axis.ATTRIBUTE) { + return "@" + nodeTest.toString(); + } + if (axis.type == Axis.CHILD) { + return nodeTest.toString(); + } + if (axis.type == Axis.DESCENDANT) { + return "//"; + } + return "??? ("+axis.type+')'; + } // toString():String + + /** Returns a clone of this object. */ + public Object clone() { + return new Step(this); + } // clone():Object + + } // class Step + + /** + * Axis. + * + * @xerces.internal + * + * @author Andy Clark, IBM + */ + public static class Axis + implements Cloneable { + + // + // Constants + // + + /** Type: child. */ + public static final short CHILD = 1; + + /** Type: attribute. */ + public static final short ATTRIBUTE = 2; + + /** Type: self. */ + public static final short SELF = 3; + + + /** Type: descendant. */ + public static final short DESCENDANT = 4; + // + // Data + // + + /** Axis type. */ + public final short type; + + // + // Constructors + // + + /** Constructs an axis with the specified type. */ + public Axis(short type) { + this.type = type; + } // (short) + + /** Copy constructor. */ + protected Axis(Axis axis) { + type = axis.type; + } // (Axis) + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + switch (type) { + case CHILD: return "child"; + case ATTRIBUTE: return "attribute"; + case SELF: return "self"; + case DESCENDANT: return "descendant"; + } + return "???"; + } // toString():String + + /** Returns a clone of this object. */ + public Object clone() { + return new Axis(this); + } // clone():Object + + } // class Axis + + /** + * Node test. + * + * @xerces.internal + * + * @author Andy Clark, IBM + */ + public static class NodeTest + implements Cloneable { + + // + // Constants + // + + /** Type: qualified name. */ + public static final short QNAME = 1; + + /** Type: wildcard. */ + public static final short WILDCARD = 2; + + /** Type: node. */ + public static final short NODE = 3; + + /** Type: namespace */ + public static final short NAMESPACE= 4; + + // + // Data + // + + /** Node test type. */ + public final short type; + + /** Node qualified name. */ + public final QName name = new QName(); + + // + // Constructors + // + + /** Constructs a node test of type WILDCARD or NODE. */ + public NodeTest(short type) { + this.type = type; + } // (int) + + /** Constructs a node test of type QName. */ + public NodeTest(QName name) { + this.type = QNAME; + this.name.setValues(name); + } // (QName) + /** Constructs a node test of type Namespace. */ + public NodeTest(String prefix, String uri) { + this.type = NAMESPACE; + this.name.setValues(prefix, null, null, uri); + } // (String,String) + + /** Copy constructor. */ + public NodeTest(NodeTest nodeTest) { + type = nodeTest.type; + name.setValues(nodeTest.name); + } // (NodeTest) + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + + switch (type) { + case QNAME: { + if (name.prefix.length() !=0) { + if (name.uri != null) { + return name.prefix+':'+name.localpart; + } + return "{"+name.uri+'}'+name.prefix+':'+name.localpart; + } + return name.localpart; + } + case NAMESPACE: { + if (name.prefix.length() !=0) { + if (name.uri != null) { + return name.prefix+":*"; + } + return "{"+name.uri+'}'+name.prefix+":*"; + } + return "???:*"; + } + case WILDCARD: { + return "*"; + } + case NODE: { + return "node()"; + } + } + return "???"; + + } // toString():String + + /** Returns a clone of this object. */ + public Object clone() { + return new NodeTest(this); + } // clone():Object + + } // class NodeTest + + // xpath implementation + + // NOTE: The XPath implementation classes are kept internal because + // this implementation is just a temporary hack until a better + // and/or more appropriate implementation can be written. + // keeping the code in separate source files would "muddy" the + // CVS directory when it's not needed. -Ac + + /** + * List of tokens. + * + * @xerces.internal + * + * @author Glenn Marcy, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ + private static final class Tokens { + + static final boolean DUMP_TOKENS = false; + + /** + * [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::' + * | NameTest | NodeType | Operator | FunctionName + * | AxisName | Literal | Number | VariableReference + */ + public static final int + EXPRTOKEN_OPEN_PAREN = 0, + EXPRTOKEN_CLOSE_PAREN = 1, + EXPRTOKEN_OPEN_BRACKET = 2, + EXPRTOKEN_CLOSE_BRACKET = 3, + EXPRTOKEN_PERIOD = 4, + EXPRTOKEN_DOUBLE_PERIOD = 5, + EXPRTOKEN_ATSIGN = 6, + EXPRTOKEN_COMMA = 7, + EXPRTOKEN_DOUBLE_COLON = 8, + // + // [37] NameTest ::= '*' | NCName ':' '*' | QName + // + // followed by symbol handle of NCName or QName + // + EXPRTOKEN_NAMETEST_ANY = 9, + EXPRTOKEN_NAMETEST_NAMESPACE = 10, + EXPRTOKEN_NAMETEST_QNAME = 11, + // + // [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node' + // + EXPRTOKEN_NODETYPE_COMMENT = 12, + EXPRTOKEN_NODETYPE_TEXT = 13, + EXPRTOKEN_NODETYPE_PI = 14, + EXPRTOKEN_NODETYPE_NODE = 15, + // + // [32] Operator ::= OperatorName + // | MultiplyOperator + // | '/' | '//' | '|' | '+' | '-' | '=' | '!=' | '<' | '<=' | '>' | '>=' + // [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div' + // [34] MultiplyOperator ::= '*' + // + EXPRTOKEN_OPERATOR_AND = 16, + EXPRTOKEN_OPERATOR_OR = 17, + EXPRTOKEN_OPERATOR_MOD = 18, + EXPRTOKEN_OPERATOR_DIV = 19, + EXPRTOKEN_OPERATOR_MULT = 20, + EXPRTOKEN_OPERATOR_SLASH = 21, + EXPRTOKEN_OPERATOR_DOUBLE_SLASH = 22, + EXPRTOKEN_OPERATOR_UNION = 23, + EXPRTOKEN_OPERATOR_PLUS = 24, + EXPRTOKEN_OPERATOR_MINUS = 25, + EXPRTOKEN_OPERATOR_EQUAL = 26, + EXPRTOKEN_OPERATOR_NOT_EQUAL = 27, + EXPRTOKEN_OPERATOR_LESS = 28, + EXPRTOKEN_OPERATOR_LESS_EQUAL = 29, + EXPRTOKEN_OPERATOR_GREATER = 30, + EXPRTOKEN_OPERATOR_GREATER_EQUAL = 31, + + //EXPRTOKEN_FIRST_OPERATOR = EXPRTOKEN_OPERATOR_AND, + //EXPRTOKEN_LAST_OPERATOR = EXPRTOKEN_OPERATOR_GREATER_EQUAL, + + // + // [35] FunctionName ::= QName - NodeType + // + // followed by symbol handle + // + EXPRTOKEN_FUNCTION_NAME = 32, + // + // [6] AxisName ::= 'ancestor' | 'ancestor-or-self' + // | 'attribute' + // | 'child' + // | 'descendant' | 'descendant-or-self' + // | 'following' | 'following-sibling' + // | 'namespace' + // | 'parent' + // | 'preceding' | 'preceding-sibling' + // | 'self' + // + EXPRTOKEN_AXISNAME_ANCESTOR = 33, + EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF = 34, + EXPRTOKEN_AXISNAME_ATTRIBUTE = 35, + EXPRTOKEN_AXISNAME_CHILD = 36, + EXPRTOKEN_AXISNAME_DESCENDANT = 37, + EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF = 38, + EXPRTOKEN_AXISNAME_FOLLOWING = 39, + EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING = 40, + EXPRTOKEN_AXISNAME_NAMESPACE = 41, + EXPRTOKEN_AXISNAME_PARENT = 42, + EXPRTOKEN_AXISNAME_PRECEDING = 43, + EXPRTOKEN_AXISNAME_PRECEDING_SIBLING = 44, + EXPRTOKEN_AXISNAME_SELF = 45, + // + // [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'" + // + // followed by symbol handle for literal + // + EXPRTOKEN_LITERAL = 46, + // + // [30] Number ::= Digits ('.' Digits?)? | '.' Digits + // [31] Digits ::= [0-9]+ + // + // followed by number handle + // + EXPRTOKEN_NUMBER = 47, + // + // [36] VariableReference ::= '$' QName + // + // followed by symbol handle for QName + // + EXPRTOKEN_VARIABLE_REFERENCE = 48; + + private static final String[] fgTokenNames = { + "EXPRTOKEN_OPEN_PAREN", + "EXPRTOKEN_CLOSE_PAREN", + "EXPRTOKEN_OPEN_BRACKET", + "EXPRTOKEN_CLOSE_BRACKET", + "EXPRTOKEN_PERIOD", + "EXPRTOKEN_DOUBLE_PERIOD", + "EXPRTOKEN_ATSIGN", + "EXPRTOKEN_COMMA", + "EXPRTOKEN_DOUBLE_COLON", + "EXPRTOKEN_NAMETEST_ANY", + "EXPRTOKEN_NAMETEST_NAMESPACE", + "EXPRTOKEN_NAMETEST_QNAME", + "EXPRTOKEN_NODETYPE_COMMENT", + "EXPRTOKEN_NODETYPE_TEXT", + "EXPRTOKEN_NODETYPE_PI", + "EXPRTOKEN_NODETYPE_NODE", + "EXPRTOKEN_OPERATOR_AND", + "EXPRTOKEN_OPERATOR_OR", + "EXPRTOKEN_OPERATOR_MOD", + "EXPRTOKEN_OPERATOR_DIV", + "EXPRTOKEN_OPERATOR_MULT", + "EXPRTOKEN_OPERATOR_SLASH", + "EXPRTOKEN_OPERATOR_DOUBLE_SLASH", + "EXPRTOKEN_OPERATOR_UNION", + "EXPRTOKEN_OPERATOR_PLUS", + "EXPRTOKEN_OPERATOR_MINUS", + "EXPRTOKEN_OPERATOR_EQUAL", + "EXPRTOKEN_OPERATOR_NOT_EQUAL", + "EXPRTOKEN_OPERATOR_LESS", + "EXPRTOKEN_OPERATOR_LESS_EQUAL", + "EXPRTOKEN_OPERATOR_GREATER", + "EXPRTOKEN_OPERATOR_GREATER_EQUAL", + "EXPRTOKEN_FUNCTION_NAME", + "EXPRTOKEN_AXISNAME_ANCESTOR", + "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF", + "EXPRTOKEN_AXISNAME_ATTRIBUTE", + "EXPRTOKEN_AXISNAME_CHILD", + "EXPRTOKEN_AXISNAME_DESCENDANT", + "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF", + "EXPRTOKEN_AXISNAME_FOLLOWING", + "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING", + "EXPRTOKEN_AXISNAME_NAMESPACE", + "EXPRTOKEN_AXISNAME_PARENT", + "EXPRTOKEN_AXISNAME_PRECEDING", + "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING", + "EXPRTOKEN_AXISNAME_SELF", + "EXPRTOKEN_LITERAL", + "EXPRTOKEN_NUMBER", + "EXPRTOKEN_VARIABLE_REFERENCE" + }; + + /** + * + */ + private static final int INITIAL_TOKEN_COUNT = 1 << 8; + private int[] fTokens = new int[INITIAL_TOKEN_COUNT]; + private int fTokenCount = 0; // for writing + + private SymbolTable fSymbolTable; + + // REVISIT: Code something better here. -Ac + private java.util.Hashtable fSymbolMapping = new java.util.Hashtable(); + + // REVISIT: Code something better here. -Ac + private java.util.Hashtable fTokenNames = new java.util.Hashtable(); + + /** + * Current position in the token list. + */ + private int fCurrentTokenIndex; + + // + // Constructors + // + + public Tokens(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + final String[] symbols = { + "ancestor", "ancestor-or-self", "attribute", + "child", "descendant", "descendant-or-self", + "following", "following-sibling", "namespace", + "parent", "preceding", "preceding-sibling", + "self", + }; + for (int i = 0; i < symbols.length; i++) { + fSymbolMapping.put(fSymbolTable.addSymbol(symbols[i]), new Integer(i)); + } + fTokenNames.put(new Integer(EXPRTOKEN_OPEN_PAREN), "EXPRTOKEN_OPEN_PAREN"); + fTokenNames.put(new Integer(EXPRTOKEN_CLOSE_PAREN), "EXPRTOKEN_CLOSE_PAREN"); + fTokenNames.put(new Integer(EXPRTOKEN_OPEN_BRACKET), "EXPRTOKEN_OPEN_BRACKET"); + fTokenNames.put(new Integer(EXPRTOKEN_CLOSE_BRACKET), "EXPRTOKEN_CLOSE_BRACKET"); + fTokenNames.put(new Integer(EXPRTOKEN_PERIOD), "EXPRTOKEN_PERIOD"); + fTokenNames.put(new Integer(EXPRTOKEN_DOUBLE_PERIOD), "EXPRTOKEN_DOUBLE_PERIOD"); + fTokenNames.put(new Integer(EXPRTOKEN_ATSIGN), "EXPRTOKEN_ATSIGN"); + fTokenNames.put(new Integer(EXPRTOKEN_COMMA), "EXPRTOKEN_COMMA"); + fTokenNames.put(new Integer(EXPRTOKEN_DOUBLE_COLON), "EXPRTOKEN_DOUBLE_COLON"); + fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_ANY), "EXPRTOKEN_NAMETEST_ANY"); + fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_NAMESPACE), "EXPRTOKEN_NAMETEST_NAMESPACE"); + fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_QNAME), "EXPRTOKEN_NAMETEST_QNAME"); + fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_COMMENT), "EXPRTOKEN_NODETYPE_COMMENT"); + fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_TEXT), "EXPRTOKEN_NODETYPE_TEXT"); + fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_PI), "EXPRTOKEN_NODETYPE_PI"); + fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_NODE), "EXPRTOKEN_NODETYPE_NODE"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_AND), "EXPRTOKEN_OPERATOR_AND"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_OR), "EXPRTOKEN_OPERATOR_OR"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MOD), "EXPRTOKEN_OPERATOR_MOD"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_DIV), "EXPRTOKEN_OPERATOR_DIV"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MULT), "EXPRTOKEN_OPERATOR_MULT"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_SLASH), "EXPRTOKEN_OPERATOR_SLASH"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_DOUBLE_SLASH), "EXPRTOKEN_OPERATOR_DOUBLE_SLASH"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_UNION), "EXPRTOKEN_OPERATOR_UNION"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_PLUS), "EXPRTOKEN_OPERATOR_PLUS"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MINUS), "EXPRTOKEN_OPERATOR_MINUS"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_EQUAL), "EXPRTOKEN_OPERATOR_EQUAL"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_NOT_EQUAL), "EXPRTOKEN_OPERATOR_NOT_EQUAL"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_LESS), "EXPRTOKEN_OPERATOR_LESS"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_LESS_EQUAL), "EXPRTOKEN_OPERATOR_LESS_EQUAL"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_GREATER), "EXPRTOKEN_OPERATOR_GREATER"); + fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_GREATER_EQUAL), "EXPRTOKEN_OPERATOR_GREATER_EQUAL"); + fTokenNames.put(new Integer(EXPRTOKEN_FUNCTION_NAME), "EXPRTOKEN_FUNCTION_NAME"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ANCESTOR), "EXPRTOKEN_AXISNAME_ANCESTOR"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF), "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ATTRIBUTE), "EXPRTOKEN_AXISNAME_ATTRIBUTE"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_CHILD), "EXPRTOKEN_AXISNAME_CHILD"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_DESCENDANT), "EXPRTOKEN_AXISNAME_DESCENDANT"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF), "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_FOLLOWING), "EXPRTOKEN_AXISNAME_FOLLOWING"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING), "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_NAMESPACE), "EXPRTOKEN_AXISNAME_NAMESPACE"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PARENT), "EXPRTOKEN_AXISNAME_PARENT"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PRECEDING), "EXPRTOKEN_AXISNAME_PRECEDING"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PRECEDING_SIBLING), "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING"); + fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_SELF), "EXPRTOKEN_AXISNAME_SELF"); + fTokenNames.put(new Integer(EXPRTOKEN_LITERAL), "EXPRTOKEN_LITERAL"); + fTokenNames.put(new Integer(EXPRTOKEN_NUMBER), "EXPRTOKEN_NUMBER"); + fTokenNames.put(new Integer(EXPRTOKEN_VARIABLE_REFERENCE), "EXPRTOKEN_VARIABLE_REFERENCE"); + } + + // + // Public methods + // + +// public String getTokenName(int token) { +// if (token < 0 || token >= fgTokenNames.length) +// return null; +// return fgTokenNames[token]; +// } +// + public String getTokenString(int token) { + return (String)fTokenNames.get(new Integer(token)); + } + + public void addToken(String tokenStr) { + Integer tokenInt = (Integer)fTokenNames.get(tokenStr); + if (tokenInt == null) { + tokenInt = new Integer(fTokenNames.size()); + fTokenNames.put(tokenInt, tokenStr); + } + addToken(tokenInt.intValue()); + } + + public void addToken(int token) { + try { + fTokens[fTokenCount] = token; + } catch (ArrayIndexOutOfBoundsException ex) { + int[] oldList = fTokens; + fTokens = new int[fTokenCount << 1]; + System.arraycopy(oldList, 0, fTokens, 0, fTokenCount); + fTokens[fTokenCount] = token; + } + fTokenCount++; + } +// public int getTokenCount() { +// return fTokenCount; +// } +// public int getToken(int tokenIndex) { +// return fTokens[tokenIndex]; +// } + + /** + * Resets the current position to the head of the token list. + */ + public void rewind() { + fCurrentTokenIndex=0; + } + /** + * Returns true if the {@link #getNextToken()} method + * returns a valid token. + */ + public boolean hasMore() { + return fCurrentTokenIndexnew XPathException("c-general-xpath");. + */ + public int nextToken() throws XPathException { + if( fCurrentTokenIndex==fTokenCount ) + throw new XPathException("c-general-xpath"); + return fTokens[fCurrentTokenIndex++]; + } + /** + * Obtains the token at the current position, without advancing + * the current position. + * + * If there's no such next token, this method throws + * new XPathException("c-general-xpath");. + */ + public int peekToken() throws XPathException { + if( fCurrentTokenIndex==fTokenCount ) + throw new XPathException("c-general-xpath"); + return fTokens[fCurrentTokenIndex]; + } + /** + * Obtains the token at the current position as a String. + * + * If there's no current token or if the current token + * is not a string token, this method throws + * new XPathException("c-general-xpath");. + */ + public String nextTokenAsString() throws XPathException { + String s = getTokenString(nextToken()); + if(s==null) throw new XPathException("c-general-xpath"); + return s; + } + + public void dumpTokens() { + //if (DUMP_TOKENS) { + for (int i = 0; i < fTokenCount; i++) { + switch (fTokens[i]) { + case EXPRTOKEN_OPEN_PAREN: + System.out.print(""); + break; + case EXPRTOKEN_CLOSE_PAREN: + System.out.print(""); + break; + case EXPRTOKEN_OPEN_BRACKET: + System.out.print(""); + break; + case EXPRTOKEN_CLOSE_BRACKET: + System.out.print(""); + break; + case EXPRTOKEN_PERIOD: + System.out.print(""); + break; + case EXPRTOKEN_DOUBLE_PERIOD: + System.out.print(""); + break; + case EXPRTOKEN_ATSIGN: + System.out.print(""); + break; + case EXPRTOKEN_COMMA: + System.out.print(""); + break; + case EXPRTOKEN_DOUBLE_COLON: + System.out.print(""); + break; + case EXPRTOKEN_NAMETEST_ANY: + System.out.print(""); + break; + case EXPRTOKEN_NAMETEST_NAMESPACE: + System.out.print(""); + break; + case EXPRTOKEN_NAMETEST_QNAME: + System.out.print(""); + break; + case EXPRTOKEN_NODETYPE_COMMENT: + System.out.print(""); + break; + case EXPRTOKEN_NODETYPE_TEXT: + System.out.print(""); + break; + case EXPRTOKEN_NODETYPE_PI: + System.out.print(""); + break; + case EXPRTOKEN_NODETYPE_NODE: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_AND: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_OR: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_MOD: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_DIV: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_MULT: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_SLASH: + System.out.print(""); + if (i + 1 < fTokenCount) { + System.out.println(); + System.out.print(" "); + } + break; + case EXPRTOKEN_OPERATOR_DOUBLE_SLASH: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_UNION: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_PLUS: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_MINUS: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_EQUAL: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_NOT_EQUAL: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_LESS: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_LESS_EQUAL: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_GREATER: + System.out.print(""); + break; + case EXPRTOKEN_OPERATOR_GREATER_EQUAL: + System.out.print(""); + break; + case EXPRTOKEN_FUNCTION_NAME: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_ANCESTOR: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_ATTRIBUTE: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_CHILD: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_DESCENDANT: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_FOLLOWING: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_NAMESPACE: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_PARENT: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_PRECEDING: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_PRECEDING_SIBLING: + System.out.print(""); + break; + case EXPRTOKEN_AXISNAME_SELF: + System.out.print(""); + break; + case EXPRTOKEN_LITERAL: + System.out.print(""); + break; + case EXPRTOKEN_NUMBER: + System.out.print(""); + break; + case EXPRTOKEN_VARIABLE_REFERENCE: + System.out.print(""); + break; + default: + System.out.println(""); + } + } + System.out.println(); + //} + } + + } // class Tokens + + /** + * @xerces.internal + * + * @author Glenn Marcy, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ + private static class Scanner { + + /** + * 7-bit ASCII subset + * + * 0 1 2 3 4 5 6 7 8 9 A B C D E F + * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0 + * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2 + * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3 + * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4 + * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5 + * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6 + * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7 + */ + private static final byte + CHARTYPE_INVALID = 0, // invalid XML character + CHARTYPE_OTHER = 1, // not special - one of "#%&;?\^`{}~" or DEL + CHARTYPE_WHITESPACE = 2, // one of "\t\n\r " (0x09, 0x0A, 0x0D, 0x20) + CHARTYPE_EXCLAMATION = 3, // '!' (0x21) + CHARTYPE_QUOTE = 4, // '\"' or '\'' (0x22 and 0x27) + CHARTYPE_DOLLAR = 5, // '$' (0x24) + CHARTYPE_OPEN_PAREN = 6, // '(' (0x28) + CHARTYPE_CLOSE_PAREN = 7, // ')' (0x29) + CHARTYPE_STAR = 8, // '*' (0x2A) + CHARTYPE_PLUS = 9, // '+' (0x2B) + CHARTYPE_COMMA = 10, // ',' (0x2C) + CHARTYPE_MINUS = 11, // '-' (0x2D) + CHARTYPE_PERIOD = 12, // '.' (0x2E) + CHARTYPE_SLASH = 13, // '/' (0x2F) + CHARTYPE_DIGIT = 14, // '0'-'9' (0x30 to 0x39) + CHARTYPE_COLON = 15, // ':' (0x3A) + CHARTYPE_LESS = 16, // '<' (0x3C) + CHARTYPE_EQUAL = 17, // '=' (0x3D) + CHARTYPE_GREATER = 18, // '>' (0x3E) + CHARTYPE_ATSIGN = 19, // '@' (0x40) + CHARTYPE_LETTER = 20, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A) + CHARTYPE_OPEN_BRACKET = 21, // '[' (0x5B) + CHARTYPE_CLOSE_BRACKET = 22, // ']' (0x5D) + CHARTYPE_UNDERSCORE = 23, // '_' (0x5F) + CHARTYPE_UNION = 24, // '|' (0x7C) + CHARTYPE_NONASCII = 25; // Non-ASCII Unicode codepoint (>= 0x80) + + private static final byte[] fASCIICharMap = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 3, 4, 1, 5, 1, 1, 4, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 1, 16, 17, 18, 1, + 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 1, 22, 1, 23, + 1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 1, 24, 1, 1, 1 + }; + + /** + * Symbol literals + */ + + // + // Data + // + + /** Symbol table. */ + private SymbolTable fSymbolTable; + + // symbols + + private static final String fAndSymbol = "and".intern(); + private static final String fOrSymbol = "or".intern(); + private static final String fModSymbol = "mod".intern(); + private static final String fDivSymbol = "div".intern(); + + private static final String fCommentSymbol = "comment".intern(); + private static final String fTextSymbol = "text".intern(); + private static final String fPISymbol = "processing-instruction".intern(); + private static final String fNodeSymbol = "node".intern(); + + private static final String fAncestorSymbol = "ancestor".intern(); + private static final String fAncestorOrSelfSymbol = "ancestor-or-self".intern(); + private static final String fAttributeSymbol = "attribute".intern(); + private static final String fChildSymbol = "child".intern(); + private static final String fDescendantSymbol = "descendant".intern(); + private static final String fDescendantOrSelfSymbol = "descendant-or-self".intern(); + private static final String fFollowingSymbol = "following".intern(); + private static final String fFollowingSiblingSymbol = "following-sibling".intern(); + private static final String fNamespaceSymbol = "namespace".intern(); + private static final String fParentSymbol = "parent".intern(); + private static final String fPrecedingSymbol = "preceding".intern(); + private static final String fPrecedingSiblingSymbol = "preceding-sibling".intern(); + private static final String fSelfSymbol = "self".intern(); + + // + // Constructors + // + + /** Constructs an XPath expression scanner. */ + public Scanner(SymbolTable symbolTable) { + + // save pool and tokens + fSymbolTable = symbolTable; + + } // (SymbolTable) + + /** + * + */ + public boolean scanExpr(SymbolTable symbolTable, + XPath.Tokens tokens, String data, + int currentOffset, int endOffset) + throws XPathException { + + int nameOffset; + String nameHandle, prefixHandle; + boolean starIsMultiplyOperator = false; + int ch; + + while (true) { + if (currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + // + // [39] ExprWhitespace ::= S + // + while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) { + if (++currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + } + if (currentOffset == endOffset) { + break; + } + // + // [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::' + // | NameTest | NodeType | Operator | FunctionName + // | AxisName | Literal | Number | VariableReference + // + byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII : fASCIICharMap[ch]; + switch (chartype) { + case CHARTYPE_OPEN_PAREN: // '(' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_PAREN); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_CLOSE_PAREN: // ')' + addToken(tokens, XPath.Tokens.EXPRTOKEN_CLOSE_PAREN); + starIsMultiplyOperator = true; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_OPEN_BRACKET: // '[' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_BRACKET); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_CLOSE_BRACKET: // ']' + addToken(tokens, XPath.Tokens.EXPRTOKEN_CLOSE_BRACKET); + starIsMultiplyOperator = true; + if (++currentOffset == endOffset) { + break; + } + break; + // + // [30] Number ::= Digits ('.' Digits?)? | '.' Digits + // ^^^^^^^^^^ + // + case CHARTYPE_PERIOD: // '.', '..' or '.' Digits + if (currentOffset + 1 == endOffset) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD); + starIsMultiplyOperator = true; + currentOffset++; + break; + } + ch = data.charAt(currentOffset + 1); + if (ch == '.') { // '..' + addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_PERIOD); + starIsMultiplyOperator = true; + currentOffset += 2; + } else if (ch >= '0' && ch <= '9') { + addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER); + starIsMultiplyOperator = true; + currentOffset = scanNumber(tokens, data, endOffset, currentOffset/*, encoding*/); + } else if (ch == '/') { + addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD); + starIsMultiplyOperator = true; + currentOffset++; + } else if (ch == '|') { + addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD); + starIsMultiplyOperator = true; + currentOffset++; + break; + } else if (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) { + // this is legal if the next token is non-existent or | + do { + if (++currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + } while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D); + if (currentOffset == endOffset || ch == '|') { + addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD); + starIsMultiplyOperator = true; + break; + } + throw new XPathException ("c-general-xpath"); + } else { // '.' + throw new XPathException ("c-general-xpath"); + } + if (currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_ATSIGN: // '@' + addToken(tokens, XPath.Tokens.EXPRTOKEN_ATSIGN); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_COMMA: // ',' + addToken(tokens, XPath.Tokens.EXPRTOKEN_COMMA); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_COLON: // '::' + if (++currentOffset == endOffset) { + // System.out.println("abort 1a"); + return false; // REVISIT + } + ch = data.charAt(currentOffset); + if (ch != ':') { + // System.out.println("abort 1b"); + return false; // REVISIT + } + addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_COLON); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_SLASH: // '/' and '//' + if (++currentOffset == endOffset) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH); + starIsMultiplyOperator = false; + break; + } + ch = data.charAt(currentOffset); + if (ch == '/') { // '//' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + } else { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH); + starIsMultiplyOperator = false; + } + break; + case CHARTYPE_UNION: // '|' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_UNION); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_PLUS: // '+' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_PLUS); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_MINUS: // '-' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_EQUAL: // '=' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_EQUAL); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_EXCLAMATION: // '!=' + if (++currentOffset == endOffset) { + // System.out.println("abort 2a"); + return false; // REVISIT + } + ch = data.charAt(currentOffset); + if (ch != '=') { + // System.out.println("abort 2b"); + return false; // REVISIT + } + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_NOT_EQUAL); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + case CHARTYPE_LESS: // '<' and '<=' + if (++currentOffset == endOffset) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS); + starIsMultiplyOperator = false; + break; + } + ch = data.charAt(currentOffset); + if (ch == '=') { // '<=' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS_EQUAL); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + } else { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS); + starIsMultiplyOperator = false; + } + break; + case CHARTYPE_GREATER: // '>' and '>=' + if (++currentOffset == endOffset) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER); + starIsMultiplyOperator = false; + break; + } + ch = data.charAt(currentOffset); + if (ch == '=') { // '>=' + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER_EQUAL); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + } else { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER); + starIsMultiplyOperator = false; + } + break; + // + // [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'" + // + case CHARTYPE_QUOTE: // '\"' or '\'' + int qchar = ch; + if (++currentOffset == endOffset) { + // System.out.println("abort 2c"); + return false; // REVISIT + } + ch = data.charAt(currentOffset); + int litOffset = currentOffset; + while (ch != qchar) { + if (++currentOffset == endOffset) { + // System.out.println("abort 2d"); + return false; // REVISIT + } + ch = data.charAt(currentOffset); + } + int litLength = currentOffset - litOffset; + addToken(tokens, XPath.Tokens.EXPRTOKEN_LITERAL); + starIsMultiplyOperator = true; + tokens.addToken(symbolTable.addSymbol(data.substring(litOffset, litOffset + litLength))); + if (++currentOffset == endOffset) { + break; + } + break; + // + // [30] Number ::= Digits ('.' Digits?)? | '.' Digits + // [31] Digits ::= [0-9]+ + // + case CHARTYPE_DIGIT: + addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER); + starIsMultiplyOperator = true; + currentOffset = scanNumber(tokens, data, endOffset, currentOffset/*, encoding*/); + break; + // + // [36] VariableReference ::= '$' QName + // + case CHARTYPE_DOLLAR: + if (++currentOffset == endOffset) { + // System.out.println("abort 3a"); + return false; // REVISIT + } + nameOffset = currentOffset; + currentOffset = scanNCName(data, endOffset, currentOffset); + if (currentOffset == nameOffset) { + // System.out.println("abort 3b"); + return false; // REVISIT + } + if (currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } + else { + ch = -1; + } + nameHandle = symbolTable.addSymbol(data.substring(nameOffset, currentOffset)); + if (ch != ':') { + prefixHandle = XMLSymbols.EMPTY_STRING; + } else { + prefixHandle = nameHandle; + if (++currentOffset == endOffset) { + // System.out.println("abort 4a"); + return false; // REVISIT + } + nameOffset = currentOffset; + currentOffset = scanNCName(data, endOffset, currentOffset); + if (currentOffset == nameOffset) { + // System.out.println("abort 4b"); + return false; // REVISIT + } + if (currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } + else { + ch = -1; + } + nameHandle = symbolTable.addSymbol(data.substring(nameOffset, currentOffset)); + } + addToken(tokens, XPath.Tokens.EXPRTOKEN_VARIABLE_REFERENCE); + starIsMultiplyOperator = true; + tokens.addToken(prefixHandle); + tokens.addToken(nameHandle); + break; + // + // [37] NameTest ::= '*' | NCName ':' '*' | QName + // [34] MultiplyOperator ::= '*' + // + case CHARTYPE_STAR: // '*' + // + // 3.7 Lexical Structure + // + // If there is a preceding token and the preceding token is not one of @, ::, (, [, , or + // an Operator, then a * must be recognized as a MultiplyOperator. + // + // Otherwise, the token must not be recognized as a MultiplyOperator. + // + if (starIsMultiplyOperator) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MULT); + starIsMultiplyOperator = false; + } else { + addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_ANY); + starIsMultiplyOperator = true; + } + if (++currentOffset == endOffset) { + break; + } + break; + // + // NCName, QName and non-terminals + // + case CHARTYPE_NONASCII: // possibly a valid non-ascii 'Letter' (BaseChar | Ideographic) + case CHARTYPE_LETTER: + case CHARTYPE_UNDERSCORE: + // + // 3.7 Lexical Structure + // + // If there is a preceding token and the preceding token is not one of @, ::, (, [, , or + // an Operator, then an NCName must be recognized as an OperatorName. + // + // If the character following an NCName (possibly after intervening ExprWhitespace) is (, + // then the token must be recognized as a NodeType or a FunctionName. + // + // If the two characters following an NCName (possibly after intervening ExprWhitespace) + // are ::, then the token must be recognized as an AxisName. + // + // Otherwise, the token must not be recognized as an OperatorName, a NodeType, a + // FunctionName, or an AxisName. + // + // [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div' + // [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node' + // [35] FunctionName ::= QName - NodeType + // [6] AxisName ::= (see above) + // + // [37] NameTest ::= '*' | NCName ':' '*' | QName + // [5] NCName ::= (Letter | '_') (NCNameChar)* + // [?] NCNameChar ::= Letter | Digit | '.' | '-' | '_' (ascii subset of 'NCNameChar') + // [?] QName ::= (NCName ':')? NCName + // [?] Letter ::= [A-Za-z] (ascii subset of 'Letter') + // [?] Digit ::= [0-9] (ascii subset of 'Digit') + // + nameOffset = currentOffset; + currentOffset = scanNCName(data, endOffset, currentOffset); + if (currentOffset == nameOffset) { + // System.out.println("abort 4c"); + return false; // REVISIT + } + if (currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } + else { + ch = -1; + } + nameHandle = symbolTable.addSymbol(data.substring(nameOffset, currentOffset)); + boolean isNameTestNCName = false; + boolean isAxisName = false; + prefixHandle = XMLSymbols.EMPTY_STRING; + if (ch == ':') { + if (++currentOffset == endOffset) { + // System.out.println("abort 5"); + return false; // REVISIT + } + ch = data.charAt(currentOffset); + if (ch == '*') { + if (++currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } + isNameTestNCName = true; + } else if (ch == ':') { + if (++currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } + isAxisName = true; + } else { + prefixHandle = nameHandle; + nameOffset = currentOffset; + currentOffset = scanNCName(data, endOffset, currentOffset); + if (currentOffset == nameOffset) { + // System.out.println("abort 5b"); + return false; // REVISIT + } + if (currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } + else { + ch = -1; + } + nameHandle = symbolTable.addSymbol(data.substring(nameOffset, currentOffset)); + } + } + // + // [39] ExprWhitespace ::= S + // + while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) { + if (++currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + } + // + // If there is a preceding token and the preceding token is not one of @, ::, (, [, , or + // an Operator, then an NCName must be recognized as an OperatorName. + // + if (starIsMultiplyOperator) { + if (nameHandle == fAndSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_AND); + starIsMultiplyOperator = false; + } else if (nameHandle == fOrSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_OR); + starIsMultiplyOperator = false; + } else if (nameHandle == fModSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MOD); + starIsMultiplyOperator = false; + } else if (nameHandle == fDivSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_DIV); + starIsMultiplyOperator = false; + } else { + // System.out.println("abort 6"); + return false; // REVISIT + } + if (isNameTestNCName) { + // System.out.println("abort 7"); + return false; // REVISIT - NCName:* where an OperatorName is required + } else if (isAxisName) { + // System.out.println("abort 8"); + return false; // REVISIT - AxisName:: where an OperatorName is required + } + break; + } + // + // If the character following an NCName (possibly after intervening ExprWhitespace) is (, + // then the token must be recognized as a NodeType or a FunctionName. + // + if (ch == '(' && !isNameTestNCName && !isAxisName) { + if (nameHandle == fCommentSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_COMMENT); + } else if (nameHandle == fTextSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_TEXT); + } else if (nameHandle == fPISymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_PI); + } else if (nameHandle == fNodeSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_NODE); + } else { + addToken(tokens, XPath.Tokens.EXPRTOKEN_FUNCTION_NAME); + tokens.addToken(prefixHandle); + tokens.addToken(nameHandle); + } + addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_PAREN); + starIsMultiplyOperator = false; + if (++currentOffset == endOffset) { + break; + } + break; + } + // + // If the two characters following an NCName (possibly after intervening ExprWhitespace) + // are ::, then the token must be recognized as an AxisName. + // + if (isAxisName || + (ch == ':' && currentOffset + 1 < endOffset && + data.charAt(currentOffset + 1) == ':')) { + if (nameHandle == fAncestorSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR); + } else if (nameHandle == fAncestorOrSelfSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF); + } else if (nameHandle == fAttributeSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE); + } else if (nameHandle == fChildSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD); + } else if (nameHandle == fDescendantSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT); + } else if (nameHandle == fDescendantOrSelfSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF); + } else if (nameHandle == fFollowingSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING); + } else if (nameHandle == fFollowingSiblingSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING); + } else if (nameHandle == fNamespaceSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_NAMESPACE); + } else if (nameHandle == fParentSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PARENT); + } else if (nameHandle == fPrecedingSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING); + } else if (nameHandle == fPrecedingSiblingSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING_SIBLING); + } else if (nameHandle == fSelfSymbol) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_SELF); + } else { + // System.out.println("abort 9"); + return false; // REVISIT + } + if (isNameTestNCName) { + // System.out.println("abort 10"); + return false; // REVISIT - "NCName:* ::" where "AxisName ::" is required + } + addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_COLON); + starIsMultiplyOperator = false; + if (!isAxisName) { + currentOffset++; + if (++currentOffset == endOffset) { + break; + } + } + break; + } + // + // Otherwise, the token must not be recognized as an OperatorName, a NodeType, a + // FunctionName, or an AxisName. + // + if (isNameTestNCName) { + addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE); + starIsMultiplyOperator = true; + tokens.addToken(nameHandle); + } else { + addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME); + starIsMultiplyOperator = true; + tokens.addToken(prefixHandle); + tokens.addToken(nameHandle); + } + break; + default: + // CHARTYPE_INVALID or CHARTYPE_OTHER + // We're not expecting to find either of these in a valid expression. + return false; + } + } + if (XPath.Tokens.DUMP_TOKENS) { + tokens.dumpTokens(); + } + return true; + } + // + // [5] NCName ::= (Letter | '_') (NCNameChar)* + // [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender + // + int scanNCName(String data, int endOffset, int currentOffset) { + int ch = data.charAt(currentOffset); + if (ch >= 0x80) { + if (!XMLChar.isNameStart(ch)) + /*** // REVISIT: Make sure this is a negation. *** + if ((XMLCharacterProperties.fgCharFlags[ch] & + XMLCharacterProperties.E_InitialNameCharFlag) == 0) + /***/ + { + return currentOffset; + } + } + else { + byte chartype = fASCIICharMap[ch]; + if (chartype != CHARTYPE_LETTER && chartype != CHARTYPE_UNDERSCORE) { + return currentOffset; + } + } + while (++currentOffset < endOffset) { + ch = data.charAt(currentOffset); + if (ch >= 0x80) { + if (!XMLChar.isName(ch)) + /*** // REVISIT: Make sure this is a negation. *** + if ((XMLCharacterProperties.fgCharFlags[ch] & + XMLCharacterProperties.E_NameCharFlag) == 0) + /***/ + { + break; + } + } + else { + byte chartype = fASCIICharMap[ch]; + if (chartype != CHARTYPE_LETTER && chartype != CHARTYPE_DIGIT && + chartype != CHARTYPE_PERIOD && chartype != CHARTYPE_MINUS && + chartype != CHARTYPE_UNDERSCORE) + { + break; + } + } + } + return currentOffset; + } + // + // [30] Number ::= Digits ('.' Digits?)? | '.' Digits + // [31] Digits ::= [0-9]+ + // + private int scanNumber(XPath.Tokens tokens, String/*byte[]*/ data, int endOffset, int currentOffset/*, EncodingSupport encoding*/) { + int ch = data.charAt(currentOffset); + int whole = 0; + int part = 0; + while (ch >= '0' && ch <= '9') { + whole = (whole * 10) + (ch - '0'); + if (++currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + } + if (ch == '.') { + if (++currentOffset < endOffset) { + /** int start = currentOffset; **/ + ch = data.charAt(currentOffset); + while (ch >= '0' && ch <= '9') { + part = (part * 10) + (ch - '0'); + if (++currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + } + if (part != 0) { + /*** + part = tokens.addSymbol(data, start, currentOffset - start, encoding); + /***/ + throw new RuntimeException("find a solution!"); + //part = fStringPool.addSymbol(data.substring(start, currentOffset)); + /***/ + } + } + } + tokens.addToken(whole); + tokens.addToken(part); + return currentOffset; + } + + // + // Protected methods + // + + /** + * This method adds the specified token to the token list. By + * default, this method allows all tokens. However, subclasses + * of the XPathExprScanner can override this method in order + * to disallow certain tokens from being used in the scanned + * XPath expression. This is a convenient way of allowing only + * a subset of XPath. + */ + protected void addToken(XPath.Tokens tokens, int token) + throws XPathException { + tokens.addToken(token); + } // addToken(int) + + } // class Scanner + + // + // MAIN + // + + /** Main program entry. */ + public static void main(String[] argv) throws Exception { + + for (int i = 0; i < argv.length; i++) { + final String expression = argv[i]; + System.out.println("# XPath expression: \""+expression+'"'); + try { + SymbolTable symbolTable = new SymbolTable(); + XPath xpath = new XPath(expression, symbolTable, null); + System.out.println("expanded xpath: \""+xpath.toString()+'"'); + } + catch (XPathException e) { + System.out.println("error: "+e.getMessage()); + } + } + + } // main(String[]) + +} // class XPath diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/XPathException.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/XPathException.java new file mode 100644 index 0000000..e50c9b7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/XPathException.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath; + +/** + * XPath exception. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XPathException + extends Exception { + + /** Serialization version. */ + static final long serialVersionUID = -948482312169512085L; + + // Data + + // hold the value of the key this Exception refers to. + private final String fKey; + // + // Constructors + // + + /** Constructs an exception. */ + public XPathException() { + super(); + fKey = "c-general-xpath"; + } // () + + /** Constructs an exception with the specified key. */ + public XPathException(String key) { + super(); + fKey = key; + } // (String) + + public String getKey() { + return fKey; + } // getKey(): String + +} // class XPathException diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/BMPattern.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/BMPattern.java new file mode 100644 index 0000000..d720af4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/BMPattern.java @@ -0,0 +1,236 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +import java.text.CharacterIterator; + +/** + * Boyer-Moore searcher. + * + * @xerces.internal + * + * @version $Id$ + */ +public class BMPattern { + final char[] pattern; + final int[] shiftTable; + final boolean ignoreCase; + + public BMPattern(String pat, boolean ignoreCase) { + this(pat, 256, ignoreCase); + } + + public BMPattern(String pat, int tableSize, boolean ignoreCase) { + this.pattern = pat.toCharArray(); + this.shiftTable = new int[tableSize]; + this.ignoreCase = ignoreCase; + + int length = pattern.length; + for (int i = 0; i < this.shiftTable.length; i ++) + this.shiftTable[i] = length; + + for (int i = 0; i < length; i ++) { + char ch = this.pattern[i]; + int diff = length-i-1; + int index = ch % this.shiftTable.length; + if (diff < this.shiftTable[index]) + this.shiftTable[index] = diff; + if (this.ignoreCase) { + ch = Character.toUpperCase(ch); + index = ch % this.shiftTable.length; + if (diff < this.shiftTable[index]) + this.shiftTable[index] = diff; + ch = Character.toLowerCase(ch); + index = ch % this.shiftTable.length; + if (diff < this.shiftTable[index]) + this.shiftTable[index] = diff; + } + } + } + + /** + * + * @return -1 if iterator does not contain this pattern. + */ + public int matches(CharacterIterator iterator, int start, int limit) { + if (this.ignoreCase) return this.matchesIgnoreCase(iterator, start, limit); + int plength = this.pattern.length; + if (plength == 0) return start; + int index = start+plength; + while (index <= limit) { + int pindex = plength; + int nindex = index+1; + char ch; + do { + if ((ch = iterator.setIndex(--index)) != this.pattern[--pindex]) + break; + if (pindex == 0) + return index; + } while (pindex > 0); + index += this.shiftTable[ch % this.shiftTable.length]+1; + if (index < nindex) index = nindex; + } + return -1; + } + + /** + * + * @return -1 if str does not contain this pattern. + */ + public int matches(String str, int start, int limit) { + if (this.ignoreCase) return this.matchesIgnoreCase(str, start, limit); + int plength = this.pattern.length; + if (plength == 0) return start; + int index = start+plength; + while (index <= limit) { + //System.err.println("Starts at "+index); + int pindex = plength; + int nindex = index+1; + char ch; + do { + if ((ch = str.charAt(--index)) != this.pattern[--pindex]) + break; + if (pindex == 0) + return index; + } while (pindex > 0); + index += this.shiftTable[ch % this.shiftTable.length]+1; + if (index < nindex) index = nindex; + } + return -1; + } + /** + * + * @return -1 if chars does not contain this pattern. + */ + public int matches(char[] chars, int start, int limit) { + if (this.ignoreCase) return this.matchesIgnoreCase(chars, start, limit); + int plength = this.pattern.length; + if (plength == 0) return start; + int index = start+plength; + while (index <= limit) { + //System.err.println("Starts at "+index); + int pindex = plength; + int nindex = index+1; + char ch; + do { + if ((ch = chars[--index]) != this.pattern[--pindex]) + break; + if (pindex == 0) + return index; + } while (pindex > 0); + index += this.shiftTable[ch % this.shiftTable.length]+1; + if (index < nindex) index = nindex; + } + return -1; + } + + int matchesIgnoreCase(CharacterIterator iterator, int start, int limit) { + int plength = this.pattern.length; + if (plength == 0) return start; + int index = start+plength; + while (index <= limit) { + int pindex = plength; + int nindex = index+1; + char ch; + do { + char ch1 = ch = iterator.setIndex(--index); + char ch2 = this.pattern[--pindex]; + if (ch1 != ch2) { + ch1 = Character.toUpperCase(ch1); + ch2 = Character.toUpperCase(ch2); + if (ch1 != ch2 && Character.toLowerCase(ch1) != Character.toLowerCase(ch2)) + break; + } + if (pindex == 0) + return index; + } while (pindex > 0); + index += this.shiftTable[ch % this.shiftTable.length]+1; + if (index < nindex) index = nindex; + } + return -1; + } + + int matchesIgnoreCase(String text, int start, int limit) { + int plength = this.pattern.length; + if (plength == 0) return start; + int index = start+plength; + while (index <= limit) { + int pindex = plength; + int nindex = index+1; + char ch; + do { + char ch1 = ch = text.charAt(--index); + char ch2 = this.pattern[--pindex]; + if (ch1 != ch2) { + ch1 = Character.toUpperCase(ch1); + ch2 = Character.toUpperCase(ch2); + if (ch1 != ch2 && Character.toLowerCase(ch1) != Character.toLowerCase(ch2)) + break; + } + if (pindex == 0) + return index; + } while (pindex > 0); + index += this.shiftTable[ch % this.shiftTable.length]+1; + if (index < nindex) index = nindex; + } + return -1; + } + int matchesIgnoreCase(char[] chars, int start, int limit) { + int plength = this.pattern.length; + if (plength == 0) return start; + int index = start+plength; + while (index <= limit) { + int pindex = plength; + int nindex = index+1; + char ch; + do { + char ch1 = ch = chars[--index]; + char ch2 = this.pattern[--pindex]; + if (ch1 != ch2) { + ch1 = Character.toUpperCase(ch1); + ch2 = Character.toUpperCase(ch2); + if (ch1 != ch2 && Character.toLowerCase(ch1) != Character.toLowerCase(ch2)) + break; + } + if (pindex == 0) + return index; + } while (pindex > 0); + index += this.shiftTable[ch % this.shiftTable.length]+1; + if (index < nindex) index = nindex; + } + return -1; + } + + /* + public static void main(String[] argv) { + try { + int[] shiftTable = new int[256]; + initializeBoyerMoore(argv[0], shiftTable, true); + int o = -1; + CharacterIterator ite = new java.text.StringCharacterIterator(argv[1]); + long start = System.currentTimeMillis(); + //for (int i = 0; i < 10000; i ++) + o = searchIgnoreCasesWithBoyerMoore(ite, 0, argv[0], shiftTable); + start = System.currentTimeMillis()-start; + System.out.println("Result: "+o+", Elapsed: "+start); + } catch (Exception ex) { + ex.printStackTrace(); + } + }*/ +} + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/CaseInsensitiveMap.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/CaseInsensitiveMap.java new file mode 100644 index 0000000..010ead2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/CaseInsensitiveMap.java @@ -0,0 +1,162 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +/** + * @xerces.internal + * + * @version $Id$ + */ +final class CaseInsensitiveMap { + + private static int CHUNK_SHIFT = 10; /* 2^10 = 1k */ + private static int CHUNK_SIZE = (1<>> CHUNK_SHIFT; + int offset = codePoint & CHUNK_MASK; + + return caseInsensitiveMap[chunk][offset]; + } + + private static void buildCaseInsensitiveMap() { + caseInsensitiveMap = new int[INITIAL_CHUNK_COUNT][CHUNK_SIZE][]; + int lc, uc; + for (int i=0; i<0x10000; i++) { + lc = Character.toLowerCase((char) i); + uc = Character.toUpperCase((char) i); + + // lower/upper case value is not the same as code point + if (lc != uc || lc != i) { + int[] map = new int[2]; + int index = 0; + + if (lc != i) { + map[index++] = lc; + map[index++] = LOWER_CASE_MATCH; + int[] lcMap = getMapping(lc); + if (lcMap != null) { + map = updateMap(i, map, lc, lcMap, LOWER_CASE_MATCH); + } + } + + if (uc != i) { + if (index == map.length) { + map = expandMap(map, 2); + } + map[index++] = uc; + map[index++] = UPPER_CASE_MATCH; + int[] ucMap = getMapping(uc); + if (ucMap != null) { + map = updateMap(i, map, uc, ucMap, UPPER_CASE_MATCH); + } + } + + set(i, map); + } + } + } + + private static int[] expandMap(int[] srcMap, int expandBy) { + final int oldLen = srcMap.length; + int[] newMap = new int[oldLen + expandBy]; + + System.arraycopy(srcMap, 0, newMap, 0, oldLen); + return newMap; + } + + private static void set(int codePoint, int[] map) { + int chunk = codePoint >>> CHUNK_SHIFT; + int offset = codePoint & CHUNK_MASK; + + caseInsensitiveMap[chunk][offset] = map; + } + + private static int[] updateMap(int codePoint, int[] codePointMap, + int ciCodePoint, int[] ciCodePointMap, int matchType) { + for (int i=0; i 0) { + ma.setNumberOfGroups(this.nofgroups); + if (this.ciSource != null) ma.setSource(this.ciSource); + if (this.strSource != null) ma.setSource(this.strSource); + for (int i = 0; i < this.nofgroups; i ++) { + ma.setBeginning(i, this.getBeginning(i)); + ma.setEnd(i, this.getEnd(i)); + } + } + return ma; + } + + /** + * + */ + protected void setNumberOfGroups(int n) { + int oldn = this.nofgroups; + this.nofgroups = n; + if (oldn <= 0 + || oldn < n || n*2 < oldn) { + this.beginpos = new int[n]; + this.endpos = new int[n]; + } + for (int i = 0; i < n; i ++) { + this.beginpos[i] = -1; + this.endpos[i] = -1; + } + } + + /** + * + */ + protected void setSource(CharacterIterator ci) { + this.ciSource = ci; + this.strSource = null; + this.charSource = null; + } + /** + * + */ + protected void setSource(String str) { + this.ciSource = null; + this.strSource = str; + this.charSource = null; + } + /** + * + */ + protected void setSource(char[] chars) { + this.ciSource = null; + this.strSource = null; + this.charSource = chars; + } + + /** + * + */ + protected void setBeginning(int index, int v) { + this.beginpos[index] = v; + } + + /** + * + */ + protected void setEnd(int index, int v) { + this.endpos[index] = v; + } + + /** + * Return the number of regular expression groups. + * This method returns 1 when the regular expression has no capturing-parenthesis. + */ + public int getNumberOfGroups() { + if (this.nofgroups <= 0) + throw new IllegalStateException("A result is not set."); + return this.nofgroups; + } + + /** + * Return a start position in the target text matched to specified regular expression group. + * + * @param index Less than getNumberOfGroups(). + */ + public int getBeginning(int index) { + if (this.beginpos == null) + throw new IllegalStateException("A result is not set."); + if (index < 0 || this.nofgroups <= index) + throw new IllegalArgumentException("The parameter must be less than " + +this.nofgroups+": "+index); + return this.beginpos[index]; + } + + /** + * Return an end position in the target text matched to specified regular expression group. + * + * @param index Less than getNumberOfGroups(). + */ + public int getEnd(int index) { + if (this.endpos == null) + throw new IllegalStateException("A result is not set."); + if (index < 0 || this.nofgroups <= index) + throw new IllegalArgumentException("The parameter must be less than " + +this.nofgroups+": "+index); + return this.endpos[index]; + } + + /** + * Return an substring of the target text matched to specified regular expression group. + * + * @param index Less than getNumberOfGroups(). + */ + public String getCapturedText(int index) { + if (this.beginpos == null) + throw new IllegalStateException("match() has never been called."); + if (index < 0 || this.nofgroups <= index) + throw new IllegalArgumentException("The parameter must be less than " + +this.nofgroups+": "+index); + String ret; + int begin = this.beginpos[index], end = this.endpos[index]; + if (begin < 0 || end < 0) return null; + if (this.ciSource != null) { + ret = REUtil.substring(this.ciSource, begin, end); + } else if (this.strSource != null) { + ret = this.strSource.substring(begin, end); + } else { + ret = new String(this.charSource, begin, end-begin); + } + return ret; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/Op.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/Op.java new file mode 100644 index 0000000..c13b331 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/Op.java @@ -0,0 +1,252 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +import java.util.Vector; + +/** + * @xerces.internal + * + * @version $Id$ + */ +class Op { + static final int DOT = 0; + static final int CHAR = 1; // Single character + static final int RANGE = 3; // [a-zA-Z] + static final int NRANGE = 4; // [^a-zA-Z] + static final int ANCHOR = 5; // ^ $ ... + static final int STRING = 6; // literal String + static final int CLOSURE = 7; // X* + static final int NONGREEDYCLOSURE = 8; // X*? + static final int QUESTION = 9; // X? + static final int NONGREEDYQUESTION = 10; // X?? + static final int UNION = 11; // X|Y + static final int CAPTURE = 15; // ( and ) + static final int BACKREFERENCE = 16; // \1 \2 ... + static final int LOOKAHEAD = 20; // (?=...) + static final int NEGATIVELOOKAHEAD = 21; // (?!...) + static final int LOOKBEHIND = 22; // (?<=...) + static final int NEGATIVELOOKBEHIND = 23; // (?...) + static final int MODIFIER = 25; // (?ims-ims:...) + static final int CONDITION = 26; // (?(..)yes|no) + + static int nofinstances = 0; + static final boolean COUNT = false; + + static Op createDot() { + if (Op.COUNT) Op.nofinstances ++; + return new Op(Op.DOT); + } + static CharOp createChar(int data) { + if (Op.COUNT) Op.nofinstances ++; + return new CharOp(Op.CHAR, data); + } + static CharOp createAnchor(int data) { + if (Op.COUNT) Op.nofinstances ++; + return new CharOp(Op.ANCHOR, data); + } + static CharOp createCapture(int number, Op next) { + if (Op.COUNT) Op.nofinstances ++; + CharOp op = new CharOp(Op.CAPTURE, number); + op.next = next; + return op; + } + static UnionOp createUnion(int size) { + if (Op.COUNT) Op.nofinstances ++; + //System.err.println("Creates UnionOp"); + return new UnionOp(Op.UNION, size); + } + static ChildOp createClosure(int id) { + if (Op.COUNT) Op.nofinstances ++; + return new ModifierOp(Op.CLOSURE, id, -1); + } + static ChildOp createNonGreedyClosure() { + if (Op.COUNT) Op.nofinstances ++; + return new ChildOp(Op.NONGREEDYCLOSURE); + } + static ChildOp createQuestion(boolean nongreedy) { + if (Op.COUNT) Op.nofinstances ++; + return new ChildOp(nongreedy ? Op.NONGREEDYQUESTION : Op.QUESTION); + } + static RangeOp createRange(Token tok) { + if (Op.COUNT) Op.nofinstances ++; + return new RangeOp(Op.RANGE, tok); + } + static ChildOp createLook(int type, Op next, Op branch) { + if (Op.COUNT) Op.nofinstances ++; + ChildOp op = new ChildOp(type); + op.setChild(branch); + op.next = next; + return op; + } + static CharOp createBackReference(int refno) { + if (Op.COUNT) Op.nofinstances ++; + return new CharOp(Op.BACKREFERENCE, refno); + } + static StringOp createString(String literal) { + if (Op.COUNT) Op.nofinstances ++; + return new StringOp(Op.STRING, literal); + } + static ChildOp createIndependent(Op next, Op branch) { + if (Op.COUNT) Op.nofinstances ++; + ChildOp op = new ChildOp(Op.INDEPENDENT); + op.setChild(branch); + op.next = next; + return op; + } + static ModifierOp createModifier(Op next, Op branch, int add, int mask) { + if (Op.COUNT) Op.nofinstances ++; + ModifierOp op = new ModifierOp(Op.MODIFIER, add, mask); + op.setChild(branch); + op.next = next; + return op; + } + static ConditionOp createCondition(Op next, int ref, Op conditionflow, Op yesflow, Op noflow) { + if (Op.COUNT) Op.nofinstances ++; + ConditionOp op = new ConditionOp(Op.CONDITION, ref, conditionflow, yesflow, noflow); + op.next = next; + return op; + } + + final int type; + Op next = null; + + protected Op(int type) { + this.type = type; + } + + int size() { // for UNION + return 0; + } + Op elementAt(int index) { // for UNIoN + throw new RuntimeException("Internal Error: type="+this.type); + } + Op getChild() { // for CLOSURE, QUESTION + throw new RuntimeException("Internal Error: type="+this.type); + } + // ModifierOp + int getData() { // CharOp for CHAR, BACKREFERENCE, CAPTURE, ANCHOR, + throw new RuntimeException("Internal Error: type="+this.type); + } + int getData2() { // ModifierOp + throw new RuntimeException("Internal Error: type="+this.type); + } + RangeToken getToken() { // RANGE, NRANGE + throw new RuntimeException("Internal Error: type="+this.type); + } + String getString() { // STRING + throw new RuntimeException("Internal Error: type="+this.type); + } + + // ================================================================ + static class CharOp extends Op { + final int charData; + CharOp(int type, int data) { + super(type); + this.charData = data; + } + int getData() { + return this.charData; + } + } + + // ================================================================ + static class UnionOp extends Op { + final Vector branches; + UnionOp(int type, int size) { + super(type); + this.branches = new Vector(size); + } + void addElement(Op op) { + this.branches.addElement(op); + } + int size() { + return this.branches.size(); + } + Op elementAt(int index) { + return (Op)this.branches.elementAt(index); + } + } + + // ================================================================ + static class ChildOp extends Op { + Op child; + ChildOp(int type) { + super(type); + } + void setChild(Op child) { + this.child = child; + } + Op getChild() { + return this.child; + } + } + // ================================================================ + static class ModifierOp extends ChildOp { + final int v1; + final int v2; + ModifierOp(int type, int v1, int v2) { + super(type); + this.v1 = v1; + this.v2 = v2; + } + int getData() { + return this.v1; + } + int getData2() { + return this.v2; + } + } + // ================================================================ + static class RangeOp extends Op { + final Token tok; + RangeOp(int type, Token tok) { + super(type); + this.tok = tok; + } + RangeToken getToken() { + return (RangeToken)this.tok; + } + } + // ================================================================ + static class StringOp extends Op { + final String string; + StringOp(int type, String literal) { + super(type); + this.string = literal; + } + String getString() { + return this.string; + } + } + // ================================================================ + static class ConditionOp extends Op { + final int refNumber; + final Op condition; + final Op yes; + final Op no; + ConditionOp(int type, int refno, Op conditionflow, Op yesflow, Op noflow) { + super(type); + this.refNumber = refno; + this.condition = conditionflow; + this.yes = yesflow; + this.no = noflow; + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/ParseException.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/ParseException.java new file mode 100644 index 0000000..134694b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/ParseException.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +/** + * @xerces.internal + * + * @author TAMURA Kent <kent@trl.ibm.co.jp> + * @version $Id$ + */ +public class ParseException extends RuntimeException { + + /** Serialization version. */ + static final long serialVersionUID = -7012400318097691370L; + + final int location; + + /* + public ParseException(String mes) { + this(mes, -1); + } + */ + /** + * + */ + public ParseException(String mes, int location) { + super(mes); + this.location = location; + } + + /** + * + * @return -1 if location information is not available. + */ + public int getLocation() { + return this.location; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/ParserForXMLSchema.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/ParserForXMLSchema.java new file mode 100644 index 0000000..fca38bb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/ParserForXMLSchema.java @@ -0,0 +1,514 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +import java.util.Hashtable; +import java.util.Locale; + +/** + * A regular expression parser for the XML Schema. + * + * @xerces.internal + * + * @author TAMURA Kent <kent@trl.ibm.co.jp> + * @version $Id$ + */ +class ParserForXMLSchema extends RegexParser { + + public ParserForXMLSchema() { + //this.setLocale(Locale.getDefault()); + } + public ParserForXMLSchema(Locale locale) { + super(locale); + } + + Token processCaret() throws ParseException { + this.next(); + return Token.createChar('^'); + } + Token processDollar() throws ParseException { + this.next(); + return Token.createChar('$'); + } + Token processLookahead() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processNegativelookahead() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processLookbehind() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processNegativelookbehind() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_A() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_Z() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_z() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_b() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_B() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_lt() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_gt() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processStar(Token tok) throws ParseException { + this.next(); + return Token.createClosure(tok); + } + Token processPlus(Token tok) throws ParseException { + // X+ -> XX* + this.next(); + return Token.createConcat(tok, Token.createClosure(tok)); + } + Token processQuestion(Token tok) throws ParseException { + // X? -> X| + this.next(); + Token par = Token.createUnion(); + par.addChild(tok); + par.addChild(Token.createEmpty()); + return par; + } + boolean checkQuestion(int off) { + return false; + } + Token processParen() throws ParseException { + this.next(); + Token tok = Token.createParen(this.parseRegex(), 0); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); // Skips ')' + return tok; + } + Token processParen2() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processCondition() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processModifiers() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processIndependent() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_c() throws ParseException { + this.next(); + return this.getTokenForShorthand('c'); + } + Token processBacksolidus_C() throws ParseException { + this.next(); + return this.getTokenForShorthand('C'); + } + Token processBacksolidus_i() throws ParseException { + this.next(); + return this.getTokenForShorthand('i'); + } + Token processBacksolidus_I() throws ParseException { + this.next(); + return this.getTokenForShorthand('I'); + } + Token processBacksolidus_g() throws ParseException { + throw this.ex("parser.process.1", this.offset-2); + } + Token processBacksolidus_X() throws ParseException { + throw ex("parser.process.1", this.offset-2); + } + Token processBackreference() throws ParseException { + throw ex("parser.process.1", this.offset-4); + } + + int processCIinCharacterClass(RangeToken tok, int c) { + tok.mergeRanges(this.getTokenForShorthand(c)); + return -1; + } + + + /** + * Parses a character-class-expression, not a character-class-escape. + * + * c-c-expression ::= '[' c-group ']' + * c-group ::= positive-c-group | negative-c-group | c-c-subtraction + * positive-c-group ::= (c-range | c-c-escape)+ + * negative-c-group ::= '^' positive-c-group + * c-c-subtraction ::= (positive-c-group | negative-c-group) subtraction + * subtraction ::= '-' c-c-expression + * c-range ::= single-range | from-to-range + * single-range ::= multi-c-escape | category-c-escape | block-c-escape | <any XML char> + * cc-normal-c ::= <any character except [, ], \> + * from-to-range ::= cc-normal-c '-' cc-normal-c + * + * @param useNrage Ignored. + * @return This returns no NrageToken. + */ + protected RangeToken parseCharacterClass(boolean useNrange) throws ParseException { + this.setContext(S_INBRACKETS); + this.next(); // '[' + boolean nrange = false; + boolean wasDecoded = false; // used to detect if the last - was escaped. + RangeToken base = null; + RangeToken tok; + if (this.read() == T_CHAR && this.chardata == '^') { + nrange = true; + this.next(); // '^' + base = Token.createRange(); + base.addRange(0, Token.UTF16_MAX); + tok = Token.createRange(); + } else { + tok = Token.createRange(); + } + int type; + boolean firstloop = true; + while ((type = this.read()) != T_EOF) { // Don't use 'cotinue' for this loop. + + wasDecoded = false; + // single-range | from-to-range | subtraction + if (type == T_CHAR && this.chardata == ']' && !firstloop) { + if (nrange) { + base.subtractRanges(tok); + tok = base; + } + break; + } + int c = this.chardata; + boolean end = false; + if (type == T_BACKSOLIDUS) { + switch (c) { + case 'd': case 'D': + case 'w': case 'W': + case 's': case 'S': + tok.mergeRanges(this.getTokenForShorthand(c)); + end = true; + break; + + case 'i': case 'I': + case 'c': case 'C': + c = this.processCIinCharacterClass(tok, c); + if (c < 0) end = true; + break; + + case 'p': + case 'P': + int pstart = this.offset; + RangeToken tok2 = this.processBacksolidus_pP(c); + if (tok2 == null) throw this.ex("parser.atom.5", pstart); + tok.mergeRanges(tok2); + end = true; + break; + + case '-': + c = this.decodeEscaped(); + wasDecoded = true; + break; + + default: + c = this.decodeEscaped(); + } // \ + c + } // backsolidus + else if (type == T_XMLSCHEMA_CC_SUBTRACTION && !firstloop) { + // Subraction + if (nrange) { + base.subtractRanges(tok); + tok = base; + } + RangeToken range2 = this.parseCharacterClass(false); + tok.subtractRanges(range2); + if (this.read() != T_CHAR || this.chardata != ']') + throw this.ex("parser.cc.5", this.offset); + break; // Exit this loop + } + this.next(); + if (!end) { // if not shorthands... + if (type == T_CHAR) { + if (c == '[') throw this.ex("parser.cc.6", this.offset-2); + if (c == ']') throw this.ex("parser.cc.7", this.offset-2); + if (c == '-' && this.chardata != ']' && !firstloop) throw this.ex("parser.cc.8", this.offset-2); // if regex = '[-]' then invalid + } + if (this.read() != T_CHAR || this.chardata != '-' || c == '-' && !wasDecoded && firstloop) { // Here is no '-'. + if (!this.isSet(RegularExpression.IGNORE_CASE) || c > 0xffff) { + tok.addRange(c, c); + } + else { + addCaseInsensitiveChar(tok, c); + } + } else { // Found '-' + // Is this '-' is a from-to token?? + this.next(); // Skips '-' + if ((type = this.read()) == T_EOF) throw this.ex("parser.cc.2", this.offset); + // c '-' ']' -> '-' is a single-range. + if(type == T_CHAR && this.chardata == ']') { // if - is at the last position of the group + if (!this.isSet(RegularExpression.IGNORE_CASE) || c > 0xffff) { + tok.addRange(c, c); + } + else { + addCaseInsensitiveChar(tok, c); + } + tok.addRange('-', '-'); + } + else if (type == T_XMLSCHEMA_CC_SUBTRACTION) { + throw this.ex("parser.cc.8", this.offset-1); + } else { + + int rangeend = this.chardata; + if (type == T_CHAR) { + if (rangeend == '[') throw this.ex("parser.cc.6", this.offset-1); + if (rangeend == ']') throw this.ex("parser.cc.7", this.offset-1); + if (rangeend == '-') throw this.ex("parser.cc.8", this.offset-2); + } + else if (type == T_BACKSOLIDUS) + rangeend = this.decodeEscaped(); + this.next(); + + if (c > rangeend) throw this.ex("parser.ope.3", this.offset-1); + if (!this.isSet(RegularExpression.IGNORE_CASE) || + (c > 0xffff && rangeend > 0xffff)) { + tok.addRange(c, rangeend); + } + else { + addCaseInsensitiveCharRange(tok, c, rangeend); + } + } + } + } + firstloop = false; + } + if (this.read() == T_EOF) + throw this.ex("parser.cc.2", this.offset); + tok.sortRanges(); + tok.compactRanges(); + //tok.dumpRanges(); + this.setContext(S_NORMAL); + this.next(); // Skips ']' + + return tok; + } + + protected RangeToken parseSetOperations() throws ParseException { + throw this.ex("parser.process.1", this.offset); + } + + Token getTokenForShorthand(int ch) { + switch (ch) { + case 'd': + return ParserForXMLSchema.getRange("xml:isDigit", true); + case 'D': + return ParserForXMLSchema.getRange("xml:isDigit", false); + case 'w': + return ParserForXMLSchema.getRange("xml:isWord", true); + case 'W': + return ParserForXMLSchema.getRange("xml:isWord", false); + case 's': + return ParserForXMLSchema.getRange("xml:isSpace", true); + case 'S': + return ParserForXMLSchema.getRange("xml:isSpace", false); + case 'c': + return ParserForXMLSchema.getRange("xml:isNameChar", true); + case 'C': + return ParserForXMLSchema.getRange("xml:isNameChar", false); + case 'i': + return ParserForXMLSchema.getRange("xml:isInitialNameChar", true); + case 'I': + return ParserForXMLSchema.getRange("xml:isInitialNameChar", false); + default: + throw new RuntimeException("Internal Error: shorthands: \\u"+Integer.toString(ch, 16)); + } + } + int decodeEscaped() throws ParseException { + if (this.read() != T_BACKSOLIDUS) throw ex("parser.next.1", this.offset-1); + int c = this.chardata; + switch (c) { + case 'n': c = '\n'; break; // LINE FEED U+000A + case 'r': c = '\r'; break; // CRRIAGE RETURN U+000D + case 't': c = '\t'; break; // HORIZONTAL TABULATION U+0009 + case '\\': + case '|': + case '.': + case '^': + case '-': + case '?': + case '*': + case '+': + case '{': + case '}': + case '(': + case ')': + case '[': + case ']': + break; // return actucal char + default: + throw ex("parser.process.1", this.offset-2); + } + return c; + } + + static private Hashtable ranges = null; + static private Hashtable ranges2 = null; + static synchronized protected RangeToken getRange(String name, boolean positive) { + if (ranges == null) { + ranges = new Hashtable(); + ranges2 = new Hashtable(); + + Token tok = Token.createRange(); + setupRange(tok, SPACES); + ranges.put("xml:isSpace", tok); + ranges2.put("xml:isSpace", Token.complementRanges(tok)); + + tok = Token.createRange(); +// setupRange(tok, DIGITS); + setupRange(tok, DIGITS_INTS); + ranges.put("xml:isDigit", tok); + ranges2.put("xml:isDigit", Token.complementRanges(tok)); + + /* + * \w is defined by the XML Schema specification to be: + * [#x0000-#x10FFFF]-[\p{P}\p{Z}\p{C}] (all characters except the set of "punctuation", "separator" and "other" characters) + */ + tok = Token.createRange(); + tok.mergeRanges(Token.getRange("P", true)); + tok.mergeRanges(Token.getRange("Z", true)); + tok.mergeRanges(Token.getRange("C", true)); + ranges2.put("xml:isWord", tok); + ranges.put("xml:isWord", Token.complementRanges(tok)); + + tok = Token.createRange(); + setupRange(tok, NAMECHARS); + ranges.put("xml:isNameChar", tok); + ranges2.put("xml:isNameChar", Token.complementRanges(tok)); + + tok = Token.createRange(); + setupRange(tok, LETTERS); + tok.addRange('_', '_'); + tok.addRange(':', ':'); + ranges.put("xml:isInitialNameChar", tok); + ranges2.put("xml:isInitialNameChar", Token.complementRanges(tok)); + } + RangeToken tok = positive ? (RangeToken)ranges.get(name) + : (RangeToken)ranges2.get(name); + return tok; + } + + static void setupRange(Token range, String src) { + int len = src.length(); + for (int i = 0; i < len; i += 2) + range.addRange(src.charAt(i), src.charAt(i+1)); + } + + static void setupRange(Token range, int[] src) { + int len = src.length; + for (int i = 0; i < len; i += 2) + range.addRange(src[i], src[i+1]); + } + + private static final String SPACES = "\t\n\r\r "; + private static final String NAMECHARS = + "\u002d\u002e\u0030\u003a\u0041\u005a\u005f\u005f\u0061\u007a\u00b7\u00b7\u00c0\u00d6" + +"\u00d8\u00f6\u00f8\u0131\u0134\u013e\u0141\u0148\u014a\u017e\u0180\u01c3\u01cd\u01f0" + +"\u01f4\u01f5\u01fa\u0217\u0250\u02a8\u02bb\u02c1\u02d0\u02d1\u0300\u0345\u0360\u0361" + +"\u0386\u038a\u038c\u038c\u038e\u03a1\u03a3\u03ce\u03d0\u03d6\u03da\u03da\u03dc\u03dc" + +"\u03de\u03de\u03e0\u03e0\u03e2\u03f3\u0401\u040c\u040e\u044f\u0451\u045c\u045e\u0481" + +"\u0483\u0486\u0490\u04c4\u04c7\u04c8\u04cb\u04cc\u04d0\u04eb\u04ee\u04f5\u04f8\u04f9" + +"\u0531\u0556\u0559\u0559\u0561\u0586\u0591\u05a1\u05a3\u05b9\u05bb\u05bd\u05bf\u05bf" + +"\u05c1\u05c2\u05c4\u05c4\u05d0\u05ea\u05f0\u05f2\u0621\u063a\u0640\u0652\u0660\u0669" + +"\u0670\u06b7\u06ba\u06be\u06c0\u06ce\u06d0\u06d3\u06d5\u06e8\u06ea\u06ed\u06f0\u06f9" + +"\u0901\u0903\u0905\u0939\u093c\u094d\u0951\u0954\u0958\u0963\u0966\u096f\u0981\u0983" + +"\u0985\u098c\u098f\u0990\u0993\u09a8\u09aa\u09b0\u09b2\u09b2\u09b6\u09b9\u09bc\u09bc" + +"\u09be\u09c4\u09c7\u09c8\u09cb\u09cd\u09d7\u09d7\u09dc\u09dd\u09df\u09e3\u09e6\u09f1" + +"\u0a02\u0a02\u0a05\u0a0a\u0a0f\u0a10\u0a13\u0a28\u0a2a\u0a30\u0a32\u0a33\u0a35\u0a36" + +"\u0a38\u0a39\u0a3c\u0a3c\u0a3e\u0a42\u0a47\u0a48\u0a4b\u0a4d\u0a59\u0a5c\u0a5e\u0a5e" + +"\u0a66\u0a74\u0a81\u0a83\u0a85\u0a8b\u0a8d\u0a8d\u0a8f\u0a91\u0a93\u0aa8\u0aaa\u0ab0" + +"\u0ab2\u0ab3\u0ab5\u0ab9\u0abc\u0ac5\u0ac7\u0ac9\u0acb\u0acd\u0ae0\u0ae0\u0ae6\u0aef" + +"\u0b01\u0b03\u0b05\u0b0c\u0b0f\u0b10\u0b13\u0b28\u0b2a\u0b30\u0b32\u0b33\u0b36\u0b39" + +"\u0b3c\u0b43\u0b47\u0b48\u0b4b\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f\u0b61\u0b66\u0b6f" + +"\u0b82\u0b83\u0b85\u0b8a\u0b8e\u0b90\u0b92\u0b95\u0b99\u0b9a\u0b9c\u0b9c\u0b9e\u0b9f" + +"\u0ba3\u0ba4\u0ba8\u0baa\u0bae\u0bb5\u0bb7\u0bb9\u0bbe\u0bc2\u0bc6\u0bc8\u0bca\u0bcd" + +"\u0bd7\u0bd7\u0be7\u0bef\u0c01\u0c03\u0c05\u0c0c\u0c0e\u0c10\u0c12\u0c28\u0c2a\u0c33" + +"\u0c35\u0c39\u0c3e\u0c44\u0c46\u0c48\u0c4a\u0c4d\u0c55\u0c56\u0c60\u0c61\u0c66\u0c6f" + +"\u0c82\u0c83\u0c85\u0c8c\u0c8e\u0c90\u0c92\u0ca8\u0caa\u0cb3\u0cb5\u0cb9\u0cbe\u0cc4" + +"\u0cc6\u0cc8\u0cca\u0ccd\u0cd5\u0cd6\u0cde\u0cde\u0ce0\u0ce1\u0ce6\u0cef\u0d02\u0d03" + +"\u0d05\u0d0c\u0d0e\u0d10\u0d12\u0d28\u0d2a\u0d39\u0d3e\u0d43\u0d46\u0d48\u0d4a\u0d4d" + +"\u0d57\u0d57\u0d60\u0d61\u0d66\u0d6f\u0e01\u0e2e\u0e30\u0e3a\u0e40\u0e4e\u0e50\u0e59" + +"\u0e81\u0e82\u0e84\u0e84\u0e87\u0e88\u0e8a\u0e8a\u0e8d\u0e8d\u0e94\u0e97\u0e99\u0e9f" + +"\u0ea1\u0ea3\u0ea5\u0ea5\u0ea7\u0ea7\u0eaa\u0eab\u0ead\u0eae\u0eb0\u0eb9\u0ebb\u0ebd" + +"\u0ec0\u0ec4\u0ec6\u0ec6\u0ec8\u0ecd\u0ed0\u0ed9\u0f18\u0f19\u0f20\u0f29\u0f35\u0f35" + +"\u0f37\u0f37\u0f39\u0f39\u0f3e\u0f47\u0f49\u0f69\u0f71\u0f84\u0f86\u0f8b\u0f90\u0f95" + +"\u0f97\u0f97\u0f99\u0fad\u0fb1\u0fb7\u0fb9\u0fb9\u10a0\u10c5\u10d0\u10f6\u1100\u1100" + +"\u1102\u1103\u1105\u1107\u1109\u1109\u110b\u110c\u110e\u1112\u113c\u113c\u113e\u113e" + +"\u1140\u1140\u114c\u114c\u114e\u114e\u1150\u1150\u1154\u1155\u1159\u1159\u115f\u1161" + +"\u1163\u1163\u1165\u1165\u1167\u1167\u1169\u1169\u116d\u116e\u1172\u1173\u1175\u1175" + +"\u119e\u119e\u11a8\u11a8\u11ab\u11ab\u11ae\u11af\u11b7\u11b8\u11ba\u11ba\u11bc\u11c2" + +"\u11eb\u11eb\u11f0\u11f0\u11f9\u11f9\u1e00\u1e9b\u1ea0\u1ef9\u1f00\u1f15\u1f18\u1f1d" + +"\u1f20\u1f45\u1f48\u1f4d\u1f50\u1f57\u1f59\u1f59\u1f5b\u1f5b\u1f5d\u1f5d\u1f5f\u1f7d" + +"\u1f80\u1fb4\u1fb6\u1fbc\u1fbe\u1fbe\u1fc2\u1fc4\u1fc6\u1fcc\u1fd0\u1fd3\u1fd6\u1fdb" + +"\u1fe0\u1fec\u1ff2\u1ff4\u1ff6\u1ffc\u20d0\u20dc\u20e1\u20e1\u2126\u2126\u212a\u212b" + +"\u212e\u212e\u2180\u2182\u3005\u3005\u3007\u3007\u3021\u302f\u3031\u3035\u3041\u3094" + +"\u3099\u309a\u309d\u309e\u30a1\u30fa\u30fc\u30fe\u3105\u312c\u4e00\u9fa5\uac00\ud7a3" + +""; + private static final String LETTERS = + "\u0041\u005a\u0061\u007a\u00c0\u00d6\u00d8\u00f6\u00f8\u0131\u0134\u013e\u0141\u0148" + +"\u014a\u017e\u0180\u01c3\u01cd\u01f0\u01f4\u01f5\u01fa\u0217\u0250\u02a8\u02bb\u02c1" + +"\u0386\u0386\u0388\u038a\u038c\u038c\u038e\u03a1\u03a3\u03ce\u03d0\u03d6\u03da\u03da" + +"\u03dc\u03dc\u03de\u03de\u03e0\u03e0\u03e2\u03f3\u0401\u040c\u040e\u044f\u0451\u045c" + +"\u045e\u0481\u0490\u04c4\u04c7\u04c8\u04cb\u04cc\u04d0\u04eb\u04ee\u04f5\u04f8\u04f9" + +"\u0531\u0556\u0559\u0559\u0561\u0586\u05d0\u05ea\u05f0\u05f2\u0621\u063a\u0641\u064a" + +"\u0671\u06b7\u06ba\u06be\u06c0\u06ce\u06d0\u06d3\u06d5\u06d5\u06e5\u06e6\u0905\u0939" + +"\u093d\u093d\u0958\u0961\u0985\u098c\u098f\u0990\u0993\u09a8\u09aa\u09b0\u09b2\u09b2" + +"\u09b6\u09b9\u09dc\u09dd\u09df\u09e1\u09f0\u09f1\u0a05\u0a0a\u0a0f\u0a10\u0a13\u0a28" + +"\u0a2a\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59\u0a5c\u0a5e\u0a5e\u0a72\u0a74" + +"\u0a85\u0a8b\u0a8d\u0a8d\u0a8f\u0a91\u0a93\u0aa8\u0aaa\u0ab0\u0ab2\u0ab3\u0ab5\u0ab9" + +"\u0abd\u0abd\u0ae0\u0ae0\u0b05\u0b0c\u0b0f\u0b10\u0b13\u0b28\u0b2a\u0b30\u0b32\u0b33" + +"\u0b36\u0b39\u0b3d\u0b3d\u0b5c\u0b5d\u0b5f\u0b61\u0b85\u0b8a\u0b8e\u0b90\u0b92\u0b95" + +"\u0b99\u0b9a\u0b9c\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8\u0baa\u0bae\u0bb5\u0bb7\u0bb9" + +"\u0c05\u0c0c\u0c0e\u0c10\u0c12\u0c28\u0c2a\u0c33\u0c35\u0c39\u0c60\u0c61\u0c85\u0c8c" + +"\u0c8e\u0c90\u0c92\u0ca8\u0caa\u0cb3\u0cb5\u0cb9\u0cde\u0cde\u0ce0\u0ce1\u0d05\u0d0c" + +"\u0d0e\u0d10\u0d12\u0d28\u0d2a\u0d39\u0d60\u0d61\u0e01\u0e2e\u0e30\u0e30\u0e32\u0e33" + +"\u0e40\u0e45\u0e81\u0e82\u0e84\u0e84\u0e87\u0e88\u0e8a\u0e8a\u0e8d\u0e8d\u0e94\u0e97" + +"\u0e99\u0e9f\u0ea1\u0ea3\u0ea5\u0ea5\u0ea7\u0ea7\u0eaa\u0eab\u0ead\u0eae\u0eb0\u0eb0" + +"\u0eb2\u0eb3\u0ebd\u0ebd\u0ec0\u0ec4\u0f40\u0f47\u0f49\u0f69\u10a0\u10c5\u10d0\u10f6" + +"\u1100\u1100\u1102\u1103\u1105\u1107\u1109\u1109\u110b\u110c\u110e\u1112\u113c\u113c" + +"\u113e\u113e\u1140\u1140\u114c\u114c\u114e\u114e\u1150\u1150\u1154\u1155\u1159\u1159" + +"\u115f\u1161\u1163\u1163\u1165\u1165\u1167\u1167\u1169\u1169\u116d\u116e\u1172\u1173" + +"\u1175\u1175\u119e\u119e\u11a8\u11a8\u11ab\u11ab\u11ae\u11af\u11b7\u11b8\u11ba\u11ba" + +"\u11bc\u11c2\u11eb\u11eb\u11f0\u11f0\u11f9\u11f9\u1e00\u1e9b\u1ea0\u1ef9\u1f00\u1f15" + +"\u1f18\u1f1d\u1f20\u1f45\u1f48\u1f4d\u1f50\u1f57\u1f59\u1f59\u1f5b\u1f5b\u1f5d\u1f5d" + +"\u1f5f\u1f7d\u1f80\u1fb4\u1fb6\u1fbc\u1fbe\u1fbe\u1fc2\u1fc4\u1fc6\u1fcc\u1fd0\u1fd3" + +"\u1fd6\u1fdb\u1fe0\u1fec\u1ff2\u1ff4\u1ff6\u1ffc\u2126\u2126\u212a\u212b\u212e\u212e" + +"\u2180\u2182\u3007\u3007\u3021\u3029\u3041\u3094\u30a1\u30fa\u3105\u312c\u4e00\u9fa5" + +"\uac00\ud7a3"; + private static final String DIGITS = + "\u0030\u0039\u0660\u0669\u06F0\u06F9\u0966\u096F\u09E6\u09EF\u0A66\u0A6F\u0AE6\u0AEF" + +"\u0B66\u0B6F\u0BE7\u0BEF\u0C66\u0C6F\u0CE6\u0CEF\u0D66\u0D6F\u0E50\u0E59\u0ED0\u0ED9" + +"\u0F20\u0F29"; + private static final int[] DIGITS_INTS = { + 0x0030, 0x0039, 0x0660, 0x0669, 0x06F0, 0x06F9, 0x0966, 0x096F, + 0x09E6, 0x09EF, 0x0A66, 0x0A6F, 0x0AE6, 0x0AEF, 0x0B66, 0x0B6F, + 0x0BE7, 0x0BEF, 0x0C66, 0x0C6F, 0x0CE6, 0x0CEF, 0x0D66, 0x0D6F, + 0x0E50, 0x0E59, 0x0ED0, 0x0ED9, 0x0F20, 0x0F29, 0x1040, 0x1049, + 0x1369, 0x1371, 0x17E0, 0x17E9, 0x1810, 0x1819, 0xFF10, 0xFF19, + 0x1D7CE, 0x1D7FF + }; +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/REUtil.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/REUtil.java new file mode 100644 index 0000000..2c54732 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/REUtil.java @@ -0,0 +1,363 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +import java.text.CharacterIterator; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public final class REUtil { + private REUtil() { + } + + static final int composeFromSurrogates(int high, int low) { + return 0x10000 + ((high-0xd800)<<10) + low-0xdc00; + } + + static final boolean isLowSurrogate(int ch) { + return (ch & 0xfc00) == 0xdc00; + } + + static final boolean isHighSurrogate(int ch) { + return (ch & 0xfc00) == 0xd800; + } + + static final String decomposeToSurrogates(int ch) { + char[] chs = new char[2]; + ch -= 0x10000; + chs[0] = (char)((ch>>10)+0xd800); + chs[1] = (char)((ch&0x3ff)+0xdc00); + return new String(chs); + } + + static final String substring(CharacterIterator iterator, int begin, int end) { + char[] src = new char[end-begin]; + for (int i = 0; i < src.length; i ++) + src[i] = iterator.setIndex(i+begin); + return new String(src); + } + + // ================================================================ + + static final int getOptionValue(int ch) { + int ret = 0; + switch (ch) { + case 'i': + ret = RegularExpression.IGNORE_CASE; + break; + case 'm': + ret = RegularExpression.MULTIPLE_LINES; + break; + case 's': + ret = RegularExpression.SINGLE_LINE; + break; + case 'x': + ret = RegularExpression.EXTENDED_COMMENT; + break; + case 'u': + ret = RegularExpression.USE_UNICODE_CATEGORY; + break; + case 'w': + ret = RegularExpression.UNICODE_WORD_BOUNDARY; + break; + case 'F': + ret = RegularExpression.PROHIBIT_FIXED_STRING_OPTIMIZATION; + break; + case 'H': + ret = RegularExpression.PROHIBIT_HEAD_CHARACTER_OPTIMIZATION; + break; + case 'X': + ret = RegularExpression.XMLSCHEMA_MODE; + break; + case ',': + ret = RegularExpression.SPECIAL_COMMA; + break; + default: + } + return ret; + } + + static final int parseOptions(String opts) throws ParseException { + if (opts == null) return 0; + int options = 0; + for (int i = 0; i < opts.length(); i ++) { + int v = getOptionValue(opts.charAt(i)); + if (v == 0) + throw new ParseException("Unknown Option: "+opts.substring(i), -1); + options |= v; + } + return options; + } + + static final String createOptionString(int options) { + StringBuffer sb = new StringBuffer(9); + if ((options & RegularExpression.PROHIBIT_FIXED_STRING_OPTIMIZATION) != 0) + sb.append((char)'F'); + if ((options & RegularExpression.PROHIBIT_HEAD_CHARACTER_OPTIMIZATION) != 0) + sb.append((char)'H'); + if ((options & RegularExpression.XMLSCHEMA_MODE) != 0) + sb.append((char)'X'); + if ((options & RegularExpression.IGNORE_CASE) != 0) + sb.append((char)'i'); + if ((options & RegularExpression.MULTIPLE_LINES) != 0) + sb.append((char)'m'); + if ((options & RegularExpression.SINGLE_LINE) != 0) + sb.append((char)'s'); + if ((options & RegularExpression.USE_UNICODE_CATEGORY) != 0) + sb.append((char)'u'); + if ((options & RegularExpression.UNICODE_WORD_BOUNDARY) != 0) + sb.append((char)'w'); + if ((options & RegularExpression.EXTENDED_COMMENT) != 0) + sb.append((char)'x'); + if ((options & RegularExpression.SPECIAL_COMMA) != 0) + sb.append((char)','); + return sb.toString().intern(); + } + + // ================================================================ + + static String stripExtendedComment(String regex) { + int len = regex.length(); + StringBuffer buffer = new StringBuffer(len); + int offset = 0; + int charClass = 0; + while (offset < len) { + int ch = regex.charAt(offset++); + // Skips a white space. + if (ch == '\t' || ch == '\n' || ch == '\f' || ch == '\r' || ch == ' ') { + // if we are inside a character class, we keep the white space + if (charClass > 0) { + buffer.append((char)ch); + } + continue; + } + + if (ch == '#') { // Skips chracters between '#' and a line end. + while (offset < len) { + ch = regex.charAt(offset++); + if (ch == '\r' || ch == '\n') + break; + } + continue; + } + + int next; // Strips an escaped white space. + if (ch == '\\' && offset < len) { + if ((next = regex.charAt(offset)) == '#' + || next == '\t' || next == '\n' || next == '\f' + || next == '\r' || next == ' ') { + buffer.append((char)next); + offset ++; + } else { // Other escaped character. + buffer.append((char)'\\'); + buffer.append((char)next); + offset ++; + } + } + else if (ch == '[') { + charClass++; + buffer.append((char)ch); + if (offset < len) { + next = regex.charAt(offset); + if (next == '[' || next ==']') { + buffer.append((char)next); + offset ++; + } + else if (next == '^' && offset + 1 < len) { + next = regex.charAt(offset + 1); + if (next == '[' || next ==']') { + buffer.append((char)'^'); + buffer.append((char)next); + offset += 2; + } + } + } + } + else { + if (charClass > 0 && ch == ']') { + --charClass; + } + buffer.append((char)ch); + } + } + return buffer.toString(); + } + + // ================================================================ + + /** + * Sample entry. + *
Usage: org.apache.xerces.utils.regex.REUtil <regex> <string>
+ */ + public static void main(String[] argv) { + String pattern = null; + try { + String options = ""; + String target = null; + if( argv.length == 0 ) { + System.out.println( "Error:Usage: java REUtil -i|-m|-s|-u|-w|-X regularExpression String" ); + System.exit( 0 ); + } + for (int i = 0; i < argv.length; i ++) { + if (argv[i].length() == 0 || argv[i].charAt(0) != '-') { + if (pattern == null) + pattern = argv[i]; + else if (target == null) + target = argv[i]; + else + System.err.println("Unnecessary: "+argv[i]); + } else if (argv[i].equals("-i")) { + options += "i"; + } else if (argv[i].equals("-m")) { + options += "m"; + } else if (argv[i].equals("-s")) { + options += "s"; + } else if (argv[i].equals("-u")) { + options += "u"; + } else if (argv[i].equals("-w")) { + options += "w"; + } else if (argv[i].equals("-X")) { + options += "X"; + } else { + System.err.println("Unknown option: "+argv[i]); + } + } + RegularExpression reg = new RegularExpression(pattern, options); + System.out.println("RegularExpression: "+reg); + Match match = new Match(); + reg.matches(target, match); + for (int i = 0; i < match.getNumberOfGroups(); i ++) { + if (i == 0 ) System.out.print("Matched range for the whole pattern: "); + else System.out.print("["+i+"]: "); + if (match.getBeginning(i) < 0) + System.out.println("-1"); + else { + System.out.print(match.getBeginning(i)+", "+match.getEnd(i)+", "); + System.out.println("\""+match.getCapturedText(i)+"\""); + } + } + } catch (ParseException pe) { + if (pattern == null) { + pe.printStackTrace(); + } else { + System.err.println("org.apache.xerces.utils.regex.ParseException: "+pe.getMessage()); + String indent = " "; + System.err.println(indent+pattern); + int loc = pe.getLocation(); + if (loc >= 0) { + System.err.print(indent); + for (int i = 0; i < loc; i ++) System.err.print("-"); + System.err.println("^"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + static final int CACHESIZE = 20; + static final RegularExpression[] regexCache = new RegularExpression[CACHESIZE]; + /** + * Creates a RegularExpression instance. + * This method caches created instances. + * + * @see RegularExpression#RegularExpression(java.lang.String, java.lang.String) + */ + public static RegularExpression createRegex(String pattern, String options) + throws ParseException { + RegularExpression re = null; + int intOptions = REUtil.parseOptions(options); + synchronized (REUtil.regexCache) { + int i; + for (i = 0; i < REUtil.CACHESIZE; i ++) { + RegularExpression cached = REUtil.regexCache[i]; + if (cached == null) { + i = -1; + break; + } + if (cached.equals(pattern, intOptions)) { + re = cached; + break; + } + } + if (re != null) { + if (i != 0) { + System.arraycopy(REUtil.regexCache, 0, REUtil.regexCache, 1, i); + REUtil.regexCache[0] = re; + } + } else { + re = new RegularExpression(pattern, options); + System.arraycopy(REUtil.regexCache, 0, REUtil.regexCache, 1, REUtil.CACHESIZE-1); + REUtil.regexCache[0] = re; + } + } + return re; + } + + /** + * + * @see RegularExpression#matches(java.lang.String) + */ + public static boolean matches(String regex, String target) throws ParseException { + return REUtil.createRegex(regex, null).matches(target); + } + + /** + * + * @see RegularExpression#matches(java.lang.String) + */ + public static boolean matches(String regex, String options, String target) throws ParseException { + return REUtil.createRegex(regex, options).matches(target); + } + + // ================================================================ + + /** + * + */ + public static String quoteMeta(String literal) { + int len = literal.length(); + StringBuffer buffer = null; + for (int i = 0; i < len; i ++) { + int ch = literal.charAt(i); + if (".*+?{[()|\\^$".indexOf(ch) >= 0) { + if (buffer == null) { + buffer = new StringBuffer(i+(len-i)*2); + if (i > 0) buffer.append(literal.substring(0, i)); + } + buffer.append((char)'\\'); + buffer.append((char)ch); + } else if (buffer != null) + buffer.append((char)ch); + } + return buffer != null ? buffer.toString() : literal; + } + + // ================================================================ + + static void dumpString(String v) { + for (int i = 0; i < v.length(); i ++) { + System.out.print(Integer.toHexString(v.charAt(i))); + System.out.print(" "); + } + System.out.println(); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/RangeToken.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/RangeToken.java new file mode 100644 index 0000000..060eb6b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/RangeToken.java @@ -0,0 +1,623 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +/** + * This class represents a character class such as [a-z] or a period. + * + * @xerces.internal + * + * @version $Id$ + */ +final class RangeToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = -553983121197679934L; + + int[] ranges; + boolean sorted; + boolean compacted; + RangeToken icaseCache = null; + int[] map = null; + int nonMapIndex; + + RangeToken(int type) { + super(type); + this.setSorted(false); + } + + // for RANGE or NRANGE + protected void addRange(int start, int end) { + this.icaseCache = null; + //System.err.println("Token#addRange(): "+start+" "+end); + int r1, r2; + if (start <= end) { + r1 = start; + r2 = end; + } else { + r1 = end; + r2 = start; + } + + int pos = 0; + if (this.ranges == null) { + this.ranges = new int[2]; + this.ranges[0] = r1; + this.ranges[1] = r2; + this.setSorted(true); + } else { + pos = this.ranges.length; + if (this.ranges[pos-1]+1 == r1) { + this.ranges[pos-1] = r2; + return; + } + int[] temp = new int[pos+2]; + System.arraycopy(this.ranges, 0, temp, 0, pos); + this.ranges = temp; + if (this.ranges[pos-1] >= r1) + this.setSorted(false); + this.ranges[pos++] = r1; + this.ranges[pos] = r2; + if (!this.sorted) + this.sortRanges(); + } + } + + private final boolean isSorted() { + return this.sorted; + } + private final void setSorted(boolean sort) { + this.sorted = sort; + if (!sort) this.compacted = false; + } + private final boolean isCompacted() { + return this.compacted; + } + private final void setCompacted() { + this.compacted = true; + } + + protected void sortRanges() { + if (this.isSorted()) + return; + if (this.ranges == null) + return; + //System.err.println("Do sorting: "+this.ranges.length); + + // Bubble sort + // Why? -- In many cases, + // this.ranges has few elements. + for (int i = this.ranges.length-4; i >= 0; i -= 2) { + for (int j = 0; j <= i; j += 2) { + if (this.ranges[j] > this.ranges[j+2] + || this.ranges[j] == this.ranges[j+2] && this.ranges[j+1] > this.ranges[j+3]) { + int tmp; + tmp = this.ranges[j+2]; + this.ranges[j+2] = this.ranges[j]; + this.ranges[j] = tmp; + tmp = this.ranges[j+3]; + this.ranges[j+3] = this.ranges[j+1]; + this.ranges[j+1] = tmp; + } + } + } + this.setSorted(true); + } + + /** + * this.ranges is sorted. + */ + protected void compactRanges() { + boolean DEBUG = false; + if (this.ranges == null || this.ranges.length <= 2) + return; + if (this.isCompacted()) + return; + int base = 0; // Index of writing point + int target = 0; // Index of processing point + + while (target < this.ranges.length) { + if (base != target) { + this.ranges[base] = this.ranges[target++]; + this.ranges[base+1] = this.ranges[target++]; + } else + target += 2; + int baseend = this.ranges[base+1]; + while (target < this.ranges.length) { + if (baseend+1 < this.ranges[target]) + break; + if (baseend+1 == this.ranges[target]) { + if (DEBUG) + System.err.println("Token#compactRanges(): Compaction: ["+this.ranges[base] + +", "+this.ranges[base+1] + +"], ["+this.ranges[target] + +", "+this.ranges[target+1] + +"] -> ["+this.ranges[base] + +", "+this.ranges[target+1] + +"]"); + this.ranges[base+1] = this.ranges[target+1]; + baseend = this.ranges[base+1]; + target += 2; + } else if (baseend >= this.ranges[target+1]) { + if (DEBUG) + System.err.println("Token#compactRanges(): Compaction: ["+this.ranges[base] + +", "+this.ranges[base+1] + +"], ["+this.ranges[target] + +", "+this.ranges[target+1] + +"] -> ["+this.ranges[base] + +", "+this.ranges[base+1] + +"]"); + target += 2; + } else if (baseend < this.ranges[target+1]) { + if (DEBUG) + System.err.println("Token#compactRanges(): Compaction: ["+this.ranges[base] + +", "+this.ranges[base+1] + +"], ["+this.ranges[target] + +", "+this.ranges[target+1] + +"] -> ["+this.ranges[base] + +", "+this.ranges[target+1] + +"]"); + this.ranges[base+1] = this.ranges[target+1]; + baseend = this.ranges[base+1]; + target += 2; + } else { + throw new RuntimeException("Token#compactRanges(): Internel Error: [" + +this.ranges[base] + +","+this.ranges[base+1] + +"] ["+this.ranges[target] + +","+this.ranges[target+1]+"]"); + } + } // while + base += 2; + } + + if (base != this.ranges.length) { + int[] result = new int[base]; + System.arraycopy(this.ranges, 0, result, 0, base); + this.ranges = result; + } + this.setCompacted(); + } + + protected void mergeRanges(Token token) { + RangeToken tok = (RangeToken)token; + this.sortRanges(); + tok.sortRanges(); + if (tok.ranges == null) + return; + this.icaseCache = null; + this.setSorted(true); + if (this.ranges == null) { + this.ranges = new int[tok.ranges.length]; + System.arraycopy(tok.ranges, 0, this.ranges, 0, tok.ranges.length); + return; + } + int[] result = new int[this.ranges.length+tok.ranges.length]; + for (int i = 0, j = 0, k = 0; i < this.ranges.length || j < tok.ranges.length;) { + if (i >= this.ranges.length) { + result[k++] = tok.ranges[j++]; + result[k++] = tok.ranges[j++]; + } else if (j >= tok.ranges.length) { + result[k++] = this.ranges[i++]; + result[k++] = this.ranges[i++]; + } else if (tok.ranges[j] < this.ranges[i] + || tok.ranges[j] == this.ranges[i] && tok.ranges[j+1] < this.ranges[i+1]) { + result[k++] = tok.ranges[j++]; + result[k++] = tok.ranges[j++]; + } else { + result[k++] = this.ranges[i++]; + result[k++] = this.ranges[i++]; + } + } + this.ranges = result; + } + + protected void subtractRanges(Token token) { + if (token.type == NRANGE) { + this.intersectRanges(token); + return; + } + RangeToken tok = (RangeToken)token; + if (tok.ranges == null || this.ranges == null) + return; + this.icaseCache = null; + this.sortRanges(); + this.compactRanges(); + tok.sortRanges(); + tok.compactRanges(); + + //System.err.println("Token#substractRanges(): Entry: "+this.ranges.length+", "+tok.ranges.length); + + int[] result = new int[this.ranges.length+tok.ranges.length]; + int wp = 0, src = 0, sub = 0; + while (src < this.ranges.length && sub < tok.ranges.length) { + int srcbegin = this.ranges[src]; + int srcend = this.ranges[src+1]; + int subbegin = tok.ranges[sub]; + int subend = tok.ranges[sub+1]; + if (srcend < subbegin) { // Not overlapped + // src: o-----o + // sub: o-----o + // res: o-----o + // Reuse sub + result[wp++] = this.ranges[src++]; + result[wp++] = this.ranges[src++]; + } else if (srcend >= subbegin + && srcbegin <= subend) { // Overlapped + // src: o--------o + // sub: o----o + // sub: o----o + // sub: o----o + // sub: o------------o + if (subbegin <= srcbegin && srcend <= subend) { + // src: o--------o + // sub: o------------o + // res: empty + // Reuse sub + src += 2; + } else if (subbegin <= srcbegin) { + // src: o--------o + // sub: o----o + // res: o-----o + // Reuse src(=res) + this.ranges[src] = subend+1; + sub += 2; + } else if (srcend <= subend) { + // src: o--------o + // sub: o----o + // res: o-----o + // Reuse sub + result[wp++] = srcbegin; + result[wp++] = subbegin-1; + src += 2; + } else { + // src: o--------o + // sub: o----o + // res: o-o o-o + // Reuse src(=right res) + result[wp++] = srcbegin; + result[wp++] = subbegin-1; + this.ranges[src] = subend+1; + sub += 2; + } + } else if (subend < srcbegin) { + // Not overlapped + // src: o-----o + // sub: o----o + sub += 2; + } else { + throw new RuntimeException("Token#subtractRanges(): Internal Error: ["+this.ranges[src] + +","+this.ranges[src+1] + +"] - ["+tok.ranges[sub] + +","+tok.ranges[sub+1] + +"]"); + } + } + while (src < this.ranges.length) { + result[wp++] = this.ranges[src++]; + result[wp++] = this.ranges[src++]; + } + this.ranges = new int[wp]; + System.arraycopy(result, 0, this.ranges, 0, wp); + // this.ranges is sorted and compacted. + } + + /** + * @param tok Ignore whether it is NRANGE or not. + */ + protected void intersectRanges(Token token) { + RangeToken tok = (RangeToken)token; + if (tok.ranges == null || this.ranges == null) + return; + this.icaseCache = null; + this.sortRanges(); + this.compactRanges(); + tok.sortRanges(); + tok.compactRanges(); + + int[] result = new int[this.ranges.length+tok.ranges.length]; + int wp = 0, src1 = 0, src2 = 0; + while (src1 < this.ranges.length && src2 < tok.ranges.length) { + int src1begin = this.ranges[src1]; + int src1end = this.ranges[src1+1]; + int src2begin = tok.ranges[src2]; + int src2end = tok.ranges[src2+1]; + if (src1end < src2begin) { // Not overlapped + // src1: o-----o + // src2: o-----o + // res: empty + // Reuse src2 + src1 += 2; + } else if (src1end >= src2begin + && src1begin <= src2end) { // Overlapped + // src1: o--------o + // src2: o----o + // src2: o----o + // src2: o----o + // src2: o------------o + if (src2begin <= src1begin && src1end <= src2end) { + // src1: o--------o + // src2: o------------o + // res: o--------o + // Reuse src2 + result[wp++] = src1begin; + result[wp++] = src1end; + src1 += 2; + } else if (src2begin <= src1begin) { + // src1: o--------o + // src2: o----o + // res: o--o + // Reuse the rest of src1 + result[wp++] = src1begin; + result[wp++] = src2end; + this.ranges[src1] = src2end+1; + src2 += 2; + } else if (src1end <= src2end) { + // src1: o--------o + // src2: o----o + // res: o--o + // Reuse src2 + result[wp++] = src2begin; + result[wp++] = src1end; + src1 += 2; + } else { + // src1: o--------o + // src2: o----o + // res: o----o + // Reuse the rest of src1 + result[wp++] = src2begin; + result[wp++] = src2end; + this.ranges[src1] = src2end+1; + } + } else if (src2end < src1begin) { + // Not overlapped + // src1: o-----o + // src2: o----o + src2 += 2; + } else { + throw new RuntimeException("Token#intersectRanges(): Internal Error: [" + +this.ranges[src1] + +","+this.ranges[src1+1] + +"] & ["+tok.ranges[src2] + +","+tok.ranges[src2+1] + +"]"); + } + } + while (src1 < this.ranges.length) { + result[wp++] = this.ranges[src1++]; + result[wp++] = this.ranges[src1++]; + } + this.ranges = new int[wp]; + System.arraycopy(result, 0, this.ranges, 0, wp); + // this.ranges is sorted and compacted. + } + + /** + * for RANGE: Creates complement. + * for NRANGE: Creates the same meaning RANGE. + */ + static Token complementRanges(Token token) { + if (token.type != RANGE && token.type != NRANGE) + throw new IllegalArgumentException("Token#complementRanges(): must be RANGE: "+token.type); + RangeToken tok = (RangeToken)token; + tok.sortRanges(); + tok.compactRanges(); + int len = tok.ranges.length+2; + if (tok.ranges[0] == 0) + len -= 2; + int last = tok.ranges[tok.ranges.length-1]; + if (last == UTF16_MAX) + len -= 2; + RangeToken ret = Token.createRange(); + ret.ranges = new int[len]; + int wp = 0; + if (tok.ranges[0] > 0) { + ret.ranges[wp++] = 0; + ret.ranges[wp++] = tok.ranges[0]-1; + } + for (int i = 1; i < tok.ranges.length-2; i += 2) { + ret.ranges[wp++] = tok.ranges[i]+1; + ret.ranges[wp++] = tok.ranges[i+1]-1; + } + if (last != UTF16_MAX) { + ret.ranges[wp++] = last+1; + ret.ranges[wp] = UTF16_MAX; + } + ret.setCompacted(); + return ret; + } + + synchronized RangeToken getCaseInsensitiveToken() { + if (this.icaseCache != null) + return this.icaseCache; + + RangeToken uppers = this.type == Token.RANGE ? Token.createRange() : Token.createNRange(); + for (int i = 0; i < this.ranges.length; i += 2) { + for (int ch = this.ranges[i]; ch <= this.ranges[i+1]; ch ++) { + if (ch > 0xffff) + uppers.addRange(ch, ch); + else { + char uch = Character.toUpperCase((char)ch); + uppers.addRange(uch, uch); + } + } + } + RangeToken lowers = this.type == Token.RANGE ? Token.createRange() : Token.createNRange(); + for (int i = 0; i < uppers.ranges.length; i += 2) { + for (int ch = uppers.ranges[i]; ch <= uppers.ranges[i+1]; ch ++) { + if (ch > 0xffff) + lowers.addRange(ch, ch); + else { + char uch = Character.toLowerCase((char)ch); + lowers.addRange(uch, uch); + } + } + } + lowers.mergeRanges(uppers); + lowers.mergeRanges(this); + lowers.compactRanges(); + + this.icaseCache = lowers; + return lowers; + } + + void dumpRanges() { + System.err.print("RANGE: "); + if (this.ranges == null) { + System.err.println(" NULL"); + return; + } + for (int i = 0; i < this.ranges.length; i += 2) { + System.err.print("["+this.ranges[i]+","+this.ranges[i+1]+"] "); + } + System.err.println(""); + } + + boolean match(int ch) { + if (this.map == null) this.createMap(); + boolean ret; + if (this.type == RANGE) { + if (ch < MAPSIZE) + return (this.map[ch/32] & (1<<(ch&0x1f))) != 0; + ret = false; + for (int i = this.nonMapIndex; i < this.ranges.length; i += 2) { + if (this.ranges[i] <= ch && ch <= this.ranges[i+1]) + return true; + } + } else { + if (ch < MAPSIZE) + return (this.map[ch/32] & (1<<(ch&0x1f))) == 0; + ret = true; + for (int i = this.nonMapIndex; i < this.ranges.length; i += 2) { + if (this.ranges[i] <= ch && ch <= this.ranges[i+1]) + return false; + } + } + return ret; + } + + private static final int MAPSIZE = 256; + private void createMap() { + int asize = MAPSIZE/32; // 32 is the number of bits in `int'. + int [] map = new int[asize]; + int nonMapIndex = this.ranges.length; + for (int i = 0; i < asize; ++i) { + map[i] = 0; + } + for (int i = 0; i < this.ranges.length; i += 2) { + int s = this.ranges[i]; + int e = this.ranges[i+1]; + if (s < MAPSIZE) { + for (int j = s; j <= e && j < MAPSIZE; j++) { + map[j/32] |= 1<<(j&0x1f); // s&0x1f : 0-31 + } + } + else { + nonMapIndex = i; + break; + } + if (e >= MAPSIZE) { + nonMapIndex = i; + break; + } + } + this.map = map; + this.nonMapIndex = nonMapIndex; + //for (int i = 0; i < asize; i ++) System.err.println("Map: "+Integer.toString(this.map[i], 16)); + } + + public String toString(int options) { + String ret; + if (this.type == RANGE) { + if (this == Token.token_dot) + ret = "."; + else if (this == Token.token_0to9) + ret = "\\d"; + else if (this == Token.token_wordchars) + ret = "\\w"; + else if (this == Token.token_spaces) + ret = "\\s"; + else { + StringBuffer sb = new StringBuffer(); + sb.append('['); + for (int i = 0; i < this.ranges.length; i += 2) { + if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(','); + if (this.ranges[i] == this.ranges[i+1]) { + sb.append(escapeCharInCharClass(this.ranges[i])); + } else { + sb.append(escapeCharInCharClass(this.ranges[i])); + sb.append((char)'-'); + sb.append(escapeCharInCharClass(this.ranges[i+1])); + } + } + sb.append(']'); + ret = sb.toString(); + } + } else { + if (this == Token.token_not_0to9) + ret = "\\D"; + else if (this == Token.token_not_wordchars) + ret = "\\W"; + else if (this == Token.token_not_spaces) + ret = "\\S"; + else { + StringBuffer sb = new StringBuffer(); + sb.append("[^"); + for (int i = 0; i < this.ranges.length; i += 2) { + if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(','); + if (this.ranges[i] == this.ranges[i+1]) { + sb.append(escapeCharInCharClass(this.ranges[i])); + } else { + sb.append(escapeCharInCharClass(this.ranges[i])); + sb.append('-'); + sb.append(escapeCharInCharClass(this.ranges[i+1])); + } + } + sb.append(']'); + ret = sb.toString(); + } + } + return ret; + } + + private static String escapeCharInCharClass(int ch) { + String ret; + switch (ch) { + case '[': case ']': case '-': case '^': + case ',': case '\\': + ret = "\\"+(char)ch; + break; + case '\f': ret = "\\f"; break; + case '\n': ret = "\\n"; break; + case '\r': ret = "\\r"; break; + case '\t': ret = "\\t"; break; + case 0x1b: ret = "\\e"; break; + //case 0x0b: ret = "\\v"; break; + default: + if (ch < 0x20) { + String pre = "0"+Integer.toHexString(ch); + ret = "\\x"+pre.substring(pre.length()-2, pre.length()); + } else if (ch >= 0x10000) { + String pre = "0"+Integer.toHexString(ch); + ret = "\\v"+pre.substring(pre.length()-6, pre.length()); + } else + ret = ""+(char)ch; + } + return ret; + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/RegexParser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/RegexParser.java new file mode 100644 index 0000000..2da0e14 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/RegexParser.java @@ -0,0 +1,1232 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Vector; + +/** + * A Regular Expression Parser. + * + * @xerces.internal + * + * @version $Id$ + */ +class RegexParser { + static final int T_CHAR = 0; + static final int T_EOF = 1; + static final int T_OR = 2; // '|' + static final int T_STAR = 3; // '*' + static final int T_PLUS = 4; // '+' + static final int T_QUESTION = 5; // '?' + static final int T_LPAREN = 6; // '(' + static final int T_RPAREN = 7; // ')' + static final int T_DOT = 8; // '.' + static final int T_LBRACKET = 9; // '[' + static final int T_BACKSOLIDUS = 10; // '\' + static final int T_CARET = 11; // '^' + static final int T_DOLLAR = 12; // '$' + static final int T_LPAREN2 = 13; // '(?:' + static final int T_LOOKAHEAD = 14; // '(?=' + static final int T_NEGATIVELOOKAHEAD = 15; // '(?!' + static final int T_LOOKBEHIND = 16; // '(?<=' + static final int T_NEGATIVELOOKBEHIND = 17; // '(?' + static final int T_SET_OPERATIONS = 19; // '(?[' + static final int T_POSIX_CHARCLASS_START = 20; // '[:' in a character class + static final int T_COMMENT = 21; // '(?#' + static final int T_MODIFIERS = 22; // '(?' [\-,a-z,A-Z] + static final int T_CONDITION = 23; // '(?(' + static final int T_XMLSCHEMA_CC_SUBTRACTION = 24; // '-[' in a character class + + static class ReferencePosition { + int refNumber; + int position; + ReferencePosition(int n, int pos) { + this.refNumber = n; + this.position = pos; + } + } + + int offset; + String regex; + int regexlen; + int options; + ResourceBundle resources; + int chardata; + int nexttoken; + static protected final int S_NORMAL = 0; + static protected final int S_INBRACKETS = 1; + static protected final int S_INXBRACKETS = 2; + int context = S_NORMAL; + int parenOpened = 1; + int parennumber = 1; + boolean hasBackReferences; + Vector references = null; + + public RegexParser() { + this.setLocale(Locale.getDefault()); + } + public RegexParser(Locale locale) { + this.setLocale(locale); + } + + public void setLocale(Locale locale) { + try { + if (locale != null) { + this.resources = ResourceBundle.getBundle("org.apache.xerces.impl.xpath.regex.message", locale); + } + else { + this.resources = ResourceBundle.getBundle("org.apache.xerces.impl.xpath.regex.message"); + } + } + catch (MissingResourceException mre) { + throw new RuntimeException("Installation Problem??? Couldn't load messages: " + + mre.getMessage()); + } + } + + final ParseException ex(String key, int loc) { + return new ParseException(this.resources.getString(key), loc); + } + + protected final boolean isSet(int flag) { + return (this.options & flag) == flag; + } + + synchronized Token parse(String regex, int options) throws ParseException { + this.options = options; + this.offset = 0; + this.setContext(S_NORMAL); + this.parennumber = 1; + this.parenOpened = 1; + this.hasBackReferences = false; + this.regex = regex; + if (this.isSet(RegularExpression.EXTENDED_COMMENT)) + this.regex = REUtil.stripExtendedComment(this.regex); + this.regexlen = this.regex.length(); + + + this.next(); + Token ret = this.parseRegex(); + if (this.offset != this.regexlen) + throw ex("parser.parse.1", this.offset); + if (this.read() != T_EOF) { + throw ex("parser.parse.1", this.offset-1); + } + if (this.references != null) { + for (int i = 0; i < this.references.size(); i ++) { + ReferencePosition position = (ReferencePosition)this.references.elementAt(i); + if (this.parennumber <= position.refNumber) + throw ex("parser.parse.2", position.position); + } + this.references.removeAllElements(); + } + return ret; + } + + /* + public RegularExpression createRegex(String regex, int options) throws ParseException { + Token tok = this.parse(regex, options); + return new RegularExpression(regex, tok, this.parennumber, this.hasBackReferences, options); + } + */ + + protected final void setContext(int con) { + this.context = con; + } + + final int read() { + return this.nexttoken; + } + + final void next() { + if (this.offset >= this.regexlen) { + this.chardata = -1; + this.nexttoken = T_EOF; + return; + } + + int ret; + int ch = this.regex.charAt(this.offset++); + this.chardata = ch; + + if (this.context == S_INBRACKETS) { + // In a character class, this.chardata has one character, that is to say, + // a pair of surrogates is composed and stored to this.chardata. + switch (ch) { + case '\\': + ret = T_BACKSOLIDUS; + if (this.offset >= this.regexlen) + throw ex("parser.next.1", this.offset-1); + this.chardata = this.regex.charAt(this.offset++); + break; + + case '-': + // Allow character class subtraction (regardless of whether we are in + // XML Schema mode or not) + if (this.offset < this.regexlen && this.regex.charAt(this.offset) == '[') { + this.offset++; + ret = T_XMLSCHEMA_CC_SUBTRACTION; + } else + ret = T_CHAR; + break; + + case '[': + if (!this.isSet(RegularExpression.XMLSCHEMA_MODE) + && this.offset < this.regexlen && this.regex.charAt(this.offset) == ':') { + this.offset++; + ret = T_POSIX_CHARCLASS_START; + break; + } // Through down + default: + if (REUtil.isHighSurrogate(ch) && this.offset < this.regexlen) { + int low = this.regex.charAt(this.offset); + if (REUtil.isLowSurrogate(low)) { + this.chardata = REUtil.composeFromSurrogates(ch, low); + this.offset ++; + } + } + ret = T_CHAR; + } + this.nexttoken = ret; + return; + } + + switch (ch) { + case '|': ret = T_OR; break; + case '*': ret = T_STAR; break; + case '+': ret = T_PLUS; break; + case '?': ret = T_QUESTION; break; + case ')': ret = T_RPAREN; break; + case '.': ret = T_DOT; break; + case '[': ret = T_LBRACKET; break; + case '^': + if (this.isSet(RegularExpression.XMLSCHEMA_MODE)) { + ret = T_CHAR; + } + else { + ret = T_CARET; + } + break; + case '$': + if (this.isSet(RegularExpression.XMLSCHEMA_MODE)) { + ret = T_CHAR; + } + else { + ret = T_DOLLAR; + } + break; + case '(': + ret = T_LPAREN; + if (this.offset >= this.regexlen) + break; + if (this.regex.charAt(this.offset) != '?') + break; + if (++this.offset >= this.regexlen) + throw ex("parser.next.2", this.offset-1); + ch = this.regex.charAt(this.offset++); + switch (ch) { + case ':': ret = T_LPAREN2; break; + case '=': ret = T_LOOKAHEAD; break; + case '!': ret = T_NEGATIVELOOKAHEAD; break; + case '[': ret = T_SET_OPERATIONS; break; + case '>': ret = T_INDEPENDENT; break; + case '<': + if (this.offset >= this.regexlen) + throw ex("parser.next.2", this.offset-3); + ch = this.regex.charAt(this.offset++); + if (ch == '=') { + ret = T_LOOKBEHIND; + } else if (ch == '!') { + ret = T_NEGATIVELOOKBEHIND; + } else + throw ex("parser.next.3", this.offset-3); + break; + case '#': + while (this.offset < this.regexlen) { + ch = this.regex.charAt(this.offset++); + if (ch == ')') break; + } + if (ch != ')') + throw ex("parser.next.4", this.offset-1); + ret = T_COMMENT; + break; + default: + if (ch == '-' || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') {// Options + this.offset --; + ret = T_MODIFIERS; + break; + } else if (ch == '(') { // conditional + ret = T_CONDITION; // this.offsets points the next of '('. + break; + } + throw ex("parser.next.2", this.offset-2); + } + break; + + case '\\': + ret = T_BACKSOLIDUS; + if (this.offset >= this.regexlen) + throw ex("parser.next.1", this.offset-1); + this.chardata = this.regex.charAt(this.offset++); + break; + + default: + ret = T_CHAR; + } + this.nexttoken = ret; + } + + /** + * regex ::= term (`|` term)* + * term ::= factor+ + * factor ::= ('^' | '$' | '\A' | '\Z' | '\z' | '\b' | '\B' | '\<' | '\>' + * | atom (('*' | '+' | '?' | minmax ) '?'? )?) + * | '(?=' regex ')' | '(?!' regex ')' | '(?<=' regex ')' | '(?<!' regex ')' + * atom ::= char | '.' | range | '(' regex ')' | '(?:' regex ')' | '\' [0-9] + * | '\w' | '\W' | '\d' | '\D' | '\s' | '\S' | category-block + */ + Token parseRegex() throws ParseException { + Token tok = this.parseTerm(); + Token parent = null; + while (this.read() == T_OR) { + this.next(); // '|' + if (parent == null) { + parent = Token.createUnion(); + parent.addChild(tok); + tok = parent; + } + tok.addChild(this.parseTerm()); + } + return tok; + } + + /** + * term ::= factor+ + */ + Token parseTerm() throws ParseException { + int ch = this.read(); + if (ch == T_OR || ch == T_RPAREN || ch == T_EOF) { + return Token.createEmpty(); + } else { + Token tok = this.parseFactor(); + Token concat = null; + while ((ch = this.read()) != T_OR && ch != T_RPAREN && ch != T_EOF) { + if (concat == null) { + concat = Token.createConcat(); + concat.addChild(tok); + tok = concat; + } + concat.addChild(this.parseFactor()); + //tok = Token.createConcat(tok, this.parseFactor()); + } + return tok; + } + } + + // ---------------------------------------------------------------- + + Token processCaret() throws ParseException { + this.next(); + return Token.token_linebeginning; + } + Token processDollar() throws ParseException { + this.next(); + return Token.token_lineend; + } + Token processLookahead() throws ParseException { + this.next(); + Token tok = Token.createLook(Token.LOOKAHEAD, this.parseRegex()); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); // ')' + return tok; + } + Token processNegativelookahead() throws ParseException { + this.next(); + Token tok = Token.createLook(Token.NEGATIVELOOKAHEAD, this.parseRegex()); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); // ')' + return tok; + } + Token processLookbehind() throws ParseException { + this.next(); + Token tok = Token.createLook(Token.LOOKBEHIND, this.parseRegex()); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); // ')' + return tok; + } + Token processNegativelookbehind() throws ParseException { + this.next(); + Token tok = Token.createLook(Token.NEGATIVELOOKBEHIND, this.parseRegex()); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); // ')' + return tok; + } + Token processBacksolidus_A() throws ParseException { + this.next(); + return Token.token_stringbeginning; + } + Token processBacksolidus_Z() throws ParseException { + this.next(); + return Token.token_stringend2; + } + Token processBacksolidus_z() throws ParseException { + this.next(); + return Token.token_stringend; + } + Token processBacksolidus_b() throws ParseException { + this.next(); + return Token.token_wordedge; + } + Token processBacksolidus_B() throws ParseException { + this.next(); + return Token.token_not_wordedge; + } + Token processBacksolidus_lt() throws ParseException { + this.next(); + return Token.token_wordbeginning; + } + Token processBacksolidus_gt() throws ParseException { + this.next(); + return Token.token_wordend; + } + Token processStar(Token tok) throws ParseException { + this.next(); + if (this.read() == T_QUESTION) { + this.next(); + return Token.createNGClosure(tok); + } else + return Token.createClosure(tok); + } + Token processPlus(Token tok) throws ParseException { + // X+ -> XX* + this.next(); + if (this.read() == T_QUESTION) { + this.next(); + return Token.createConcat(tok, Token.createNGClosure(tok)); + } else + return Token.createConcat(tok, Token.createClosure(tok)); + } + Token processQuestion(Token tok) throws ParseException { + // X? -> X| + this.next(); + Token par = Token.createUnion(); + if (this.read() == T_QUESTION) { + this.next(); + par.addChild(Token.createEmpty()); + par.addChild(tok); + } else { + par.addChild(tok); + par.addChild(Token.createEmpty()); + } + return par; + } + boolean checkQuestion(int off) { + return off < this.regexlen && this.regex.charAt(off) == '?'; + } + Token processParen() throws ParseException { + this.next(); + int p = this.parenOpened++; + Token tok = Token.createParen(this.parseRegex(), p); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.parennumber++; + this.next(); // Skips ')' + return tok; + } + Token processParen2() throws ParseException { + this.next(); + Token tok = Token.createParen(this.parseRegex(), 0); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); // Skips ')' + return tok; + } + Token processCondition() throws ParseException { + // this.offset points the next of '(' + if (this.offset+1 >= this.regexlen) throw ex("parser.factor.4", this.offset); + // Parses a condition. + int refno = -1; + Token condition = null; + int ch = this.regex.charAt(this.offset); + if ('1' <= ch && ch <= '9') { + refno = ch-'0'; + int finalRefno = refno; + + if (this.parennumber <= refno) + throw ex("parser.parse.2", this.offset); + + while (this.offset + 1 < this.regexlen) { + ch = this.regex.charAt(this.offset + 1); + if ('0' <= ch && ch <= '9') { + refno = (refno * 10) + (ch - '0'); + if (refno < this.parennumber) { + finalRefno= refno; + ++this.offset; + } + else { + break; + } + } + else { + break; + } + } + + this.hasBackReferences = true; + if (this.references == null) this.references = new Vector(); + this.references.addElement(new ReferencePosition(finalRefno, this.offset)); + this.offset ++; + if (this.regex.charAt(this.offset) != ')') throw ex("parser.factor.1", this.offset); + this.offset ++; + } else { + if (ch == '?') this.offset --; // Points '('. + this.next(); + condition = this.parseFactor(); + switch (condition.type) { + case Token.LOOKAHEAD: + case Token.NEGATIVELOOKAHEAD: + case Token.LOOKBEHIND: + case Token.NEGATIVELOOKBEHIND: + break; + case Token.ANCHOR: + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + break; + default: + throw ex("parser.factor.5", this.offset); + } + } + // Parses yes/no-patterns. + this.next(); + Token yesPattern = this.parseRegex(); + Token noPattern = null; + if (yesPattern.type == Token.UNION) { + if (yesPattern.size() != 2) throw ex("parser.factor.6", this.offset); + noPattern = yesPattern.getChild(1); + yesPattern = yesPattern.getChild(0); + } + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); + return Token.createCondition(refno, condition, yesPattern, noPattern); + } + Token processModifiers() throws ParseException { + // this.offset points the next of '?'. + // modifiers ::= [imsw]* ('-' [imsw]*)? ':' + int add = 0, mask = 0, ch = -1; + while (this.offset < this.regexlen) { + ch = this.regex.charAt(this.offset); + int v = REUtil.getOptionValue(ch); + if (v == 0) break; // '-' or ':'? + add |= v; + this.offset ++; + } + if (this.offset >= this.regexlen) throw ex("parser.factor.2", this.offset-1); + if (ch == '-') { + this.offset ++; + while (this.offset < this.regexlen) { + ch = this.regex.charAt(this.offset); + int v = REUtil.getOptionValue(ch); + if (v == 0) break; // ':'? + mask |= v; + this.offset ++; + } + if (this.offset >= this.regexlen) throw ex("parser.factor.2", this.offset-1); + } + Token tok; + if (ch == ':') { + this.offset ++; + this.next(); + tok = Token.createModifierGroup(this.parseRegex(), add, mask); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); + } else if (ch == ')') { // such as (?-i) + this.offset ++; + this.next(); + tok = Token.createModifierGroup(this.parseRegex(), add, mask); + } else + throw ex("parser.factor.3", this.offset); + + return tok; + } + Token processIndependent() throws ParseException { + this.next(); + Token tok = Token.createLook(Token.INDEPENDENT, this.parseRegex()); + if (this.read() != T_RPAREN) throw ex("parser.factor.1", this.offset-1); + this.next(); // Skips ')' + return tok; + } + Token processBacksolidus_c() throws ParseException { + int ch2; // Must be in 0x0040-0x005f + if (this.offset >= this.regexlen + || ((ch2 = this.regex.charAt(this.offset++)) & 0xffe0) != 0x0040) + throw ex("parser.atom.1", this.offset-1); + this.next(); + return Token.createChar(ch2-0x40); + } + Token processBacksolidus_C() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_i() throws ParseException { + Token tok = Token.createChar('i'); + this.next(); + return tok; + } + Token processBacksolidus_I() throws ParseException { + throw ex("parser.process.1", this.offset); + } + Token processBacksolidus_g() throws ParseException { + this.next(); + return Token.getGraphemePattern(); + } + Token processBacksolidus_X() throws ParseException { + this.next(); + return Token.getCombiningCharacterSequence(); + } + Token processBackreference() throws ParseException { + int refnum = this.chardata-'0'; + int finalRefnum = refnum; + + if (this.parennumber <= refnum) + throw ex("parser.parse.2", this.offset-2); + + while (this.offset < this.regexlen) { + final int ch = this.regex.charAt(this.offset); + if ('0' <= ch && ch <= '9') { + refnum = (refnum * 10) + (ch - '0'); + if (refnum < this.parennumber) { + ++this.offset; + finalRefnum = refnum; + this.chardata = ch; + } + else { + break; + } + } + else { + break; + } + } + + Token tok = Token.createBackReference(finalRefnum); + this.hasBackReferences = true; + if (this.references == null) this.references = new Vector(); + this.references.addElement(new ReferencePosition(finalRefnum, this.offset-2)); + this.next(); + return tok; + } + + // ---------------------------------------------------------------- + + /** + * factor ::= ('^' | '$' | '\A' | '\Z' | '\z' | '\b' | '\B' | '\<' | '\>' + * | atom (('*' | '+' | '?' | minmax ) '?'? )?) + * | '(?=' regex ')' | '(?!' regex ')' | '(?<=' regex ')' | '(?<!' regex ')' + * | '(?#' [^)]* ')' + * minmax ::= '{' min (',' max?)? '}' + * min ::= [0-9]+ + * max ::= [0-9]+ + */ + Token parseFactor() throws ParseException { + int ch = this.read(); + Token tok; + switch (ch) { + case T_CARET: return this.processCaret(); + case T_DOLLAR: return this.processDollar(); + case T_LOOKAHEAD: return this.processLookahead(); + case T_NEGATIVELOOKAHEAD: return this.processNegativelookahead(); + case T_LOOKBEHIND: return this.processLookbehind(); + case T_NEGATIVELOOKBEHIND: return this.processNegativelookbehind(); + + case T_COMMENT: + this.next(); + return Token.createEmpty(); + + case T_BACKSOLIDUS: + switch (this.chardata) { + case 'A': return this.processBacksolidus_A(); + case 'Z': return this.processBacksolidus_Z(); + case 'z': return this.processBacksolidus_z(); + case 'b': return this.processBacksolidus_b(); + case 'B': return this.processBacksolidus_B(); + case '<': return this.processBacksolidus_lt(); + case '>': return this.processBacksolidus_gt(); + } + // through down + } + tok = this.parseAtom(); + ch = this.read(); + switch (ch) { + case T_STAR: return this.processStar(tok); + case T_PLUS: return this.processPlus(tok); + case T_QUESTION: return this.processQuestion(tok); + case T_CHAR: + if (this.chardata == '{' && this.offset < this.regexlen) { + + int off = this.offset; // this.offset -> next of '{' + int min = 0, max = -1; + + if ((ch = this.regex.charAt(off++)) >= '0' && ch <= '9') { + + min = ch -'0'; + while (off < this.regexlen + && (ch = this.regex.charAt(off++)) >= '0' && ch <= '9') { + min = min*10 +ch-'0'; + if (min < 0) + throw ex("parser.quantifier.5", this.offset); + } + } + else { + throw ex("parser.quantifier.1", this.offset); + } + + max = min; + if (ch == ',') { + + if (off >= this.regexlen) { + throw ex("parser.quantifier.3", this.offset); + } + else if ((ch = this.regex.charAt(off++)) >= '0' && ch <= '9') { + + max = ch -'0'; // {min,max} + while (off < this.regexlen + && (ch = this.regex.charAt(off++)) >= '0' + && ch <= '9') { + max = max*10 +ch-'0'; + if (max < 0) + throw ex("parser.quantifier.5", this.offset); + } + + if (min > max) + throw ex("parser.quantifier.4", this.offset); + } + else { // assume {min,} + max = -1; + } + } + + if (ch != '}') + throw ex("parser.quantifier.2", this.offset); + + if (this.checkQuestion(off)) { // off -> next of '}' + tok = Token.createNGClosure(tok); + this.offset = off+1; + } else { + tok = Token.createClosure(tok); + this.offset = off; + } + + tok.setMin(min); + tok.setMax(max); + //System.err.println("CLOSURE: "+min+", "+max); + this.next(); + } + } + return tok; + } + + /** + * atom ::= char | '.' | char-class | '(' regex ')' | '(?:' regex ')' | '\' [0-9] + * | '\w' | '\W' | '\d' | '\D' | '\s' | '\S' | category-block + * | '(?>' regex ')' + * char ::= '\\' | '\' [efnrt] | bmp-code | character-1 + */ + Token parseAtom() throws ParseException { + int ch = this.read(); + Token tok = null; + switch (ch) { + case T_LPAREN: return this.processParen(); + case T_LPAREN2: return this.processParen2(); // '(?:' + case T_CONDITION: return this.processCondition(); // '(?(' + case T_MODIFIERS: return this.processModifiers(); // (?modifiers ... ) + case T_INDEPENDENT: return this.processIndependent(); + case T_DOT: + this.next(); // Skips '.' + tok = Token.token_dot; + break; + + /** + * char-class ::= '[' ( '^'? range ','?)+ ']' + * range ::= '\d' | '\w' | '\s' | category-block | range-char + * | range-char '-' range-char + * range-char ::= '\[' | '\]' | '\\' | '\' [,-efnrtv] | bmp-code | character-2 + * bmp-char ::= '\' 'u' [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] + */ + case T_LBRACKET: return this.parseCharacterClass(true); + case T_SET_OPERATIONS: return this.parseSetOperations(); + + case T_BACKSOLIDUS: + switch (this.chardata) { + case 'd': case 'D': + case 'w': case 'W': + case 's': case 'S': + tok = this.getTokenForShorthand(this.chardata); + this.next(); + return tok; + + case 'e': case 'f': case 'n': case 'r': + case 't': case 'u': case 'v': case 'x': + { + int ch2 = this.decodeEscaped(); + if (ch2 < 0x10000) { + tok = Token.createChar(ch2); + } else { + tok = Token.createString(REUtil.decomposeToSurrogates(ch2)); + } + } + break; + + case 'c': return this.processBacksolidus_c(); + case 'C': return this.processBacksolidus_C(); + case 'i': return this.processBacksolidus_i(); + case 'I': return this.processBacksolidus_I(); + case 'g': return this.processBacksolidus_g(); + case 'X': return this.processBacksolidus_X(); + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return this.processBackreference(); + + case 'P': + case 'p': + int pstart = this.offset; + tok = processBacksolidus_pP(this.chardata); + if (tok == null) throw this.ex("parser.atom.5", pstart); + break; + + default: + tok = Token.createChar(this.chardata); + } + this.next(); + break; + + case T_CHAR: + if (this.chardata == ']' || this.chardata == '{' || this.chardata == '}') + throw this.ex("parser.atom.4", this.offset-1); + tok = Token.createChar(this.chardata); + int high = this.chardata; + this.next(); + if (REUtil.isHighSurrogate(high) + && this.read() == T_CHAR && REUtil.isLowSurrogate(this.chardata)) { + char[] sur = new char[2]; + sur[0] = (char)high; + sur[1] = (char)this.chardata; + tok = Token.createParen(Token.createString(new String(sur)), 0); + this.next(); + } + break; + + default: + throw this.ex("parser.atom.4", this.offset-1); + } + return tok; + } + + protected RangeToken processBacksolidus_pP(int c) throws ParseException { + + this.next(); + if (this.read() != T_CHAR || this.chardata != '{') + throw this.ex("parser.atom.2", this.offset-1); + + // handle category escape + boolean positive = c == 'p'; + int namestart = this.offset; + int nameend = this.regex.indexOf('}', namestart); + + if (nameend < 0) + throw this.ex("parser.atom.3", this.offset); + + String pname = this.regex.substring(namestart, nameend); + this.offset = nameend+1; + + return Token.getRange(pname, positive, this.isSet(RegularExpression.XMLSCHEMA_MODE)); + } + + int processCIinCharacterClass(RangeToken tok, int c) { + return this.decodeEscaped(); + } + + /** + * char-class ::= '[' ( '^'? range ','?)+ ']' + * range ::= '\d' | '\w' | '\s' | category-block | range-char + * | range-char '-' range-char + * range-char ::= '\[' | '\]' | '\\' | '\' [,-efnrtv] | bmp-code | character-2 + * bmp-code ::= '\' 'u' [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] + */ + protected RangeToken parseCharacterClass(boolean useNrange) throws ParseException { + this.setContext(S_INBRACKETS); + this.next(); // '[' + boolean nrange = false; + RangeToken base = null; + RangeToken tok; + if (this.read() == T_CHAR && this.chardata == '^') { + nrange = true; + this.next(); // '^' + if (useNrange) { + tok = Token.createNRange(); + } else { + base = Token.createRange(); + base.addRange(0, Token.UTF16_MAX); + tok = Token.createRange(); + } + } else { + tok = Token.createRange(); + } + int type; + boolean firstloop = true; + while ((type = this.read()) != T_EOF) { + if (type == T_CHAR && this.chardata == ']' && !firstloop) + break; + int c = this.chardata; + boolean end = false; + if (type == T_BACKSOLIDUS) { + switch (c) { + case 'd': case 'D': + case 'w': case 'W': + case 's': case 'S': + tok.mergeRanges(this.getTokenForShorthand(c)); + end = true; + break; + + case 'i': case 'I': + case 'c': case 'C': + c = this.processCIinCharacterClass(tok, c); + if (c < 0) end = true; + break; + + case 'p': + case 'P': + int pstart = this.offset; + RangeToken tok2 = this.processBacksolidus_pP(c); + if (tok2 == null) throw this.ex("parser.atom.5", pstart); + tok.mergeRanges(tok2); + end = true; + break; + + default: + c = this.decodeEscaped(); + } // \ + c + } // backsolidus + // POSIX Character class such as [:alnum:] + else if (type == T_POSIX_CHARCLASS_START) { + int nameend = this.regex.indexOf(':', this.offset); + if (nameend < 0) throw this.ex("parser.cc.1", this.offset); + boolean positive = true; + if (this.regex.charAt(this.offset) == '^') { + this.offset ++; + positive = false; + } + String name = this.regex.substring(this.offset, nameend); + RangeToken range = Token.getRange(name, positive, + this.isSet(RegularExpression.XMLSCHEMA_MODE)); + if (range == null) throw this.ex("parser.cc.3", this.offset); + tok.mergeRanges(range); + end = true; + if (nameend+1 >= this.regexlen || this.regex.charAt(nameend+1) != ']') + throw this.ex("parser.cc.1", nameend); + this.offset = nameend+2; + } + else if (type == T_XMLSCHEMA_CC_SUBTRACTION && !firstloop) { + if (nrange) { + nrange = false; + if (useNrange) { + tok = (RangeToken) Token.complementRanges(tok); + } + else { + base.subtractRanges(tok); + tok = base; + } + } + RangeToken range2 = this.parseCharacterClass(false); + tok.subtractRanges(range2); + if (this.read() != T_CHAR || this.chardata != ']') { + throw this.ex("parser.cc.5", this.offset); + } + break; // Exit this loop + } + this.next(); + if (!end) { // if not shorthands... + if (this.read() != T_CHAR || this.chardata != '-') { // Here is no '-'. + if (!this.isSet(RegularExpression.IGNORE_CASE) || c > 0xffff) { + tok.addRange(c, c); + } + else { + addCaseInsensitiveChar(tok, c); + } + } + else if (type == T_XMLSCHEMA_CC_SUBTRACTION) { + throw this.ex("parser.cc.8", this.offset-1); + } + else { + this.next(); // Skips '-' + if ((type = this.read()) == T_EOF) throw this.ex("parser.cc.2", this.offset); + if (type == T_CHAR && this.chardata == ']') { + if (!this.isSet(RegularExpression.IGNORE_CASE) || c > 0xffff) { + tok.addRange(c, c); + } + else { + addCaseInsensitiveChar(tok, c); + } + tok.addRange('-', '-'); + } else { + int rangeend = this.chardata; + if (type == T_BACKSOLIDUS) { + rangeend = this.decodeEscaped(); + } + this.next(); + if (c > rangeend) { + throw this.ex("parser.ope.3", this.offset-1); + } + if (!this.isSet(RegularExpression.IGNORE_CASE) || + (c > 0xffff && rangeend > 0xffff)) { + tok.addRange(c, rangeend); + } + else { + addCaseInsensitiveCharRange(tok, c, rangeend); + } + } + } + } + if (this.isSet(RegularExpression.SPECIAL_COMMA) + && this.read() == T_CHAR && this.chardata == ',') { + this.next(); + } + firstloop = false; + } + if (this.read() == T_EOF) { + throw this.ex("parser.cc.2", this.offset); + } + + if (!useNrange && nrange) { + base.subtractRanges(tok); + tok = base; + } + tok.sortRanges(); + tok.compactRanges(); + this.setContext(S_NORMAL); + this.next(); // Skips ']' + + return tok; + } + + /** + * '(?[' ... ']' (('-' | '+' | '&') '[' ... ']')? ')' + */ + protected RangeToken parseSetOperations() throws ParseException { + RangeToken tok = this.parseCharacterClass(false); + int type; + while ((type = this.read()) != T_RPAREN) { + int ch = this.chardata; + if (type == T_CHAR && (ch == '-' || ch == '&') + || type == T_PLUS) { + this.next(); + if (this.read() != T_LBRACKET) throw ex("parser.ope.1", this.offset-1); + RangeToken t2 = this.parseCharacterClass(false); + if (type == T_PLUS) + tok.mergeRanges(t2); + else if (ch == '-') + tok.subtractRanges(t2); + else if (ch == '&') + tok.intersectRanges(t2); + else + throw new RuntimeException("ASSERT"); + } else { + throw ex("parser.ope.2", this.offset-1); + } + } + this.next(); + return tok; + } + + Token getTokenForShorthand(int ch) { + Token tok; + switch (ch) { + case 'd': + tok = this.isSet(RegularExpression.USE_UNICODE_CATEGORY) + ? Token.getRange("Nd", true) : Token.token_0to9; + break; + case 'D': + tok = this.isSet(RegularExpression.USE_UNICODE_CATEGORY) + ? Token.getRange("Nd", false) : Token.token_not_0to9; + break; + case 'w': + tok = this.isSet(RegularExpression.USE_UNICODE_CATEGORY) + ? Token.getRange("IsWord", true) : Token.token_wordchars; + break; + case 'W': + tok = this.isSet(RegularExpression.USE_UNICODE_CATEGORY) + ? Token.getRange("IsWord", false) : Token.token_not_wordchars; + break; + case 's': + tok = this.isSet(RegularExpression.USE_UNICODE_CATEGORY) + ? Token.getRange("IsSpace", true) : Token.token_spaces; + break; + case 'S': + tok = this.isSet(RegularExpression.USE_UNICODE_CATEGORY) + ? Token.getRange("IsSpace", false) : Token.token_not_spaces; + break; + + default: + throw new RuntimeException("Internal Error: shorthands: \\u"+Integer.toString(ch, 16)); + } + return tok; + } + + /** + */ + int decodeEscaped() throws ParseException { + if (this.read() != T_BACKSOLIDUS) throw ex("parser.next.1", this.offset-1); + int c = this.chardata; + switch (c) { + case 'e': c = 0x1b; break; // ESCAPE U+001B + case 'f': c = '\f'; break; // FORM FEED U+000C + case 'n': c = '\n'; break; // LINE FEED U+000A + case 'r': c = '\r'; break; // CRRIAGE RETURN U+000D + case 't': c = '\t'; break; // HORIZONTAL TABULATION U+0009 + //case 'v': c = 0x0b; break; // VERTICAL TABULATION U+000B + case 'x': + this.next(); + if (this.read() != T_CHAR) throw ex("parser.descape.1", this.offset-1); + if (this.chardata == '{') { + int v1 = 0; + int uv = 0; + do { + this.next(); + if (this.read() != T_CHAR) throw ex("parser.descape.1", this.offset-1); + if ((v1 = hexChar(this.chardata)) < 0) + break; + if (uv > uv*16) throw ex("parser.descape.2", this.offset-1); + uv = uv*16+v1; + } while (true); + if (this.chardata != '}') throw ex("parser.descape.3", this.offset-1); + if (uv > Token.UTF16_MAX) throw ex("parser.descape.4", this.offset-1); + c = uv; + } else { + int v1 = 0; + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + int uv = v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + c = uv; + } + break; + + case 'u': + int v1 = 0; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + int uv = v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + c = uv; + break; + + case 'v': + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + this.next(); + if (this.read() != T_CHAR || (v1 = hexChar(this.chardata)) < 0) + throw ex("parser.descape.1", this.offset-1); + uv = uv*16+v1; + if (uv > Token.UTF16_MAX) throw ex("parser.descappe.4", this.offset-1); + c = uv; + break; + case 'A': + case 'Z': + case 'z': + throw ex("parser.descape.5", this.offset-2); + default: + } + return c; + } + + static private final int hexChar(int ch) { + if (ch < '0') return -1; + if (ch > 'f') return -1; + if (ch <= '9') return ch-'0'; + if (ch < 'A') return -1; + if (ch <= 'F') return ch-'A'+10; + if (ch < 'a') return -1; + return ch-'a'+10; + } + + static protected final void addCaseInsensitiveChar(RangeToken tok, int c) { + final int[] caseMap = CaseInsensitiveMap.get(c); + tok.addRange(c, c); + + if (caseMap != null) { + for (int i=0; i + *

How to use

+ * + *
+ *
A. Standard way + *
+ *
+ * RegularExpression re = new RegularExpression(regex);
+ * if (re.matches(text)) { ... }
+ * 
+ * + *
B. Capturing groups + *
+ *
+ * RegularExpression re = new RegularExpression(regex);
+ * Match match = new Match();
+ * if (re.matches(text, match)) {
+ *     ... // You can refer captured texts with methods of the Match class.
+ * }
+ * 
+ * + *
+ * + *

Case-insensitive matching

+ *
+ * RegularExpression re = new RegularExpression(regex, "i");
+ * if (re.matches(text) >= 0) { ...}
+ * 
+ * + *

Options

+ *

You can specify options to RegularExpression(regex, options) + * or setPattern(regex, options). + * This options parameter consists of the following characters. + *

+ *
+ *
"i" + *
This option indicates case-insensitive matching. + *
"m" + *
^ and $ consider the EOL characters within the text. + *
"s" + *
. matches any one character. + *
"u" + *
Redefines \d \D \w \W \s \S \b \B \< \> as becoming to Unicode. + *
"w" + *
By this option, \b \B \< \> are processed with the method of + * 'Unicode Regular Expression Guidelines' Revision 4. + * When "w" and "u" are specified at the same time, + * \b \B \< \> are processed for the "w" option. + *
"," + *
The parser treats a comma in a character class as a range separator. + * [a,b] matches a or , or b without this option. + * [a,b] matches a or b with this option. + * + *
"X" + *
+ * By this option, the engine confoms to XML Schema: Regular Expression. + * The match() method does not do subsring matching + * but entire string matching. + * + *
+ * + *
+ *

Syntax

+ * + * + * + * + *
+ *

Differences from the Perl 5 regular expression

+ *
    + *
  • There is 6-digit hexadecimal character representation (\u005cvHHHHHH.) + *
  • Supports subtraction, union, and intersection operations for character classes. + *
  • Not supported: \ooo (Octal character representations), + * \G, \C, \lc, + * \u005c uc, \L, \U, + * \E, \Q, \N{name}, + * (?{code}), (??{code}) + *
+ *
+ * + *

Meta characters are `. * + ? { [ ( ) | \ ^ $'.

+ *
    + *
  • Character + *
    + *
    . (A period) + *
    Matches any one character except the following characters. + *
    LINE FEED (U+000A), CARRIAGE RETURN (U+000D), + * PARAGRAPH SEPARATOR (U+2029), LINE SEPARATOR (U+2028) + *
    This expression matches one code point in Unicode. It can match a pair of surrogates. + *
    When the "s" option is specified, + * it matches any character including the above four characters. + * + *
    \e \f \n \r \t + *
    Matches ESCAPE (U+001B), FORM FEED (U+000C), LINE FEED (U+000A), + * CARRIAGE RETURN (U+000D), HORIZONTAL TABULATION (U+0009) + * + *
    \cC + *
    Matches a control character. + * The C must be one of '@', 'A'-'Z', + * '[', '\u005c', ']', '^', '_'. + * It matches a control character of which the character code is less than + * the character code of the C by 0x0040. + *
    For example, a \cJ matches a LINE FEED (U+000A), + * and a \c[ matches an ESCAPE (U+001B). + * + *
    a non-meta character + *
    Matches the character. + * + *
    \ + a meta character + *
    Matches the meta character. + * + *
    \u005cxHH \u005cx{HHHH} + *
    Matches a character of which code point is HH (Hexadecimal) in Unicode. + * You can write just 2 digits for \u005cxHH, and + * variable length digits for \u005cx{HHHH}. + * + * + * + *
    \u005cvHHHHHH + *
    Matches a character of which code point is HHHHHH (Hexadecimal) in Unicode. + * + *
    \g + *
    Matches a grapheme. + *
    It is equivalent to (?[\p{ASSIGNED}]-[\p{M}\p{C}])?(?:\p{M}|[\x{094D}\x{09CD}\x{0A4D}\x{0ACD}\x{0B3D}\x{0BCD}\x{0C4D}\x{0CCD}\x{0D4D}\x{0E3A}\x{0F84}]\p{L}|[\x{1160}-\x{11A7}]|[\x{11A8}-\x{11FF}]|[\x{FF9E}\x{FF9F}])* + * + *
    \X + *
    Matches a combining character sequence. + * It is equivalent to (?:\PM\pM*) + *
    + *
  • + * + *
  • Character class + *
    ++ *
    [R1R2...Rn] (without "," option) ++ *
    [R1,R2,...,Rn] (with "," option) + *
    Positive character class. It matches a character in ranges. + *
    Rn: + *
      + *
    • A character (including \e \f \n \r \t \u005cxHH \u005cx{HHHH} \u005cvHHHHHH) + *

      This range matches the character. + *

    • C1-C2 + *

      This range matches a character which has a code point that is >= C1's code point and <= C2's code point. ++ *

    • A POSIX character class: [:alpha:] [:alnum:] [:ascii:] [:cntrl:] [:digit:] [:graph:] [:lower:] [:print:] [:punct:] [:space:] [:upper:] [:xdigit:], ++ * and negative POSIX character classes in Perl like [:^alpha:] + *

      ... + *

    • \d \D \s \S \w \W \p{name} \P{name} + *

      These expressions specifies the same ranges as the following expressions. + *

    + *

    Enumerated ranges are merged (union operation). + * [a-ec-z] is equivalent to [a-z] + * + *

    [^R1R2...Rn] (without a "," option) + *
    [^R1,R2,...,Rn] (with a "," option) + *
    Negative character class. It matches a character not in ranges. + * + *
    (?[ranges]op[ranges]op[ranges] ... ) + * (op is - or + or &.) + *
    Subtraction or union or intersection for character classes. + *
    For exmaple, (?[A-Z]-[CF]) is equivalent to [A-BD-EG-Z], and (?[0x00-0x7f]-[K]&[\p{Lu}]) is equivalent to [A-JL-Z]. + *
    The result of this operations is a positive character class + * even if an expression includes any negative character classes. + * You have to take care on this in case-insensitive matching. + * For instance, (?[^b]) is equivalent to [\x00-ac-\x{10ffff}], + * which is equivalent to [^b] in case-sensitive matching. + * But, in case-insensitive matching, (?[^b]) matches any character because + * it includes 'B' and 'B' matches 'b' + * though [^b] is processed as [^Bb]. + * + *
    [R1R2...-[RnRn+1...]] (with an "X" option)
    + *
    Character class subtraction for the XML Schema. + * You can use this syntax when you specify an "X" option. + * + *
    \d + *
    Equivalent to [0-9]. + *
    When a "u" option is set, it is equivalent to + * \p{Nd}. + * + *
    \D + *
    Equivalent to [^0-9] + *
    When a "u" option is set, it is equivalent to + * \P{Nd}. + * + *
    \s + *
    Equivalent to [ \f\n\r\t] + *
    When a "u" option is set, it is equivalent to + * [ \f\n\r\t\p{Z}]. + * + *
    \S + *
    Equivalent to [^ \f\n\r\t] + *
    When a "u" option is set, it is equivalent to + * [^ \f\n\r\t\p{Z}]. + * + *
    \w + *
    Equivalent to [a-zA-Z0-9_] + *
    When a "u" option is set, it is equivalent to + * [\p{Lu}\p{Ll}\p{Lo}\p{Nd}_]. + * + *
    \W + *
    Equivalent to [^a-zA-Z0-9_] + *
    When a "u" option is set, it is equivalent to + * [^\p{Lu}\p{Ll}\p{Lo}\p{Nd}_]. + * + *
    \p{name} + *
    Matches one character in the specified General Category (the second field in UnicodeData.txt) or the specified Block. + * The following names are available: + *
    + *
    Unicode General Categories: + *
    + * L, M, N, Z, C, P, S, Lu, Ll, Lt, Lm, Lo, Mn, Me, Mc, Nd, Nl, No, Zs, Zl, Zp, + * Cc, Cf, Cn, Co, Cs, Pd, Ps, Pe, Pc, Po, Sm, Sc, Sk, So, + * + *
    (Currently the Cn category includes U+10000-U+10FFFF characters) + *
    Unicode Blocks: + *
    + * Basic Latin, Latin-1 Supplement, Latin Extended-A, Latin Extended-B, + * IPA Extensions, Spacing Modifier Letters, Combining Diacritical Marks, Greek, + * Cyrillic, Armenian, Hebrew, Arabic, Devanagari, Bengali, Gurmukhi, Gujarati, + * Oriya, Tamil, Telugu, Kannada, Malayalam, Thai, Lao, Tibetan, Georgian, + * Hangul Jamo, Latin Extended Additional, Greek Extended, General Punctuation, + * Superscripts and Subscripts, Currency Symbols, Combining Marks for Symbols, + * Letterlike Symbols, Number Forms, Arrows, Mathematical Operators, + * Miscellaneous Technical, Control Pictures, Optical Character Recognition, + * Enclosed Alphanumerics, Box Drawing, Block Elements, Geometric Shapes, + * Miscellaneous Symbols, Dingbats, CJK Symbols and Punctuation, Hiragana, + * Katakana, Bopomofo, Hangul Compatibility Jamo, Kanbun, + * Enclosed CJK Letters and Months, CJK Compatibility, CJK Unified Ideographs, + * Hangul Syllables, High Surrogates, High Private Use Surrogates, Low Surrogates, + * Private Use, CJK Compatibility Ideographs, Alphabetic Presentation Forms, + * Arabic Presentation Forms-A, Combining Half Marks, CJK Compatibility Forms, + * Small Form Variants, Arabic Presentation Forms-B, Specials, + * Halfwidth and Fullwidth Forms + * + *
    Others: + *
    ALL (Equivalent to [\u005cu0000-\u005cv10FFFF]) + *
    ASSGINED (\p{ASSIGNED} is equivalent to \P{Cn}) + *
    UNASSGINED + * (\p{UNASSIGNED} is equivalent to \p{Cn}) + *
    + * + *
    \P{name} + *
    Matches one character not in the specified General Category or the specified Block. + *
    + *
  • + * + *
  • Selection and Quantifier + *
    + *
    X|Y + *
    ... + * + *
    X* + *
    Matches 0 or more X. + * + *
    X+ + *
    Matches 1 or more X. + * + *
    X? + *
    Matches 0 or 1 X. + * + *
    X{number} + *
    Matches number times. + * + *
    X{min,} + *
    ... + * + *
    X{min,max} + *
    ... + * + *
    X*? + *
    X+? + *
    X?? + *
    X{min,}? + *
    X{min,max}? + *
    Non-greedy matching. + *
    + *
  • + * + *
  • Grouping, Capturing, and Back-reference + *
    + *
    (?:X) + *
    Grouping. "foo+" matches "foo" or "foooo". + * If you want it matches "foofoo" or "foofoofoo", + * you have to write "(?:foo)+". + * + *
    (X) + *
    Grouping with capturing. + * It make a group and applications can know + * where in target text a group matched with methods of a Match instance + * after matches(String,Match). + * The 0th group means whole of this regular expression. + * The Nth gorup is the inside of the Nth left parenthesis. + * + *

    For instance, a regular expression is + * " *([^<:]*) +<([^>]*)> *" + * and target text is + * "From: TAMURA Kent <kent@trl.ibm.co.jp>": + *

      + *
    • Match.getCapturedText(0): + * " TAMURA Kent <kent@trl.ibm.co.jp>" + *
    • Match.getCapturedText(1): "TAMURA Kent" + *
    • Match.getCapturedText(2): "kent@trl.ibm.co.jp" + *
    + * + *
    \1 \2 \3 \4 \5 \6 \7 \8 \9 + *
    + * + *
    (?>X) + *
    Independent expression group. ................ + * + *
    (?options:X) + *
    (?options-options2:X) + *
    ............................ + *
    The options or the options2 consists of 'i' 'm' 's' 'w'. + * Note that it can not contain 'u'. + * + *
    (?options) + *
    (?options-options2) + *
    ...... + *
    These expressions must be at the beginning of a group. + *
    + *
  • + * + *
  • Anchor + *
    + *
    \A + *
    Matches the beginnig of the text. + * + *
    \Z + *
    Matches the end of the text, or before an EOL character at the end of the text, + * or CARRIAGE RETURN + LINE FEED at the end of the text. + * + *
    \z + *
    Matches the end of the text. + * + *
    ^ + *
    Matches the beginning of the text. It is equivalent to \A. + *
    When a "m" option is set, + * it matches the beginning of the text, or after one of EOL characters ( + * LINE FEED (U+000A), CARRIAGE RETURN (U+000D), LINE SEPARATOR (U+2028), + * PARAGRAPH SEPARATOR (U+2029).) + * + *
    $ + *
    Matches the end of the text, or before an EOL character at the end of the text, + * or CARRIAGE RETURN + LINE FEED at the end of the text. + *
    When a "m" option is set, + * it matches the end of the text, or before an EOL character. + * + *
    \b + *
    Matches word boundary. + * (See a "w" option) + * + *
    \B + *
    Matches non word boundary. + * (See a "w" option) + * + *
    \< + *
    Matches the beginning of a word. + * (See a "w" option) + * + *
    \> + *
    Matches the end of a word. + * (See a "w" option) + *
    + *
  • + *
  • Lookahead and lookbehind + *
    + *
    (?=X) + *
    Lookahead. + * + *
    (?!X) + *
    Negative lookahead. + * + *
    (?<=X) + *
    Lookbehind. + *
    (Note for text capturing......) + * + *
    (?<!X) + *
    Negative lookbehind. + *
    + *
  • + * + *
  • Misc. + *
    + *
    (?(condition)yes-pattern|no-pattern), + *
    (?(condition)yes-pattern) + *
    ...... + *
    (?#comment) + *
    Comment. A comment string consists of characters except ')'. + * You can not write comments in character classes and before quantifiers. + *
    + *
  • + *
+ * + * + *
+ *

BNF for the regular expression

+ *
+ * regex ::= ('(?' options ')')? term ('|' term)*
+ * term ::= factor+
+ * factor ::= anchors | atom (('*' | '+' | '?' | minmax ) '?'? )?
+ *            | '(?#' [^)]* ')'
+ * minmax ::= '{' ([0-9]+ | [0-9]+ ',' | ',' [0-9]+ | [0-9]+ ',' [0-9]+) '}'
+ * atom ::= char | '.' | char-class | '(' regex ')' | '(?:' regex ')' | '\' [0-9]
+ *          | '\w' | '\W' | '\d' | '\D' | '\s' | '\S' | category-block | '\X'
+ *          | '(?>' regex ')' | '(?' options ':' regex ')'
+ *          | '(?' ('(' [0-9] ')' | '(' anchors ')' | looks) term ('|' term)? ')'
+ * options ::= [imsw]* ('-' [imsw]+)?
+ * anchors ::= '^' | '$' | '\A' | '\Z' | '\z' | '\b' | '\B' | '\<' | '\>'
+ * looks ::= '(?=' regex ')'  | '(?!' regex ')'
+ *           | '(?<=' regex ')' | '(?<!' regex ')'
+ * char ::= '\\' | '\' [efnrtv] | '\c' [@-_] | code-point | character-1
+ * category-block ::= '\' [pP] category-symbol-1
+ *                    | ('\p{' | '\P{') (category-symbol | block-name
+ *                                       | other-properties) '}'
+ * category-symbol-1 ::= 'L' | 'M' | 'N' | 'Z' | 'C' | 'P' | 'S'
+ * category-symbol ::= category-symbol-1 | 'Lu' | 'Ll' | 'Lt' | 'Lm' | Lo'
+ *                     | 'Mn' | 'Me' | 'Mc' | 'Nd' | 'Nl' | 'No'
+ *                     | 'Zs' | 'Zl' | 'Zp' | 'Cc' | 'Cf' | 'Cn' | 'Co' | 'Cs'
+ *                     | 'Pd' | 'Ps' | 'Pe' | 'Pc' | 'Po'
+ *                     | 'Sm' | 'Sc' | 'Sk' | 'So'
+ * block-name ::= (See above)
+ * other-properties ::= 'ALL' | 'ASSIGNED' | 'UNASSIGNED'
+ * character-1 ::= (any character except meta-characters)
+ *
+ * char-class ::= '[' ranges ']'
+ *                | '(?[' ranges ']' ([-+&] '[' ranges ']')? ')'
+ * ranges ::= '^'? (range ','?)+
+ * range ::= '\d' | '\w' | '\s' | '\D' | '\W' | '\S' | category-block
+ *           | range-char | range-char '-' range-char
+ * range-char ::= '\[' | '\]' | '\\' | '\' [,-efnrtv] | code-point | character-2
+ * code-point ::= '\x' hex-char hex-char
+ *                | '\x{' hex-char+ '}'
+ *                | '\v' hex-char hex-char hex-char hex-char hex-char hex-char
+ * hex-char ::= [0-9a-fA-F]
+ * character-2 ::= (any character except \[]-,)
+ * 
+ * + *
+ *

TODO

+ * + * + *
+ * + * @xerces.internal + * + * @author TAMURA Kent <kent@trl.ibm.co.jp> + * @version $Id$ + */ +public class RegularExpression implements java.io.Serializable { + + private static final long serialVersionUID = 6242499334195006401L; + + static final boolean DEBUG = false; + + /** + * Compiles a token tree into an operation flow. + */ + private synchronized void compile(Token tok) { + if (this.operations != null) + return; + this.numberOfClosures = 0; + this.operations = this.compile(tok, null, false); + } + + /** + * Converts a token to an operation. + */ + private Op compile(Token tok, Op next, boolean reverse) { + Op ret; + switch (tok.type) { + case Token.DOT: + ret = Op.createDot(); + ret.next = next; + break; + + case Token.CHAR: + ret = Op.createChar(tok.getChar()); + ret.next = next; + break; + + case Token.ANCHOR: + ret = Op.createAnchor(tok.getChar()); + ret.next = next; + break; + + case Token.RANGE: + case Token.NRANGE: + ret = Op.createRange(tok); + ret.next = next; + break; + + case Token.CONCAT: + ret = next; + if (!reverse) { + for (int i = tok.size()-1; i >= 0; i --) { + ret = compile(tok.getChild(i), ret, false); + } + } else { + for (int i = 0; i < tok.size(); i ++) { + ret = compile(tok.getChild(i), ret, true); + } + } + break; + + case Token.UNION: + Op.UnionOp uni = Op.createUnion(tok.size()); + for (int i = 0; i < tok.size(); i ++) { + uni.addElement(compile(tok.getChild(i), next, reverse)); + } + ret = uni; // ret.next is null. + break; + + case Token.CLOSURE: + case Token.NONGREEDYCLOSURE: + Token child = tok.getChild(0); + int min = tok.getMin(); + int max = tok.getMax(); + if (min >= 0 && min == max) { // {n} + ret = next; + for (int i = 0; i < min; i ++) { + ret = compile(child, ret, reverse); + } + break; + } + if (min > 0 && max > 0) + max -= min; + if (max > 0) { + // X{2,6} -> XX(X(X(XX?)?)?)? + ret = next; + for (int i = 0; i < max; i ++) { + Op.ChildOp q = Op.createQuestion(tok.type == Token.NONGREEDYCLOSURE); + q.next = next; + q.setChild(compile(child, ret, reverse)); + ret = q; + } + } else { + Op.ChildOp op; + if (tok.type == Token.NONGREEDYCLOSURE) { + op = Op.createNonGreedyClosure(); + } else { // Token.CLOSURE + op = Op.createClosure(this.numberOfClosures++); + } + op.next = next; + op.setChild(compile(child, op, reverse)); + ret = op; + } + if (min > 0) { + for (int i = 0; i < min; i ++) { + ret = compile(child, ret, reverse); + } + } + break; + + case Token.EMPTY: + ret = next; + break; + + case Token.STRING: + ret = Op.createString(tok.getString()); + ret.next = next; + break; + + case Token.BACKREFERENCE: + ret = Op.createBackReference(tok.getReferenceNumber()); + ret.next = next; + break; + + case Token.PAREN: + if (tok.getParenNumber() == 0) { + ret = compile(tok.getChild(0), next, reverse); + } else if (reverse) { + next = Op.createCapture(tok.getParenNumber(), next); + next = compile(tok.getChild(0), next, reverse); + ret = Op.createCapture(-tok.getParenNumber(), next); + } else { + next = Op.createCapture(-tok.getParenNumber(), next); + next = compile(tok.getChild(0), next, reverse); + ret = Op.createCapture(tok.getParenNumber(), next); + } + break; + + case Token.LOOKAHEAD: + ret = Op.createLook(Op.LOOKAHEAD, next, compile(tok.getChild(0), null, false)); + break; + case Token.NEGATIVELOOKAHEAD: + ret = Op.createLook(Op.NEGATIVELOOKAHEAD, next, compile(tok.getChild(0), null, false)); + break; + case Token.LOOKBEHIND: + ret = Op.createLook(Op.LOOKBEHIND, next, compile(tok.getChild(0), null, true)); + break; + case Token.NEGATIVELOOKBEHIND: + ret = Op.createLook(Op.NEGATIVELOOKBEHIND, next, compile(tok.getChild(0), null, true)); + break; + + case Token.INDEPENDENT: + ret = Op.createIndependent(next, compile(tok.getChild(0), null, reverse)); + break; + + case Token.MODIFIERGROUP: + ret = Op.createModifier(next, compile(tok.getChild(0), null, reverse), + ((Token.ModifierToken)tok).getOptions(), + ((Token.ModifierToken)tok).getOptionsMask()); + break; + + case Token.CONDITION: + Token.ConditionToken ctok = (Token.ConditionToken)tok; + int ref = ctok.refNumber; + Op condition = ctok.condition == null ? null : compile(ctok.condition, null, reverse); + Op yes = compile(ctok.yes, next, reverse); + Op no = ctok.no == null ? null : compile(ctok.no, next, reverse); + ret = Op.createCondition(next, ref, condition, yes, no); + break; + + default: + throw new RuntimeException("Unknown token type: "+tok.type); + } // switch (tok.type) + return ret; + } + + +//Public + + /** + * Checks whether the target text contains this pattern or not. + * + * @return true if the target is matched to this regular expression. + */ + public boolean matches(char[] target) { + return this.matches(target, 0, target .length , (Match)null); + } + + /** + * Checks whether the target text contains this pattern + * in specified range or not. + * + * @param start Start offset of the range. + * @param end End offset +1 of the range. + * @return true if the target is matched to this regular expression. + */ + public boolean matches(char[] target, int start, int end) { + return this.matches(target, start, end, (Match)null); + } + + /** + * Checks whether the target text contains this pattern or not. + * + * @param match A Match instance for storing matching result. + * @return Offset of the start position in target; or -1 if not match. + */ + public boolean matches(char[] target, Match match) { + return this.matches(target, 0, target .length , match); + } + + + /** + * Checks whether the target text contains this pattern + * in specified range or not. + * + * @param start Start offset of the range. + * @param end End offset +1 of the range. + * @param match A Match instance for storing matching result. + * @return Offset of the start position in target; or -1 if not match. + */ + public boolean matches(char[] target, int start, int end, Match match) { + + synchronized (this) { + if (this.operations == null) + this.prepare(); + if (this.context == null) + this.context = new Context(); + } + Context con = null; + synchronized (this.context) { + con = this.context.inuse ? new Context() : this.context; + con.reset(target, start, end, this.numberOfClosures); + } + if (match != null) { + match.setNumberOfGroups(this.nofparen); + match.setSource(target); + } else if (this.hasBackReferences) { + match = new Match(); + match.setNumberOfGroups(this.nofparen); + // Need not to call setSource() because + // a caller can not access this match instance. + } + con.match = match; + + if (RegularExpression.isSet(this.options, XMLSCHEMA_MODE)) { + int matchEnd = this. match(con, this.operations, con.start, 1, this.options); + //System.err.println("DEBUG: matchEnd="+matchEnd); + if (matchEnd == con.limit) { + if (con.match != null) { + con.match.setBeginning(0, con.start); + con.match.setEnd(0, matchEnd); + } + con.setInUse(false); + return true; + } + return false; + } + + /* + * The pattern has only fixed string. + * The engine uses Boyer-Moore. + */ + if (this.fixedStringOnly) { + //System.err.println("DEBUG: fixed-only: "+this.fixedString); + int o = this.fixedStringTable.matches(target, con.start, con.limit); + if (o >= 0) { + if (con.match != null) { + con.match.setBeginning(0, o); + con.match.setEnd(0, o+this.fixedString.length()); + } + con.setInUse(false); + return true; + } + con.setInUse(false); + return false; + } + + /* + * The pattern contains a fixed string. + * The engine checks with Boyer-Moore whether the text contains the fixed string or not. + * If not, it return with false. + */ + if (this.fixedString != null) { + int o = this.fixedStringTable.matches(target, con.start, con.limit); + if (o < 0) { + //System.err.println("Non-match in fixed-string search."); + con.setInUse(false); + return false; + } + } + + int limit = con.limit-this.minlength; + int matchStart; + int matchEnd = -1; + + /* + * Checks whether the expression starts with ".*". + */ + if (this.operations != null + && this.operations.type == Op.CLOSURE && this.operations.getChild().type == Op.DOT) { + if (isSet(this.options, SINGLE_LINE)) { + matchStart = con.start; + matchEnd = this. match(con, this.operations, con.start, 1, this.options); + } else { + boolean previousIsEOL = true; + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + int ch = target [ matchStart ] ; + if (isEOLChar(ch)) { + previousIsEOL = true; + } else { + if (previousIsEOL) { + if (0 <= (matchEnd = this. match(con, this.operations, + matchStart, 1, this.options))) + break; + } + previousIsEOL = false; + } + } + } + } + + /* + * Optimization against the first character. + */ + else if (this.firstChar != null) { + //System.err.println("DEBUG: with firstchar-matching: "+this.firstChar); + RangeToken range = this.firstChar; + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + int ch = target [matchStart] ; + if (REUtil.isHighSurrogate(ch) && matchStart+1 < con.limit) { + ch = REUtil.composeFromSurrogates(ch, target[matchStart+1]); + } + if (!range.match(ch)) { + continue; + } + if (0 <= (matchEnd = this. match(con, this.operations, + matchStart, 1, this.options))) { + break; + } + } + } + + /* + * Straightforward matching. + */ + else { + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + if (0 <= (matchEnd = this. match(con, this.operations, matchStart, 1, this.options))) + break; + } + } + + if (matchEnd >= 0) { + if (con.match != null) { + con.match.setBeginning(0, matchStart); + con.match.setEnd(0, matchEnd); + } + con.setInUse(false); + return true; + } else { + con.setInUse(false); + return false; + } + } + + /** + * Checks whether the target text contains this pattern or not. + * + * @return true if the target is matched to this regular expression. + */ + public boolean matches(String target) { + return this.matches(target, 0, target .length() , (Match)null); + } + + /** + * Checks whether the target text contains this pattern + * in specified range or not. + * + * @param start Start offset of the range. + * @param end End offset +1 of the range. + * @return true if the target is matched to this regular expression. + */ + public boolean matches(String target, int start, int end) { + return this.matches(target, start, end, (Match)null); + } + + /** + * Checks whether the target text contains this pattern or not. + * + * @param match A Match instance for storing matching result. + * @return Offset of the start position in target; or -1 if not match. + */ + public boolean matches(String target, Match match) { + return this.matches(target, 0, target .length() , match); + } + + /** + * Checks whether the target text contains this pattern + * in specified range or not. + * + * @param start Start offset of the range. + * @param end End offset +1 of the range. + * @param match A Match instance for storing matching result. + * @return Offset of the start position in target; or -1 if not match. + */ + public boolean matches(String target, int start, int end, Match match) { + + synchronized (this) { + if (this.operations == null) + this.prepare(); + if (this.context == null) + this.context = new Context(); + } + Context con = null; + synchronized (this.context) { + con = this.context.inuse ? new Context() : this.context; + con.reset(target, start, end, this.numberOfClosures); + } + if (match != null) { + match.setNumberOfGroups(this.nofparen); + match.setSource(target); + } else if (this.hasBackReferences) { + match = new Match(); + match.setNumberOfGroups(this.nofparen); + // Need not to call setSource() because + // a caller can not access this match instance. + } + con.match = match; + + if (RegularExpression.isSet(this.options, XMLSCHEMA_MODE)) { + if (DEBUG) { + System.err.println("target string="+target); + } + int matchEnd = this. match(con, this.operations, con.start, 1, this.options); + if (DEBUG) { + System.err.println("matchEnd="+matchEnd); + System.err.println("con.limit="+con.limit); + } + if (matchEnd == con.limit) { + if (con.match != null) { + con.match.setBeginning(0, con.start); + con.match.setEnd(0, matchEnd); + } + con.setInUse(false); + return true; + } + return false; + } + + /* + * The pattern has only fixed string. + * The engine uses Boyer-Moore. + */ + if (this.fixedStringOnly) { + //System.err.println("DEBUG: fixed-only: "+this.fixedString); + int o = this.fixedStringTable.matches(target, con.start, con.limit); + if (o >= 0) { + if (con.match != null) { + con.match.setBeginning(0, o); + con.match.setEnd(0, o+this.fixedString.length()); + } + con.setInUse(false); + return true; + } + con.setInUse(false); + return false; + } + + /* + * The pattern contains a fixed string. + * The engine checks with Boyer-Moore whether the text contains the fixed string or not. + * If not, it return with false. + */ + if (this.fixedString != null) { + int o = this.fixedStringTable.matches(target, con.start, con.limit); + if (o < 0) { + //System.err.println("Non-match in fixed-string search."); + con.setInUse(false); + return false; + } + } + + int limit = con.limit-this.minlength; + int matchStart; + int matchEnd = -1; + + /* + * Checks whether the expression starts with ".*". + */ + if (this.operations != null + && this.operations.type == Op.CLOSURE && this.operations.getChild().type == Op.DOT) { + if (isSet(this.options, SINGLE_LINE)) { + matchStart = con.start; + matchEnd = this.match(con, this.operations, con.start, 1, this.options); + } else { + boolean previousIsEOL = true; + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + int ch = target .charAt( matchStart ) ; + if (isEOLChar(ch)) { + previousIsEOL = true; + } else { + if (previousIsEOL) { + if (0 <= (matchEnd = this.match(con, this.operations, + matchStart, 1, this.options))) + break; + } + previousIsEOL = false; + } + } + } + } + + /* + * Optimization against the first character. + */ + else if (this.firstChar != null) { + //System.err.println("DEBUG: with firstchar-matching: "+this.firstChar); + RangeToken range = this.firstChar; + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + int ch = target .charAt( matchStart ) ; + if (REUtil.isHighSurrogate(ch) && matchStart+1 < con.limit) { + ch = REUtil.composeFromSurrogates(ch, target.charAt(matchStart+1)); + } + if (!range.match(ch)) { + continue; + } + if (0 <= (matchEnd = this.match(con, this.operations, + matchStart, 1, this.options))) { + break; + } + } + } + + /* + * Straightforward matching. + */ + else { + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + if (0 <= (matchEnd = this.match(con, this.operations, matchStart, 1, this.options))) + break; + } + } + + if (matchEnd >= 0) { + if (con.match != null) { + con.match.setBeginning(0, matchStart); + con.match.setEnd(0, matchEnd); + } + con.setInUse(false); + return true; + } else { + con.setInUse(false); + return false; + } + } + + /** + * @return -1 when not match; offset of the end of matched string when match. + */ + private int match(Context con, Op op, int offset, int dx, int opts) { + final ExpressionTarget target = con.target; + final Stack opStack = new Stack(); + final IntStack dataStack = new IntStack(); + final boolean isSetIgnoreCase = isSet(opts, IGNORE_CASE); + int retValue = -1; + boolean returned = false; + + for (;;) { + if (op == null || offset > con.limit || offset < con.start) { + if (op == null) { + retValue = isSet(opts, XMLSCHEMA_MODE) && offset != con.limit ? -1 : offset; + } + else { + retValue = -1; + } + returned = true; + } + else { + retValue = -1; + // dx value is either 1 or -1 + switch (op.type) { + case Op.CHAR: + { + final int o1 = (dx > 0) ? offset : offset -1; + if (o1 >= con.limit || o1 < 0 || !matchChar(op.getData(), target.charAt(o1), isSetIgnoreCase)) { + returned = true; + break; + } + offset += dx; + op = op.next; + } + break; + + case Op.DOT: + { + int o1 = (dx > 0) ? offset : offset - 1; + if (o1 >= con.limit || o1 < 0) { + returned = true; + break; + } + if (isSet(opts, SINGLE_LINE)) { + if (REUtil.isHighSurrogate(target.charAt(o1)) && o1+dx >= 0 && o1+dx < con.limit) { + o1 += dx; + } + } + else { + int ch = target.charAt(o1); + if (REUtil.isHighSurrogate(ch) && o1+dx >= 0 && o1+dx < con.limit) { + o1 += dx; + ch = REUtil.composeFromSurrogates(ch, target.charAt(o1)); + } + if (isEOLChar(ch)) { + returned = true; + break; + } + } + offset = (dx > 0) ? o1 + 1 : o1; + op = op.next; + } + break; + + case Op.RANGE: + case Op.NRANGE: + { + int o1 = (dx > 0) ? offset : offset -1; + if (o1 >= con.limit || o1 < 0) { + returned = true; + break; + } + int ch = target.charAt(offset); + if (REUtil.isHighSurrogate(ch) && o1+dx < con.limit && o1+dx >=0) { + o1 += dx; + ch = REUtil.composeFromSurrogates(ch, target.charAt(o1)); + } + final RangeToken tok = op.getToken(); + if (!tok.match(ch)) { + returned = true; + break; + } + offset = (dx > 0) ? o1+1 : o1; + op = op.next; + } + break; + + case Op.ANCHOR: + { + if (!matchAnchor(target, op, con, offset, opts)) { + returned = true; + break; + } + op = op.next; + } + break; + + case Op.BACKREFERENCE: + { + int refno = op.getData(); + if (refno <= 0 || refno >= this.nofparen) { + throw new RuntimeException("Internal Error: Reference number must be more than zero: "+refno); + } + if (con.match.getBeginning(refno) < 0 || con.match.getEnd(refno) < 0) { + returned = true; + break; + } + int o2 = con.match.getBeginning(refno); + int literallen = con.match.getEnd(refno)-o2; + if (dx > 0) { + if (!target.regionMatches(isSetIgnoreCase, offset, con.limit, o2, literallen)) { + returned = true; + break; + } + offset += literallen; + } + else { + if (!target.regionMatches(isSetIgnoreCase, offset-literallen, con.limit, o2, literallen)) { + returned = true; + break; + } + offset -= literallen; + } + op = op.next; + } + break; + + case Op.STRING: + { + String literal = op.getString(); + int literallen = literal.length(); + if (dx > 0) { + if (!target.regionMatches(isSetIgnoreCase, offset, con.limit, literal, literallen)) { + returned = true; + break; + } + offset += literallen; + } + else { + if (!target.regionMatches(isSetIgnoreCase, offset-literallen, con.limit, literal, literallen)) { + returned = true; + break; + } + offset -= literallen; + } + op = op.next; + } + break; + + case Op.CLOSURE: + { + // Saves current position to avoid zero-width repeats. + final int id = op.getData(); + if (con.closureContexts[id].contains(offset)) { + returned = true; + break; + } + + con.closureContexts[id].addOffset(offset); + } + // fall through + + case Op.QUESTION: + { + opStack.push(op); + dataStack.push(offset); + op = op.getChild(); + } + break; + + case Op.NONGREEDYCLOSURE: + case Op.NONGREEDYQUESTION: + { + opStack.push(op); + dataStack.push(offset); + op = op.next; + } + break; + + case Op.UNION: + if (op.size() == 0) { + returned = true; + } + else { + opStack.push(op); + dataStack.push(0); + dataStack.push(offset); + op = op.elementAt(0); + } + break; + + case Op.CAPTURE: + { + final int refno = op.getData(); + if (con.match != null) { + if (refno > 0) { + dataStack.push(con.match.getBeginning(refno)); + con.match.setBeginning(refno, offset); + } + else { + final int index = -refno; + dataStack.push(con.match.getEnd(index)); + con.match.setEnd(index, offset); + } + opStack.push(op); + dataStack.push(offset); + } + op = op.next; + } + break; + + case Op.LOOKAHEAD: + case Op.NEGATIVELOOKAHEAD: + case Op.LOOKBEHIND: + case Op.NEGATIVELOOKBEHIND: + { + opStack.push(op); + dataStack.push(dx); + dataStack.push(offset); + dx = (op.type == Op.LOOKAHEAD || op.type == Op.NEGATIVELOOKAHEAD) ? 1 : -1; + op = op.getChild(); + } + break; + + case Op.INDEPENDENT: + { + opStack.push(op); + dataStack.push(offset); + op = op.getChild(); + } + break; + + case Op.MODIFIER: + { + int localopts = opts; + localopts |= op.getData(); + localopts &= ~op.getData2(); + opStack.push(op); + dataStack.push(opts); + dataStack.push(offset); + opts = localopts; + op = op.getChild(); + } + break; + + case Op.CONDITION: + { + Op.ConditionOp cop = (Op.ConditionOp)op; + if (cop.refNumber > 0) { + if (cop.refNumber >= this.nofparen) { + throw new RuntimeException("Internal Error: Reference number must be more than zero: "+cop.refNumber); + } + if (con.match.getBeginning(cop.refNumber) >= 0 + && con.match.getEnd(cop.refNumber) >= 0) { + op = cop.yes; + } + else if (cop.no != null) { + op = cop.no; + } + else { + op = cop.next; + } + } + else { + opStack.push(op); + dataStack.push(offset); + op = cop.condition; + } + } + break; + + default: + throw new RuntimeException("Unknown operation type: " + op.type); + } + } + + // handle recursive operations + while (returned) { + // exhausted all the operations + if (opStack.isEmpty()) { + return retValue; + } + + op = (Op) opStack.pop(); + offset = dataStack.pop(); + + switch (op.type) { + case Op.CLOSURE: + case Op.QUESTION: + if (retValue < 0) { + op = op.next; + returned = false; + } + break; + + case Op.NONGREEDYCLOSURE: + case Op.NONGREEDYQUESTION: + if (retValue < 0) { + op = op.getChild(); + returned = false; + } + break; + + case Op.UNION: + { + int unionIndex = dataStack.pop(); + if (DEBUG) { + System.err.println("UNION: "+unionIndex+", ret="+retValue); + } + + if (retValue < 0) { + if (++unionIndex < op.size()) { + opStack.push(op); + dataStack.push(unionIndex); + dataStack.push(offset); + op = op.elementAt(unionIndex); + returned = false; + } + else { + retValue = -1; + } + } + } + break; + + case Op.CAPTURE: + final int refno = op.getData(); + final int saved = dataStack.pop(); + if (retValue < 0) { + if (refno > 0) { + con.match.setBeginning(refno, saved); + } + else { + con.match.setEnd(-refno, saved); + } + } + break; + + case Op.LOOKAHEAD: + case Op.LOOKBEHIND: + { + dx = dataStack.pop(); + if (0 <= retValue) { + op = op.next; + returned = false; + } + retValue = -1; + } + break; + + case Op.NEGATIVELOOKAHEAD: + case Op.NEGATIVELOOKBEHIND: + { + dx = dataStack.pop(); + if (0 > retValue) { + op = op.next; + returned = false; + } + retValue = -1; + } + break; + + case Op.MODIFIER: + opts = dataStack.pop(); + // fall through + + case Op.INDEPENDENT: + if (retValue >= 0) { + offset = retValue; + op = op.next; + returned = false; + } + break; + + case Op.CONDITION: + { + final Op.ConditionOp cop = (Op.ConditionOp)op; + if (0 <= retValue) { + op = cop.yes; + } + else if (cop.no != null) { + op = cop.no; + } + else { + op = cop.next; + } + } + returned = false; + break; + + default: + break; + } + } + } + } + + private boolean matchChar(int ch, int other, boolean ignoreCase) { + return (ignoreCase) ? matchIgnoreCase(ch, other) : ch == other; + } + + boolean matchAnchor(ExpressionTarget target, Op op, Context con, int offset, int opts) { + boolean go = false; + switch (op.getData()) { + case '^': + if (isSet(opts, MULTIPLE_LINES)) { + if (!(offset == con.start + || offset > con.start && offset < con.limit && isEOLChar(target.charAt(offset-1)))) + return false; + } else { + if (offset != con.start) + return false; + } + break; + + case '@': // Internal use only. + // The @ always matches line beginnings. + if (!(offset == con.start + || offset > con.start && isEOLChar(target.charAt(offset-1)))) + return false; + break; + + case '$': + if (isSet(opts, MULTIPLE_LINES)) { + if (!(offset == con.limit + || offset < con.limit && isEOLChar(target.charAt(offset)))) + return false; + } else { + if (!(offset == con.limit + || offset+1 == con.limit && isEOLChar(target.charAt(offset)) + || offset+2 == con.limit && target.charAt(offset) == CARRIAGE_RETURN + && target.charAt(offset+1) == LINE_FEED)) + return false; + } + break; + + case 'A': + if (offset != con.start) return false; + break; + + case 'Z': + if (!(offset == con.limit + || offset+1 == con.limit && isEOLChar(target.charAt(offset)) + || offset+2 == con.limit && target.charAt(offset) == CARRIAGE_RETURN + && target.charAt(offset+1) == LINE_FEED)) + return false; + break; + + case 'z': + if (offset != con.limit) return false; + break; + + case 'b': + if (con.length == 0) + return false; + { + int after = getWordType(target, con.start, con.limit, offset, opts); + if (after == WT_IGNORE) return false; + int before = getPreviousWordType(target, con.start, con.limit, offset, opts); + if (after == before) return false; + } + break; + + case 'B': + if (con.length == 0) + go = true; + else { + int after = getWordType(target, con.start, con.limit, offset, opts); + go = after == WT_IGNORE + || after == getPreviousWordType(target, con.start, con.limit, offset, opts); + } + if (!go) return false; + break; + + case '<': + if (con.length == 0 || offset == con.limit) return false; + if (getWordType(target, con.start, con.limit, offset, opts) != WT_LETTER + || getPreviousWordType(target, con.start, con.limit, offset, opts) != WT_OTHER) + return false; + break; + + case '>': + if (con.length == 0 || offset == con.start) return false; + if (getWordType(target, con.start, con.limit, offset, opts) != WT_OTHER + || getPreviousWordType(target, con.start, con.limit, offset, opts) != WT_LETTER) + return false; + break; + } // switch anchor type + + return true; + } + + private static final int getPreviousWordType(ExpressionTarget target, int begin, int end, + int offset, int opts) { + int ret = getWordType(target, begin, end, --offset, opts); + while (ret == WT_IGNORE) + ret = getWordType(target, begin, end, --offset, opts); + return ret; + } + + private static final int getWordType(ExpressionTarget target, int begin, int end, + int offset, int opts) { + if (offset < begin || offset >= end) return WT_OTHER; + return getWordType0(target.charAt(offset) , opts); + } + + + /** + * Checks whether the target text contains this pattern or not. + * + * @return true if the target is matched to this regular expression. + */ + public boolean matches(CharacterIterator target) { + return this.matches(target, (Match)null); + } + + + /** + * Checks whether the target text contains this pattern or not. + * + * @param match A Match instance for storing matching result. + * @return Offset of the start position in target; or -1 if not match. + */ + public boolean matches(CharacterIterator target, Match match) { + int start = target.getBeginIndex(); + int end = target.getEndIndex(); + + + + synchronized (this) { + if (this.operations == null) + this.prepare(); + if (this.context == null) + this.context = new Context(); + } + Context con = null; + synchronized (this.context) { + con = this.context.inuse ? new Context() : this.context; + con.reset(target, start, end, this.numberOfClosures); + } + if (match != null) { + match.setNumberOfGroups(this.nofparen); + match.setSource(target); + } else if (this.hasBackReferences) { + match = new Match(); + match.setNumberOfGroups(this.nofparen); + // Need not to call setSource() because + // a caller can not access this match instance. + } + con.match = match; + + if (RegularExpression.isSet(this.options, XMLSCHEMA_MODE)) { + int matchEnd = this.match(con, this.operations, con.start, 1, this.options); + //System.err.println("DEBUG: matchEnd="+matchEnd); + if (matchEnd == con.limit) { + if (con.match != null) { + con.match.setBeginning(0, con.start); + con.match.setEnd(0, matchEnd); + } + con.setInUse(false); + return true; + } + return false; + } + + /* + * The pattern has only fixed string. + * The engine uses Boyer-Moore. + */ + if (this.fixedStringOnly) { + //System.err.println("DEBUG: fixed-only: "+this.fixedString); + int o = this.fixedStringTable.matches(target, con.start, con.limit); + if (o >= 0) { + if (con.match != null) { + con.match.setBeginning(0, o); + con.match.setEnd(0, o+this.fixedString.length()); + } + con.setInUse(false); + return true; + } + con.setInUse(false); + return false; + } + + /* + * The pattern contains a fixed string. + * The engine checks with Boyer-Moore whether the text contains the fixed string or not. + * If not, it return with false. + */ + if (this.fixedString != null) { + int o = this.fixedStringTable.matches(target, con.start, con.limit); + if (o < 0) { + //System.err.println("Non-match in fixed-string search."); + con.setInUse(false); + return false; + } + } + + int limit = con.limit-this.minlength; + int matchStart; + int matchEnd = -1; + + /* + * Checks whether the expression starts with ".*". + */ + if (this.operations != null + && this.operations.type == Op.CLOSURE && this.operations.getChild().type == Op.DOT) { + if (isSet(this.options, SINGLE_LINE)) { + matchStart = con.start; + matchEnd = this.match(con, this.operations, con.start, 1, this.options); + } else { + boolean previousIsEOL = true; + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + int ch = target .setIndex( matchStart ) ; + if (isEOLChar(ch)) { + previousIsEOL = true; + } else { + if (previousIsEOL) { + if (0 <= (matchEnd = this.match(con, this.operations, + matchStart, 1, this.options))) + break; + } + previousIsEOL = false; + } + } + } + } + + /* + * Optimization against the first character. + */ + else if (this.firstChar != null) { + //System.err.println("DEBUG: with firstchar-matching: "+this.firstChar); + RangeToken range = this.firstChar; + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + int ch = target .setIndex( matchStart ) ; + if (REUtil.isHighSurrogate(ch) && matchStart+1 < con.limit) { + ch = REUtil.composeFromSurrogates(ch, target.setIndex(matchStart+1)); + } + if (!range.match(ch)) { + continue; + } + if (0 <= (matchEnd = this.match(con, this.operations, + matchStart, 1, this.options))) { + break; + } + } + } + + /* + * Straightforward matching. + */ + else { + for (matchStart = con.start; matchStart <= limit; matchStart ++) { + if (0 <= (matchEnd = this. match(con, this.operations, matchStart, 1, this.options))) + break; + } + } + + if (matchEnd >= 0) { + if (con.match != null) { + con.match.setBeginning(0, matchStart); + con.match.setEnd(0, matchEnd); + } + con.setInUse(false); + return true; + } else { + con.setInUse(false); + return false; + } + } + + // ================================================================ + + /** + * A regular expression. + * @serial + */ + String regex; + /** + * @serial + */ + int options; + + /** + * The number of parenthesis in the regular expression. + * @serial + */ + int nofparen; + /** + * Internal representation of the regular expression. + * @serial + */ + Token tokentree; + + boolean hasBackReferences = false; + + transient int minlength; + transient Op operations = null; + transient int numberOfClosures; + transient Context context = null; + transient RangeToken firstChar = null; + + transient String fixedString = null; + transient int fixedStringOptions; + transient BMPattern fixedStringTable = null; + transient boolean fixedStringOnly = false; + + static abstract class ExpressionTarget { + abstract char charAt(int index); + abstract boolean regionMatches(boolean ignoreCase, int offset, int limit, String part, int partlen); + abstract boolean regionMatches(boolean ignoreCase, int offset, int limit, int offset2, int partlen); + } + + static final class StringTarget extends ExpressionTarget { + + private String target; + + StringTarget(String target) { + this.target = target; + } + + final void resetTarget(String target) { + this.target = target; + } + + final char charAt(int index) { + return target.charAt(index); + } + + final boolean regionMatches(boolean ignoreCase, int offset, int limit, + String part, int partlen) { + if (limit-offset < partlen) { + return false; + } + return (ignoreCase) ? target.regionMatches(true, offset, part, 0, partlen) : target.regionMatches(offset, part, 0, partlen); + } + + final boolean regionMatches(boolean ignoreCase, int offset, int limit, + int offset2, int partlen) { + if (limit-offset < partlen) { + return false; + } + return (ignoreCase) ? target.regionMatches(true, offset, target, offset2, partlen) + : target.regionMatches(offset, target, offset2, partlen); + } + } + + static final class CharArrayTarget extends ExpressionTarget { + + char[] target; + + CharArrayTarget(char[] target) { + this.target = target; + } + + final void resetTarget(char[] target) { + this.target = target; + } + + char charAt(int index) { + return target[index]; + } + + final boolean regionMatches(boolean ignoreCase, int offset, int limit, + String part, int partlen) { + if (offset < 0 || limit-offset < partlen) { + return false; + } + return (ignoreCase) ? regionMatchesIgnoreCase(offset, limit, part, partlen) + : regionMatches(offset, limit, part, partlen); + } + + private final boolean regionMatches(int offset, int limit, String part, int partlen) { + int i = 0; + while (partlen-- > 0) { + if (target[offset++] != part.charAt(i++)) { + return false; + } + } + return true; + } + + private final boolean regionMatchesIgnoreCase(int offset, int limit, String part, int partlen) { + int i = 0; + while (partlen-- > 0) { + final char ch1 = target[offset++] ; + final char ch2 = part.charAt(i++); + if (ch1 == ch2) { + continue; + } + final char uch1 = Character.toUpperCase(ch1); + final char uch2 = Character.toUpperCase(ch2); + if (uch1 == uch2) { + continue; + } + if (Character.toLowerCase(uch1) != Character.toLowerCase(uch2)) { + return false; + } + } + return true; + } + + final boolean regionMatches(boolean ignoreCase, int offset, int limit, int offset2, int partlen) { + if (offset < 0 || limit-offset < partlen) { + return false; + } + return (ignoreCase) ? regionMatchesIgnoreCase(offset, limit, offset2, partlen) + : regionMatches(offset, limit, offset2, partlen); + } + + private final boolean regionMatches(int offset, int limit, int offset2, int partlen) { + int i = offset2; + while (partlen-- > 0) { + if ( target [ offset++ ] != target [ i++ ] ) + return false; + } + return true; + } + + private final boolean regionMatchesIgnoreCase(int offset, int limit, int offset2, int partlen) { + int i = offset2; + while (partlen-- > 0) { + final char ch1 = target[offset++] ; + final char ch2 = target[i++] ; + if (ch1 == ch2) { + continue; + } + final char uch1 = Character.toUpperCase(ch1); + final char uch2 = Character.toUpperCase(ch2); + if (uch1 == uch2) { + continue; + } + if (Character.toLowerCase(uch1) != Character.toLowerCase(uch2)) { + return false; + } + } + return true; + } + } + + static final class CharacterIteratorTarget extends ExpressionTarget { + CharacterIterator target; + + CharacterIteratorTarget(CharacterIterator target) { + this.target = target; + } + + final void resetTarget(CharacterIterator target) { + this.target = target; + } + + final char charAt(int index) { + return target.setIndex(index); + } + + final boolean regionMatches(boolean ignoreCase, int offset, int limit, + String part, int partlen) { + if (offset < 0 || limit-offset < partlen) { + return false; + } + return (ignoreCase) ? regionMatchesIgnoreCase(offset, limit, part, partlen) + : regionMatches(offset, limit, part, partlen); + } + + private final boolean regionMatches(int offset, int limit, String part, int partlen) { + int i = 0; + while (partlen-- > 0) { + if (target.setIndex(offset++) != part.charAt(i++)) { + return false; + } + } + return true; + } + + private final boolean regionMatchesIgnoreCase(int offset, int limit, String part, int partlen) { + int i = 0; + while (partlen-- > 0) { + final char ch1 = target.setIndex(offset++) ; + final char ch2 = part.charAt(i++); + if (ch1 == ch2) { + continue; + } + final char uch1 = Character.toUpperCase(ch1); + final char uch2 = Character.toUpperCase(ch2); + if (uch1 == uch2) { + continue; + } + if (Character.toLowerCase(uch1) != Character.toLowerCase(uch2)) { + return false; + } + } + return true; + } + + final boolean regionMatches(boolean ignoreCase, int offset, int limit, int offset2, int partlen) { + if (offset < 0 || limit-offset < partlen) { + return false; + } + return (ignoreCase) ? regionMatchesIgnoreCase(offset, limit, offset2, partlen) + : regionMatches(offset, limit, offset2, partlen); + } + + private final boolean regionMatches(int offset, int limit, int offset2, int partlen) { + int i = offset2; + while (partlen-- > 0) { + if (target.setIndex(offset++) != target.setIndex(i++)) { + return false; + } + } + return true; + } + + private final boolean regionMatchesIgnoreCase(int offset, int limit, int offset2, int partlen) { + int i = offset2; + while (partlen-- > 0) { + final char ch1 = target.setIndex(offset++) ; + final char ch2 = target.setIndex(i++) ; + if (ch1 == ch2) { + continue; + } + final char uch1 = Character.toUpperCase(ch1); + final char uch2 = Character.toUpperCase(ch2); + if (uch1 == uch2) { + continue; + } + if (Character.toLowerCase(uch1) != Character.toLowerCase(uch2)) { + return false; + } + } + return true; + } + } + + static final class ClosureContext { + + int[] offsets = new int[4]; + int currentIndex = 0; + + boolean contains(int offset) { + for (int i=0; i= 0x10000) { // Op.CHAR + this.fixedString = REUtil.decomposeToSurrogates(this.operations.getData()); + } else { + char[] ac = new char[1]; + ac[0] = (char)this.operations.getData(); + this.fixedString = new String(ac); + } + this.fixedStringOptions = this.options; + this.fixedStringTable = new BMPattern(this.fixedString, 256, + isSet(this.fixedStringOptions, IGNORE_CASE)); + } else if (!isSet(this.options, PROHIBIT_FIXED_STRING_OPTIMIZATION) + && !isSet(this.options, XMLSCHEMA_MODE)) { + Token.FixedStringContainer container = new Token.FixedStringContainer(); + this.tokentree.findFixedString(container, this.options); + this.fixedString = container.token == null ? null : container.token.getString(); + this.fixedStringOptions = container.options; + if (this.fixedString != null && this.fixedString.length() < 2) + this.fixedString = null; + // This pattern has a fixed string of which length is more than one. + if (this.fixedString != null) { + this.fixedStringTable = new BMPattern(this.fixedString, 256, + isSet(this.fixedStringOptions, IGNORE_CASE)); + if (DEBUG) { + System.err.println("DEBUG: The longest fixed string: "+this.fixedString.length() + +"/" //+this.fixedString + +"/"+REUtil.createOptionString(this.fixedStringOptions)); + System.err.print("String: "); + REUtil.dumpString(this.fixedString); + } + } + } + } + + /** + * An option. + * If you specify this option, (X) + * captures matched text, and (:?X) + * does not capture. + * + * @see #RegularExpression(java.lang.String,int) + * @see #setPattern(java.lang.String,int) + static final int MARK_PARENS = 1<<0; + */ + + /** + * "i" + */ + static final int IGNORE_CASE = 1<<1; + + /** + * "s" + */ + static final int SINGLE_LINE = 1<<2; + + /** + * "m" + */ + static final int MULTIPLE_LINES = 1<<3; + + /** + * "x" + */ + static final int EXTENDED_COMMENT = 1<<4; + + /** + * This option redefines \d \D \w \W \s \S. + * + * @see #RegularExpression(java.lang.String,int) + * @see #setPattern(java.lang.String,int) + * @see #UNICODE_WORD_BOUNDARY + */ + static final int USE_UNICODE_CATEGORY = 1<<5; // "u" + + /** + * An option. + * This enables to process locale-independent word boundary for \b \B \< \>. + *

By default, the engine considers a position between a word character + * (\w) and a non word character + * is a word boundary. + *

By this option, the engine checks word boundaries with the method of + * 'Unicode Regular Expression Guidelines' Revision 4. + * + * @see #RegularExpression(java.lang.String,int) + * @see #setPattern(java.lang.String,int) + */ + static final int UNICODE_WORD_BOUNDARY = 1<<6; // "w" + + /** + * "H" + */ + static final int PROHIBIT_HEAD_CHARACTER_OPTIMIZATION = 1<<7; + /** + * "F" + */ + static final int PROHIBIT_FIXED_STRING_OPTIMIZATION = 1<<8; + /** + * "X". XML Schema mode. + */ + static final int XMLSCHEMA_MODE = 1<<9; + /** + * ",". + */ + static final int SPECIAL_COMMA = 1<<10; + + + private static final boolean isSet(int options, int flag) { + return (options & flag) == flag; + } + + /** + * Creates a new RegularExpression instance. + * + * @param regex A regular expression + * @exception org.apache.xerces.utils.regex.ParseException regex is not conforming to the syntax. + */ + public RegularExpression(String regex) throws ParseException { + this(regex, null); + } + + /** + * Creates a new RegularExpression instance with options. + * + * @param regex A regular expression + * @param options A String consisted of "i" "m" "s" "u" "w" "," "X" + * @exception org.apache.xerces.utils.regex.ParseException regex is not conforming to the syntax. + */ + public RegularExpression(String regex, String options) throws ParseException { + this.setPattern(regex, options); + } + + /** + * Creates a new RegularExpression instance with options. + * + * @param regex A regular expression + * @param options A String consisted of "i" "m" "s" "u" "w" "," "X" + * @exception org.apache.xerces.utils.regex.ParseException regex is not conforming to the syntax. + */ + public RegularExpression(String regex, String options, Locale locale) throws ParseException { + this.setPattern(regex, options, locale); + } + + RegularExpression(String regex, Token tok, int parens, boolean hasBackReferences, int options) { + this.regex = regex; + this.tokentree = tok; + this.nofparen = parens; + this.options = options; + this.hasBackReferences = hasBackReferences; + } + + /** + * + */ + public void setPattern(String newPattern) throws ParseException { + this.setPattern(newPattern, Locale.getDefault()); + } + + public void setPattern(String newPattern, Locale locale) throws ParseException { + this.setPattern(newPattern, this.options, locale); + } + + private void setPattern(String newPattern, int options, Locale locale) throws ParseException { + this.regex = newPattern; + this.options = options; + RegexParser rp = RegularExpression.isSet(this.options, RegularExpression.XMLSCHEMA_MODE) + ? new ParserForXMLSchema(locale) : new RegexParser(locale); + this.tokentree = rp.parse(this.regex, this.options); + this.nofparen = rp.parennumber; + this.hasBackReferences = rp.hasBackReferences; + + this.operations = null; + this.context = null; + } + /** + * + */ + public void setPattern(String newPattern, String options) throws ParseException { + this.setPattern(newPattern, options, Locale.getDefault()); + } + + public void setPattern(String newPattern, String options, Locale locale) throws ParseException { + this.setPattern(newPattern, REUtil.parseOptions(options), locale); + } + + /** + * + */ + public String getPattern() { + return this.regex; + } + + /** + * Represents this instence in String. + */ + public String toString() { + return this.tokentree.toString(this.options); + } + + /** + * Returns a option string. + * The order of letters in it may be different from a string specified + * in a constructor or setPattern(). + * + * @see #RegularExpression(java.lang.String,java.lang.String) + * @see #setPattern(java.lang.String,java.lang.String) + */ + public String getOptions() { + return REUtil.createOptionString(this.options); + } + + /** + * Return true if patterns are the same and the options are equivalent. + */ + public boolean equals(Object obj) { + if (obj == null) return false; + if (!(obj instanceof RegularExpression)) + return false; + RegularExpression r = (RegularExpression)obj; + return this.regex.equals(r.regex) && this.options == r.options; + } + + boolean equals(String pattern, int options) { + return this.regex.equals(pattern) && this.options == options; + } + + /** + * + */ + public int hashCode() { + return (this.regex+"/"+this.getOptions()).hashCode(); + } + + /** + * Return the number of regular expression groups. + * This method returns 1 when the regular expression has no capturing-parenthesis. + * + */ + public int getNumberOfGroups() { + return this.nofparen; + } + + // ================================================================ + + private static final int WT_IGNORE = 0; + private static final int WT_LETTER = 1; + private static final int WT_OTHER = 2; + private static final int getWordType0(char ch, int opts) { + if (!isSet(opts, UNICODE_WORD_BOUNDARY)) { + if (isSet(opts, USE_UNICODE_CATEGORY)) { + return (Token.getRange("IsWord", true).match(ch)) ? WT_LETTER : WT_OTHER; + } + return isWordChar(ch) ? WT_LETTER : WT_OTHER; + } + + switch (Character.getType(ch)) { + case Character.UPPERCASE_LETTER: // L + case Character.LOWERCASE_LETTER: // L + case Character.TITLECASE_LETTER: // L + case Character.MODIFIER_LETTER: // L + case Character.OTHER_LETTER: // L + case Character.LETTER_NUMBER: // N + case Character.DECIMAL_DIGIT_NUMBER: // N + case Character.OTHER_NUMBER: // N + case Character.COMBINING_SPACING_MARK: // Mc + return WT_LETTER; + + case Character.FORMAT: // Cf + case Character.NON_SPACING_MARK: // Mn + case Character.ENCLOSING_MARK: // Mc + return WT_IGNORE; + + case Character.CONTROL: // Cc + switch (ch) { + case '\t': + case '\n': + case '\u000B': + case '\f': + case '\r': + return WT_OTHER; + default: + return WT_IGNORE; + } + + default: + return WT_OTHER; + } + } + + // ================================================================ + + static final int LINE_FEED = 0x000A; + static final int CARRIAGE_RETURN = 0x000D; + static final int LINE_SEPARATOR = 0x2028; + static final int PARAGRAPH_SEPARATOR = 0x2029; + + private static final boolean isEOLChar(int ch) { + return ch == LINE_FEED || ch == CARRIAGE_RETURN || ch == LINE_SEPARATOR + || ch == PARAGRAPH_SEPARATOR; + } + + private static final boolean isWordChar(int ch) { // Legacy word characters + if (ch == '_') return true; + if (ch < '0') return false; + if (ch > 'z') return false; + if (ch <= '9') return true; + if (ch < 'A') return false; + if (ch <= 'Z') return true; + if (ch < 'a') return false; + return true; + } + + private static final boolean matchIgnoreCase(int chardata, int ch) { + if (chardata == ch) return true; + if (chardata > 0xffff || ch > 0xffff) return false; + char uch1 = Character.toUpperCase((char)chardata); + char uch2 = Character.toUpperCase((char)ch); + if (uch1 == uch2) return true; + return Character.toLowerCase(uch1) == Character.toLowerCase(uch2); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/Token.java b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/Token.java new file mode 100644 index 0000000..df1b1fe --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/Token.java @@ -0,0 +1,1531 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xpath.regex; + +import java.util.Hashtable; +import java.util.Vector; + +/** + * This class represents a node in parse tree. + * + * @xerces.internal + * + * @version $Id$ + */ +class Token implements java.io.Serializable { + + private static final long serialVersionUID = 8484976002585487481L; + + static final boolean COUNTTOKENS = true; + static int tokens = 0; + + static final int CHAR = 0; // Literal char + static final int DOT = 11; // . + static final int CONCAT = 1; // XY + static final int UNION = 2; // X|Y|Z + static final int CLOSURE = 3; // X* + static final int RANGE = 4; // [a-zA-Z] etc. + static final int NRANGE = 5; // [^a-zA-Z] etc. + static final int PAREN = 6; // (X) or (?:X) + static final int EMPTY = 7; // + static final int ANCHOR = 8; // ^ $ \b \B \< \> \A \Z \z + static final int NONGREEDYCLOSURE = 9; // *? +? + static final int STRING = 10; // strings + static final int BACKREFERENCE = 12; // back references + static final int LOOKAHEAD = 20; // (?=...) + static final int NEGATIVELOOKAHEAD = 21; // (?!...) + static final int LOOKBEHIND = 22; // (?<=...) + static final int NEGATIVELOOKBEHIND = 23; // (?...) + static final int MODIFIERGROUP = 25; // (?ims-ims:...) + static final int CONDITION = 26; // (?(...)yes|no) + + static final int UTF16_MAX = 0x10ffff; + + final int type; + + static Token token_dot; + static Token token_0to9; + static Token token_wordchars; + static Token token_not_0to9; + static Token token_not_wordchars; + static Token token_spaces; + static Token token_not_spaces; + static Token token_empty; + static Token token_linebeginning; + static Token token_linebeginning2; + static Token token_lineend; + static Token token_stringbeginning; + static Token token_stringend; + static Token token_stringend2; + static Token token_wordedge; + static Token token_not_wordedge; + static Token token_wordbeginning; + static Token token_wordend; + static { + Token.token_empty = new Token(Token.EMPTY); + + Token.token_linebeginning = Token.createAnchor('^'); + Token.token_linebeginning2 = Token.createAnchor('@'); + Token.token_lineend = Token.createAnchor('$'); + Token.token_stringbeginning = Token.createAnchor('A'); + Token.token_stringend = Token.createAnchor('z'); + Token.token_stringend2 = Token.createAnchor('Z'); + Token.token_wordedge = Token.createAnchor('b'); + Token.token_not_wordedge = Token.createAnchor('B'); + Token.token_wordbeginning = Token.createAnchor('<'); + Token.token_wordend = Token.createAnchor('>'); + + Token.token_dot = new Token(Token.DOT); + + Token.token_0to9 = Token.createRange(); + Token.token_0to9.addRange('0', '9'); + Token.token_wordchars = Token.createRange(); + Token.token_wordchars.addRange('0', '9'); + Token.token_wordchars.addRange('A', 'Z'); + Token.token_wordchars.addRange('_', '_'); + Token.token_wordchars.addRange('a', 'z'); + Token.token_spaces = Token.createRange(); + Token.token_spaces.addRange('\t', '\t'); + Token.token_spaces.addRange('\n', '\n'); + Token.token_spaces.addRange('\f', '\f'); + Token.token_spaces.addRange('\r', '\r'); + Token.token_spaces.addRange(' ', ' '); + + Token.token_not_0to9 = Token.complementRanges(Token.token_0to9); + Token.token_not_wordchars = Token.complementRanges(Token.token_wordchars); + Token.token_not_spaces = Token.complementRanges(Token.token_spaces); + } + + static Token.ParenToken createLook(int type, Token child) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.ParenToken(type, child, 0); + } + static Token.ParenToken createParen(Token child, int pnumber) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.ParenToken(Token.PAREN, child, pnumber); + } + static Token.ClosureToken createClosure(Token tok) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.ClosureToken(Token.CLOSURE, tok); + } + static Token.ClosureToken createNGClosure(Token tok) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.ClosureToken(Token.NONGREEDYCLOSURE, tok); + } + static Token.ConcatToken createConcat(Token tok1, Token tok2) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.ConcatToken(tok1, tok2); + } + static Token.UnionToken createConcat() { + if (COUNTTOKENS) Token.tokens ++; + return new Token.UnionToken(Token.CONCAT); // *** It is not a bug. + } + static Token.UnionToken createUnion() { + if (COUNTTOKENS) Token.tokens ++; + return new Token.UnionToken(Token.UNION); + } + static Token createEmpty() { + return Token.token_empty; + } + static RangeToken createRange() { + if (COUNTTOKENS) Token.tokens ++; + return new RangeToken(Token.RANGE); + } + static RangeToken createNRange() { + if (COUNTTOKENS) Token.tokens ++; + return new RangeToken(Token.NRANGE); + } + static Token.CharToken createChar(int ch) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.CharToken(Token.CHAR, ch); + } + static private Token.CharToken createAnchor(int ch) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.CharToken(Token.ANCHOR, ch); + } + static Token.StringToken createBackReference(int refno) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.StringToken(Token.BACKREFERENCE, null, refno); + } + static Token.StringToken createString(String str) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.StringToken(Token.STRING, str, 0); + } + static Token.ModifierToken createModifierGroup(Token child, int add, int mask) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.ModifierToken(child, add, mask); + } + static Token.ConditionToken createCondition(int refno, Token condition, + Token yespat, Token nopat) { + if (COUNTTOKENS) Token.tokens ++; + return new Token.ConditionToken(refno, condition, yespat, nopat); + } + + protected Token(int type) { + this.type = type; + } + + /** + * A number of children. + */ + int size() { + return 0; + } + Token getChild(int index) { + return null; + } + void addChild(Token tok) { + throw new RuntimeException("Not supported."); + } + + // for RANGE or NRANGE + protected void addRange(int start, int end) { + throw new RuntimeException("Not supported."); + } + protected void sortRanges() { + throw new RuntimeException("Not supported."); + } + protected void compactRanges() { + throw new RuntimeException("Not supported."); + } + protected void mergeRanges(Token tok) { + throw new RuntimeException("Not supported."); + } + protected void subtractRanges(Token tok) { + throw new RuntimeException("Not supported."); + } + protected void intersectRanges(Token tok) { + throw new RuntimeException("Not supported."); + } + static Token complementRanges(Token tok) { + return RangeToken.complementRanges(tok); + } + + + void setMin(int min) { // for CLOSURE + } + void setMax(int max) { // for CLOSURE + } + int getMin() { // for CLOSURE + return -1; + } + int getMax() { // for CLOSURE + return -1; + } + int getReferenceNumber() { // for STRING + return 0; + } + String getString() { // for STRING + return null; + } + + int getParenNumber() { + return 0; + } + int getChar() { + return -1; + } + + public String toString() { + return this.toString(0); + } + public String toString(int options) { + return this.type == Token.DOT ? "." : ""; + } + + /** + * How many characters are needed? + */ + final int getMinLength() { + switch (this.type) { + case CONCAT: + int sum = 0; + for (int i = 0; i < this.size(); i ++) + sum += this.getChild(i).getMinLength(); + return sum; + + case CONDITION: + case UNION: + if (this.size() == 0) + return 0; + int ret = this.getChild(0).getMinLength(); + for (int i = 1; i < this.size(); i ++) { + int min = this.getChild(i).getMinLength(); + if (min < ret) ret = min; + } + return ret; + + case CLOSURE: + case NONGREEDYCLOSURE: + if (this.getMin() >= 0) + return this.getMin() * this.getChild(0).getMinLength(); + return 0; + + case EMPTY: + case ANCHOR: + return 0; + + case DOT: + case CHAR: + case RANGE: + case NRANGE: + return 1; + + case INDEPENDENT: + case PAREN: + case MODIFIERGROUP: + return this.getChild(0).getMinLength(); + + case BACKREFERENCE: + return 0; // ******* + + case STRING: + return this.getString().length(); + + case LOOKAHEAD: + case NEGATIVELOOKAHEAD: + case LOOKBEHIND: + case NEGATIVELOOKBEHIND: + return 0; // ***** Really? + + default: + throw new RuntimeException("Token#getMinLength(): Invalid Type: "+this.type); + } + } + + final int getMaxLength() { + switch (this.type) { + case CONCAT: + int sum = 0; + for (int i = 0; i < this.size(); i ++) { + int d = this.getChild(i).getMaxLength(); + if (d < 0) return -1; + sum += d; + } + return sum; + + case CONDITION: + case UNION: + if (this.size() == 0) + return 0; + int ret = this.getChild(0).getMaxLength(); + for (int i = 1; ret >= 0 && i < this.size(); i ++) { + int max = this.getChild(i).getMaxLength(); + if (max < 0) { // infinity + ret = -1; + break; + } + if (max > ret) ret = max; + } + return ret; + + case CLOSURE: + case NONGREEDYCLOSURE: + if (this.getMax() >= 0) + // When this.child.getMaxLength() < 0, + // this returns minus value + return this.getMax() * this.getChild(0).getMaxLength(); + return -1; + + case EMPTY: + case ANCHOR: + return 0; + + case CHAR: + return 1; + case DOT: + case RANGE: + case NRANGE: + return 2; + + case INDEPENDENT: + case PAREN: + case MODIFIERGROUP: + return this.getChild(0).getMaxLength(); + + case BACKREFERENCE: + return -1; // ****** + + case STRING: + return this.getString().length(); + + case LOOKAHEAD: + case NEGATIVELOOKAHEAD: + case LOOKBEHIND: + case NEGATIVELOOKBEHIND: + return 0; // ***** Really? + + default: + throw new RuntimeException("Token#getMaxLength(): Invalid Type: "+this.type); + } + } + + static final int FC_CONTINUE = 0; + static final int FC_TERMINAL = 1; + static final int FC_ANY = 2; + private static final boolean isSet(int options, int flag) { + return (options & flag) == flag; + } + final int analyzeFirstCharacter(RangeToken result, int options) { + switch (this.type) { + case CONCAT: + int ret = FC_CONTINUE; + for (int i = 0; i < this.size(); i ++) + if ((ret = this.getChild(i).analyzeFirstCharacter(result, options)) != FC_CONTINUE) + break; + return ret; + + case UNION: + if (this.size() == 0) + return FC_CONTINUE; + /* + * a|b|c -> FC_TERMINAL + * a|.|c -> FC_ANY + * a|b| -> FC_CONTINUE + */ + int ret2 = FC_CONTINUE; + boolean hasEmpty = false; + for (int i = 0; i < this.size(); i ++) { + ret2 = this.getChild(i).analyzeFirstCharacter(result, options); + if (ret2 == FC_ANY) + break; + else if (ret2 == FC_CONTINUE) + hasEmpty = true; + } + return hasEmpty ? FC_CONTINUE : ret2; + + case CONDITION: + int ret3 = this.getChild(0).analyzeFirstCharacter(result, options); + if (this.size() == 1) return FC_CONTINUE; + if (ret3 == FC_ANY) return ret3; + int ret4 = this.getChild(1).analyzeFirstCharacter(result, options); + if (ret4 == FC_ANY) return ret4; + return ret3 == FC_CONTINUE || ret4 == FC_CONTINUE ? FC_CONTINUE : FC_TERMINAL; + + case CLOSURE: + case NONGREEDYCLOSURE: + this.getChild(0).analyzeFirstCharacter(result, options); + return FC_CONTINUE; + + case EMPTY: + case ANCHOR: + return FC_CONTINUE; + + case CHAR: + int ch = this.getChar(); + result.addRange(ch, ch); + if (ch < 0x10000 && isSet(options, RegularExpression.IGNORE_CASE)) { + ch = Character.toUpperCase((char)ch); + result.addRange(ch, ch); + ch = Character.toLowerCase((char)ch); + result.addRange(ch, ch); + } + return FC_TERMINAL; + + case DOT: + return FC_ANY; + + case RANGE: + result.mergeRanges(this); + return FC_TERMINAL; + + case NRANGE: // **** + result.mergeRanges(Token.complementRanges(this)); + return FC_TERMINAL; + + case INDEPENDENT: + case PAREN: + return this.getChild(0).analyzeFirstCharacter(result, options); + + case MODIFIERGROUP: + options |= ((ModifierToken)this).getOptions(); + options &= ~((ModifierToken)this).getOptionsMask(); + return this.getChild(0).analyzeFirstCharacter(result, options); + + case BACKREFERENCE: + result.addRange(0, UTF16_MAX); // **** We can not optimize. + return FC_ANY; + + case STRING: + int cha = this.getString().charAt(0); + int ch2; + if (REUtil.isHighSurrogate(cha) + && this.getString().length() >= 2 + && REUtil.isLowSurrogate((ch2 = this.getString().charAt(1)))) + cha = REUtil.composeFromSurrogates(cha, ch2); + result.addRange(cha, cha); + if (cha < 0x10000 && isSet(options, RegularExpression.IGNORE_CASE)) { + cha = Character.toUpperCase((char)cha); + result.addRange(cha, cha); + cha = Character.toLowerCase((char)cha); + result.addRange(cha, cha); + } + return FC_TERMINAL; + + case LOOKAHEAD: + case NEGATIVELOOKAHEAD: + case LOOKBEHIND: + case NEGATIVELOOKBEHIND: + return FC_CONTINUE; + + default: + throw new RuntimeException("Token#analyzeHeadCharacter(): Invalid Type: "+this.type); + } + } + + private final boolean isShorterThan(Token tok) { + if (tok == null) return false; + /* + int mylength; + if (this.type == STRING) mylength = this.getString().length(); + else if (this.type == CHAR) mylength = this.getChar() >= 0x10000 ? 2 : 1; + else throw new RuntimeException("Internal Error: Illegal type: "+this.type); + int otherlength; + if (tok.type == STRING) otherlength = tok.getString().length(); + else if (tok.type == CHAR) otherlength = tok.getChar() >= 0x10000 ? 2 : 1; + else throw new RuntimeException("Internal Error: Illegal type: "+tok.type); + */ + int mylength; + if (this.type == STRING) mylength = this.getString().length(); + else throw new RuntimeException("Internal Error: Illegal type: "+this.type); + int otherlength; + if (tok.type == STRING) otherlength = tok.getString().length(); + else throw new RuntimeException("Internal Error: Illegal type: "+tok.type); + return mylength < otherlength; + } + + static class FixedStringContainer { + Token token = null; + int options = 0; + FixedStringContainer() { + } + } + + final void findFixedString(FixedStringContainer container, int options) { + switch (this.type) { + case CONCAT: + Token prevToken = null; + int prevOptions = 0; + for (int i = 0; i < this.size(); i ++) { + this.getChild(i).findFixedString(container, options); + if (prevToken == null || prevToken.isShorterThan(container.token)) { + prevToken = container.token; + prevOptions = container.options; + } + } + container.token = prevToken; + container.options = prevOptions; + return; + + case UNION: + case CLOSURE: + case NONGREEDYCLOSURE: + case EMPTY: + case ANCHOR: + case RANGE: + case DOT: + case NRANGE: + case BACKREFERENCE: + case LOOKAHEAD: + case NEGATIVELOOKAHEAD: + case LOOKBEHIND: + case NEGATIVELOOKBEHIND: + case CONDITION: + container.token = null; + return; + + case CHAR: // Ignore CHAR tokens. + container.token = null; // ** + return; // ** + + case STRING: + container.token = this; + container.options = options; + return; + + case INDEPENDENT: + case PAREN: + this.getChild(0).findFixedString(container, options); + return; + + case MODIFIERGROUP: + options |= ((ModifierToken)this).getOptions(); + options &= ~((ModifierToken)this).getOptionsMask(); + this.getChild(0).findFixedString(container, options); + return; + + default: + throw new RuntimeException("Token#findFixedString(): Invalid Type: "+this.type); + } + } + + boolean match(int ch) { + throw new RuntimeException("NFAArrow#match(): Internal error: "+this.type); + } + + // ------------------------------------------------------ + private final static Hashtable categories = new Hashtable(); + private final static Hashtable categories2 = new Hashtable(); + private static final String[] categoryNames = { + "Cn", "Lu", "Ll", "Lt", "Lm", "Lo", "Mn", "Me", "Mc", "Nd", + "Nl", "No", "Zs", "Zl", "Zp", "Cc", "Cf", null, "Co", "Cs", + "Pd", "Ps", "Pe", "Pc", "Po", "Sm", "Sc", "Sk", "So", // 28 + "Pi", "Pf", // 29, 30 + "L", "M", "N", "Z", "C", "P", "S", // 31-37 + }; + + // Schema Rec. {Datatypes} - Punctuation + static final int CHAR_INIT_QUOTE = 29; // Pi - initial quote + static final int CHAR_FINAL_QUOTE = 30; // Pf - final quote + static final int CHAR_LETTER = 31; + static final int CHAR_MARK = 32; + static final int CHAR_NUMBER = 33; + static final int CHAR_SEPARATOR = 34; + static final int CHAR_OTHER = 35; + static final int CHAR_PUNCTUATION = 36; + static final int CHAR_SYMBOL = 37; + + //blockNames in UNICODE 3.1 that supported by XML Schema REC + private static final String[] blockNames = { + /*0000..007F;*/ "Basic Latin", + /*0080..00FF;*/ "Latin-1 Supplement", + /*0100..017F;*/ "Latin Extended-A", + /*0180..024F;*/ "Latin Extended-B", + /*0250..02AF;*/ "IPA Extensions", + /*02B0..02FF;*/ "Spacing Modifier Letters", + /*0300..036F;*/ "Combining Diacritical Marks", + /*0370..03FF;*/ "Greek", + /*0400..04FF;*/ "Cyrillic", + /*0530..058F;*/ "Armenian", + /*0590..05FF;*/ "Hebrew", + /*0600..06FF;*/ "Arabic", + /*0700..074F;*/ "Syriac", + /*0780..07BF;*/ "Thaana", + /*0900..097F;*/ "Devanagari", + /*0980..09FF;*/ "Bengali", + /*0A00..0A7F;*/ "Gurmukhi", + /*0A80..0AFF;*/ "Gujarati", + /*0B00..0B7F;*/ "Oriya", + /*0B80..0BFF;*/ "Tamil", + /*0C00..0C7F;*/ "Telugu", + /*0C80..0CFF;*/ "Kannada", + /*0D00..0D7F;*/ "Malayalam", + /*0D80..0DFF;*/ "Sinhala", + /*0E00..0E7F;*/ "Thai", + /*0E80..0EFF;*/ "Lao", + /*0F00..0FFF;*/ "Tibetan", + /*1000..109F;*/ "Myanmar", + /*10A0..10FF;*/ "Georgian", + /*1100..11FF;*/ "Hangul Jamo", + /*1200..137F;*/ "Ethiopic", + /*13A0..13FF;*/ "Cherokee", + /*1400..167F;*/ "Unified Canadian Aboriginal Syllabics", + /*1680..169F;*/ "Ogham", + /*16A0..16FF;*/ "Runic", + /*1780..17FF;*/ "Khmer", + /*1800..18AF;*/ "Mongolian", + /*1E00..1EFF;*/ "Latin Extended Additional", + /*1F00..1FFF;*/ "Greek Extended", + /*2000..206F;*/ "General Punctuation", + /*2070..209F;*/ "Superscripts and Subscripts", + /*20A0..20CF;*/ "Currency Symbols", + /*20D0..20FF;*/ "Combining Marks for Symbols", + /*2100..214F;*/ "Letterlike Symbols", + /*2150..218F;*/ "Number Forms", + /*2190..21FF;*/ "Arrows", + /*2200..22FF;*/ "Mathematical Operators", + /*2300..23FF;*/ "Miscellaneous Technical", + /*2400..243F;*/ "Control Pictures", + /*2440..245F;*/ "Optical Character Recognition", + /*2460..24FF;*/ "Enclosed Alphanumerics", + /*2500..257F;*/ "Box Drawing", + /*2580..259F;*/ "Block Elements", + /*25A0..25FF;*/ "Geometric Shapes", + /*2600..26FF;*/ "Miscellaneous Symbols", + /*2700..27BF;*/ "Dingbats", + /*2800..28FF;*/ "Braille Patterns", + /*2E80..2EFF;*/ "CJK Radicals Supplement", + /*2F00..2FDF;*/ "Kangxi Radicals", + /*2FF0..2FFF;*/ "Ideographic Description Characters", + /*3000..303F;*/ "CJK Symbols and Punctuation", + /*3040..309F;*/ "Hiragana", + /*30A0..30FF;*/ "Katakana", + /*3100..312F;*/ "Bopomofo", + /*3130..318F;*/ "Hangul Compatibility Jamo", + /*3190..319F;*/ "Kanbun", + /*31A0..31BF;*/ "Bopomofo Extended", + /*3200..32FF;*/ "Enclosed CJK Letters and Months", + /*3300..33FF;*/ "CJK Compatibility", + /*3400..4DB5;*/ "CJK Unified Ideographs Extension A", + /*4E00..9FFF;*/ "CJK Unified Ideographs", + /*A000..A48F;*/ "Yi Syllables", + /*A490..A4CF;*/ "Yi Radicals", + /*AC00..D7A3;*/ "Hangul Syllables", + /*E000..F8FF;*/ "Private Use", + /*F900..FAFF;*/ "CJK Compatibility Ideographs", + /*FB00..FB4F;*/ "Alphabetic Presentation Forms", + /*FB50..FDFF;*/ "Arabic Presentation Forms-A", + /*FE20..FE2F;*/ "Combining Half Marks", + /*FE30..FE4F;*/ "CJK Compatibility Forms", + /*FE50..FE6F;*/ "Small Form Variants", + /*FE70..FEFE;*/ "Arabic Presentation Forms-B", + /*FEFF..FEFF;*/ "Specials", + /*FF00..FFEF;*/ "Halfwidth and Fullwidth Forms", + //missing Specials add manually + /*10300..1032F;*/ "Old Italic", // 84 + /*10330..1034F;*/ "Gothic", + /*10400..1044F;*/ "Deseret", + /*1D000..1D0FF;*/ "Byzantine Musical Symbols", + /*1D100..1D1FF;*/ "Musical Symbols", + /*1D400..1D7FF;*/ "Mathematical Alphanumeric Symbols", + /*20000..2A6D6;*/ "CJK Unified Ideographs Extension B", + /*2F800..2FA1F;*/ "CJK Compatibility Ideographs Supplement", + /*E0000..E007F;*/ "Tags", + //missing 2 private use add manually + + }; + //ADD THOSE MANUALLY + //F0000..FFFFD; "Private Use", + //100000..10FFFD; "Private Use" + //FFF0..FFFD; "Specials", + static final String blockRanges = + "\u0000\u007F\u0080\u00FF\u0100\u017F\u0180\u024F\u0250\u02AF\u02B0\u02FF\u0300\u036F" + +"\u0370\u03FF\u0400\u04FF\u0530\u058F\u0590\u05FF\u0600\u06FF\u0700\u074F\u0780\u07BF" + +"\u0900\u097F\u0980\u09FF\u0A00\u0A7F\u0A80\u0AFF\u0B00\u0B7F\u0B80\u0BFF\u0C00\u0C7F\u0C80\u0CFF" + +"\u0D00\u0D7F\u0D80\u0DFF\u0E00\u0E7F\u0E80\u0EFF\u0F00\u0FFF\u1000\u109F\u10A0\u10FF\u1100\u11FF" + +"\u1200\u137F\u13A0\u13FF\u1400\u167F\u1680\u169F\u16A0\u16FF\u1780\u17FF\u1800\u18AF\u1E00\u1EFF" + +"\u1F00\u1FFF\u2000\u206F\u2070\u209F\u20A0\u20CF\u20D0\u20FF\u2100\u214F\u2150\u218F\u2190\u21FF\u2200\u22FF" + +"\u2300\u23FF\u2400\u243F\u2440\u245F\u2460\u24FF\u2500\u257F\u2580\u259F\u25A0\u25FF\u2600\u26FF\u2700\u27BF" + +"\u2800\u28FF\u2E80\u2EFF\u2F00\u2FDF\u2FF0\u2FFF\u3000\u303F\u3040\u309F\u30A0\u30FF\u3100\u312F\u3130\u318F" + +"\u3190\u319F\u31A0\u31BF\u3200\u32FF\u3300\u33FF\u3400\u4DB5\u4E00\u9FFF\uA000\uA48F\uA490\uA4CF" + +"\uAC00\uD7A3\uE000\uF8FF\uF900\uFAFF\uFB00\uFB4F\uFB50\uFDFF" + +"\uFE20\uFE2F\uFE30\uFE4F\uFE50\uFE6F\uFE70\uFEFE\uFEFF\uFEFF\uFF00\uFFEF"; + static final int[] nonBMPBlockRanges = { + 0x10300, 0x1032F, // 84 + 0x10330, 0x1034F, + 0x10400, 0x1044F, + 0x1D000, 0x1D0FF, + 0x1D100, 0x1D1FF, + 0x1D400, 0x1D7FF, + 0x20000, 0x2A6D6, + 0x2F800, 0x2FA1F, + 0xE0000, 0xE007F + }; + private static final int NONBMP_BLOCK_START = 84; + + static protected RangeToken getRange(String name, boolean positive) { + if (Token.categories.size() == 0) { + synchronized (Token.categories) { + Token[] ranges = new Token[Token.categoryNames.length]; + for (int i = 0; i < ranges.length; i ++) { + ranges[i] = Token.createRange(); + } + int type; + for (int i = 0; i < 0x10000; i ++) { + type = Character.getType((char)i); + if (type == Character.START_PUNCTUATION || + type == Character.END_PUNCTUATION) { + //build table of Pi values + if (i == 0x00AB || i == 0x2018 || i == 0x201B || i == 0x201C || + i == 0x201F || i == 0x2039) { + type = CHAR_INIT_QUOTE; + } + //build table of Pf values + if (i == 0x00BB || i == 0x2019 || i == 0x201D || i == 0x203A ) { + type = CHAR_FINAL_QUOTE; + } + } + ranges[type].addRange(i, i); + switch (type) { + case Character.UPPERCASE_LETTER: + case Character.LOWERCASE_LETTER: + case Character.TITLECASE_LETTER: + case Character.MODIFIER_LETTER: + case Character.OTHER_LETTER: + type = CHAR_LETTER; + break; + case Character.NON_SPACING_MARK: + case Character.COMBINING_SPACING_MARK: + case Character.ENCLOSING_MARK: + type = CHAR_MARK; + break; + case Character.DECIMAL_DIGIT_NUMBER: + case Character.LETTER_NUMBER: + case Character.OTHER_NUMBER: + type = CHAR_NUMBER; + break; + case Character.SPACE_SEPARATOR: + case Character.LINE_SEPARATOR: + case Character.PARAGRAPH_SEPARATOR: + type = CHAR_SEPARATOR; + break; + case Character.CONTROL: + case Character.FORMAT: + case Character.SURROGATE: + case Character.PRIVATE_USE: + case Character.UNASSIGNED: + type = CHAR_OTHER; + break; + case Character.CONNECTOR_PUNCTUATION: + case Character.DASH_PUNCTUATION: + case Character.START_PUNCTUATION: + case Character.END_PUNCTUATION: + case CHAR_INIT_QUOTE: + case CHAR_FINAL_QUOTE: + case Character.OTHER_PUNCTUATION: + type = CHAR_PUNCTUATION; + break; + case Character.MATH_SYMBOL: + case Character.CURRENCY_SYMBOL: + case Character.MODIFIER_SYMBOL: + case Character.OTHER_SYMBOL: + type = CHAR_SYMBOL; + break; + default: + throw new RuntimeException("org.apache.xerces.utils.regex.Token#getRange(): Unknown Unicode category: "+type); + } + ranges[type].addRange(i, i); + } // for all characters + ranges[Character.UNASSIGNED].addRange(0x10000, Token.UTF16_MAX); + ranges[CHAR_OTHER].addRange(0x10000, Token.UTF16_MAX); + + for (int i = 0; i < ranges.length; i ++) { + if (Token.categoryNames[i] != null) { + if (i == Character.UNASSIGNED) { // Unassigned + ranges[i].addRange(0x10000, Token.UTF16_MAX); + } + Token.categories.put(Token.categoryNames[i], ranges[i]); + Token.categories2.put(Token.categoryNames[i], + Token.complementRanges(ranges[i])); + } + } + //REVISIT: do we really need to support block names as in Unicode 3.1 + // or we can just create all the names in IsBLOCKNAME format (XML Schema REC)? + // + StringBuffer buffer = new StringBuffer(50); + for (int i = 0; i < Token.blockNames.length; i ++) { + Token r1 = Token.createRange(); + int location; + if (i < NONBMP_BLOCK_START) { + location = i*2; + int rstart = Token.blockRanges.charAt(location); + int rend = Token.blockRanges.charAt(location+1); + //DEBUGING + //System.out.println(n+" " +Integer.toHexString(rstart) + // +"-"+ Integer.toHexString(rend)); + r1.addRange(rstart, rend); + } else { + location = (i - NONBMP_BLOCK_START) * 2; + r1.addRange(Token.nonBMPBlockRanges[location], + Token.nonBMPBlockRanges[location + 1]); + } + String n = Token.blockNames[i]; + if (n.equals("Specials")) + r1.addRange(0xfff0, 0xfffd); + if (n.equals("Private Use")) { + r1.addRange(0xF0000,0xFFFFD); + r1.addRange(0x100000,0x10FFFD); + } + Token.categories.put(n, r1); + Token.categories2.put(n, Token.complementRanges(r1)); + buffer.setLength(0); + buffer.append("Is"); + if (n.indexOf(' ') >= 0) { + for (int ci = 0; ci < n.length(); ci ++) + if (n.charAt(ci) != ' ') buffer.append((char)n.charAt(ci)); + } + else { + buffer.append(n); + } + Token.setAlias(buffer.toString(), n, true); + } + + // TR#18 1.2 + Token.setAlias("ASSIGNED", "Cn", false); + Token.setAlias("UNASSIGNED", "Cn", true); + Token all = Token.createRange(); + all.addRange(0, Token.UTF16_MAX); + Token.categories.put("ALL", all); + Token.categories2.put("ALL", Token.complementRanges(all)); + Token.registerNonXS("ASSIGNED"); + Token.registerNonXS("UNASSIGNED"); + Token.registerNonXS("ALL"); + + Token isalpha = Token.createRange(); + isalpha.mergeRanges(ranges[Character.UPPERCASE_LETTER]); // Lu + isalpha.mergeRanges(ranges[Character.LOWERCASE_LETTER]); // Ll + isalpha.mergeRanges(ranges[Character.OTHER_LETTER]); // Lo + Token.categories.put("IsAlpha", isalpha); + Token.categories2.put("IsAlpha", Token.complementRanges(isalpha)); + Token.registerNonXS("IsAlpha"); + + Token isalnum = Token.createRange(); + isalnum.mergeRanges(isalpha); // Lu Ll Lo + isalnum.mergeRanges(ranges[Character.DECIMAL_DIGIT_NUMBER]); // Nd + Token.categories.put("IsAlnum", isalnum); + Token.categories2.put("IsAlnum", Token.complementRanges(isalnum)); + Token.registerNonXS("IsAlnum"); + + Token isspace = Token.createRange(); + isspace.mergeRanges(Token.token_spaces); + isspace.mergeRanges(ranges[CHAR_SEPARATOR]); // Z + Token.categories.put("IsSpace", isspace); + Token.categories2.put("IsSpace", Token.complementRanges(isspace)); + Token.registerNonXS("IsSpace"); + + Token isword = Token.createRange(); + isword.mergeRanges(isalnum); // Lu Ll Lo Nd + isword.addRange('_', '_'); + Token.categories.put("IsWord", isword); + Token.categories2.put("IsWord", Token.complementRanges(isword)); + Token.registerNonXS("IsWord"); + + Token isascii = Token.createRange(); + isascii.addRange(0, 127); + Token.categories.put("IsASCII", isascii); + Token.categories2.put("IsASCII", Token.complementRanges(isascii)); + Token.registerNonXS("IsASCII"); + + Token isnotgraph = Token.createRange(); + isnotgraph.mergeRanges(ranges[CHAR_OTHER]); + isnotgraph.addRange(' ', ' '); + Token.categories.put("IsGraph", Token.complementRanges(isnotgraph)); + Token.categories2.put("IsGraph", isnotgraph); + Token.registerNonXS("IsGraph"); + + Token isxdigit = Token.createRange(); + isxdigit.addRange('0', '9'); + isxdigit.addRange('A', 'F'); + isxdigit.addRange('a', 'f'); + Token.categories.put("IsXDigit", Token.complementRanges(isxdigit)); + Token.categories2.put("IsXDigit", isxdigit); + Token.registerNonXS("IsXDigit"); + + Token.setAlias("IsDigit", "Nd", true); + Token.setAlias("IsUpper", "Lu", true); + Token.setAlias("IsLower", "Ll", true); + Token.setAlias("IsCntrl", "C", true); + Token.setAlias("IsPrint", "C", false); + Token.setAlias("IsPunct", "P", true); + Token.registerNonXS("IsDigit"); + Token.registerNonXS("IsUpper"); + Token.registerNonXS("IsLower"); + Token.registerNonXS("IsCntrl"); + Token.registerNonXS("IsPrint"); + Token.registerNonXS("IsPunct"); + + Token.setAlias("alpha", "IsAlpha", true); + Token.setAlias("alnum", "IsAlnum", true); + Token.setAlias("ascii", "IsASCII", true); + Token.setAlias("cntrl", "IsCntrl", true); + Token.setAlias("digit", "IsDigit", true); + Token.setAlias("graph", "IsGraph", true); + Token.setAlias("lower", "IsLower", true); + Token.setAlias("print", "IsPrint", true); + Token.setAlias("punct", "IsPunct", true); + Token.setAlias("space", "IsSpace", true); + Token.setAlias("upper", "IsUpper", true); + Token.setAlias("word", "IsWord", true); // Perl extension + Token.setAlias("xdigit", "IsXDigit", true); + Token.registerNonXS("alpha"); + Token.registerNonXS("alnum"); + Token.registerNonXS("ascii"); + Token.registerNonXS("cntrl"); + Token.registerNonXS("digit"); + Token.registerNonXS("graph"); + Token.registerNonXS("lower"); + Token.registerNonXS("print"); + Token.registerNonXS("punct"); + Token.registerNonXS("space"); + Token.registerNonXS("upper"); + Token.registerNonXS("word"); + Token.registerNonXS("xdigit"); + } // synchronized + } // if null + RangeToken tok = positive ? (RangeToken)Token.categories.get(name) + : (RangeToken)Token.categories2.get(name); + //if (tok == null) System.out.println(name); + return tok; + } + static protected RangeToken getRange(String name, boolean positive, boolean xs) { + RangeToken range = Token.getRange(name, positive); + if (xs && range != null && Token.isRegisterNonXS(name)) + range = null; + return range; + } + + static Hashtable nonxs = null; + /** + * This method is called by only getRange(). + * So this method need not MT-safe. + */ + static protected void registerNonXS(String name) { + if (Token.nonxs == null) + Token.nonxs = new Hashtable(); + Token.nonxs.put(name, name); + } + static protected boolean isRegisterNonXS(String name) { + if (Token.nonxs == null) + return false; + //DEBUG + //System.err.println("isRegisterNonXS: "+name); + return Token.nonxs.containsKey(name); + } + + private static void setAlias(String newName, String name, boolean positive) { + Token t1 = (Token)Token.categories.get(name); + Token t2 = (Token)Token.categories2.get(name); + if (positive) { + Token.categories.put(newName, t1); + Token.categories2.put(newName, t2); + } else { + Token.categories2.put(newName, t1); + Token.categories.put(newName, t2); + } + } + + // ------------------------------------------------------ + + static final String viramaString = + "\u094D"// ;DEVANAGARI SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u09CD"//;BENGALI SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u0A4D"//;GURMUKHI SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u0ACD"//;GUJARATI SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u0B4D"//;ORIYA SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u0BCD"//;TAMIL SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u0C4D"//;TELUGU SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u0CCD"//;KANNADA SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u0D4D"//;MALAYALAM SIGN VIRAMA;Mn;9;ON;;;;;N;;;;; + +"\u0E3A"//;THAI CHARACTER PHINTHU;Mn;9;ON;;;;;N;THAI VOWEL SIGN PHINTHU;;;; + +"\u0F84";//;TIBETAN MARK HALANTA;Mn;9;ON;;;;;N;TIBETAN VIRAMA;;;; + + static private Token token_grapheme = null; + static synchronized Token getGraphemePattern() { + if (Token.token_grapheme != null) + return Token.token_grapheme; + + Token base_char = Token.createRange(); // [{ASSIGNED}]-[{M},{C}] + base_char.mergeRanges(Token.getRange("ASSIGNED", true)); + base_char.subtractRanges(Token.getRange("M", true)); + base_char.subtractRanges(Token.getRange("C", true)); + + Token virama = Token.createRange(); + for (int i = 0; i < Token.viramaString.length(); i++) { + virama.addRange(i, i); + } + + Token combiner_wo_virama = Token.createRange(); + combiner_wo_virama.mergeRanges(Token.getRange("M", true)); + combiner_wo_virama.addRange(0x1160, 0x11ff); // hangul_medial and hangul_final + combiner_wo_virama.addRange(0xff9e, 0xff9f); // extras + + Token left = Token.createUnion(); // base_char? + left.addChild(base_char); + left.addChild(Token.token_empty); + + Token foo = Token.createUnion(); + foo.addChild(Token.createConcat(virama, Token.getRange("L", true))); + foo.addChild(combiner_wo_virama); + + foo = Token.createClosure(foo); + + foo = Token.createConcat(left, foo); + + Token.token_grapheme = foo; + return Token.token_grapheme; + } + + /** + * Combing Character Sequence in Perl 5.6. + */ + static private Token token_ccs = null; + static synchronized Token getCombiningCharacterSequence() { + if (Token.token_ccs != null) + return Token.token_ccs; + + Token foo = Token.createClosure(Token.getRange("M", true)); // \pM* + foo = Token.createConcat(Token.getRange("M", false), foo); // \PM + \pM* + Token.token_ccs = foo; + return Token.token_ccs; + } + + // ------------------------------------------------------ + + // ------------------------------------------------------ + /** + * This class represents a node in parse tree. + */ + static class StringToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = -4614366944218504172L; + + String string; + final int refNumber; + + StringToken(int type, String str, int n) { + super(type); + this.string = str; + this.refNumber = n; + } + + int getReferenceNumber() { // for STRING + return this.refNumber; + } + String getString() { // for STRING + return this.string; + } + + public String toString(int options) { + if (this.type == BACKREFERENCE) + return "\\"+this.refNumber; + else + return REUtil.quoteMeta(this.string); + } + } + + /** + * This class represents a node in parse tree. + */ + static class ConcatToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = 8717321425541346381L; + + final Token child; + final Token child2; + + ConcatToken(Token t1, Token t2) { + super(Token.CONCAT); + this.child = t1; + this.child2 = t2; + } + + int size() { + return 2; + } + Token getChild(int index) { + return index == 0 ? this.child : this.child2; + } + + public String toString(int options) { + String ret; + if (this.child2.type == CLOSURE && this.child2.getChild(0) == this.child) { + ret = this.child.toString(options)+"+"; + } else if (this.child2.type == NONGREEDYCLOSURE && this.child2.getChild(0) == this.child) { + ret = this.child.toString(options)+"+?"; + } else + ret = this.child.toString(options)+this.child2.toString(options); + return ret; + } + } + + /** + * This class represents a node in parse tree. + */ + static class CharToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = -4394272816279496989L; + + final int chardata; + + CharToken(int type, int ch) { + super(type); + this.chardata = ch; + } + + int getChar() { + return this.chardata; + } + + public String toString(int options) { + String ret; + switch (this.type) { + case CHAR: + switch (this.chardata) { + case '|': case '*': case '+': case '?': + case '(': case ')': case '.': case '[': + case '{': case '\\': + ret = "\\"+(char)this.chardata; + break; + case '\f': ret = "\\f"; break; + case '\n': ret = "\\n"; break; + case '\r': ret = "\\r"; break; + case '\t': ret = "\\t"; break; + case 0x1b: ret = "\\e"; break; + //case 0x0b: ret = "\\v"; break; + default: + if (this.chardata >= 0x10000) { + String pre = "0"+Integer.toHexString(this.chardata); + ret = "\\v"+pre.substring(pre.length()-6, pre.length()); + } else + ret = ""+(char)this.chardata; + } + break; + + case ANCHOR: + if (this == Token.token_linebeginning || this == Token.token_lineend) + ret = ""+(char)this.chardata; + else + ret = "\\"+(char)this.chardata; + break; + + default: + ret = null; + } + return ret; + } + + boolean match(int ch) { + if (this.type == CHAR) { + return ch == this.chardata; + } else + throw new RuntimeException("NFAArrow#match(): Internal error: "+this.type); + } + } + + /** + * This class represents a node in parse tree. + */ + static class ClosureToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = 1308971930673997452L; + + int min; + int max; + final Token child; + + ClosureToken(int type, Token tok) { + super(type); + this.child = tok; + this.setMin(-1); + this.setMax(-1); + } + + int size() { + return 1; + } + Token getChild(int index) { + return this.child; + } + + final void setMin(int min) { + this.min = min; + } + final void setMax(int max) { + this.max = max; + } + final int getMin() { + return this.min; + } + final int getMax() { + return this.max; + } + + public String toString(int options) { + String ret; + if (this.type == CLOSURE) { + if (this.getMin() < 0 && this.getMax() < 0) { + ret = this.child.toString(options)+"*"; + } else if (this.getMin() == this.getMax()) { + ret = this.child.toString(options)+"{"+this.getMin()+"}"; + } else if (this.getMin() >= 0 && this.getMax() >= 0) { + ret = this.child.toString(options)+"{"+this.getMin()+","+this.getMax()+"}"; + } else if (this.getMin() >= 0 && this.getMax() < 0) { + ret = this.child.toString(options)+"{"+this.getMin()+",}"; + } else + throw new RuntimeException("Token#toString(): CLOSURE " + +this.getMin()+", "+this.getMax()); + } else { + if (this.getMin() < 0 && this.getMax() < 0) { + ret = this.child.toString(options)+"*?"; + } else if (this.getMin() == this.getMax()) { + ret = this.child.toString(options)+"{"+this.getMin()+"}?"; + } else if (this.getMin() >= 0 && this.getMax() >= 0) { + ret = this.child.toString(options)+"{"+this.getMin()+","+this.getMax()+"}?"; + } else if (this.getMin() >= 0 && this.getMax() < 0) { + ret = this.child.toString(options)+"{"+this.getMin()+",}?"; + } else + throw new RuntimeException("Token#toString(): NONGREEDYCLOSURE " + +this.getMin()+", "+this.getMax()); + } + return ret; + } + } + + /** + * This class represents a node in parse tree. + */ + static class ParenToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = -5938014719827987704L; + + final Token child; + final int parennumber; + + ParenToken(int type, Token tok, int paren) { + super(type); + this.child = tok; + this.parennumber = paren; + } + + int size() { + return 1; + } + Token getChild(int index) { + return this.child; + } + + int getParenNumber() { + return this.parennumber; + } + + public String toString(int options) { + String ret = null; + switch (this.type) { + case PAREN: + if (this.parennumber == 0) { + ret = "(?:"+this.child.toString(options)+")"; + } else { + ret = "("+this.child.toString(options)+")"; + } + break; + + case LOOKAHEAD: + ret = "(?="+this.child.toString(options)+")"; + break; + case NEGATIVELOOKAHEAD: + ret = "(?!"+this.child.toString(options)+")"; + break; + case LOOKBEHIND: + ret = "(?<="+this.child.toString(options)+")"; + break; + case NEGATIVELOOKBEHIND: + ret = "(?"+this.child.toString(options)+")"; + break; + } + return ret; + } + } + + /** + * (?(condition)yes-pattern|no-pattern) + */ + static class ConditionToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = 4353765277910594411L; + + final int refNumber; + final Token condition; + final Token yes; + final Token no; + ConditionToken(int refno, Token cond, Token yespat, Token nopat) { + super(Token.CONDITION); + this.refNumber = refno; + this.condition = cond; + this.yes = yespat; + this.no = nopat; + } + int size() { + return this.no == null ? 1 : 2; + } + Token getChild(int index) { + if (index == 0) return this.yes; + if (index == 1) return this.no; + throw new RuntimeException("Internal Error: "+index); + } + + public String toString(int options) { + String ret; + if (refNumber > 0) { + ret = "(?("+refNumber+")"; + } else if (this.condition.type == Token.ANCHOR) { + ret = "(?("+this.condition+")"; + } else { + ret = "(?"+this.condition; + } + + if (this.no == null) { + ret += this.yes+")"; + } else { + ret += this.yes+"|"+this.no+")"; + } + return ret; + } + } + + /** + * (ims-ims: .... ) + */ + static class ModifierToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = -9114536559696480356L; + + final Token child; + final int add; + final int mask; + + ModifierToken(Token tok, int add, int mask) { + super(Token.MODIFIERGROUP); + this.child = tok; + this.add = add; + this.mask = mask; + } + + int size() { + return 1; + } + Token getChild(int index) { + return this.child; + } + + int getOptions() { + return this.add; + } + int getOptionsMask() { + return this.mask; + } + + public String toString(int options) { + return "(?" + +(this.add == 0 ? "" : REUtil.createOptionString(this.add)) + +(this.mask == 0 ? "" : REUtil.createOptionString(this.mask)) + +":" + +this.child.toString(options) + +")"; + } + } + + /** + * This class represents a node in parse tree. + * for UNION or CONCAT. + */ + static class UnionToken extends Token implements java.io.Serializable { + + private static final long serialVersionUID = -2568843945989489861L; + + Vector children; + + UnionToken(int type) { + super(type); + } + + void addChild(Token tok) { + if (tok == null) return; + if (this.children == null) this.children = new Vector(); + if (this.type == UNION) { + this.children.addElement(tok); + return; + } + // This is CONCAT, and new child is CONCAT. + if (tok.type == CONCAT) { + for (int i = 0; i < tok.size(); i ++) + this.addChild(tok.getChild(i)); // Recursion + return; + } + int size = this.children.size(); + if (size == 0) { + this.children.addElement(tok); + return; + } + Token previous = (Token)this.children.elementAt(size-1); + if (!((previous.type == CHAR || previous.type == STRING) + && (tok.type == CHAR || tok.type == STRING))) { + this.children.addElement(tok); + return; + } + + //System.err.println("Merge '"+previous+"' and '"+tok+"'."); + + StringBuffer buffer; + int nextMaxLength = (tok.type == CHAR ? 2 : tok.getString().length()); + if (previous.type == CHAR) { // Replace previous token by STRING + buffer = new StringBuffer(2 + nextMaxLength); + int ch = previous.getChar(); + if (ch >= 0x10000) + buffer.append(REUtil.decomposeToSurrogates(ch)); + else + buffer.append((char)ch); + previous = Token.createString(null); + this.children.setElementAt(previous, size-1); + } else { // STRING + buffer = new StringBuffer(previous.getString().length() + nextMaxLength); + buffer.append(previous.getString()); + } + + if (tok.type == CHAR) { + int ch = tok.getChar(); + if (ch >= 0x10000) + buffer.append(REUtil.decomposeToSurrogates(ch)); + else + buffer.append((char)ch); + } else { + buffer.append(tok.getString()); + } + + ((StringToken)previous).string = new String(buffer); + } + + int size() { + return this.children == null ? 0 : this.children.size(); + } + Token getChild(int index) { + return (Token)this.children.elementAt(index); + } + + public String toString(int options) { + String ret; + if (this.type == CONCAT) { + if (this.children.size() == 2) { + Token ch = this.getChild(0); + Token ch2 = this.getChild(1); + if (ch2.type == CLOSURE && ch2.getChild(0) == ch) { + ret = ch.toString(options)+"+"; + } else if (ch2.type == NONGREEDYCLOSURE && ch2.getChild(0) == ch) { + ret = ch.toString(options)+"+?"; + } else + ret = ch.toString(options)+ch2.toString(options); + } else { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < this.children.size(); i ++) { + sb.append(((Token)this.children.elementAt(i)).toString(options)); + } + ret = new String(sb); + } + return ret; + } + if (this.children.size() == 2 && this.getChild(1).type == EMPTY) { + ret = this.getChild(0).toString(options)+"?"; + } else if (this.children.size() == 2 + && this.getChild(0).type == EMPTY) { + ret = this.getChild(1).toString(options)+"??"; + } else { + StringBuffer sb = new StringBuffer(); + sb.append(((Token)this.children.elementAt(0)).toString(options)); + for (int i = 1; i < this.children.size(); i ++) { + sb.append((char)'|'); + sb.append(((Token)this.children.elementAt(i)).toString(options)); + } + ret = new String(sb); + } + return ret; + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/message.properties b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/message.properties new file mode 100644 index 0000000..7e15bfe --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xpath/regex/message.properties @@ -0,0 +1,58 @@ +# +# 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. +# + +# @version $Id$ + +parser.parse.1=Wrong character. +parser.parse.2=Invalid reference number. +parser.next.1=A character is required after \\. +parser.next.2='?' is not expected. '(?:' or '(?=' or '(?!' or '(?<' or '(?#' or '(?>'? +parser.next.3='(?<=' or '(?'? +parser.next.3='(?<=' ou '(?'? +parser.next.3='(?<=' \u307e\u305f\u306f '(? 0) { + final StringList errorMessages = attrPSVI.getErrorMessages(); + final String[] errors = new String[length << 1]; + for (int i = 0, j = 0; i < length; ++i) { + errors[j++] = errorCodes.item(i); + errors[j++] = errorMessages.item(i); + } + fErrors = errors; + } + } + fValidationContext = attrPSVI.getValidationContext(); + fIsConstant = isConstant; + } + + // + // AttributePSVI methods + // + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#constant() + */ + public ItemPSVI constant() { + if (isConstant()) { + return this; + } + return new AttributePSVImpl(true, this); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#isConstant() + */ + public boolean isConstant() { + return fIsConstant; + } + + /** + * [schema default] + * + * @return The canonical lexical representation of the declaration's {value constraint} value. + * @see XML Schema Part 1: Structures [schema normalized value] + * @return the normalized value of this item after validation + */ + public String getSchemaNormalizedValue() { + return fValue.getNormalizedValue(); + } + + /** + * [schema specified] + * @see XML Schema Part 1: Structures [schema specified] + * @return true - value was specified in schema, false - value comes from the infoset + */ + public boolean getIsSchemaSpecified() { + return fSpecified; + } + + + /** + * Determines the extent to which the document has been validated + * + * @return return the [validation attempted] property. The possible values are + * NO_VALIDATION, PARTIAL_VALIDATION and FULL_VALIDATION + */ + public short getValidationAttempted() { + return fValidationAttempted; + } + + /** + * Determine the validity of the node with respect + * to the validation being attempted + * + * @return return the [validity] property. Possible values are: + * UNKNOWN_VALIDITY, INVALID_VALIDITY, VALID_VALIDITY + */ + public short getValidity() { + return fValidity; + } + + /** + * A list of error codes generated from validation attempts. + * Need to find all the possible subclause reports that need reporting + * + * @return list of error codes + */ + public StringList getErrorCodes() { + if (fErrors == null || fErrors.length == 0) { + return StringListImpl.EMPTY_LIST; + } + return new PSVIErrorList(fErrors, true); + } + + /** + * A list of error messages generated from the validation attempt or + * an empty StringList if no errors occurred during the + * validation attempt. The indices of error messages in this list are + * aligned with those in the [schema error code] list. + */ + public StringList getErrorMessages() { + if (fErrors == null || fErrors.length == 0) { + return StringListImpl.EMPTY_LIST; + } + return new PSVIErrorList(fErrors, false); + } + + // This is the only information we can provide in a pipeline. + public String getValidationContext() { + return fValidationContext; + } + + /** + * An item isomorphic to the type definition used to validate this element. + * + * @return a type declaration + */ + public XSTypeDefinition getTypeDefinition() { + return fTypeDecl; + } + + /** + * If and only if that type definition is a simple type definition + * with {variety} union, or a complex type definition whose {content type} + * is a simple thype definition with {variety} union, then an item isomorphic + * to that member of the union's {member type definitions} which actually + * validated the element item's normalized value. + * + * @return a simple type declaration + */ + public XSSimpleTypeDefinition getMemberTypeDefinition() { + return fValue.getMemberTypeDefinition(); + } + + /** + * An item isomorphic to the attribute declaration used to validate + * this attribute. + * + * @return an attribute declaration + */ + public XSAttributeDeclaration getAttributeDeclaration() { + return fDeclaration; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getActualNormalizedValue() + */ + public Object getActualNormalizedValue() { + return fValue.getActualValue(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getActualNormalizedValueType() + */ + public short getActualNormalizedValueType() { + return fValue.getActualValueType(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getItemValueTypes() + */ + public ShortList getItemValueTypes() { + return fValue.getListValueTypes(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getSchemaValue() + */ + public XSValue getSchemaValue() { + return fValue; + } + + /** + * Reset() + */ + public void reset() { + fValue.reset(); + fDeclaration = null; + fTypeDecl = null; + fSpecified = false; + fValidationAttempted = AttributePSVI.VALIDATION_NONE; + fValidity = AttributePSVI.VALIDITY_NOTKNOWN; + fErrors = null; + fValidationContext = null; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/ElementPSVImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/ElementPSVImpl.java new file mode 100644 index 0000000..6673bbc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/ElementPSVImpl.java @@ -0,0 +1,340 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.ItemPSVI; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSElementDeclaration; +import org.apache.xerces.xs.XSModel; +import org.apache.xerces.xs.XSNotationDeclaration; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; +import org.apache.xerces.xs.XSValue; + +/** + * Element PSV infoset augmentations implementation. + * The following information will be available at the startElement call: + * name, namespace, type, notation, validation context + * + * The following information will be available at the endElement call: + * nil, specified, normalized value, member type, validity, error codes, + * default + * + * @xerces.internal + * + * @author Elena Litani IBM + * @version $Id$ + */ +public class ElementPSVImpl implements ElementPSVI { + + /** element declaration */ + protected XSElementDeclaration fDeclaration = null; + + /** type of element, could be xsi:type */ + protected XSTypeDefinition fTypeDecl = null; + + /** true if clause 3.2 of Element Locally Valid (Element) (3.3.4) + * is satisfied, otherwise false + */ + protected boolean fNil = false; + + /** true if the element value was provided by the schema; false otherwise. + */ + protected boolean fSpecified = false; + + /** Schema value */ + protected ValidatedInfo fValue = new ValidatedInfo(); + + /** http://www.w3.org/TR/xmlschema-1/#e-notation*/ + protected XSNotationDeclaration fNotation = null; + + /** validation attempted: none, partial, full */ + protected short fValidationAttempted = ElementPSVI.VALIDATION_NONE; + + /** validity: valid, invalid, unknown */ + protected short fValidity = ElementPSVI.VALIDITY_NOTKNOWN; + + /** error codes and error messages */ + protected String[] fErrors = null; + + /** validation context: could be QName or XPath expression*/ + protected String fValidationContext = null; + + /** deferred XSModel **/ + protected SchemaGrammar[] fGrammars = null; + + /** the schema information property */ + protected XSModel fSchemaInformation = null; + + /** true if this object is immutable **/ + protected boolean fIsConstant; + + public ElementPSVImpl() {} + + public ElementPSVImpl(boolean isConstant, ElementPSVI elementPSVI) { + fDeclaration = elementPSVI.getElementDeclaration(); + fTypeDecl = elementPSVI.getTypeDefinition(); + fNil = elementPSVI.getNil(); + fSpecified = elementPSVI.getIsSchemaSpecified(); + fValue.copyFrom(elementPSVI.getSchemaValue()); + fNotation = elementPSVI.getNotation(); + fValidationAttempted = elementPSVI.getValidationAttempted(); + fValidity = elementPSVI.getValidity(); + fValidationContext = elementPSVI.getValidationContext(); + if (elementPSVI instanceof ElementPSVImpl) { + final ElementPSVImpl elementPSVIImpl = (ElementPSVImpl) elementPSVI; + fErrors = (elementPSVIImpl.fErrors != null) ? + (String[]) elementPSVIImpl.fErrors.clone() : null; + elementPSVIImpl.copySchemaInformationTo(this); + } + else { + final StringList errorCodes = elementPSVI.getErrorCodes(); + final int length = errorCodes.getLength(); + if (length > 0) { + final StringList errorMessages = elementPSVI.getErrorMessages(); + final String[] errors = new String[length << 1]; + for (int i = 0, j = 0; i < length; ++i) { + errors[j++] = errorCodes.item(i); + errors[j++] = errorMessages.item(i); + } + fErrors = errors; + } + fSchemaInformation = elementPSVI.getSchemaInformation(); + } + fIsConstant = isConstant; + } + + // + // ElementPSVI methods + // + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#constant() + */ + public ItemPSVI constant() { + if (isConstant()) { + return this; + } + return new ElementPSVImpl(true, this); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#isConstant() + */ + public boolean isConstant() { + return fIsConstant; + } + + /** + * [schema default] + * + * @return The canonical lexical representation of the declaration's {value constraint} value. + * @see XML Schema Part 1: Structures [schema normalized value] + * @return the normalized value of this item after validation + */ + public String getSchemaNormalizedValue() { + return fValue.getNormalizedValue(); + } + + /** + * [schema specified] + * @see XML Schema Part 1: Structures [schema specified] + * @return true - value was specified in schema, false - value comes from the infoset + */ + public boolean getIsSchemaSpecified() { + return fSpecified; + } + + /** + * Determines the extent to which the document has been validated + * + * @return return the [validation attempted] property. The possible values are + * NO_VALIDATION, PARTIAL_VALIDATION and FULL_VALIDATION + */ + public short getValidationAttempted() { + return fValidationAttempted; + } + + /** + * Determine the validity of the node with respect + * to the validation being attempted + * + * @return return the [validity] property. Possible values are: + * UNKNOWN_VALIDITY, INVALID_VALIDITY, VALID_VALIDITY + */ + public short getValidity() { + return fValidity; + } + + /** + * A list of error codes generated from validation attempts. + * Need to find all the possible subclause reports that need reporting + * + * @return Array of error codes + */ + public StringList getErrorCodes() { + if (fErrors == null || fErrors.length == 0) { + return StringListImpl.EMPTY_LIST; + } + return new PSVIErrorList(fErrors, true); + } + + /** + * A list of error messages generated from the validation attempt or + * an empty StringList if no errors occurred during the + * validation attempt. The indices of error messages in this list are + * aligned with those in the [schema error code] list. + */ + public StringList getErrorMessages() { + if (fErrors == null || fErrors.length == 0) { + return StringListImpl.EMPTY_LIST; + } + return new PSVIErrorList(fErrors, false); + } + + // This is the only information we can provide in a pipeline. + public String getValidationContext() { + return fValidationContext; + } + + /** + * [nil] + * @see XML Schema Part 1: Structures [notation] + * @return The notation declaration. + */ + public XSNotationDeclaration getNotation() { + return fNotation; + } + + /** + * An item isomorphic to the type definition used to validate this element. + * + * @return a type declaration + */ + public XSTypeDefinition getTypeDefinition() { + return fTypeDecl; + } + + /** + * If and only if that type definition is a simple type definition + * with {variety} union, or a complex type definition whose {content type} + * is a simple thype definition with {variety} union, then an item isomorphic + * to that member of the union's {member type definitions} which actually + * validated the element item's normalized value. + * + * @return a simple type declaration + */ + public XSSimpleTypeDefinition getMemberTypeDefinition() { + return fValue.getMemberTypeDefinition(); + } + + /** + * An item isomorphic to the element declaration used to validate + * this element. + * + * @return an element declaration + */ + public XSElementDeclaration getElementDeclaration() { + return fDeclaration; + } + + /** + * [schema information] + * @see XML Schema Part 1: Structures [schema information] + * @return The schema information property if it's the validation root, + * null otherwise. + */ + public synchronized XSModel getSchemaInformation() { + if (fSchemaInformation == null && fGrammars != null) { + fSchemaInformation = new XSModelImpl(fGrammars); + } + return fSchemaInformation; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getActualNormalizedValue() + */ + public Object getActualNormalizedValue() { + return fValue.getActualValue(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getActualNormalizedValueType() + */ + public short getActualNormalizedValueType() { + return fValue.getActualValueType(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getItemValueTypes() + */ + public ShortList getItemValueTypes() { + return fValue.getListValueTypes(); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.ItemPSVI#getSchemaValue() + */ + public XSValue getSchemaValue() { + return fValue; + } + + /** + * Reset() should be called in validator startElement(..) method. + */ + public void reset() { + fDeclaration = null; + fTypeDecl = null; + fNil = false; + fSpecified = false; + fNotation = null; + fValidationAttempted = ElementPSVI.VALIDATION_NONE; + fValidity = ElementPSVI.VALIDITY_NOTKNOWN; + fErrors = null; + fValidationContext = null; + fValue.reset(); + } + + public void copySchemaInformationTo(ElementPSVImpl target) { + target.fGrammars = fGrammars; + target.fSchemaInformation = fSchemaInformation; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/FilePathToURI.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/FilePathToURI.java new file mode 100644 index 0000000..76acb05 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/FilePathToURI.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +/** + * @xerces.internal + * + * @version $Id$ + */ +final class FilePathToURI { + + // which ASCII characters need to be escaped + private static boolean gNeedEscaping[] = new boolean[128]; + // the first hex character if a character needs to be escaped + private static char gAfterEscaping1[] = new char[128]; + // the second hex character if a character needs to be escaped + private static char gAfterEscaping2[] = new char[128]; + private static char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + // initialize the above 3 arrays + static { + for (int i = 0; i <= 0x1f; i++) { + gNeedEscaping[i] = true; + gAfterEscaping1[i] = gHexChs[i >> 4]; + gAfterEscaping2[i] = gHexChs[i & 0xf]; + } + gNeedEscaping[0x7f] = true; + gAfterEscaping1[0x7f] = '7'; + gAfterEscaping2[0x7f] = 'F'; + char[] escChs = {' ', '<', '>', '#', '%', '"', '{', '}', + '|', '\\', '^', '~', '[', ']', '`'}; + int len = escChs.length; + char ch; + for (int i = 0; i < len; i++) { + ch = escChs[i]; + gNeedEscaping[ch] = true; + gAfterEscaping1[ch] = gHexChs[ch >> 4]; + gAfterEscaping2[ch] = gHexChs[ch & 0xf]; + } + } + + private FilePathToURI() {} + + // To escape a file path to a URI, by using %HH to represent + // special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', '#', '%' + // and '"' and non-ASCII characters (whose value >= 128). + public static String filepath2URI(String path){ + // return null if path is null. + if (path == null) + return null; + + char separator = java.io.File.separatorChar; + path = path.replace(separator, '/'); + + int len = path.length(), ch; + StringBuffer buffer = new StringBuffer(len*3); + buffer.append("file://"); + // change C:/blah to /C:/blah + if (len >= 2 && path.charAt(1) == ':') { + ch = Character.toUpperCase(path.charAt(0)); + if (ch >= 'A' && ch <= 'Z') { + buffer.append('/'); + } + } + + // for each character in the path + int i = 0; + for (; i < len; i++) { + ch = path.charAt(i); + // if it's not an ASCII character, break here, and use UTF-8 encoding + if (ch >= 128) + break; + if (gNeedEscaping[ch]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[ch]); + buffer.append(gAfterEscaping2[ch]); + // record the fact that it's escaped + } + else { + buffer.append((char)ch); + } + } + + // we saw some non-ascii character + if (i < len) { + // get UTF-8 bytes for the remaining sub-string + byte[] bytes = null; + byte b; + try { + bytes = path.substring(i).getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException e) { + // should never happen + return path; + } + len = bytes.length; + + // for each byte + for (i = 0; i < len; i++) { + b = bytes[i]; + // for non-ascii character: make it positive, then escape + if (b < 0) { + ch = b + 256; + buffer.append('%'); + buffer.append(gHexChs[ch >> 4]); + buffer.append(gHexChs[ch & 0xf]); + } + else if (gNeedEscaping[b]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[b]); + buffer.append(gAfterEscaping2[b]); + } + else { + buffer.append((char)b); + } + } + } + + return buffer.toString(); + } + +} //FilePathToURI diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/PSVIErrorList.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/PSVIErrorList.java new file mode 100644 index 0000000..36e2615 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/PSVIErrorList.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.util.AbstractList; + +import org.apache.xerces.xs.StringList; + +/** + * StringList implementation for schema error codes and error messages. + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +final class PSVIErrorList extends AbstractList implements StringList { + + private final String[] fArray; + private final int fLength; + private final int fOffset; + + public PSVIErrorList(String[] array, boolean even) { + fArray = array; + fLength = (fArray.length >> 1); + fOffset = even ? 0 : 1; + } + + public boolean contains(String item) { + if (item == null) { + for (int i = 0; i < fLength; ++i) { + if (fArray[(i << 1) + fOffset] == null) { + return true; + } + } + } + else { + for (int i = 0; i < fLength; ++i) { + if (item.equals(fArray[(i << 1) + fOffset])) { + return true; + } + } + } + return false; + } + + public int getLength() { + return fLength; + } + + public String item(int index) { + if (index < 0 || index >= fLength) { + return null; + } + return fArray[(index << 1) + fOffset]; + } + + /* + * List methods + */ + + public Object get(int index) { + if (index >= 0 && index < fLength) { + return fArray[(index << 1) + fOffset]; + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + +} // class PSVIErrorList diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaGrammar.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaGrammar.java new file mode 100644 index 0000000..ae88c28 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaGrammar.java @@ -0,0 +1,1689 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.lang.ref.SoftReference; +import java.util.Vector; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.dv.SchemaDVFactory; +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.xs.identity.IdentityConstraint; +import org.apache.xerces.impl.xs.util.ObjectListImpl; +import org.apache.xerces.impl.xs.util.SimpleLocator; +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.impl.xs.util.XSNamedMap4Types; +import org.apache.xerces.impl.xs.util.XSNamedMapImpl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.parsers.SAXParser; +import org.apache.xerces.parsers.XML11Configuration; +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XSGrammar; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSAttributeDeclaration; +import org.apache.xerces.xs.XSAttributeGroupDefinition; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSElementDeclaration; +import org.apache.xerces.xs.XSIDCDefinition; +import org.apache.xerces.xs.XSModel; +import org.apache.xerces.xs.XSModelGroupDefinition; +import org.apache.xerces.xs.XSNamedMap; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSNotationDeclaration; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; +import org.apache.xerces.xs.XSWildcard; +import org.apache.xerces.xs.datatypes.ObjectList; +import org.xml.sax.SAXException; + +/** + * This class is to hold all schema component declaration that are declared + * within one namespace. + * + * The Grammar class this class extends contains what little + * commonality there is between XML Schema and DTD grammars. It's + * useful to distinguish grammar objects from other kinds of object + * when they exist in pools or caches. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @author Elena Litani, IBM + * + * @version $Id$ + */ + +public class SchemaGrammar implements XSGrammar, XSNamespaceItem { + + // the target namespace of grammar + String fTargetNamespace; + + // global decls: map from decl name to decl object + SymbolHash fGlobalAttrDecls; + SymbolHash fGlobalAttrGrpDecls; + SymbolHash fGlobalElemDecls; + SymbolHash fGlobalGroupDecls; + SymbolHash fGlobalNotationDecls; + SymbolHash fGlobalIDConstraintDecls; + SymbolHash fGlobalTypeDecls; + + // extended global decls: map from schema location + decl name to decl object + // key is location,name + SymbolHash fGlobalAttrDeclsExt; + SymbolHash fGlobalAttrGrpDeclsExt; + SymbolHash fGlobalElemDeclsExt; + SymbolHash fGlobalGroupDeclsExt; + SymbolHash fGlobalNotationDeclsExt; + SymbolHash fGlobalIDConstraintDeclsExt; + SymbolHash fGlobalTypeDeclsExt; + + // A global map of all global element declarations - used for substitution group computation + // (handy when sharing components by reference, since we might end up with duplicate components + // that are not added to either of the global element declarations above) + SymbolHash fAllGlobalElemDecls; + + // the XMLGrammarDescription member + XSDDescription fGrammarDescription = null; + + // annotations associated with the "root" schema of this targetNamespace + XSAnnotationImpl [] fAnnotations = null; + + // number of annotations declared + int fNumAnnotations; + + // symbol table for constructing parsers (annotation support) + private SymbolTable fSymbolTable = null; + // parsers for annotation support + private SoftReference fSAXParser = null; + private SoftReference fDOMParser = null; + + // is this grammar immutable? (fully constructed and not changeable) + private boolean fIsImmutable = false; + + // + // Constructors + // + + // needed to make BuiltinSchemaGrammar work. + protected SchemaGrammar() {} + + /** + * Default constructor. + * + * @param targetNamespace + * @param grammarDesc the XMLGrammarDescription corresponding to this objec + * at the least a systemId should always be known. + * @param symbolTable needed for annotation support + */ + public SchemaGrammar(String targetNamespace, XSDDescription grammarDesc, + SymbolTable symbolTable) { + fTargetNamespace = targetNamespace; + fGrammarDescription = grammarDesc; + fSymbolTable = symbolTable; + + // REVISIT: the initial sizes being chosen for each SymbolHash + // may not be ideal and could still be tuned. They were chosen + // somewhat arbitrarily to reduce the initial footprint of + // SymbolHash buckets from 1,515 to 177 (about 12% of the + // default size). + fGlobalAttrDecls = new SymbolHash(12); + fGlobalAttrGrpDecls = new SymbolHash(5); + fGlobalElemDecls = new SymbolHash(25); + fGlobalGroupDecls = new SymbolHash(5); + fGlobalNotationDecls = new SymbolHash(1); + fGlobalIDConstraintDecls = new SymbolHash(3); + + // Extended tables + fGlobalAttrDeclsExt = new SymbolHash(12); + fGlobalAttrGrpDeclsExt = new SymbolHash(5); + fGlobalElemDeclsExt = new SymbolHash(25); + fGlobalGroupDeclsExt = new SymbolHash(5); + fGlobalNotationDeclsExt = new SymbolHash(1); + fGlobalIDConstraintDeclsExt = new SymbolHash(3); + fGlobalTypeDeclsExt = new SymbolHash(25); + + // All global elements table + fAllGlobalElemDecls = new SymbolHash(25); + + // if we are parsing S4S, put built-in types in first + // they might get overwritten by the types from S4S, but that's + // considered what the application wants to do. + if (fTargetNamespace == SchemaSymbols.URI_SCHEMAFORSCHEMA) { + fGlobalTypeDecls = SG_SchemaNS.fGlobalTypeDecls.makeClone(); + } + else { + fGlobalTypeDecls = new SymbolHash(25); + } + } // (String, XSDDescription) + + // Clone an existing schema grammar + public SchemaGrammar(SchemaGrammar grammar) { + fTargetNamespace = grammar.fTargetNamespace; + fGrammarDescription = grammar.fGrammarDescription.makeClone(); + //fGrammarDescription.fContextType |= XSDDescription.CONTEXT_COLLISION; // REVISIT + fSymbolTable = grammar.fSymbolTable; // REVISIT + + fGlobalAttrDecls = grammar.fGlobalAttrDecls.makeClone(); + fGlobalAttrGrpDecls = grammar.fGlobalAttrGrpDecls.makeClone(); + fGlobalElemDecls = grammar.fGlobalElemDecls.makeClone(); + fGlobalGroupDecls = grammar.fGlobalGroupDecls.makeClone(); + fGlobalNotationDecls = grammar.fGlobalNotationDecls.makeClone(); + fGlobalIDConstraintDecls = grammar.fGlobalIDConstraintDecls.makeClone(); + fGlobalTypeDecls = grammar.fGlobalTypeDecls.makeClone(); + + // Extended tables + fGlobalAttrDeclsExt = grammar.fGlobalAttrDeclsExt.makeClone(); + fGlobalAttrGrpDeclsExt = grammar.fGlobalAttrGrpDeclsExt.makeClone(); + fGlobalElemDeclsExt = grammar.fGlobalElemDeclsExt.makeClone(); + fGlobalGroupDeclsExt = grammar.fGlobalGroupDeclsExt.makeClone(); + fGlobalNotationDeclsExt = grammar.fGlobalNotationDeclsExt.makeClone(); + fGlobalIDConstraintDeclsExt = grammar.fGlobalIDConstraintDeclsExt.makeClone(); + fGlobalTypeDeclsExt = grammar.fGlobalTypeDeclsExt.makeClone(); + + // All global elements table + fAllGlobalElemDecls = grammar.fAllGlobalElemDecls.makeClone(); + + // Annotations associated with the "root" schema of this targetNamespace + fNumAnnotations = grammar.fNumAnnotations; + if (fNumAnnotations > 0) { + fAnnotations = new XSAnnotationImpl[grammar.fAnnotations.length]; + System.arraycopy(grammar.fAnnotations, 0, fAnnotations, 0, fNumAnnotations); + } + + // All substitution group information declared in this namespace + fSubGroupCount = grammar.fSubGroupCount; + if (fSubGroupCount > 0) { + fSubGroups = new XSElementDecl[grammar.fSubGroups.length]; + System.arraycopy(grammar.fSubGroups, 0, fSubGroups, 0, fSubGroupCount); + } + + // Array to store complex type decls for constraint checking + fCTCount = grammar.fCTCount; + if (fCTCount > 0) { + fComplexTypeDecls = new XSComplexTypeDecl[grammar.fComplexTypeDecls.length]; + fCTLocators = new SimpleLocator[grammar.fCTLocators.length]; + System.arraycopy(grammar.fComplexTypeDecls, 0, fComplexTypeDecls, 0, fCTCount); + System.arraycopy(grammar.fCTLocators, 0, fCTLocators, 0, fCTCount); + } + + // Groups being redefined by restriction + fRGCount = grammar.fRGCount; + if (fRGCount > 0) { + fRedefinedGroupDecls = new XSGroupDecl[grammar.fRedefinedGroupDecls.length]; + fRGLocators = new SimpleLocator[grammar.fRGLocators.length]; + System.arraycopy(grammar.fRedefinedGroupDecls, 0, fRedefinedGroupDecls, 0, fRGCount); + System.arraycopy(grammar.fRGLocators, 0, fRGLocators, 0, fRGCount/2); + } + + // List of imported grammars + if (grammar.fImported != null) { + fImported = new Vector(); + for (int i=0; i(String, XSDDescription) + + // number of built-in XSTypes we need to create for base and full + // datatype set + private static final int BASICSET_COUNT = 29; + private static final int FULLSET_COUNT = 46; + + private static final int GRAMMAR_XS = 1; + private static final int GRAMMAR_XSI = 2; + + // this class makes sure the static, built-in schema grammars + // are immutable. + public static class BuiltinSchemaGrammar extends SchemaGrammar { + + private static final String EXTENDED_SCHEMA_FACTORY_CLASS = "org.apache.xerces.impl.dv.xs.ExtendedSchemaDVFactoryImpl"; + + /** + * Special constructor to create the grammars for the schema namespaces + * + * @param grammar + */ + public BuiltinSchemaGrammar(int grammar, short schemaVersion) { + SchemaDVFactory schemaFactory; + if (schemaVersion == Constants.SCHEMA_VERSION_1_0) { + schemaFactory = SchemaDVFactory.getInstance(); + } + else { + schemaFactory = SchemaDVFactory.getInstance(EXTENDED_SCHEMA_FACTORY_CLASS); + } + + if (grammar == GRAMMAR_XS) { + // target namespace + fTargetNamespace = SchemaSymbols.URI_SCHEMAFORSCHEMA; + + // grammar description + fGrammarDescription = new XSDDescription(); + fGrammarDescription.fContextType = XSDDescription.CONTEXT_PREPARSE; + fGrammarDescription.setNamespace(SchemaSymbols.URI_SCHEMAFORSCHEMA); + + // no global decls other than types + fGlobalAttrDecls = new SymbolHash(1); + fGlobalAttrGrpDecls = new SymbolHash(1); + fGlobalElemDecls = new SymbolHash(1); + fGlobalGroupDecls = new SymbolHash(1); + fGlobalNotationDecls = new SymbolHash(1); + fGlobalIDConstraintDecls = new SymbolHash(1); + + // no extended global decls + fGlobalAttrDeclsExt = new SymbolHash(1); + fGlobalAttrGrpDeclsExt = new SymbolHash(1); + fGlobalElemDeclsExt = new SymbolHash(1); + fGlobalGroupDeclsExt = new SymbolHash(1); + fGlobalNotationDeclsExt = new SymbolHash(1); + fGlobalIDConstraintDeclsExt = new SymbolHash(1); + fGlobalTypeDeclsExt = new SymbolHash(1); + + // all global element decls table + fAllGlobalElemDecls = new SymbolHash(1); + + // get all built-in types + fGlobalTypeDecls = schemaFactory.getBuiltInTypes(); + + // assign the built-in schema grammar as the XSNamespaceItem + // for each of the built-in simple type definitions. + int length = fGlobalTypeDecls.getLength(); + XSTypeDefinition [] typeDefinitions = new XSTypeDefinition[length]; + fGlobalTypeDecls.getValues(typeDefinitions, 0); + for (int i = 0; i < length; ++i) { + XSTypeDefinition xtd = typeDefinitions[i]; + if (xtd instanceof XSSimpleTypeDecl) { + ((XSSimpleTypeDecl) xtd).setNamespaceItem(this); + } + } + + // add anyType + fGlobalTypeDecls.put(fAnyType.getName(), fAnyType); + } + else if (grammar == GRAMMAR_XSI) { + // target namespace + fTargetNamespace = SchemaSymbols.URI_XSI; + // grammar description + fGrammarDescription = new XSDDescription(); + fGrammarDescription.fContextType = XSDDescription.CONTEXT_PREPARSE; + fGrammarDescription.setNamespace(SchemaSymbols.URI_XSI); + + // no global decls other than attributes + fGlobalAttrGrpDecls = new SymbolHash(1); + fGlobalElemDecls = new SymbolHash(1); + fGlobalGroupDecls = new SymbolHash(1); + fGlobalNotationDecls = new SymbolHash(1); + fGlobalIDConstraintDecls = new SymbolHash(1); + fGlobalTypeDecls = new SymbolHash(1); + + // no extended global decls + fGlobalAttrDeclsExt = new SymbolHash(1); + fGlobalAttrGrpDeclsExt = new SymbolHash(1); + fGlobalElemDeclsExt = new SymbolHash(1); + fGlobalGroupDeclsExt = new SymbolHash(1); + fGlobalNotationDeclsExt = new SymbolHash(1); + fGlobalIDConstraintDeclsExt = new SymbolHash(1); + fGlobalTypeDeclsExt = new SymbolHash(1); + + // no all global element decls + fAllGlobalElemDecls = new SymbolHash(1); + + // 4 attributes, so initialize the size as 4*2 = 8 + fGlobalAttrDecls = new SymbolHash(8); + String name = null; + String tns = null; + XSSimpleType type = null; + short scope = XSConstants.SCOPE_GLOBAL; + + // xsi:type + name = SchemaSymbols.XSI_TYPE; + tns = SchemaSymbols.URI_XSI; + type = schemaFactory.getBuiltInType(SchemaSymbols.ATTVAL_QNAME); + fGlobalAttrDecls.put(name, new BuiltinAttrDecl(name, tns, type, scope)); + + // xsi:nil + name = SchemaSymbols.XSI_NIL; + tns = SchemaSymbols.URI_XSI; + type = schemaFactory.getBuiltInType(SchemaSymbols.ATTVAL_BOOLEAN); + fGlobalAttrDecls.put(name, new BuiltinAttrDecl(name, tns, type, scope)); + + XSSimpleType anyURI = schemaFactory.getBuiltInType(SchemaSymbols.ATTVAL_ANYURI); + + // xsi:schemaLocation + name = SchemaSymbols.XSI_SCHEMALOCATION; + tns = SchemaSymbols.URI_XSI; + type = schemaFactory.createTypeList("#AnonType_schemaLocation", SchemaSymbols.URI_XSI, (short)0, anyURI, null); + if (type instanceof XSSimpleTypeDecl) { + ((XSSimpleTypeDecl)type).setAnonymous(true); + } + fGlobalAttrDecls.put(name, new BuiltinAttrDecl(name, tns, type, scope)); + + // xsi:noNamespaceSchemaLocation + name = SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION; + tns = SchemaSymbols.URI_XSI; + type = anyURI; + fGlobalAttrDecls.put(name, new BuiltinAttrDecl(name, tns, type, scope)); + } + } // (int) + + // return the XMLGrammarDescription corresponding to this + // object + public XMLGrammarDescription getGrammarDescription() { + return fGrammarDescription.makeClone(); + } // getGrammarDescription(): XMLGrammarDescription + + // override these methods solely so that these + // objects cannot be modified once they're created. + public void setImportedGrammars(Vector importedGrammars) { + // ignore + } + public void addGlobalAttributeDecl(XSAttributeDecl decl) { + // ignore + } + public void addGlobalAttributeDecl(XSAttributeDecl decl, String location) { + // ignore + } + public void addGlobalAttributeGroupDecl(XSAttributeGroupDecl decl) { + // ignore + } + public void addGlobalAttributeGroupDecl(XSAttributeGroupDecl decl, String location) { + // ignore + } + public void addGlobalElementDecl(XSElementDecl decl) { + // ignore + } + public void addGlobalElementDecl(XSElementDecl decl, String location) { + // ignore + } + public void addGlobalElementDeclAll(XSElementDecl decl) { + // ignore + } + public void addGlobalGroupDecl(XSGroupDecl decl) { + // ignore + } + public void addGlobalGroupDecl(XSGroupDecl decl, String location) { + // ignore + } + public void addGlobalNotationDecl(XSNotationDecl decl) { + // ignore + } + public void addGlobalNotationDecl(XSNotationDecl decl, String location) { + // ignore + } + public void addGlobalTypeDecl(XSTypeDefinition decl) { + // ignore + } + public void addGlobalTypeDecl(XSTypeDefinition decl, String location) { + // ignore + } + public void addGlobalComplexTypeDecl(XSComplexTypeDecl decl) { + // ignore + } + public void addGlobalComplexTypeDecl(XSComplexTypeDecl decl, String location) { + // ignore + } + public void addGlobalSimpleTypeDecl(XSSimpleType decl) { + // ignore + } + public void addGlobalSimpleTypeDecl(XSSimpleType decl, String location) { + // ignore + } + public void addComplexTypeDecl(XSComplexTypeDecl decl, SimpleLocator locator) { + // ignore + } + public void addRedefinedGroupDecl(XSGroupDecl derived, XSGroupDecl base, SimpleLocator locator) { + // ignore + } + public synchronized void addDocument(Object document, String location) { + // ignore + } + + // annotation support + synchronized DOMParser getDOMParser() { + return null; + } + synchronized SAXParser getSAXParser() { + return null; + } + } + + /** + *

A partial schema for schemas for validating annotations.

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + */ + public static final class Schema4Annotations extends SchemaGrammar { + + /** + * Singleton instance. + */ + public static final Schema4Annotations INSTANCE = new Schema4Annotations(); + + /** + * Special constructor to create a schema + * capable of validating annotations. + */ + private Schema4Annotations() { + + // target namespace + fTargetNamespace = SchemaSymbols.URI_SCHEMAFORSCHEMA; + + // grammar description + fGrammarDescription = new XSDDescription(); + fGrammarDescription.fContextType = XSDDescription.CONTEXT_PREPARSE; + fGrammarDescription.setNamespace(SchemaSymbols.URI_SCHEMAFORSCHEMA); + + // no global decls other than types and + // element declarations for , and . + fGlobalAttrDecls = new SymbolHash(1); + fGlobalAttrGrpDecls = new SymbolHash(1); + fGlobalElemDecls = new SymbolHash(6); + fGlobalGroupDecls = new SymbolHash(1); + fGlobalNotationDecls = new SymbolHash(1); + fGlobalIDConstraintDecls = new SymbolHash(1); + + // no extended global decls + fGlobalAttrDeclsExt = new SymbolHash(1); + fGlobalAttrGrpDeclsExt = new SymbolHash(1); + fGlobalElemDeclsExt = new SymbolHash(6); + fGlobalGroupDeclsExt = new SymbolHash(1); + fGlobalNotationDeclsExt = new SymbolHash(1); + fGlobalIDConstraintDeclsExt = new SymbolHash(1); + fGlobalTypeDeclsExt = new SymbolHash(1); + + // all global element declarations + fAllGlobalElemDecls = new SymbolHash(6); + + // get all built-in types + fGlobalTypeDecls = SG_SchemaNS.fGlobalTypeDecls; + + // create element declarations for , and + XSElementDecl annotationDecl = createAnnotationElementDecl(SchemaSymbols.ELT_ANNOTATION); + XSElementDecl documentationDecl = createAnnotationElementDecl(SchemaSymbols.ELT_DOCUMENTATION); + XSElementDecl appinfoDecl = createAnnotationElementDecl(SchemaSymbols.ELT_APPINFO); + + // add global element declarations + fGlobalElemDecls.put(annotationDecl.fName, annotationDecl); + fGlobalElemDecls.put(documentationDecl.fName, documentationDecl); + fGlobalElemDecls.put(appinfoDecl.fName, appinfoDecl); + + fGlobalElemDeclsExt.put(","+annotationDecl.fName, annotationDecl); + fGlobalElemDeclsExt.put(","+documentationDecl.fName, documentationDecl); + fGlobalElemDeclsExt.put(","+appinfoDecl.fName, appinfoDecl); + + fAllGlobalElemDecls.put(annotationDecl, annotationDecl); + fAllGlobalElemDecls.put(documentationDecl, documentationDecl); + fAllGlobalElemDecls.put(appinfoDecl, appinfoDecl); + + // create complex type declarations for , and + XSComplexTypeDecl annotationType = new XSComplexTypeDecl(); + XSComplexTypeDecl documentationType = new XSComplexTypeDecl(); + XSComplexTypeDecl appinfoType = new XSComplexTypeDecl(); + + // set the types on their element declarations + annotationDecl.fType = annotationType; + documentationDecl.fType = documentationType; + appinfoDecl.fType = appinfoType; + + // create attribute groups for , and + XSAttributeGroupDecl annotationAttrs = new XSAttributeGroupDecl(); + XSAttributeGroupDecl documentationAttrs = new XSAttributeGroupDecl(); + XSAttributeGroupDecl appinfoAttrs = new XSAttributeGroupDecl(); + + // fill in attribute groups + { + // create and fill attribute uses for , and + XSAttributeUseImpl annotationIDAttr = new XSAttributeUseImpl(); + annotationIDAttr.fAttrDecl = new XSAttributeDecl(); + annotationIDAttr.fAttrDecl.setValues(SchemaSymbols.ATT_ID, null, (XSSimpleType) fGlobalTypeDecls.get(SchemaSymbols.ATTVAL_ID), + XSConstants.VC_NONE, XSConstants.SCOPE_LOCAL, null, annotationType, null); + annotationIDAttr.fUse = SchemaSymbols.USE_OPTIONAL; + annotationIDAttr.fConstraintType = XSConstants.VC_NONE; + + XSAttributeUseImpl documentationSourceAttr = new XSAttributeUseImpl(); + documentationSourceAttr.fAttrDecl = new XSAttributeDecl(); + documentationSourceAttr.fAttrDecl.setValues(SchemaSymbols.ATT_SOURCE, null, (XSSimpleType) fGlobalTypeDecls.get(SchemaSymbols.ATTVAL_ANYURI), + XSConstants.VC_NONE, XSConstants.SCOPE_LOCAL, null, documentationType, null); + documentationSourceAttr.fUse = SchemaSymbols.USE_OPTIONAL; + documentationSourceAttr.fConstraintType = XSConstants.VC_NONE; + + XSAttributeUseImpl documentationLangAttr = new XSAttributeUseImpl(); + documentationLangAttr.fAttrDecl = new XSAttributeDecl(); + documentationLangAttr.fAttrDecl.setValues("lang".intern(), NamespaceContext.XML_URI, (XSSimpleType) fGlobalTypeDecls.get(SchemaSymbols.ATTVAL_LANGUAGE), + XSConstants.VC_NONE, XSConstants.SCOPE_LOCAL, null, documentationType, null); + documentationLangAttr.fUse = SchemaSymbols.USE_OPTIONAL; + documentationLangAttr.fConstraintType = XSConstants.VC_NONE; + + XSAttributeUseImpl appinfoSourceAttr = new XSAttributeUseImpl(); + appinfoSourceAttr.fAttrDecl = new XSAttributeDecl(); + appinfoSourceAttr.fAttrDecl.setValues(SchemaSymbols.ATT_SOURCE, null, (XSSimpleType) fGlobalTypeDecls.get(SchemaSymbols.ATTVAL_ANYURI), + XSConstants.VC_NONE, XSConstants.SCOPE_LOCAL, null, appinfoType, null); + appinfoSourceAttr.fUse = SchemaSymbols.USE_OPTIONAL; + appinfoSourceAttr.fConstraintType = XSConstants.VC_NONE; + + // create lax attribute wildcard for , and + XSWildcardDecl otherAttrs = new XSWildcardDecl(); + otherAttrs.fNamespaceList = new String [] {fTargetNamespace, null}; + otherAttrs.fType = XSWildcard.NSCONSTRAINT_NOT; + otherAttrs.fProcessContents = XSWildcard.PC_LAX; + + // add attribute uses and wildcards to attribute groups for , and + annotationAttrs.addAttributeUse(annotationIDAttr); + annotationAttrs.fAttributeWC = otherAttrs; + + documentationAttrs.addAttributeUse(documentationSourceAttr); + documentationAttrs.addAttributeUse(documentationLangAttr); + documentationAttrs.fAttributeWC = otherAttrs; + + appinfoAttrs.addAttributeUse(appinfoSourceAttr); + appinfoAttrs.fAttributeWC = otherAttrs; + } + + // create particles for + XSParticleDecl annotationParticle = createUnboundedModelGroupParticle(); + { + XSModelGroupImpl annotationChoice = new XSModelGroupImpl(); + annotationChoice.fCompositor = XSModelGroupImpl.MODELGROUP_CHOICE; + annotationChoice.fParticleCount = 2; + annotationChoice.fParticles = new XSParticleDecl[2]; + annotationChoice.fParticles[0] = createChoiceElementParticle(appinfoDecl); + annotationChoice.fParticles[1] = createChoiceElementParticle(documentationDecl); + annotationParticle.fValue = annotationChoice; + } + + // create wildcard particle for and + XSParticleDecl anyWCSequenceParticle = createUnboundedAnyWildcardSequenceParticle(); + + // fill complex types + annotationType.setValues("#AnonType_" + SchemaSymbols.ELT_ANNOTATION, fTargetNamespace, SchemaGrammar.fAnyType, + XSConstants.DERIVATION_RESTRICTION, XSConstants.DERIVATION_NONE, (short) (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION), + XSComplexTypeDecl.CONTENTTYPE_ELEMENT, false, annotationAttrs, null, annotationParticle, XSObjectListImpl.EMPTY_LIST); + annotationType.setName("#AnonType_" + SchemaSymbols.ELT_ANNOTATION); + annotationType.setIsAnonymous(); + + documentationType.setValues("#AnonType_" + SchemaSymbols.ELT_DOCUMENTATION, fTargetNamespace, SchemaGrammar.fAnyType, + XSConstants.DERIVATION_RESTRICTION, XSConstants.DERIVATION_NONE, (short) (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION), + XSComplexTypeDecl.CONTENTTYPE_MIXED, false, documentationAttrs, null, anyWCSequenceParticle, XSObjectListImpl.EMPTY_LIST); + documentationType.setName("#AnonType_" + SchemaSymbols.ELT_DOCUMENTATION); + documentationType.setIsAnonymous(); + + appinfoType.setValues("#AnonType_" + SchemaSymbols.ELT_APPINFO, fTargetNamespace, SchemaGrammar.fAnyType, + XSConstants.DERIVATION_RESTRICTION, XSConstants.DERIVATION_NONE, (short) (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION), + XSComplexTypeDecl.CONTENTTYPE_MIXED, false, appinfoAttrs, null, anyWCSequenceParticle, XSObjectListImpl.EMPTY_LIST); + appinfoType.setName("#AnonType_" + SchemaSymbols.ELT_APPINFO); + appinfoType.setIsAnonymous(); + + } // (int) + + // return the XMLGrammarDescription corresponding to this + // object + public XMLGrammarDescription getGrammarDescription() { + return fGrammarDescription.makeClone(); + } // getGrammarDescription(): XMLGrammarDescription + + // override these methods solely so that these + // objects cannot be modified once they're created. + public void setImportedGrammars(Vector importedGrammars) { + // ignore + } + public void addGlobalAttributeDecl(XSAttributeDecl decl) { + // ignore + } + public void addGlobalAttributeDecl(XSAttributeGroupDecl decl, String location) { + // ignore + } + public void addGlobalAttributeGroupDecl(XSAttributeGroupDecl decl) { + // ignore + } + public void addGlobalAttributeGroupDecl(XSAttributeGroupDecl decl, String location) { + // ignore + } + public void addGlobalElementDecl(XSElementDecl decl) { + // ignore + } + public void addGlobalElementDecl(XSElementDecl decl, String location) { + // ignore + } + public void addGlobalElementDeclAll(XSElementDecl decl) { + // ignore + } + public void addGlobalGroupDecl(XSGroupDecl decl) { + // ignore + } + public void addGlobalGroupDecl(XSGroupDecl decl, String location) { + // ignore + } + public void addGlobalNotationDecl(XSNotationDecl decl) { + // ignore + } + public void addGlobalNotationDecl(XSNotationDecl decl, String location) { + // ignore + } + public void addGlobalTypeDecl(XSTypeDefinition decl) { + // ignore + } + public void addGlobalTypeDecl(XSTypeDefinition decl, String location) { + // ignore + } + public void addGlobalComplexTypeDecl(XSComplexTypeDecl decl) { + // ignore + } + public void addGlobalComplexTypeDecl(XSComplexTypeDecl decl, String location) { + // ignore + } + public void addGlobalSimpleTypeDecl(XSSimpleType decl) { + // ignore + } + public void addGlobalSimpleTypeDecl(XSSimpleType decl, String location) { + // ignore + } + public void addComplexTypeDecl(XSComplexTypeDecl decl, SimpleLocator locator) { + // ignore + } + public void addRedefinedGroupDecl(XSGroupDecl derived, XSGroupDecl base, SimpleLocator locator) { + // ignore + } + public synchronized void addDocument(Object document, String location) { + // ignore + } + + // annotation support + synchronized DOMParser getDOMParser() { + return null; + } + synchronized SAXParser getSAXParser() { + return null; + } + + // + // private helper methods + // + + private XSElementDecl createAnnotationElementDecl(String localName) { + XSElementDecl eDecl = new XSElementDecl(); + eDecl.fName = localName; + eDecl.fTargetNamespace = fTargetNamespace; + eDecl.setIsGlobal(); + eDecl.fBlock = (XSConstants.DERIVATION_EXTENSION | + XSConstants.DERIVATION_RESTRICTION | XSConstants.DERIVATION_SUBSTITUTION); + eDecl.setConstraintType(XSConstants.VC_NONE); + return eDecl; + } + + private XSParticleDecl createUnboundedModelGroupParticle() { + XSParticleDecl particle = new XSParticleDecl(); + particle.fMinOccurs = 0; + particle.fMaxOccurs = SchemaSymbols.OCCURRENCE_UNBOUNDED; + particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; + return particle; + } + + private XSParticleDecl createChoiceElementParticle(XSElementDecl ref) { + XSParticleDecl particle = new XSParticleDecl(); + particle.fMinOccurs = 1; + particle.fMaxOccurs = 1; + particle.fType = XSParticleDecl.PARTICLE_ELEMENT; + particle.fValue = ref; + return particle; + } + + private XSParticleDecl createUnboundedAnyWildcardSequenceParticle() { + XSParticleDecl particle = createUnboundedModelGroupParticle(); + XSModelGroupImpl sequence = new XSModelGroupImpl(); + sequence.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE; + sequence.fParticleCount = 1; + sequence.fParticles = new XSParticleDecl[1]; + sequence.fParticles[0] = createAnyLaxWildcardParticle(); + particle.fValue = sequence; + return particle; + } + + private XSParticleDecl createAnyLaxWildcardParticle() { + XSParticleDecl particle = new XSParticleDecl(); + particle.fMinOccurs = 1; + particle.fMaxOccurs = 1; + particle.fType = XSParticleDecl.PARTICLE_WILDCARD; + + XSWildcardDecl anyWC = new XSWildcardDecl(); + anyWC.fNamespaceList = null; + anyWC.fType = XSWildcard.NSCONSTRAINT_ANY; + anyWC.fProcessContents = XSWildcard.PC_LAX; + + particle.fValue = anyWC; + return particle; + } + } + + // Grammar methods + + // return the XMLGrammarDescription corresponding to this + // object + public XMLGrammarDescription getGrammarDescription() { + return fGrammarDescription; + } // getGrammarDescription(): XMLGrammarDescription + + // DTDGrammar methods + public boolean isNamespaceAware () { + return true; + } // isNamespaceAware():boolean + + Vector fImported = null; + + public void setImportedGrammars(Vector importedGrammars) { + fImported = importedGrammars; + } + + public Vector getImportedGrammars() { + return fImported; + } + + /** + * Returns this grammar's target namespace. + */ + public final String getTargetNamespace() { + return fTargetNamespace; + } // getTargetNamespace():String + + /** + * register one global attribute + */ + public void addGlobalAttributeDecl(XSAttributeDecl decl) { + fGlobalAttrDecls.put(decl.fName, decl); + decl.setNamespaceItem(this); + } + + public void addGlobalAttributeDecl(XSAttributeDecl decl, String location) { + fGlobalAttrDeclsExt.put(((location!=null) ? location : "") + "," + decl.fName, decl); + if (decl.getNamespaceItem() == null) { + decl.setNamespaceItem(this); + } + } + + /** + * register one global attribute group + */ + public void addGlobalAttributeGroupDecl(XSAttributeGroupDecl decl) { + fGlobalAttrGrpDecls.put(decl.fName, decl); + decl.setNamespaceItem(this); + } + + public void addGlobalAttributeGroupDecl(XSAttributeGroupDecl decl, String location) { + fGlobalAttrGrpDeclsExt.put(((location!=null) ? location : "") + "," + decl.fName, decl); + if (decl.getNamespaceItem() == null) { + decl.setNamespaceItem(this); + } + } + + /** + * register one global element + */ + public void addGlobalElementDeclAll(XSElementDecl decl) { + if (fAllGlobalElemDecls.get(decl) == null) { + fAllGlobalElemDecls.put(decl, decl); + // if there is a substitution group affiliation, store in an array, + // for further constraint checking: UPA, PD, EDC + if (decl.fSubGroup != null) { + if (fSubGroupCount == fSubGroups.length) + fSubGroups = resize(fSubGroups, fSubGroupCount+INC_SIZE); + fSubGroups[fSubGroupCount++] = decl; + } + } + } + + public void addGlobalElementDecl(XSElementDecl decl) { + fGlobalElemDecls.put(decl.fName, decl); + decl.setNamespaceItem(this); + } + + public void addGlobalElementDecl(XSElementDecl decl, String location) { + fGlobalElemDeclsExt.put(((location != null) ? location : "") + "," + decl.fName, decl); + if (decl.getNamespaceItem() == null) { + decl.setNamespaceItem(this); + } + } + + /** + * register one global group + */ + public void addGlobalGroupDecl(XSGroupDecl decl) { + fGlobalGroupDecls.put(decl.fName, decl); + decl.setNamespaceItem(this); + } + + public void addGlobalGroupDecl(XSGroupDecl decl, String location) { + fGlobalGroupDeclsExt.put(((location!=null) ? location : "") + "," + decl.fName, decl); + if (decl.getNamespaceItem() == null) { + decl.setNamespaceItem(this); + } + } + + /** + * register one global notation + */ + public void addGlobalNotationDecl(XSNotationDecl decl) { + fGlobalNotationDecls.put(decl.fName, decl); + decl.setNamespaceItem(this); + } + + public void addGlobalNotationDecl(XSNotationDecl decl, String location) { + fGlobalNotationDeclsExt.put(((location!=null) ? location : "") + "," +decl.fName, decl); + if (decl.getNamespaceItem() == null) { + decl.setNamespaceItem(this); + } + } + + /** + * register one global type + */ + public void addGlobalTypeDecl(XSTypeDefinition decl) { + fGlobalTypeDecls.put(decl.getName(), decl); + if (decl instanceof XSComplexTypeDecl) { + ((XSComplexTypeDecl) decl).setNamespaceItem(this); + } + else if (decl instanceof XSSimpleTypeDecl) { + ((XSSimpleTypeDecl) decl).setNamespaceItem(this); + } + } + + public void addGlobalTypeDecl(XSTypeDefinition decl, String location) { + fGlobalTypeDeclsExt.put(((location!=null) ? location : "") + "," + decl.getName(), decl); + if (decl.getNamespaceItem() == null) { + if (decl instanceof XSComplexTypeDecl) { + ((XSComplexTypeDecl) decl).setNamespaceItem(this); + } + else if (decl instanceof XSSimpleTypeDecl) { + ((XSSimpleTypeDecl) decl).setNamespaceItem(this); + } + } + } + + /** + * register one global complex type + */ + public void addGlobalComplexTypeDecl(XSComplexTypeDecl decl) { + fGlobalTypeDecls.put(decl.getName(), decl); + decl.setNamespaceItem(this); + } + + public void addGlobalComplexTypeDecl(XSComplexTypeDecl decl, String location) { + fGlobalTypeDeclsExt.put(((location!=null) ? location : "") + "," + decl.getName(), decl); + if (decl.getNamespaceItem() == null) { + decl.setNamespaceItem(this); + } + } + + /** + * register one global simple type + */ + public void addGlobalSimpleTypeDecl(XSSimpleType decl) { + fGlobalTypeDecls.put(decl.getName(), decl); + if (decl instanceof XSSimpleTypeDecl) { + ((XSSimpleTypeDecl) decl).setNamespaceItem(this); + } + } + + public void addGlobalSimpleTypeDecl(XSSimpleType decl, String location) { + fGlobalTypeDeclsExt.put(((location != null) ? location : "") + "," + decl.getName(), decl); + if (decl.getNamespaceItem() == null && decl instanceof XSSimpleTypeDecl) { + ((XSSimpleTypeDecl) decl).setNamespaceItem(this); + } + } + + /** + * register one identity constraint + */ + public final void addIDConstraintDecl(XSElementDecl elmDecl, IdentityConstraint decl) { + elmDecl.addIDConstraint(decl); + fGlobalIDConstraintDecls.put(decl.getIdentityConstraintName(), decl); + } + + public final void addIDConstraintDecl(XSElementDecl elmDecl, IdentityConstraint decl, String location) { + fGlobalIDConstraintDeclsExt.put(((location != null) ? location : "") + "," + decl.getIdentityConstraintName(), decl); + } + + /** + * get one global attribute + */ + public final XSAttributeDecl getGlobalAttributeDecl(String declName) { + return(XSAttributeDecl)fGlobalAttrDecls.get(declName); + } + + public final XSAttributeDecl getGlobalAttributeDecl(String declName, String location) { + return(XSAttributeDecl)fGlobalAttrDeclsExt.get(((location != null) ? location : "") + "," + declName); + } + + /** + * get one global attribute group + */ + public final XSAttributeGroupDecl getGlobalAttributeGroupDecl(String declName) { + return(XSAttributeGroupDecl)fGlobalAttrGrpDecls.get(declName); + } + + public final XSAttributeGroupDecl getGlobalAttributeGroupDecl(String declName, String location) { + return(XSAttributeGroupDecl)fGlobalAttrGrpDeclsExt.get(((location != null) ? location : "") + "," + declName); + } + + /** + * get one global element + */ + public final XSElementDecl getGlobalElementDecl(String declName) { + return(XSElementDecl)fGlobalElemDecls.get(declName); + } + + public final XSElementDecl getGlobalElementDecl(String declName, String location) { + return(XSElementDecl)fGlobalElemDeclsExt.get(((location != null) ? location : "") + "," + declName); + } + + /** + * get one global group + */ + public final XSGroupDecl getGlobalGroupDecl(String declName) { + return(XSGroupDecl)fGlobalGroupDecls.get(declName); + } + + public final XSGroupDecl getGlobalGroupDecl(String declName, String location) { + return(XSGroupDecl)fGlobalGroupDeclsExt.get(((location != null) ? location : "") + "," + declName); + } + + /** + * get one global notation + */ + public final XSNotationDecl getGlobalNotationDecl(String declName) { + return(XSNotationDecl)fGlobalNotationDecls.get(declName); + } + + public final XSNotationDecl getGlobalNotationDecl(String declName, String location) { + return(XSNotationDecl)fGlobalNotationDeclsExt.get(((location != null) ? location : "") + "," + declName); + } + + /** + * get one global type + */ + public final XSTypeDefinition getGlobalTypeDecl(String declName) { + return(XSTypeDefinition)fGlobalTypeDecls.get(declName); + } + + public final XSTypeDefinition getGlobalTypeDecl(String declName, String location) { + return(XSTypeDefinition)fGlobalTypeDeclsExt.get(((location != null) ? location : "") + "," + declName); + } + + /** + * get one identity constraint + */ + public final IdentityConstraint getIDConstraintDecl(String declName) { + return(IdentityConstraint)fGlobalIDConstraintDecls.get(declName); + } + + public final IdentityConstraint getIDConstraintDecl(String declName, String location) { + return(IdentityConstraint)fGlobalIDConstraintDeclsExt.get(((location != null) ? location : "") + "," + declName); + } + + /** + * get one identity constraint + */ + public final boolean hasIDConstraints() { + return fGlobalIDConstraintDecls.getLength() > 0; + } + + // array to store complex type decls + private static final int INITIAL_SIZE = 16; + private static final int INC_SIZE = 16; + + private int fCTCount = 0; + private XSComplexTypeDecl[] fComplexTypeDecls = new XSComplexTypeDecl[INITIAL_SIZE]; + private SimpleLocator[] fCTLocators = new SimpleLocator[INITIAL_SIZE]; + + // an array to store groups being redefined by restriction + // even-numbered elements are the derived groups, odd-numbered ones their bases + private static final int REDEFINED_GROUP_INIT_SIZE = 2; + private int fRGCount = 0; + private XSGroupDecl[] fRedefinedGroupDecls = new XSGroupDecl[REDEFINED_GROUP_INIT_SIZE]; + private SimpleLocator[] fRGLocators = new SimpleLocator[REDEFINED_GROUP_INIT_SIZE/2]; + + // a flag to indicate whether we have checked the 3 constraints on this + // grammar. + boolean fFullChecked = false; + + /** + * add one complex type decl: for later constraint checking + */ + public void addComplexTypeDecl(XSComplexTypeDecl decl, SimpleLocator locator) { + if (fCTCount == fComplexTypeDecls.length) { + fComplexTypeDecls = resize(fComplexTypeDecls, fCTCount+INC_SIZE); + fCTLocators = resize(fCTLocators, fCTCount+INC_SIZE); + } + fCTLocators[fCTCount] = locator; + fComplexTypeDecls[fCTCount++] = decl; + } + + /** + * add a group redefined by restriction: for later constraint checking + */ + public void addRedefinedGroupDecl(XSGroupDecl derived, XSGroupDecl base, SimpleLocator locator) { + if (fRGCount == fRedefinedGroupDecls.length) { + // double array size each time. + fRedefinedGroupDecls = resize(fRedefinedGroupDecls, fRGCount << 1); + fRGLocators = resize(fRGLocators, fRGCount); + } + fRGLocators[fRGCount/2] = locator; + fRedefinedGroupDecls[fRGCount++] = derived; + fRedefinedGroupDecls[fRGCount++] = base; + } + + /** + * get all complex type decls: for later constraint checking + */ + final XSComplexTypeDecl[] getUncheckedComplexTypeDecls() { + if (fCTCount < fComplexTypeDecls.length) { + fComplexTypeDecls = resize(fComplexTypeDecls, fCTCount); + fCTLocators = resize(fCTLocators, fCTCount); + } + return fComplexTypeDecls; + } + + /** + * get the error locator of all complex type decls + */ + final SimpleLocator[] getUncheckedCTLocators() { + if (fCTCount < fCTLocators.length) { + fComplexTypeDecls = resize(fComplexTypeDecls, fCTCount); + fCTLocators = resize(fCTLocators, fCTCount); + } + return fCTLocators; + } + + /** + * get all redefined groups: for later constraint checking + */ + final XSGroupDecl[] getRedefinedGroupDecls() { + if (fRGCount < fRedefinedGroupDecls.length) { + fRedefinedGroupDecls = resize(fRedefinedGroupDecls, fRGCount); + fRGLocators = resize(fRGLocators, fRGCount/2); + } + return fRedefinedGroupDecls; + } + + /** + * get the error locator of all redefined groups + */ + final SimpleLocator[] getRGLocators() { + if (fRGCount < fRedefinedGroupDecls.length) { + fRedefinedGroupDecls = resize(fRedefinedGroupDecls, fRGCount); + fRGLocators = resize(fRGLocators, fRGCount/2); + } + return fRGLocators; + } + + /** + * after the first-round checking, some types don't need to be checked + * against UPA again. here we trim the array to the proper size. + */ + final void setUncheckedTypeNum(int newSize) { + fCTCount = newSize; + fComplexTypeDecls = resize(fComplexTypeDecls, fCTCount); + fCTLocators = resize(fCTLocators, fCTCount); + } + + // used to store all substitution group information declared in + // this namespace + private int fSubGroupCount = 0; + private XSElementDecl[] fSubGroups = new XSElementDecl[INITIAL_SIZE]; + + /** + * get all substitution group information: for the 3 constraint checking + */ + final XSElementDecl[] getSubstitutionGroups() { + if (fSubGroupCount < fSubGroups.length) + fSubGroups = resize(fSubGroups, fSubGroupCount); + return fSubGroups; + } + + // anyType and anySimpleType: because there are so many places where + // we need direct access to these two types + public final static XSComplexTypeDecl fAnyType = new XSAnyType(); + private static class XSAnyType extends XSComplexTypeDecl { + public XSAnyType () { + fName = SchemaSymbols.ATTVAL_ANYTYPE; + super.fTargetNamespace = SchemaSymbols.URI_SCHEMAFORSCHEMA; + fBaseType = this; + fDerivedBy = XSConstants.DERIVATION_RESTRICTION; + fContentType = XSComplexTypeDecl.CONTENTTYPE_MIXED; + + fParticle = createParticle(); + fAttrGrp = createAttrGrp(); + } + + // overridden methods + public void setValues(String name, String targetNamespace, + XSTypeDefinition baseType, short derivedBy, short schemaFinal, + short block, short contentType, + boolean isAbstract, XSAttributeGroupDecl attrGrp, + XSSimpleType simpleType, XSParticleDecl particle) { + // don't allow this. + } + + public void setName(String name){ + // don't allow this. + } + + public void setIsAbstractType() { + // null implementation + } + + public void setContainsTypeID() { + // null implementation + } + + public void setIsAnonymous() { + // null implementation + } + + public void reset() { + // null implementation + } + + public XSObjectList getAnnotations() { + return XSObjectListImpl.EMPTY_LIST; + } + + public XSNamespaceItem getNamespaceItem() { + return SG_SchemaNS; + } + + private XSAttributeGroupDecl createAttrGrp() { + XSWildcardDecl wildcard = new XSWildcardDecl(); + wildcard.fProcessContents = XSWildcardDecl.PC_LAX; + XSAttributeGroupDecl attrGrp = new XSAttributeGroupDecl(); + attrGrp.fAttributeWC = wildcard; + return attrGrp; + } + + private XSParticleDecl createParticle() { + // the wildcard used in anyType (content and attribute) + // the spec will change strict to skip for anyType + XSWildcardDecl wildcard = new XSWildcardDecl(); + wildcard.fProcessContents = XSWildcardDecl.PC_LAX; + // the particle for the content wildcard + XSParticleDecl particleW = new XSParticleDecl(); + particleW.fMinOccurs = 0; + particleW.fMaxOccurs = SchemaSymbols.OCCURRENCE_UNBOUNDED; + particleW.fType = XSParticleDecl.PARTICLE_WILDCARD; + particleW.fValue = wildcard; + // the model group of a sequence of the above particle + XSModelGroupImpl group = new XSModelGroupImpl(); + group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE; + group.fParticleCount = 1; + group.fParticles = new XSParticleDecl[1]; + group.fParticles[0] = particleW; + // the content of anyType: particle of the above model group + XSParticleDecl particleG = new XSParticleDecl(); + particleG.fType = XSParticleDecl.PARTICLE_MODELGROUP; + particleG.fValue = group; + + return particleG; + } + } + private static class BuiltinAttrDecl extends XSAttributeDecl { + public BuiltinAttrDecl(String name, String tns, + XSSimpleType type, short scope) { + fName = name; + super.fTargetNamespace = tns; + fType = type; + fScope = scope; + } + + public void setValues(String name, String targetNamespace, + XSSimpleType simpleType, short constraintType, short scope, + ValidatedInfo valInfo, XSComplexTypeDecl enclosingCT) { + // ignore this call. + } + + public void reset () { + // also ignore this call. + } + + public XSAnnotation getAnnotation() { + return null; + } + + public XSNamespaceItem getNamespaceItem() { + return SG_XSI; + } + + } // class BuiltinAttrDecl + + // the grammars to hold components of the schema namespace + public final static BuiltinSchemaGrammar SG_SchemaNS = new BuiltinSchemaGrammar(GRAMMAR_XS, Constants.SCHEMA_VERSION_1_0); + private final static BuiltinSchemaGrammar SG_SchemaNSExtended = new BuiltinSchemaGrammar(GRAMMAR_XS, Constants.SCHEMA_VERSION_1_0_EXTENDED); + + public final static XSSimpleType fAnySimpleType = (XSSimpleType)SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_ANYSIMPLETYPE); + + // the grammars to hold components of the schema-instance namespace + public final static BuiltinSchemaGrammar SG_XSI = new BuiltinSchemaGrammar(GRAMMAR_XSI, Constants.SCHEMA_VERSION_1_0); + + public static SchemaGrammar getS4SGrammar(short schemaVersion) { + if (schemaVersion == Constants.SCHEMA_VERSION_1_0) { + return SG_SchemaNS; + } + else { + return SG_SchemaNSExtended; + } + } + + static final XSComplexTypeDecl[] resize(XSComplexTypeDecl[] oldArray, int newSize) { + XSComplexTypeDecl[] newArray = new XSComplexTypeDecl[newSize]; + System.arraycopy(oldArray, 0, newArray, 0, Math.min(oldArray.length, newSize)); + return newArray; + } + + static final XSGroupDecl[] resize(XSGroupDecl[] oldArray, int newSize) { + XSGroupDecl[] newArray = new XSGroupDecl[newSize]; + System.arraycopy(oldArray, 0, newArray, 0, Math.min(oldArray.length, newSize)); + return newArray; + } + + static final XSElementDecl[] resize(XSElementDecl[] oldArray, int newSize) { + XSElementDecl[] newArray = new XSElementDecl[newSize]; + System.arraycopy(oldArray, 0, newArray, 0, Math.min(oldArray.length, newSize)); + return newArray; + } + + static final SimpleLocator[] resize(SimpleLocator[] oldArray, int newSize) { + SimpleLocator[] newArray = new SimpleLocator[newSize]; + System.arraycopy(oldArray, 0, newArray, 0, Math.min(oldArray.length, newSize)); + return newArray; + } + + // XSNamespaceItem methods + + // the max index / the max value of XSObject type + private static final short MAX_COMP_IDX = XSTypeDefinition.SIMPLE_TYPE; + private static final boolean[] GLOBAL_COMP = {false, // null + true, // attribute + true, // element + true, // type + false, // attribute use + true, // attribute group + true, // group + false, // model group + false, // particle + false, // wildcard + true, // idc + true, // notation + false, // annotation + false, // facet + false, // multi value facet + true, // complex type + true // simple type + }; + + // store a certain kind of components from all namespaces + private XSNamedMap[] fComponents = null; + private ObjectList[] fComponentsExt = null; + + // store the documents and their locations contributing to this namespace + // REVISIT: use StringList and XSObjectList for there fields. + private Vector fDocuments = null; + private Vector fLocations = null; + + public synchronized void addDocument(Object document, String location) { + if (fDocuments == null) { + fDocuments = new Vector(); + fLocations = new Vector(); + } + fDocuments.addElement(document); + fLocations.addElement(location); + } + + public synchronized void removeDocument(int index) { + if (fDocuments != null && + index >= 0 && + index < fDocuments.size()) { + fDocuments.removeElementAt(index); + fLocations.removeElementAt(index); + } + } + + /** + * [schema namespace] + * @see [schema namespace] + * @return The target namespace of this item. + */ + public String getSchemaNamespace() { + return fTargetNamespace; + } + + // annotation support + synchronized DOMParser getDOMParser() { + if (fDOMParser != null) { + DOMParser parser = (DOMParser) fDOMParser.get(); + if (parser != null) { + return parser; + } + } + // REVISIT: when schema handles XML 1.1, will need to + // revisit this (and the practice of not prepending an XML decl to the annotation string + XML11Configuration config = new XML11Configuration(fSymbolTable); + // note that this should never produce errors or require + // entity resolution, so just a barebones configuration with + // a couple of feature set will do fine + config.setFeature(Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE, true); + config.setFeature(Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE, false); + + DOMParser parser = new DOMParser(config); + try { + parser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.DEFER_NODE_EXPANSION_FEATURE, false); + } + catch (SAXException exc) {} + fDOMParser = new SoftReference(parser); + return parser; + } + + synchronized SAXParser getSAXParser() { + if (fSAXParser != null) { + SAXParser parser = (SAXParser) fSAXParser.get(); + if (parser != null) { + return parser; + } + } + // REVISIT: when schema handles XML 1.1, will need to + // revisit this (and the practice of not prepending an XML decl to the annotation string + XML11Configuration config = new XML11Configuration(fSymbolTable); + // note that this should never produce errors or require + // entity resolution, so just a barebones configuration with + // a couple of feature set will do fine + config.setFeature(Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE, true); + config.setFeature(Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE, false); + SAXParser parser = new SAXParser(config); + fSAXParser = new SoftReference(parser); + return parser; + } + + /** + * [schema components]: a list of top-level components, i.e. element + * declarations, attribute declarations, etc. + * @param objectType The type of the declaration, i.e. + * ELEMENT_DECLARATION. Note that + * XSTypeDefinition.SIMPLE_TYPE and + * XSTypeDefinition.COMPLEX_TYPE can also be used as the + * objectType to retrieve only complex types or simple + * types, instead of all types. + * @return A list of top-level definition of the specified type in + * objectType or an empty XSNamedMap if no + * such definitions exist. + */ + public synchronized XSNamedMap getComponents(short objectType) { + if (objectType <= 0 || objectType > MAX_COMP_IDX || + !GLOBAL_COMP[objectType]) { + return XSNamedMapImpl.EMPTY_MAP; + } + + if (fComponents == null) + fComponents = new XSNamedMap[MAX_COMP_IDX+1]; + + // get the hashtable for this type of components + if (fComponents[objectType] == null) { + SymbolHash table = null; + switch (objectType) { + case XSConstants.TYPE_DEFINITION: + case XSTypeDefinition.COMPLEX_TYPE: + case XSTypeDefinition.SIMPLE_TYPE: + table = fGlobalTypeDecls; + break; + case XSConstants.ATTRIBUTE_DECLARATION: + table = fGlobalAttrDecls; + break; + case XSConstants.ELEMENT_DECLARATION: + table = fGlobalElemDecls; + break; + case XSConstants.ATTRIBUTE_GROUP: + table = fGlobalAttrGrpDecls; + break; + case XSConstants.MODEL_GROUP_DEFINITION: + table = fGlobalGroupDecls; + break; + case XSConstants.NOTATION_DECLARATION: + table = fGlobalNotationDecls; + break; + case XSConstants.IDENTITY_CONSTRAINT: + table = this.fGlobalIDConstraintDecls; + break; + } + + // for complex/simple types, create a special implementation, + // which take specific types out of the hash table + if (objectType == XSTypeDefinition.COMPLEX_TYPE || + objectType == XSTypeDefinition.SIMPLE_TYPE) { + fComponents[objectType] = new XSNamedMap4Types(fTargetNamespace, table, objectType); + } + else { + fComponents[objectType] = new XSNamedMapImpl(fTargetNamespace, table); + } + } + + return fComponents[objectType]; + } + + public synchronized ObjectList getComponentsExt(short objectType) { + if (objectType <= 0 || objectType > MAX_COMP_IDX || + !GLOBAL_COMP[objectType]) { + return ObjectListImpl.EMPTY_LIST; + } + + if (fComponentsExt == null) + fComponentsExt = new ObjectList[MAX_COMP_IDX+1]; + + // get the hashtable for this type of components + if (fComponentsExt[objectType] == null) { + SymbolHash table = null; + switch (objectType) { + case XSConstants.TYPE_DEFINITION: + case XSTypeDefinition.COMPLEX_TYPE: + case XSTypeDefinition.SIMPLE_TYPE: + table = fGlobalTypeDeclsExt; + break; + case XSConstants.ATTRIBUTE_DECLARATION: + table = fGlobalAttrDeclsExt; + break; + case XSConstants.ELEMENT_DECLARATION: + table = fGlobalElemDeclsExt; + break; + case XSConstants.ATTRIBUTE_GROUP: + table = fGlobalAttrGrpDeclsExt; + break; + case XSConstants.MODEL_GROUP_DEFINITION: + table = fGlobalGroupDeclsExt; + break; + case XSConstants.NOTATION_DECLARATION: + table = fGlobalNotationDeclsExt; + break; + case XSConstants.IDENTITY_CONSTRAINT: + table = this.fGlobalIDConstraintDeclsExt; + break; + } + + Object[] entries = table.getEntries(); + fComponentsExt[objectType] = new ObjectListImpl(entries, entries.length); + } + + return fComponentsExt[objectType]; + } + + public synchronized void resetComponents() { + fComponents = null; + fComponentsExt = null; + } + + /** + * Convenience method. Returns a top-level simple or complex type + * definition. + * @param name The name of the definition. + * @return An XSTypeDefinition or null if such definition + * does not exist. + */ + public XSTypeDefinition getTypeDefinition(String name) { + return getGlobalTypeDecl(name); + } + + /** + * Convenience method. Returns a top-level attribute declaration. + * @param name The name of the declaration. + * @return A top-level attribute declaration or null if such declaration + * does not exist. + */ + public XSAttributeDeclaration getAttributeDeclaration(String name) { + return getGlobalAttributeDecl(name); + } + + /** + * Convenience method. Returns a top-level element declaration. + * @param name The name of the declaration. + * @return A top-level element declaration or null if such declaration + * does not exist. + */ + public XSElementDeclaration getElementDeclaration(String name) { + return getGlobalElementDecl(name); + } + + /** + * Convenience method. Returns a top-level attribute group definition. + * @param name The name of the definition. + * @return A top-level attribute group definition or null if such + * definition does not exist. + */ + public XSAttributeGroupDefinition getAttributeGroup(String name) { + return getGlobalAttributeGroupDecl(name); + } + + /** + * Convenience method. Returns a top-level model group definition. + * + * @param name The name of the definition. + * @return A top-level model group definition definition or null if such + * definition does not exist. + */ + public XSModelGroupDefinition getModelGroupDefinition(String name) { + return getGlobalGroupDecl(name); + } + + /** + * Convenience method. Returns a top-level notation declaration. + * + * @param name The name of the declaration. + * @return A top-level notation declaration or null if such declaration + * does not exist. + */ + public XSNotationDeclaration getNotationDeclaration(String name) { + return getGlobalNotationDecl(name); + } + + public XSIDCDefinition getIDCDefinition(String name) { + return getIDConstraintDecl(name); + } + + + /** + * [document location] + * @see [document location] + * @return a list of document information item + */ + public StringList getDocumentLocations() { + return new StringListImpl(fLocations); + } + + /** + * Return an XSModel that represents components in this schema + * grammar. + * + * @return an XSModel representing this schema grammar + */ + public XSModel toXSModel() { + return new XSModelImpl(new SchemaGrammar[]{this}); + } + + public XSModel toXSModel(XSGrammar[] grammars) { + if (grammars == null || grammars.length == 0) + return toXSModel(); + + int len = grammars.length; + boolean hasSelf = false; + for (int i = 0; i < len; i++) { + if (grammars[i] == this) { + hasSelf = true; + break; + } + } + + SchemaGrammar[] gs = new SchemaGrammar[hasSelf ? len : len+1]; + for (int i = 0; i < len; i++) + gs[i] = (SchemaGrammar)grammars[i]; + if (!hasSelf) + gs[len] = this; + return new XSModelImpl(gs); + } + + /** + * @see org.apache.xerces.xs.XSNamespaceItem#getAnnotations() + */ + public XSObjectList getAnnotations() { + if (fNumAnnotations == 0) { + return XSObjectListImpl.EMPTY_LIST; + } + return new XSObjectListImpl(fAnnotations, fNumAnnotations); + } + + public void addAnnotation(XSAnnotationImpl annotation) { + if (annotation == null) { + return; + } + if (fAnnotations == null) { + fAnnotations = new XSAnnotationImpl[2]; + } + else if (fNumAnnotations == fAnnotations.length) { + XSAnnotationImpl[] newArray = new XSAnnotationImpl[fNumAnnotations << 1]; + System.arraycopy(fAnnotations, 0, newArray, 0, fNumAnnotations); + fAnnotations = newArray; + } + fAnnotations[fNumAnnotations++] = annotation; + } + + public void setImmutable(boolean isImmutable) { + fIsImmutable = isImmutable; + } + + public boolean isImmutable() { + return fIsImmutable; + } + +} // class SchemaGrammar diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaNamespaceSupport.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaNamespaceSupport.java new file mode 100644 index 0000000..09e5344 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaNamespaceSupport.java @@ -0,0 +1,255 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.xs.opti.ElementImpl; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * This class customizes the behaviour of the util.NamespaceSupport + * class in order to easily implement some features that we need for + * efficient schema handling. It will not be generally useful. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class SchemaNamespaceSupport + extends NamespaceSupport { + + private SchemaRootContext fSchemaRootContext = null; + + public SchemaNamespaceSupport (Element schemaRoot, SymbolTable symbolTable) { + super(); + if (schemaRoot != null && !(schemaRoot instanceof ElementImpl)) { + Document ownerDocument = schemaRoot.getOwnerDocument(); + if (ownerDocument != null && schemaRoot != ownerDocument.getDocumentElement()) { + fSchemaRootContext = new SchemaRootContext(schemaRoot, symbolTable); + } + } + } // constructor + + // more effecient than NamespaceSupport(NamespaceContext) + public SchemaNamespaceSupport(SchemaNamespaceSupport nSupport) { + fSchemaRootContext = nSupport.fSchemaRootContext; + fNamespaceSize = nSupport.fNamespaceSize; + if (fNamespace.length < fNamespaceSize) + fNamespace = new String[fNamespaceSize]; + System.arraycopy(nSupport.fNamespace, 0, fNamespace, 0, fNamespaceSize); + fCurrentContext = nSupport.fCurrentContext; + if (fContext.length <= fCurrentContext) + fContext = new int[fCurrentContext+1]; + System.arraycopy(nSupport.fContext, 0, fContext, 0, fCurrentContext+1); + } // end constructor + + /** + * This method takes a set of Strings, as stored in a + * NamespaceSupport object, and "fools" the object into thinking + * that this is one unified context. This is meant to be used in + * conjunction with things like local elements, whose declarations + * may be deeply nested but which for all practical purposes may + * be regarded as being one level below the global + * element--at least with regard to namespace declarations. + * It's worth noting that the context from which the strings are + * being imported had better be using the same SymbolTable. + */ + public void setEffectiveContext (String [] namespaceDecls) { + if(namespaceDecls == null || namespaceDecls.length == 0) return; + pushContext(); + int newSize = fNamespaceSize + namespaceDecls.length; + if (fNamespace.length < newSize) { + // expand namespace's size... + String[] tempNSArray = new String[newSize]; + System.arraycopy(fNamespace, 0, tempNSArray, 0, fNamespace.length); + fNamespace = tempNSArray; + } + System.arraycopy(namespaceDecls, 0, fNamespace, fNamespaceSize, + namespaceDecls.length); + fNamespaceSize = newSize; + } // setEffectiveContext(String):void + + /** + * This method returns an array of Strings, as would be stored in + * a NamespaceSupport object. This array contains all + * declarations except those at the global level. + */ + public String [] getEffectiveLocalContext() { + // the trick here is to recognize that all local contexts + // happen to start at fContext[3]. + // context 1: empty + // context 2: decls for xml and xmlns; + // context 3: decls on : the global ones + String[] returnVal = null; + if (fCurrentContext >= 3) { + int bottomLocalContext = fContext[3]; + int copyCount = fNamespaceSize - bottomLocalContext; + if (copyCount > 0) { + returnVal = new String[copyCount]; + System.arraycopy(fNamespace, bottomLocalContext, returnVal, 0, + copyCount); + } + } + return returnVal; + } // getEffectiveLocalContext():String + + // This method removes from this object all the namespaces + // returned by getEffectiveLocalContext. + public void makeGlobal() { + if (fCurrentContext >= 3) { + fCurrentContext = 3; + fNamespaceSize = fContext[3]; + } + } // makeGlobal + + public String getURI(String prefix) { + String uri = super.getURI(prefix); + if (uri == null && fSchemaRootContext != null) { + if (!fSchemaRootContext.fDOMContextBuilt) { + fSchemaRootContext.fillNamespaceContext(); + fSchemaRootContext.fDOMContextBuilt = true; + } + if (fSchemaRootContext.fNamespaceSize > 0 && + !containsPrefix(prefix)) { + uri = fSchemaRootContext.getURI(prefix); + } + } + return uri; + } + + /** + * This class keeps track of the namespace bindings + * declared on ancestors of the schema root. + */ + static final class SchemaRootContext { + + // + // Data + // + + /** + * Namespace binding information. This array is composed of a + * series of tuples containing the namespace binding information: + * <prefix, uri>. + */ + String[] fNamespace = new String[16 * 2]; + + /** The size of the namespace information array. */ + int fNamespaceSize = 0; + + /** + * Flag indicating whether the namespace context + * has been from the root node's ancestors. + */ + boolean fDOMContextBuilt = false; + + /** Schema root. **/ + private final Element fSchemaRoot; + + /** Symbol table. **/ + private final SymbolTable fSymbolTable; + + /** Temporary storage for attribute QNames. **/ + private final QName fAttributeQName = new QName(); + + SchemaRootContext(Element schemaRoot, SymbolTable symbolTable) { + fSchemaRoot = schemaRoot; + fSymbolTable = symbolTable; + } + + void fillNamespaceContext() { + if (fSchemaRoot != null) { + Node currentNode = fSchemaRoot.getParentNode(); + while (currentNode != null) { + if (Node.ELEMENT_NODE == currentNode.getNodeType()) { + NamedNodeMap attributes = currentNode.getAttributes(); + final int attrCount = attributes.getLength(); + for (int i = 0; i < attrCount; ++i) { + Attr attr = (Attr) attributes.item(i); + String value = attr.getValue(); + if (value == null) { + value = XMLSymbols.EMPTY_STRING; + } + fillQName(fAttributeQName, attr); + // REVISIT: Should we be looking at non-namespace attributes + // for additional mappings? Should we detect illegal namespace + // declarations and exclude them from the context? -- mrglavas + if (fAttributeQName.uri == NamespaceContext.XMLNS_URI) { + // process namespace attribute + if (fAttributeQName.prefix == XMLSymbols.PREFIX_XMLNS) { + declarePrefix(fAttributeQName.localpart, value.length() != 0 ? fSymbolTable.addSymbol(value) : null); + } + else { + declarePrefix(XMLSymbols.EMPTY_STRING, value.length() != 0 ? fSymbolTable.addSymbol(value) : null); + } + } + } + + } + currentNode = currentNode.getParentNode(); + } + } + } + + String getURI(String prefix) { + // find prefix in the DOM context + for (int i = 0; i < fNamespaceSize; i += 2) { + if (fNamespace[i] == prefix) { + return fNamespace[i + 1]; + } + } + // prefix not found + return null; + } + + private void declarePrefix(String prefix, String uri) { + // resize array, if needed + if (fNamespaceSize == fNamespace.length) { + String[] namespacearray = new String[fNamespaceSize * 2]; + System.arraycopy(fNamespace, 0, namespacearray, 0, fNamespaceSize); + fNamespace = namespacearray; + } + + // bind prefix to uri in current context + fNamespace[fNamespaceSize++] = prefix; + fNamespace[fNamespaceSize++] = uri; + } + + private void fillQName(QName toFill, Node node) { + final String prefix = node.getPrefix(); + final String localName = node.getLocalName(); + final String rawName = node.getNodeName(); + final String namespace = node.getNamespaceURI(); + toFill.prefix = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING; + toFill.localpart = (localName != null) ? fSymbolTable.addSymbol(localName) : XMLSymbols.EMPTY_STRING; + toFill.rawname = (rawName != null) ? fSymbolTable.addSymbol(rawName) : XMLSymbols.EMPTY_STRING; + toFill.uri = (namespace != null && namespace.length() > 0) ? fSymbolTable.addSymbol(namespace) : null; + } + } + +} // class NamespaceSupport diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaSymbols.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaSymbols.java new file mode 100644 index 0000000..bced403 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/SchemaSymbols.java @@ -0,0 +1,215 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + + +/** + * Collection of symbols used to parse a Schema Grammar. + * + * @xerces.internal + * + * @author jeffrey rodriguez + * @version $Id$ + */ +public final class SchemaSymbols { + + // strings that's not added to the schema symbol table, because they + // are not symbols in the schema document. + // the validator can choose to add them by itself. + + // the following strings (xsi:, xsd) will be added into the + // symbol table that comes with the parser + + // xsi attributes: in validator + public static final String URI_XSI = "http://www.w3.org/2001/XMLSchema-instance".intern(); + public static final String XSI_SCHEMALOCATION = "schemaLocation".intern(); + public static final String XSI_NONAMESPACESCHEMALOCATION = "noNamespaceSchemaLocation".intern(); + public static final String XSI_TYPE = "type".intern(); + public static final String XSI_NIL = "nil".intern(); + + // schema namespace + public static final String URI_SCHEMAFORSCHEMA = "http://www.w3.org/2001/XMLSchema".intern(); + + // all possible schema element names + public static final String ELT_ALL = "all".intern(); + public static final String ELT_ANNOTATION = "annotation".intern(); + public static final String ELT_ANY = "any".intern(); + public static final String ELT_ANYATTRIBUTE = "anyAttribute".intern(); + public static final String ELT_APPINFO = "appinfo".intern(); + public static final String ELT_ATTRIBUTE = "attribute".intern(); + public static final String ELT_ATTRIBUTEGROUP = "attributeGroup".intern(); + public static final String ELT_CHOICE = "choice".intern(); + public static final String ELT_COMPLEXCONTENT = "complexContent".intern(); + public static final String ELT_COMPLEXTYPE = "complexType".intern(); + public static final String ELT_DOCUMENTATION = "documentation".intern(); + public static final String ELT_ELEMENT = "element".intern(); + public static final String ELT_ENUMERATION = "enumeration".intern(); + public static final String ELT_EXTENSION = "extension".intern(); + public static final String ELT_FIELD = "field".intern(); + public static final String ELT_FRACTIONDIGITS = "fractionDigits".intern(); + public static final String ELT_GROUP = "group".intern(); + public static final String ELT_IMPORT = "import".intern(); + public static final String ELT_INCLUDE = "include".intern(); + public static final String ELT_KEY = "key".intern(); + public static final String ELT_KEYREF = "keyref".intern(); + public static final String ELT_LENGTH = "length".intern(); + public static final String ELT_LIST = "list".intern(); + public static final String ELT_MAXEXCLUSIVE = "maxExclusive".intern(); + public static final String ELT_MAXINCLUSIVE = "maxInclusive".intern(); + public static final String ELT_MAXLENGTH = "maxLength".intern(); + public static final String ELT_MINEXCLUSIVE = "minExclusive".intern(); + public static final String ELT_MININCLUSIVE = "minInclusive".intern(); + public static final String ELT_MINLENGTH = "minLength".intern(); + public static final String ELT_NOTATION = "notation".intern(); + public static final String ELT_PATTERN = "pattern".intern(); + public static final String ELT_REDEFINE = "redefine".intern(); + public static final String ELT_RESTRICTION = "restriction".intern(); + public static final String ELT_SCHEMA = "schema".intern(); + public static final String ELT_SELECTOR = "selector".intern(); + public static final String ELT_SEQUENCE = "sequence".intern(); + public static final String ELT_SIMPLECONTENT = "simpleContent".intern(); + public static final String ELT_SIMPLETYPE = "simpleType".intern(); + public static final String ELT_TOTALDIGITS = "totalDigits".intern(); + public static final String ELT_UNION = "union".intern(); + public static final String ELT_UNIQUE = "unique".intern(); + public static final String ELT_WHITESPACE = "whiteSpace".intern(); + + // all possible schema attribute names (and xml:lang defined on and ) + public static final String ATT_ABSTRACT = "abstract".intern(); + public static final String ATT_ATTRIBUTEFORMDEFAULT = "attributeFormDefault".intern(); + public static final String ATT_BASE = "base".intern(); + public static final String ATT_BLOCK = "block".intern(); + public static final String ATT_BLOCKDEFAULT = "blockDefault".intern(); + public static final String ATT_DEFAULT = "default".intern(); + public static final String ATT_ELEMENTFORMDEFAULT = "elementFormDefault".intern(); + public static final String ATT_FINAL = "final".intern(); + public static final String ATT_FINALDEFAULT = "finalDefault".intern(); + public static final String ATT_FIXED = "fixed".intern(); + public static final String ATT_FORM = "form".intern(); + public static final String ATT_ID = "id".intern(); + public static final String ATT_ITEMTYPE = "itemType".intern(); + public static final String ATT_MAXOCCURS = "maxOccurs".intern(); + public static final String ATT_MEMBERTYPES = "memberTypes".intern(); + public static final String ATT_MINOCCURS = "minOccurs".intern(); + public static final String ATT_MIXED = "mixed".intern(); + public static final String ATT_NAME = "name".intern(); + public static final String ATT_NAMESPACE = "namespace".intern(); + public static final String ATT_NILLABLE = "nillable".intern(); + public static final String ATT_PROCESSCONTENTS = "processContents".intern(); + public static final String ATT_REF = "ref".intern(); + public static final String ATT_REFER = "refer".intern(); + public static final String ATT_SCHEMALOCATION = "schemaLocation".intern(); + public static final String ATT_SOURCE = "source".intern(); + public static final String ATT_SUBSTITUTIONGROUP = "substitutionGroup".intern(); + public static final String ATT_SYSTEM = "system".intern(); + public static final String ATT_PUBLIC = "public".intern(); + public static final String ATT_TARGETNAMESPACE = "targetNamespace".intern(); + public static final String ATT_TYPE = "type".intern(); + public static final String ATT_USE = "use".intern(); + public static final String ATT_VALUE = "value".intern(); + public static final String ATT_VERSION = "version".intern(); + public static final String ATT_XML_LANG = "xml:lang".intern(); + public static final String ATT_XPATH = "xpath".intern(); + + // all possible schema attribute values + public static final String ATTVAL_TWOPOUNDANY = "##any"; + public static final String ATTVAL_TWOPOUNDLOCAL = "##local"; + public static final String ATTVAL_TWOPOUNDOTHER = "##other"; + public static final String ATTVAL_TWOPOUNDTARGETNS = "##targetNamespace"; + public static final String ATTVAL_POUNDALL = "#all"; + public static final String ATTVAL_FALSE_0 = "0"; + public static final String ATTVAL_TRUE_1 = "1"; + public static final String ATTVAL_ANYSIMPLETYPE = "anySimpleType"; + public static final String ATTVAL_ANYTYPE = "anyType"; + public static final String ATTVAL_ANYURI = "anyURI"; + public static final String ATTVAL_BASE64BINARY = "base64Binary"; + public static final String ATTVAL_BOOLEAN = "boolean"; + public static final String ATTVAL_BYTE = "byte"; + public static final String ATTVAL_COLLAPSE = "collapse"; + public static final String ATTVAL_DATE = "date"; + public static final String ATTVAL_DATETIME = "dateTime"; + public static final String ATTVAL_DAY = "gDay"; + public static final String ATTVAL_DECIMAL = "decimal"; + public static final String ATTVAL_DOUBLE = "double"; + public static final String ATTVAL_DURATION = "duration"; + public static final String ATTVAL_ENTITY = "ENTITY"; + public static final String ATTVAL_ENTITIES = "ENTITIES"; + public static final String ATTVAL_EXTENSION = "extension"; + public static final String ATTVAL_FALSE = "false"; + public static final String ATTVAL_FLOAT = "float"; + public static final String ATTVAL_HEXBINARY = "hexBinary"; + public static final String ATTVAL_ID = "ID"; + public static final String ATTVAL_IDREF = "IDREF"; + public static final String ATTVAL_IDREFS = "IDREFS"; + public static final String ATTVAL_INT = "int"; + public static final String ATTVAL_INTEGER = "integer"; + public static final String ATTVAL_LANGUAGE = "language"; + public static final String ATTVAL_LAX = "lax"; + public static final String ATTVAL_LIST = "list"; + public static final String ATTVAL_LONG = "long"; + public static final String ATTVAL_NAME = "Name"; + public static final String ATTVAL_NEGATIVEINTEGER = "negativeInteger"; + public static final String ATTVAL_MONTH = "gMonth"; + public static final String ATTVAL_MONTHDAY = "gMonthDay"; + public static final String ATTVAL_NCNAME = "NCName"; + public static final String ATTVAL_NMTOKEN = "NMTOKEN"; + public static final String ATTVAL_NMTOKENS = "NMTOKENS"; + public static final String ATTVAL_NONNEGATIVEINTEGER= "nonNegativeInteger"; + public static final String ATTVAL_NONPOSITIVEINTEGER= "nonPositiveInteger"; + public static final String ATTVAL_NORMALIZEDSTRING = "normalizedString"; + public static final String ATTVAL_NOTATION = "NOTATION"; + public static final String ATTVAL_OPTIONAL = "optional"; + public static final String ATTVAL_POSITIVEINTEGER = "positiveInteger"; + public static final String ATTVAL_PRESERVE = "preserve"; + public static final String ATTVAL_PROHIBITED = "prohibited"; + public static final String ATTVAL_QNAME = "QName"; + public static final String ATTVAL_QUALIFIED = "qualified"; + public static final String ATTVAL_REPLACE = "replace"; + public static final String ATTVAL_REQUIRED = "required"; + public static final String ATTVAL_RESTRICTION = "restriction"; + public static final String ATTVAL_SHORT = "short"; + public static final String ATTVAL_SKIP = "skip"; + public static final String ATTVAL_STRICT = "strict"; + public static final String ATTVAL_STRING = "string"; + public static final String ATTVAL_SUBSTITUTION = "substitution"; + public static final String ATTVAL_TIME = "time"; + public static final String ATTVAL_TOKEN = "token"; + public static final String ATTVAL_TRUE = "true"; + public static final String ATTVAL_UNBOUNDED = "unbounded"; + public static final String ATTVAL_UNION = "union"; + public static final String ATTVAL_UNQUALIFIED = "unqualified"; + public static final String ATTVAL_UNSIGNEDBYTE = "unsignedByte"; + public static final String ATTVAL_UNSIGNEDINT = "unsignedInt"; + public static final String ATTVAL_UNSIGNEDLONG = "unsignedLong"; + public static final String ATTVAL_UNSIGNEDSHORT = "unsignedShort"; + public static final String ATTVAL_YEAR = "gYear"; + public static final String ATTVAL_YEARMONTH = "gYearMonth"; + + // form qualified/unqualified + public static final short FORM_UNQUALIFIED = 0; + public static final short FORM_QUALIFIED = 1; + + // attribute use + public static final short USE_OPTIONAL = 0; + public static final short USE_REQUIRED = 1; + public static final short USE_PROHIBITED = 2; + + // maxOccurs = "unbounded" + public static final int OCCURRENCE_UNBOUNDED = -1; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/SubstitutionGroupHandler.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/SubstitutionGroupHandler.java new file mode 100644 index 0000000..ce06709 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/SubstitutionGroupHandler.java @@ -0,0 +1,353 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.util.Hashtable; +import java.util.Vector; + +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * To store and validate information about substitutionGroup + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class SubstitutionGroupHandler { + + private static final XSElementDecl[] EMPTY_GROUP = new XSElementDecl[0]; + + // global element declaration resolver + private final XSElementDeclHelper fXSElementDeclHelper; + + /** + * Default constructor + */ + public SubstitutionGroupHandler(XSElementDeclHelper elementDeclHelper) { + fXSElementDeclHelper = elementDeclHelper; + } + + // 3.9.4 Element Sequence Locally Valid (Particle) 2.3.3 + // check whether one element decl matches an element with the given qname + public XSElementDecl getMatchingElemDecl(QName element, XSElementDecl exemplar) { + if (element.localpart == exemplar.fName && + element.uri == exemplar.fTargetNamespace) { + return exemplar; + } + + // if the exemplar is not a global element decl, then it's not possible + // to be substituted by another element. + if (exemplar.fScope != XSConstants.SCOPE_GLOBAL) { + return null; + } + + // if the decl blocks substitution, return false + if ((exemplar.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0) { + return null; + } + + // get the decl for the element + XSElementDecl eDecl = fXSElementDeclHelper.getGlobalElementDecl(element); + if (eDecl == null) { + return null; + } + + // and check by using substitutionGroup information + if (substitutionGroupOK(eDecl, exemplar, exemplar.fBlock)) { + return eDecl; + } + + return null; + } + + // 3.3.6 Substitution Group OK (Transitive) + // check whether element can substitute exemplar + protected boolean substitutionGroupOK(XSElementDecl element, XSElementDecl exemplar, short blockingConstraint) { + // For an element declaration (call it D) to be validly substitutable for another element declaration (call it C) subject to a blocking constraint (a subset of {substitution, extension, restriction}, the value of a {disallowed substitutions}) one of the following must be true: + // 1. D and C are the same element declaration. + if (element == exemplar) { + return true; + } + + // 2 All of the following must be true: + // 2.1 The blocking constraint does not contain substitution. + if ((blockingConstraint & XSConstants.DERIVATION_SUBSTITUTION) != 0) { + return false; + } + + // 2.2 There is a chain of {substitution group affiliation}s from D to C, that is, either D's {substitution group affiliation} is C, or D's {substitution group affiliation}'s {substitution group affiliation} is C, or . . . + XSElementDecl subGroup = element.fSubGroup; + while (subGroup != null && subGroup != exemplar) { + subGroup = subGroup.fSubGroup; + } + + if (subGroup == null) { + return false; + } + + // 2.3 The set of all {derivation method}s involved in the derivation of D's {type definition} from C's {type definition} does not intersect with the union of the blocking constraint, C's {prohibited substitutions} (if C is complex, otherwise the empty set) and the {prohibited substitutions} (respectively the empty set) of any intermediate {type definition}s in the derivation of D's {type definition} from C's {type definition}. + // prepare the combination of {derivation method} and + // {disallowed substitution} + return typeDerivationOK(element.fType, exemplar.fType, blockingConstraint); + } + + private boolean typeDerivationOK(XSTypeDefinition derived, XSTypeDefinition base, short blockingConstraint) { + + short devMethod = 0, blockConstraint = blockingConstraint; + + // "derived" should be derived from "base" + // add derivation methods of derived types to devMethod; + // add block of base types to blockConstraint. + XSTypeDefinition type = derived; + while (type != base && type != SchemaGrammar.fAnyType) { + if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + devMethod |= ((XSComplexTypeDecl)type).fDerivedBy; + } + else { + devMethod |= XSConstants.DERIVATION_RESTRICTION; + } + type = type.getBaseType(); + // type == null means the current type is anySimpleType, + // whose base type should be anyType + if (type == null) { + type = SchemaGrammar.fAnyType; + } + if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + blockConstraint |= ((XSComplexTypeDecl)type).fBlock; + } + } + if (type != base) { + // If the base is a union, check if "derived" is allowed through any of the member types. + if (base.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { + XSSimpleTypeDefinition st = (XSSimpleTypeDefinition) base; + if (st.getVariety() == XSSimpleTypeDefinition.VARIETY_UNION) { + XSObjectList memberTypes = st.getMemberTypes(); + final int length = memberTypes.getLength(); + for (int i = 0; i < length; ++i) { + if (typeDerivationOK(derived, (XSTypeDefinition) memberTypes.item(i), blockingConstraint)) { + return true; + } + } + } + } + return false; + } + if ((devMethod & blockConstraint) != 0) { + return false; + } + return true; + } + + // check whether element is in exemplar's substitution group + public boolean inSubstitutionGroup(XSElementDecl element, XSElementDecl exemplar) { + // [Definition:] Every element declaration (call this HEAD) in the {element declarations} of a schema defines a substitution group, a subset of those {element declarations}, as follows: + // Define PSG, the potential substitution group for HEAD, as follows: + // 1 The element declaration itself is in PSG; + // 2 PSG is closed with respect to {substitution group affiliation}, that is, if any element declaration in the {element declarations} has a {substitution group affiliation} in PSG, then it is also in PSG itself. + // HEAD's actual substitution group is then the set consisting of each member of PSG such that all of the following must be true: + // 1 Its {abstract} is false. + // 2 It is validly substitutable for HEAD subject to an empty blocking constraint, as defined in Substitution Group OK (Transitive) (3.3.6). + return substitutionGroupOK(element, exemplar, exemplar.fBlock); + } + + // to store substitution group information + // the key to the hashtable is an element decl, and the value is + // - a Vector, which contains all elements that has this element as their + // substitution group affilication + // - an array of OneSubGroup, which contains its substitution group before block. + Hashtable fSubGroupsB = new Hashtable(); + private static final OneSubGroup[] EMPTY_VECTOR = new OneSubGroup[0]; + // The real substitution groups (after "block") + Hashtable fSubGroups = new Hashtable(); + + /** + * clear the internal registry of substitutionGroup information + */ + public void reset() { + fSubGroupsB.clear(); + fSubGroups.clear(); + } + + /** + * add a list of substitution group information. + */ + public void addSubstitutionGroup(XSElementDecl[] elements) { + XSElementDecl subHead, element; + Vector subGroup; + // for all elements with substitution group affiliation + for (int i = elements.length-1; i >= 0; i--) { + element = elements[i]; + subHead = element.fSubGroup; + // check whether this an entry for this element + subGroup = (Vector)fSubGroupsB.get(subHead); + if (subGroup == null) { + // if not, create a new one + subGroup = new Vector(); + fSubGroupsB.put(subHead, subGroup); + } + // add to the vactor + subGroup.addElement(element); + } + } + + /** + * get all elements that can substitute the given element, + * according to the spec, we shouldn't consider the {block} constraints. + * + * from the spec, substitution group of a given element decl also contains + * the element itself. but the array returned from this method doesn't + * containt this element. + */ + public XSElementDecl[] getSubstitutionGroup(XSElementDecl element) { + // If we already have sub group for this element, just return it. + Object subGroup = fSubGroups.get(element); + if (subGroup != null) + return (XSElementDecl[])subGroup; + + if ((element.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0) { + fSubGroups.put(element, EMPTY_GROUP); + return EMPTY_GROUP; + } + + // Otherwise, get all potential sub group elements + // (without considering "block" on this element + OneSubGroup[] groupB = getSubGroupB(element, new OneSubGroup()); + int len = groupB.length, rlen = 0; + XSElementDecl[] ret = new XSElementDecl[len]; + // For each of such elements, check whether the derivation methods + // overlap with "block". If not, add it to the sub group + for (int i = 0 ; i < len; i++) { + if ((element.fBlock & groupB[i].dMethod) == 0) + ret[rlen++] = groupB[i].sub; + } + // Resize the array if necessary + if (rlen < len) { + XSElementDecl[] ret1 = new XSElementDecl[rlen]; + System.arraycopy(ret, 0, ret1, 0, rlen); + ret = ret1; + } + // Store the subgroup + fSubGroups.put(element, ret); + + return ret; + } + + // Get potential sub group element (without considering "block") + private OneSubGroup[] getSubGroupB(XSElementDecl element, OneSubGroup methods) { + Object subGroup = fSubGroupsB.get(element); + + // substitution group for this one is empty + if (subGroup == null) { + fSubGroupsB.put(element, EMPTY_VECTOR); + return EMPTY_VECTOR; + } + + // we've already calculated the element, just return. + if (subGroup instanceof OneSubGroup[]) + return (OneSubGroup[])subGroup; + + // we only have the *direct* substitutions + Vector group = (Vector)subGroup, newGroup = new Vector(); + OneSubGroup[] group1; + // then for each of the direct substitutions, get its substitution + // group, and combine the groups together. + short dMethod, bMethod, dSubMethod, bSubMethod; + for (int i = group.size()-1, j; i >= 0; i--) { + // Check whether this element is blocked. If so, ignore it. + XSElementDecl sub = (XSElementDecl)group.elementAt(i); + if (!getDBMethods(sub.fType, element.fType, methods)) + continue; + // Remember derivation methods and blocks from the types + dMethod = methods.dMethod; + bMethod = methods.bMethod; + // Add this one to potential group + newGroup.addElement(new OneSubGroup(sub, methods.dMethod, methods.bMethod)); + // Get potential group for this element + group1 = getSubGroupB(sub, methods); + for (j = group1.length-1; j >= 0; j--) { + // For each of them, check whether it's blocked (by type) + dSubMethod = (short)(dMethod | group1[j].dMethod); + bSubMethod = (short)(bMethod | group1[j].bMethod); + // Ignore it if it's blocked + if ((dSubMethod & bSubMethod) != 0) + continue; + newGroup.addElement(new OneSubGroup(group1[j].sub, dSubMethod, bSubMethod)); + } + } + // Convert to an array + OneSubGroup[] ret = new OneSubGroup[newGroup.size()]; + for (int i = newGroup.size()-1; i >= 0; i--) { + ret[i] = (OneSubGroup)newGroup.elementAt(i); + } + // Store the potential sub group + fSubGroupsB.put(element, ret); + + return ret; + } + + private boolean getDBMethods(XSTypeDefinition typed, XSTypeDefinition typeb, + OneSubGroup methods) { + short dMethod = 0, bMethod = 0; + while (typed != typeb && typed != SchemaGrammar.fAnyType) { + if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) + dMethod |= ((XSComplexTypeDecl)typed).fDerivedBy; + else + dMethod |= XSConstants.DERIVATION_RESTRICTION; + typed = typed.getBaseType(); + // type == null means the current type is anySimpleType, + // whose base type should be anyType + if (typed == null) + typed = SchemaGrammar.fAnyType; + if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) + bMethod |= ((XSComplexTypeDecl)typed).fBlock; + } + // No derivation relation, or blocked, return false + if (typed != typeb || (dMethod & bMethod) != 0) + return false; + + // Remember the derivation methods and blocks, return true. + methods.dMethod = dMethod; + methods.bMethod = bMethod; + return true; + } + + // Record the information about how one element substitute another one + private static final class OneSubGroup { + OneSubGroup() {} + OneSubGroup(XSElementDecl sub, short dMethod, short bMethod) { + this.sub = sub; + this.dMethod = dMethod; + this.bMethod = bMethod; + } + // The element that substitutes another one + XSElementDecl sub; + // The combination of all derivation methods from sub's type to + // the head's type + short dMethod; + // The combination of {block} of the types in the derivation chain + // excluding sub's type + short bMethod; + } +} // class SubstitutionGroupHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaException.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaException.java new file mode 100644 index 0000000..3ee8159 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaException.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +/** + * This exception might be thrown by any constraint checking method. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * + * @version $Id$ + */ +public class XMLSchemaException extends Exception { + + /** Serialization version. */ + static final long serialVersionUID = -9096984648537046218L; + + // store a datatype error: error code plus the arguments + String key; + Object[] args; + + // report an error + public XMLSchemaException(String key, Object[] args) { + this.key = key; + this.args = args; + } + + public String getKey() { + return key; + } + + public Object[] getArgs() { + return args; + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaLoader.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaLoader.java new file mode 100644 index 0000000..60be549 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaLoader.java @@ -0,0 +1,1420 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.WeakHashMap; + +import org.apache.xerces.dom.DOMErrorImpl; +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.dom.DOMStringListImpl; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.SchemaDVFactory; +import org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl; +import org.apache.xerces.impl.xs.models.CMBuilder; +import org.apache.xerces.impl.xs.models.CMNodeFactory; +import org.apache.xerces.impl.xs.traversers.XSDHandler; +import org.apache.xerces.util.DOMEntityResolverWrapper; +import org.apache.xerces.util.DOMErrorHandlerWrapper; +import org.apache.xerces.util.DefaultErrorHandler; +import org.apache.xerces.util.MessageFormatter; +import org.apache.xerces.util.ParserConfigurationSettings; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.util.URI.MalformedURIException; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarLoader; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.grammars.XSGrammar; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xs.LSInputList; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSLoader; +import org.apache.xerces.xs.XSModel; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.InputSource; + +/** + * This class implements xni.grammars.XMLGrammarLoader. + * It also serves as implementation of xs.XSLoader interface and DOMConfiguration interface. + * + * This class is designed to interact either with a proxy for a user application + * which wants to preparse schemas, or with our own Schema validator. + * It is hoped that none of these "external" classes will therefore need to communicate directly + * with XSDHandler in future. + *

This class only knows how to make XSDHandler do its thing. + * The caller must ensure that all its properties (schemaLocation, JAXPSchemaSource + * etc.) have been properly set. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +public class XMLSchemaLoader implements XMLGrammarLoader, XMLComponent, XSElementDeclHelper, +// XML Component API +XSLoader, DOMConfiguration { + + // Feature identifiers: + + /** Feature identifier: schema full checking*/ + protected static final String SCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + + /** Feature identifier: continue after fatal error. */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + /** Feature identifier: allow java encodings to be recognized when parsing schema docs. */ + protected static final String ALLOW_JAVA_ENCODINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; + + /** Feature identifier: standard uri conformant feature. */ + protected static final String STANDARD_URI_CONFORMANT_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE; + + /** Feature identifier: validate annotations. */ + protected static final String VALIDATE_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE; + + /** Feature: disallow doctype*/ + protected static final String DISALLOW_DOCTYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE; + + /** Feature: generate synthetic annotations */ + protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE; + + /** Feature identifier: honour all schemaLocations */ + protected static final String HONOUR_ALL_SCHEMALOCATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; + + protected static final String AUGMENT_PSVI = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; + + protected static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + /** Feature identifier: namespace growth */ + protected static final String NAMESPACE_GROWTH = + Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; + + /** Feature identifier: tolerate duplicates */ + protected static final String TOLERATE_DUPLICATES = + Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; + + /** Property identifier: Schema DV Factory */ + protected static final String SCHEMA_DV_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY; + + // recognized features: + private static final String[] RECOGNIZED_FEATURES = { + SCHEMA_FULL_CHECKING, + AUGMENT_PSVI, + CONTINUE_AFTER_FATAL_ERROR, + ALLOW_JAVA_ENCODINGS, + STANDARD_URI_CONFORMANT_FEATURE, + DISALLOW_DOCTYPE, + GENERATE_SYNTHETIC_ANNOTATIONS, + VALIDATE_ANNOTATIONS, + HONOUR_ALL_SCHEMALOCATIONS, + NAMESPACE_GROWTH, + TOLERATE_DUPLICATES + }; + + // property identifiers + + /** Property identifier: symbol table. */ + public static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + public static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: entity resolver. */ + public static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: grammar pool. */ + public static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: schema location. */ + protected static final String SCHEMA_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION; + + /** Property identifier: no namespace schema location. */ + protected static final String SCHEMA_NONS_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION; + + /** Property identifier: JAXP schema source. */ + protected static final String JAXP_SCHEMA_SOURCE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; + + protected static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + /** Property identifier: locale. */ + protected static final String LOCALE = + Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + // recognized properties + private static final String [] RECOGNIZED_PROPERTIES = { + ENTITY_MANAGER, + SYMBOL_TABLE, + ERROR_REPORTER, + ERROR_HANDLER, + ENTITY_RESOLVER, + XMLGRAMMAR_POOL, + SCHEMA_LOCATION, + SCHEMA_NONS_LOCATION, + JAXP_SCHEMA_SOURCE, + SECURITY_MANAGER, + LOCALE, + SCHEMA_DV_FACTORY + }; + + // Data + + // features and properties + private final ParserConfigurationSettings fLoaderConfig = new ParserConfigurationSettings(); + private XMLErrorReporter fErrorReporter = new XMLErrorReporter (); + private XMLEntityManager fEntityManager = null; + private XMLEntityResolver fUserEntityResolver = null; + private XMLGrammarPool fGrammarPool = null; + private String fExternalSchemas = null; + private String fExternalNoNSSchema = null; + // JAXP property: schema source + private Object fJAXPSource = null; + // is Schema Full Checking enabled + private boolean fIsCheckedFully = false; + // boolean that tells whether we've tested the JAXP property. + private boolean fJAXPProcessed = false; + // if features/properties has not been changed, the value of this attribute is "false" + private boolean fSettingsChanged = true; + + // xml schema parsing + private XSDHandler fSchemaHandler; + private XSGrammarBucket fGrammarBucket; + private XSDeclarationPool fDeclPool = null; + private SubstitutionGroupHandler fSubGroupHandler; + private CMBuilder fCMBuilder; + private XSDDescription fXSDDescription = new XSDDescription(); + private SchemaDVFactory fDefaultSchemaDVFactory; + + private WeakHashMap fJAXPCache; + private Locale fLocale = Locale.getDefault(); + + // XSLoader attributes + private DOMStringList fRecognizedParameters = null; + + /** DOM L3 error handler */ + private DOMErrorHandlerWrapper fErrorHandler = null; + + /** DOM L3 resource resolver */ + private DOMEntityResolverWrapper fResourceResolver = null; + + // default constructor. Create objects we absolutely need: + public XMLSchemaLoader() { + this( new SymbolTable(), null, new XMLEntityManager(), null, null, null); + } + + public XMLSchemaLoader(SymbolTable symbolTable) { + this( symbolTable, null, new XMLEntityManager(), null, null, null); + } + + /** + * This constractor is used by the XMLSchemaValidator. Additional properties, i.e. XMLEntityManager, + * will be passed during reset(XMLComponentManager). + * @param errorReporter + * @param grammarBucket + * @param sHandler + * @param builder + */ + XMLSchemaLoader(XMLErrorReporter errorReporter, + XSGrammarBucket grammarBucket, + SubstitutionGroupHandler sHandler, CMBuilder builder) { + this(null, errorReporter, null, grammarBucket, sHandler, builder); + } + + XMLSchemaLoader(SymbolTable symbolTable, + XMLErrorReporter errorReporter, + XMLEntityManager entityResolver, + XSGrammarBucket grammarBucket, + SubstitutionGroupHandler sHandler, + CMBuilder builder) { + + // store properties and features in configuration + fLoaderConfig.addRecognizedFeatures(RECOGNIZED_FEATURES); + fLoaderConfig.addRecognizedProperties(RECOGNIZED_PROPERTIES); + if (symbolTable != null){ + fLoaderConfig.setProperty(SYMBOL_TABLE, symbolTable); + } + + if(errorReporter == null) { + errorReporter = new XMLErrorReporter (); + errorReporter.setLocale(fLocale); + errorReporter.setProperty(ERROR_HANDLER, new DefaultErrorHandler()); + + } + fErrorReporter = errorReporter; + // make sure error reporter knows about schemas... + if(fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter()); + } + fLoaderConfig.setProperty(ERROR_REPORTER, fErrorReporter); + fEntityManager = entityResolver; + // entity manager is null if XMLSchemaValidator creates the loader + if (fEntityManager != null){ + fLoaderConfig.setProperty(ENTITY_MANAGER, fEntityManager); + } + + // by default augment PSVI (i.e. don't use declaration pool) + fLoaderConfig.setFeature(AUGMENT_PSVI, true); + + if(grammarBucket == null ) { + grammarBucket = new XSGrammarBucket(); + } + fGrammarBucket = grammarBucket; + if (sHandler == null) { + sHandler = new SubstitutionGroupHandler(this); + } + fSubGroupHandler = sHandler; + + //get an instance of the CMNodeFactory */ + CMNodeFactory nodeFactory = new CMNodeFactory() ; + + if(builder == null) { + builder = new CMBuilder(nodeFactory); + } + fCMBuilder = builder; + fSchemaHandler = new XSDHandler(fGrammarBucket); + fJAXPCache = new WeakHashMap(); + + fSettingsChanged = true; + } + + /** + * Returns a list of feature identifiers that are recognized by + * this XMLGrammarLoader. This method may return null if no features + * are recognized. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures(): String[] + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * + * @throws XMLConfigurationException Thrown on configuration error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + return fLoaderConfig.getFeature(featureId); + } // getFeature (String): boolean + + /** + * Sets the state of a feature. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws XMLConfigurationException Thrown when a feature is not + * recognized or cannot be set. + */ + public void setFeature(String featureId, + boolean state) throws XMLConfigurationException { + fSettingsChanged = true; + if(featureId.equals(CONTINUE_AFTER_FATAL_ERROR)) { + fErrorReporter.setFeature(CONTINUE_AFTER_FATAL_ERROR, state); + } + else if(featureId.equals(GENERATE_SYNTHETIC_ANNOTATIONS)) { + fSchemaHandler.setGenerateSyntheticAnnotations(state); + } + fLoaderConfig.setFeature(featureId, state); + } // setFeature(String, boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this XMLGrammarLoader. This method may return null if no properties + * are recognized. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties(): String[] + + /** + * Returns the state of a property. + * + * @param propertyId The property identifier. + * + * @throws XMLConfigurationException Thrown on configuration error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException { + return fLoaderConfig.getProperty(propertyId); + } // getProperty(String): Object + + /** + * Sets the state of a property. + * + * @param propertyId The property identifier. + * @param state The state of the property. + * + * @throws XMLConfigurationException Thrown when a property is not + * recognized or cannot be set. + */ + public void setProperty(String propertyId, + Object state) throws XMLConfigurationException { + fSettingsChanged = true; + fLoaderConfig.setProperty(propertyId, state); + if (propertyId.equals(JAXP_SCHEMA_SOURCE)) { + fJAXPSource = state; + fJAXPProcessed = false; + } + else if (propertyId.equals(XMLGRAMMAR_POOL)) { + fGrammarPool = (XMLGrammarPool)state; + } + else if (propertyId.equals(SCHEMA_LOCATION)) { + fExternalSchemas = (String)state; + } + else if (propertyId.equals(SCHEMA_NONS_LOCATION)) { + fExternalNoNSSchema = (String) state; + } + else if (propertyId.equals(LOCALE)) { + setLocale((Locale) state); + } + else if (propertyId.equals(ENTITY_RESOLVER)) { + fEntityManager.setProperty(ENTITY_RESOLVER, state); + } + else if (propertyId.equals(ERROR_REPORTER)) { + fErrorReporter = (XMLErrorReporter)state; + if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter()); + } + } + } // setProperty(String, Object) + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) { + fLocale = locale; + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + + /** Return the Locale the XMLGrammarLoader is using. */ + public Locale getLocale() { + return fLocale; + } // getLocale(): Locale + + /** + * Sets the error handler. + * + * @param errorHandler The error handler. + */ + public void setErrorHandler(XMLErrorHandler errorHandler) { + fErrorReporter.setProperty(ERROR_HANDLER, errorHandler); + } // setErrorHandler(XMLErrorHandler) + + /** Returns the registered error handler. */ + public XMLErrorHandler getErrorHandler() { + return fErrorReporter.getErrorHandler(); + } // getErrorHandler(): XMLErrorHandler + + /** + * Sets the entity resolver. + * + * @param entityResolver The new entity resolver. + */ + public void setEntityResolver(XMLEntityResolver entityResolver) { + fUserEntityResolver = entityResolver; + fLoaderConfig.setProperty(ENTITY_RESOLVER, entityResolver); + fEntityManager.setProperty(ENTITY_RESOLVER, entityResolver); + } // setEntityResolver(XMLEntityResolver) + + /** Returns the registered entity resolver. */ + public XMLEntityResolver getEntityResolver() { + return fUserEntityResolver; + } // getEntityResolver(): XMLEntityResolver + + /** + * Returns a Grammar object by parsing the contents of the + * entities pointed to by sources. + * + * @param source the locations of the entity which forms + * the staring point of the grammars to be constructed + * @throws IOException when a problem is encounted reading the entity + * @throws XNIException when a condition arises (such as a FatalError) that requires parsing + * of the entity be terminated + */ + public void loadGrammar(XMLInputSource source[]) + throws IOException, XNIException { + int numSource = source.length; + for (int i = 0; i < numSource; ++i) { + loadGrammar(source[i]); + } + } + + /** + * Returns a Grammar object by parsing the contents of the + * entity pointed to by source. + * + * @param source the location of the entity which forms + * the starting point of the grammar to be constructed. + * @throws IOException When a problem is encountered reading the entity + * XNIException When a condition arises (such as a FatalError) that requires parsing + * of the entity be terminated. + */ + public Grammar loadGrammar(XMLInputSource source) + throws IOException, XNIException { + + // REVISIT: this method should have a namespace parameter specified by + // user. In this case we can easily detect if a schema asked to be loaded + // is already in the local cache. + + reset(fLoaderConfig); + fSettingsChanged = false; + XSDDescription desc = new XSDDescription(); + desc.fContextType = XSDDescription.CONTEXT_PREPARSE; + desc.setBaseSystemId(source.getBaseSystemId()); + desc.setLiteralSystemId( source.getSystemId()); + // none of the other fields make sense for preparsing + Hashtable locationPairs = new Hashtable(); + // Process external schema location properties. + // We don't call tokenizeSchemaLocationStr here, because we also want + // to check whether the values are valid URI. + processExternalHints(fExternalSchemas, fExternalNoNSSchema, + locationPairs, fErrorReporter); + SchemaGrammar grammar = loadSchema(desc, source, locationPairs); + + if(grammar != null && fGrammarPool != null) { + fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_SCHEMA, fGrammarBucket.getGrammars()); + // NOTE: we only need to verify full checking in case the schema was not provided via JAXP + // since full checking already verified for all JAXP schemas + if(fIsCheckedFully && fJAXPCache.get(grammar) != grammar) { + XSConstraints.fullSchemaChecking(fGrammarBucket, fSubGroupHandler, fCMBuilder, fErrorReporter); + } + } + return grammar; + } // loadGrammar(XMLInputSource): Grammar + + /** + * This method is called either from XMLGrammarLoader.loadGrammar or from XMLSchemaValidator. + * Note: in either case, the EntityManager (or EntityResolvers) are not going to be invoked + * to resolve the location of the schema in XSDDescription + * @param desc + * @param source + * @param locationPairs + * @return An XML Schema grammar + * @throws IOException + * @throws XNIException + */ + SchemaGrammar loadSchema(XSDDescription desc, + XMLInputSource source, + Hashtable locationPairs) throws IOException, XNIException { + + // this should only be done once per invocation of this object; + // unless application alters JAXPSource in the mean time. + if(!fJAXPProcessed) { + processJAXPSchemaSource(locationPairs); + } + SchemaGrammar grammar = fSchemaHandler.parseSchema(source, desc, locationPairs); + + return grammar; + } // loadSchema(XSDDescription, XMLInputSource): SchemaGrammar + + /** + * This method tries to resolve location of the given schema. + * The loader stores the namespace/location pairs in a hashtable (use "" as the + * namespace of absent namespace). When resolving an entity, loader first tries + * to find in the hashtable whether there is a value for that namespace, + * if so, pass that location value to the user-defined entity resolver. + * + * @param desc + * @param locationPairs + * @param entityResolver + * @return the XMLInputSource + * @throws IOException + */ + public static XMLInputSource resolveDocument(XSDDescription desc, Hashtable locationPairs, + XMLEntityResolver entityResolver) throws IOException { + String loc = null; + // we consider the schema location properties for import + if (desc.getContextType() == XSDDescription.CONTEXT_IMPORT || + desc.fromInstance()) { + // use empty string as the key for absent namespace + String namespace = desc.getTargetNamespace(); + String ns = namespace == null ? XMLSymbols.EMPTY_STRING : namespace; + // get the location hint for that namespace + LocationArray tempLA = (LocationArray)locationPairs.get(ns); + if(tempLA != null) + loc = tempLA.getFirstLocation(); + } + + // if it's not import, or if the target namespace is not set + // in the schema location properties, use location hint + if (loc == null) { + String[] hints = desc.getLocationHints(); + if (hints != null && hints.length > 0) + loc = hints[0]; + } + + String expandedLoc = XMLEntityManager.expandSystemId(loc, desc.getBaseSystemId(), false); + desc.setLiteralSystemId(loc); + desc.setExpandedSystemId(expandedLoc); + return entityResolver.resolveEntity(desc); + } + + // add external schema locations to the location pairs + public static void processExternalHints(String sl, String nsl, + Hashtable locations, + XMLErrorReporter er) { + if (sl != null) { + try { + // get the attribute decl for xsi:schemaLocation + // because external schema location property has the same syntax + // as xsi:schemaLocation + XSAttributeDecl attrDecl = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_SCHEMALOCATION); + // validation the string value to get the list of URI's + attrDecl.fType.validate(sl, null, null); + if (!tokenizeSchemaLocationStr(sl, locations, null)) { + // report warning (odd number of items) + er.reportError(XSMessageFormatter.SCHEMA_DOMAIN, + "SchemaLocation", + new Object[]{sl}, + XMLErrorReporter.SEVERITY_WARNING); + } + } + catch (InvalidDatatypeValueException ex) { + // report warning (not list of URI's) + er.reportError(XSMessageFormatter.SCHEMA_DOMAIN, + ex.getKey(), ex.getArgs(), + XMLErrorReporter.SEVERITY_WARNING); + } + } + + if (nsl != null) { + try { + // similarly for no ns schema location property + XSAttributeDecl attrDecl = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION); + attrDecl.fType.validate(nsl, null, null); + LocationArray la = ((LocationArray)locations.get(XMLSymbols.EMPTY_STRING)); + if(la == null) { + la = new LocationArray(); + locations.put(XMLSymbols.EMPTY_STRING, la); + } + la.addLocation(nsl); + } + catch (InvalidDatatypeValueException ex) { + // report warning (not a URI) + er.reportError(XSMessageFormatter.SCHEMA_DOMAIN, + ex.getKey(), ex.getArgs(), + XMLErrorReporter.SEVERITY_WARNING); + } + } + } + // this method takes a SchemaLocation string. + // If an error is encountered, false is returned; + // otherwise, true is returned. In either case, locations + // is augmented to include as many tokens as possible. + // @param schemaStr The schemaLocation string to tokenize + // @param locations Hashtable mapping namespaces to LocationArray objects holding lists of locaitons + // @return true if no problems; false if string could not be tokenized + public static boolean tokenizeSchemaLocationStr(String schemaStr, Hashtable locations, String base) { + if (schemaStr!= null) { + StringTokenizer t = new StringTokenizer(schemaStr, " \n\t\r"); + String namespace, location; + while (t.hasMoreTokens()) { + namespace = t.nextToken (); + if (!t.hasMoreTokens()) { + return false; // error! + } + location = t.nextToken(); + LocationArray la = ((LocationArray)locations.get(namespace)); + if(la == null) { + la = new LocationArray(); + locations.put(namespace, la); + } + if (base != null) { + try { + location = XMLEntityManager.expandSystemId(location, base, false); + } catch (MalformedURIException e) { + } + } + la.addLocation(location); + } + } + return true; + } // tokenizeSchemaLocation(String, Hashtable): boolean + + /** + * Translate the various JAXP SchemaSource property types to XNI + * XMLInputSource. Valid types are: String, org.xml.sax.InputSource, + * InputStream, File, or Object[] of any of previous types. + * REVISIT: the JAXP 1.2 spec is less than clear as to whether this property + * should be available to imported schemas. I have assumed + * that it should. - NG + * Note: all JAXP schema files will be checked for full-schema validity if the feature was set up + * + */ + private void processJAXPSchemaSource(Hashtable locationPairs) throws IOException { + fJAXPProcessed = true; + if (fJAXPSource == null) { + return; + } + + Class componentType = fJAXPSource.getClass().getComponentType(); + XMLInputSource xis = null; + String sid = null; + if (componentType == null) { + // Not an array + if (fJAXPSource instanceof InputStream || + fJAXPSource instanceof InputSource) { + SchemaGrammar g = (SchemaGrammar)fJAXPCache.get(fJAXPSource); + if (g != null) { + fGrammarBucket.putGrammar(g); + return; + } + } + fXSDDescription.reset(); + xis = xsdToXMLInputSource(fJAXPSource); + sid = xis.getSystemId(); + fXSDDescription.fContextType = XSDDescription.CONTEXT_PREPARSE; + if (sid != null) { + fXSDDescription.setBaseSystemId(xis.getBaseSystemId()); + fXSDDescription.setLiteralSystemId(sid); + fXSDDescription.setExpandedSystemId(sid); + fXSDDescription.fLocationHints = new String[]{sid}; + } + SchemaGrammar g = loadSchema(fXSDDescription, xis, locationPairs); + // it is possible that we won't be able to resolve JAXP schema-source location + if (g != null) { + if (fJAXPSource instanceof InputStream || + fJAXPSource instanceof InputSource) { + fJAXPCache.put(fJAXPSource, g); + if (fIsCheckedFully) { + XSConstraints.fullSchemaChecking(fGrammarBucket, fSubGroupHandler, fCMBuilder, fErrorReporter); + } + } + fGrammarBucket.putGrammar(g); + } + return; + } + else if ( (componentType != Object.class) && + (componentType != String.class) && + (componentType != File.class) && + (componentType != InputStream.class) && + (componentType != InputSource.class) && + !File.class.isAssignableFrom(componentType) && + !InputStream.class.isAssignableFrom(componentType) && + !InputSource.class.isAssignableFrom(componentType) && + !componentType.isInterface() + ) { + // Not an Object[], String[], File[], InputStream[], InputSource[] + MessageFormatter mf = fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN); + throw new XMLConfigurationException( + XMLConfigurationException.NOT_SUPPORTED, + mf.formatMessage(fErrorReporter.getLocale(), "jaxp12-schema-source-type.2", + new Object [] {componentType.getName()})); + } + + // JAXP spec. allow []s of type String, File, InputStream, + // InputSource also, apart from [] of type Object. + Object[] objArr = (Object[]) fJAXPSource; + // make local vector for storing target namespaces of schemasources specified in object arrays. + ArrayList jaxpSchemaSourceNamespaces = new ArrayList(); + for (int i = 0; i < objArr.length; i++) { + if (objArr[i] instanceof InputStream || + objArr[i] instanceof InputSource) { + SchemaGrammar g = (SchemaGrammar)fJAXPCache.get(objArr[i]); + if (g != null) { + fGrammarBucket.putGrammar(g); + continue; + } + } + fXSDDescription.reset(); + xis = xsdToXMLInputSource(objArr[i]); + sid = xis.getSystemId(); + fXSDDescription.fContextType = XSDDescription.CONTEXT_PREPARSE; + if (sid != null) { + fXSDDescription.setBaseSystemId(xis.getBaseSystemId()); + fXSDDescription.setLiteralSystemId(sid); + fXSDDescription.setExpandedSystemId(sid); + fXSDDescription.fLocationHints = new String[]{sid}; + } + String targetNamespace = null ; + // load schema + SchemaGrammar grammar = fSchemaHandler.parseSchema(xis,fXSDDescription, locationPairs); + + if (fIsCheckedFully) { + XSConstraints.fullSchemaChecking(fGrammarBucket, fSubGroupHandler, fCMBuilder, fErrorReporter); + } + if (grammar != null) { + targetNamespace = grammar.getTargetNamespace(); + if (jaxpSchemaSourceNamespaces.contains(targetNamespace)) { + // when an array of objects is passed it is illegal to have two schemas that share same namespace. + MessageFormatter mf = fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN); + throw new java.lang.IllegalArgumentException(mf.formatMessage(fErrorReporter.getLocale(), + "jaxp12-schema-source-ns", null)); + } + else { + jaxpSchemaSourceNamespaces.add(targetNamespace) ; + } + if (objArr[i] instanceof InputStream || + objArr[i] instanceof InputSource) { + fJAXPCache.put(objArr[i], grammar); + } + fGrammarBucket.putGrammar(grammar); + } + else { + //REVISIT: What should be the acutal behavior if grammar can't be loaded as specified in schema source? + } + } + }//processJAXPSchemaSource + + private XMLInputSource xsdToXMLInputSource(Object val) { + if (val instanceof String) { + // String value is treated as a URI that is passed through the + // EntityResolver + String loc = (String) val; + fXSDDescription.reset(); + fXSDDescription.setValues(null, loc, null, null); + XMLInputSource xis = null; + try { + xis = fEntityManager.resolveEntity(fXSDDescription); + } + catch (IOException ex) { + fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, + "schema_reference.4", + new Object[] { loc }, XMLErrorReporter.SEVERITY_ERROR); + } + if (xis == null) { + // REVISIT: can this happen? + // Treat value as a URI and pass in as systemId + return new XMLInputSource(null, loc, null); + } + return xis; + } + else if (val instanceof InputSource) { + return saxToXMLInputSource((InputSource) val); + } + else if (val instanceof InputStream) { + return new XMLInputSource(null, null, null, + (InputStream) val, null); + } + else if (val instanceof File) { + File file = (File) val; + String escapedURI = FilePathToURI.filepath2URI(file.getAbsolutePath()); + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + } + catch (FileNotFoundException ex) { + fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, + "schema_reference.4", new Object[] { file.toString() }, + XMLErrorReporter.SEVERITY_ERROR); + } + return new XMLInputSource(null, escapedURI, null, is, null); + } + MessageFormatter mf = fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN); + throw new XMLConfigurationException( + XMLConfigurationException.NOT_SUPPORTED, + mf.formatMessage(fErrorReporter.getLocale(), "jaxp12-schema-source-type.1", + new Object [] {val != null ? val.getClass().getName() : "null"})); + } + + + //Convert a SAX InputSource to an equivalent XNI XMLInputSource + + private static XMLInputSource saxToXMLInputSource(InputSource sis) { + String publicId = sis.getPublicId(); + String systemId = sis.getSystemId(); + + Reader charStream = sis.getCharacterStream(); + if (charStream != null) { + return new XMLInputSource(publicId, systemId, null, charStream, + null); + } + + InputStream byteStream = sis.getByteStream(); + if (byteStream != null) { + return new XMLInputSource(publicId, systemId, null, byteStream, + sis.getEncoding()); + } + + return new XMLInputSource(publicId, systemId, null); + } + + static class LocationArray{ + + int length ; + String [] locations = new String[2]; + + public void resize(int oldLength , int newLength){ + String [] temp = new String[newLength] ; + System.arraycopy(locations, 0, temp, 0, Math.min(oldLength, newLength)); + locations = temp ; + length = Math.min(oldLength, newLength); + } + + public void addLocation(String location){ + if(length >= locations.length ){ + resize(length, Math.max(1, length*2)); + } + locations[length++] = location; + }//setLocation() + + public String [] getLocationArray(){ + if(length < locations.length ){ + resize(locations.length, length); + } + return locations; + }//getLocationArray() + + public String getFirstLocation(){ + return length > 0 ? locations[0] : null; + } + + public int getLength(){ + return length ; + } + + } //locationArray + + /* (non-Javadoc) + * @see org.apache.xerces.xni.parser.XMLComponent#getFeatureDefault(java.lang.String) + */ + public Boolean getFeatureDefault(String featureId) { + if (featureId.equals(AUGMENT_PSVI)){ + return Boolean.TRUE; + } + return null; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.parser.XMLComponent#getPropertyDefault(java.lang.String) + */ + public Object getPropertyDefault(String propertyId) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.parser.XMLComponent#reset(org.apache.xerces.xni.parser.XMLComponentManager) + */ + public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { + + fGrammarBucket.reset(); + + fSubGroupHandler.reset(); + + if (!fSettingsChanged || !parserSettingsUpdated(componentManager)) { + // need to reprocess JAXP schema sources + fJAXPProcessed = false; + // reinitialize grammar bucket + initGrammarBucket(); + if (fDeclPool != null) { + fDeclPool.reset(); + } + return; + } + + // get registered entity manager to be able to resolve JAXP schema-source property: + // Note: in case XMLSchemaValidator has created the loader, + // the entity manager property is null + fEntityManager = (XMLEntityManager)componentManager.getProperty(ENTITY_MANAGER); + + // get the error reporter + fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); + + // Determine schema dv factory to use + SchemaDVFactory dvFactory = null; + try { + dvFactory = (SchemaDVFactory)componentManager.getProperty(SCHEMA_DV_FACTORY); + } catch (XMLConfigurationException e) { + } + if (dvFactory == null) { + if (fDefaultSchemaDVFactory == null) { + fDefaultSchemaDVFactory = SchemaDVFactory.getInstance(); + } + dvFactory = fDefaultSchemaDVFactory; + } + fSchemaHandler.setDVFactory(dvFactory); + + // get schema location properties + try { + fExternalSchemas = (String) componentManager.getProperty(SCHEMA_LOCATION); + fExternalNoNSSchema = + (String) componentManager.getProperty(SCHEMA_NONS_LOCATION); + } catch (XMLConfigurationException e) { + fExternalSchemas = null; + fExternalNoNSSchema = null; + } + // get JAXP sources if available + try { + fJAXPSource = componentManager.getProperty(JAXP_SCHEMA_SOURCE); + fJAXPProcessed = false; + + } catch (XMLConfigurationException e) { + fJAXPSource = null; + fJAXPProcessed = false; + } + + // clear grammars, and put the one for schema namespace there + try { + fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL); + } catch (XMLConfigurationException e) { + fGrammarPool = null; + } + initGrammarBucket(); + + boolean psvi = true; + try { + psvi = componentManager.getFeature(AUGMENT_PSVI); + } catch (XMLConfigurationException e) { + psvi = false; + } + + // Only use the decl pool when there is no chance that the schema + // components will be exposed or cached. + // TODO: when someone calls loadGrammar(XMLInputSource), the schema is + // always exposed even without the use of a grammar pool. + // Disabling the "decl pool" feature for now until we understand when + // it can be safely used. + if (!psvi && fGrammarPool == null && false) { + if (fDeclPool != null) { + fDeclPool.reset(); + } + else { + fDeclPool = new XSDeclarationPool(); + } + fCMBuilder.setDeclPool(fDeclPool); + fSchemaHandler.setDeclPool(fDeclPool); + if (dvFactory instanceof SchemaDVFactoryImpl) { + fDeclPool.setDVFactory((SchemaDVFactoryImpl)dvFactory); + ((SchemaDVFactoryImpl)dvFactory).setDeclPool(fDeclPool); + } + } else { + fCMBuilder.setDeclPool(null); + fSchemaHandler.setDeclPool(null); + if (dvFactory instanceof SchemaDVFactoryImpl) { + ((SchemaDVFactoryImpl)dvFactory).setDeclPool(null); + } + } + + // get continue-after-fatal-error feature + try { + boolean fatalError = componentManager.getFeature(CONTINUE_AFTER_FATAL_ERROR); + fErrorReporter.setFeature(CONTINUE_AFTER_FATAL_ERROR, fatalError); + } catch (XMLConfigurationException e) { + } + // set full validation to false + try { + fIsCheckedFully = componentManager.getFeature(SCHEMA_FULL_CHECKING); + } + catch (XMLConfigurationException e){ + fIsCheckedFully = false; + } + // get generate-synthetic-annotations feature + try { + fSchemaHandler.setGenerateSyntheticAnnotations(componentManager.getFeature(GENERATE_SYNTHETIC_ANNOTATIONS)); + } + catch (XMLConfigurationException e) { + fSchemaHandler.setGenerateSyntheticAnnotations(false); + } + fSchemaHandler.reset(componentManager); + } + + private boolean parserSettingsUpdated(XMLComponentManager componentManager) { + // If the component manager is the loader config don't bother querying it since it doesn't + // recognize the PARSER_SETTINGS feature. Prevents an XMLConfigurationException from being + // thrown. + if (componentManager != fLoaderConfig) { + try { + return componentManager.getFeature(PARSER_SETTINGS); + } + catch (XMLConfigurationException e) {} + } + return true; + } + + private void initGrammarBucket(){ + if(fGrammarPool != null) { + Grammar [] initialGrammars = fGrammarPool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA); + final int length = (initialGrammars != null) ? initialGrammars.length : 0; + for (int i = 0; i < length; ++i) { + // put this grammar into the bucket, along with grammars + // imported by it (directly or indirectly) + if (!fGrammarBucket.putGrammar((SchemaGrammar)(initialGrammars[i]), true)) { + // REVISIT: a conflict between new grammar(s) and grammars + // in the bucket. What to do? A warning? An exception? + fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, + "GrammarConflict", null, + XMLErrorReporter.SEVERITY_WARNING); + } + } + } + } + + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSLoader#getConfig() + */ + public DOMConfiguration getConfig() { + return this; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSLoader#load(org.w3c.dom.ls.LSInput) + */ + public XSModel load(LSInput is) { + try { + Grammar g = loadGrammar(dom2xmlInputSource(is)); + return ((XSGrammar) g).toXSModel(); + } catch (Exception e) { + reportDOMFatalError(e); + return null; + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSLoader#loadInputList(org.apache.xerces.xs.LSInputList) + */ + public XSModel loadInputList(LSInputList is) { + int length = is.getLength(); + SchemaGrammar[] gs = new SchemaGrammar[length]; + for (int i = 0; i < length; i++) { + try { + gs[i] = (SchemaGrammar) loadGrammar(dom2xmlInputSource(is.item(i))); + } catch (Exception e) { + reportDOMFatalError(e); + return null; + } + } + return new XSModelImpl(gs); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSLoader#loadURI(java.lang.String) + */ + public XSModel loadURI(String uri) { + try { + Grammar g = loadGrammar(new XMLInputSource(null, uri, null)); + return ((XSGrammar)g).toXSModel(); + } + catch (Exception e){ + reportDOMFatalError(e); + return null; + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSLoader#loadURIList(org.apache.xerces.xs.StringList) + */ + public XSModel loadURIList(StringList uriList) { + int length = uriList.getLength(); + SchemaGrammar[] gs = new SchemaGrammar[length]; + for (int i = 0; i < length; i++) { + try { + gs[i] = + (SchemaGrammar) loadGrammar(new XMLInputSource(null, uriList.item(i), null)); + } catch (Exception e) { + reportDOMFatalError(e); + return null; + } + } + return new XSModelImpl(gs); + } + + void reportDOMFatalError(Exception e) { + if (fErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl(); + error.fException = e; + error.fMessage = e.getMessage(); + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + fErrorHandler.getErrorHandler().handleError(error); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.dom3.DOMConfiguration#canSetParameter(java.lang.String, java.lang.Object) + */ + public boolean canSetParameter(String name, Object value) { + if(value instanceof Boolean){ + if (name.equals(Constants.DOM_VALIDATE) || + name.equals(SCHEMA_FULL_CHECKING) || + name.equals(VALIDATE_ANNOTATIONS) || + name.equals(CONTINUE_AFTER_FATAL_ERROR) || + name.equals(ALLOW_JAVA_ENCODINGS) || + name.equals(STANDARD_URI_CONFORMANT_FEATURE) || + name.equals(GENERATE_SYNTHETIC_ANNOTATIONS) || + name.equals(HONOUR_ALL_SCHEMALOCATIONS) || + name.equals(NAMESPACE_GROWTH) || + name.equals(TOLERATE_DUPLICATES)) { + return true; + + } + return false; + } + if (name.equals(Constants.DOM_ERROR_HANDLER) || + name.equals(Constants.DOM_RESOURCE_RESOLVER) || + name.equals(SYMBOL_TABLE) || + name.equals(ERROR_REPORTER) || + name.equals(ERROR_HANDLER) || + name.equals(ENTITY_RESOLVER) || + name.equals(XMLGRAMMAR_POOL) || + name.equals(SCHEMA_LOCATION) || + name.equals(SCHEMA_NONS_LOCATION) || + name.equals(JAXP_SCHEMA_SOURCE) || + name.equals(SCHEMA_DV_FACTORY)) { + return true; + } + return false; + } + + /* (non-Javadoc) + * @see org.apache.xerces.dom3.DOMConfiguration#getParameter(java.lang.String) + */ + public Object getParameter(String name) throws DOMException { + + if (name.equals(Constants.DOM_ERROR_HANDLER)){ + return (fErrorHandler != null) ? fErrorHandler.getErrorHandler() : null; + } + else if (name.equals(Constants.DOM_RESOURCE_RESOLVER)) { + return (fResourceResolver != null) ? fResourceResolver.getEntityResolver() : null; + } + + try { + boolean feature = getFeature(name); + return (feature) ? Boolean.TRUE : Boolean.FALSE; + } catch (Exception e) { + Object property; + try { + property = getProperty(name); + return property; + } catch (Exception ex) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.dom3.DOMConfiguration#getParameterNames() + */ + public DOMStringList getParameterNames() { + if (fRecognizedParameters == null){ + ArrayList v = new ArrayList(); + v.add(Constants.DOM_VALIDATE); + v.add(Constants.DOM_ERROR_HANDLER); + v.add(Constants.DOM_RESOURCE_RESOLVER); + v.add(SYMBOL_TABLE); + v.add(ERROR_REPORTER); + v.add(ERROR_HANDLER); + v.add(ENTITY_RESOLVER); + v.add(XMLGRAMMAR_POOL); + v.add(SCHEMA_LOCATION); + v.add(SCHEMA_NONS_LOCATION); + v.add(JAXP_SCHEMA_SOURCE); + v.add(SCHEMA_FULL_CHECKING); + v.add(CONTINUE_AFTER_FATAL_ERROR); + v.add(ALLOW_JAVA_ENCODINGS); + v.add(STANDARD_URI_CONFORMANT_FEATURE); + v.add(VALIDATE_ANNOTATIONS); + v.add(GENERATE_SYNTHETIC_ANNOTATIONS); + v.add(HONOUR_ALL_SCHEMALOCATIONS); + v.add(NAMESPACE_GROWTH); + v.add(TOLERATE_DUPLICATES); + fRecognizedParameters = new DOMStringListImpl(v); + } + return fRecognizedParameters; + } + + /* (non-Javadoc) + * @see org.apache.xerces.dom3.DOMConfiguration#setParameter(java.lang.String, java.lang.Object) + */ + public void setParameter(String name, Object value) throws DOMException { + if (value instanceof Boolean) { + boolean state = ((Boolean) value).booleanValue(); + if (name.equals("validate") && state) { + return; + } + try { + setFeature(name, state); + } catch (Exception e) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + return; + } + if (name.equals(Constants.DOM_ERROR_HANDLER)) { + if (value instanceof DOMErrorHandler) { + try { + fErrorHandler = new DOMErrorHandlerWrapper((DOMErrorHandler) value); + setErrorHandler(fErrorHandler); + } catch (XMLConfigurationException e) { + } + } else { + // REVISIT: type mismatch + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + return; + + } + if (name.equals(Constants.DOM_RESOURCE_RESOLVER)) { + if (value instanceof LSResourceResolver) { + try { + fResourceResolver = new DOMEntityResolverWrapper((LSResourceResolver) value); + setEntityResolver(fResourceResolver); + } + catch (XMLConfigurationException e) {} + } else { + // REVISIT: type mismatch + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + return; + } + + try { + setProperty(name, value); + } catch (Exception ex) { + + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + + } + + } + + XMLInputSource dom2xmlInputSource(LSInput is) { + // need to wrap the LSInput with an XMLInputSource + XMLInputSource xis = null; + + /** + * An LSParser looks at inputs specified in LSInput in + * the following order: characterStream, byteStream, + * stringData, systemId, publicId. For consistency + * have the same behaviour for XSLoader. + */ + + // check whether there is a Reader + // according to DOM, we need to treat such reader as "UTF-16". + if (is.getCharacterStream() != null) { + xis = new XMLInputSource(is.getPublicId(), is.getSystemId(), + is.getBaseURI(), is.getCharacterStream(), + "UTF-16"); + } + // check whether there is an InputStream + else if (is.getByteStream() != null) { + xis = new XMLInputSource(is.getPublicId(), is.getSystemId(), + is.getBaseURI(), is.getByteStream(), + is.getEncoding()); + } + // if there is a string data, use a StringReader + // according to DOM, we need to treat such data as "UTF-16". + else if (is.getStringData() != null && is.getStringData().length() != 0) { + xis = new XMLInputSource(is.getPublicId(), is.getSystemId(), + is.getBaseURI(), new StringReader(is.getStringData()), + "UTF-16"); + } + // otherwise, just use the public/system/base Ids + else { + xis = new XMLInputSource(is.getPublicId(), is.getSystemId(), + is.getBaseURI()); + } + + return xis; + } + + // Implements XSElementDeclHelper interface + public XSElementDecl getGlobalElementDecl(QName element) { + SchemaGrammar sGrammar = fGrammarBucket.getGrammar(element.uri); + if (sGrammar != null) { + return sGrammar.getGlobalElementDecl(element.localpart); + } + return null; + } + +} // XMLGrammarLoader + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaValidator.java new file mode 100644 index 0000000..1896907 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XMLSchemaValidator.java @@ -0,0 +1,4615 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Stack; +import java.util.Vector; + +import javax.xml.XMLConstants; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.RevalidationHandler; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dv.DatatypeException; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.validation.ConfigurableValidationState; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.validation.ValidationState; +import org.apache.xerces.impl.xs.identity.Field; +import org.apache.xerces.impl.xs.identity.FieldActivator; +import org.apache.xerces.impl.xs.identity.IdentityConstraint; +import org.apache.xerces.impl.xs.identity.KeyRef; +import org.apache.xerces.impl.xs.identity.Selector; +import org.apache.xerces.impl.xs.identity.UniqueOrKey; +import org.apache.xerces.impl.xs.identity.ValueStore; +import org.apache.xerces.impl.xs.identity.XPathMatcher; +import org.apache.xerces.impl.xs.models.CMBuilder; +import org.apache.xerces.impl.xs.models.CMNodeFactory; +import org.apache.xerces.impl.xs.models.XSCMValidator; +import org.apache.xerces.impl.xs.util.XS10TypeHelper; +import org.apache.xerces.util.AugmentationsImpl; +import org.apache.xerces.util.IntStack; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.util.URI.MalformedURIException; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentFilter; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * The XML Schema validator. The validator implements a document + * filter: receiving document events from the scanner; validating + * the content and structure; augmenting the InfoSet, if applicable; + * and notifying the parser of the information resulting from the + * validation process. + *

+ * This component requires the following features and properties from the + * component manager that uses it: + *

    + *
  • http://xml.org/sax/features/validation
  • + *
  • http://apache.org/xml/properties/internal/symbol-table
  • + *
  • http://apache.org/xml/properties/internal/error-reporter
  • + *
  • http://apache.org/xml/properties/internal/entity-resolver
  • + *
+ * + * @xerces.internal + * + * @author Sandy Gao IBM + * @author Elena Litani IBM + * @author Andy Clark IBM + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @version $Id$ + */ +public class XMLSchemaValidator + implements XMLComponent, XMLDocumentFilter, FieldActivator, RevalidationHandler, XSElementDeclHelper { + + // + // Constants + // + private static final boolean DEBUG = false; + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: validation. */ + protected static final String SCHEMA_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** Feature identifier: schema full checking*/ + protected static final String SCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + + /** Feature identifier: dynamic validation. */ + protected static final String DYNAMIC_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; + + /** Feature identifier: expose schema normalized value */ + protected static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + + /** Feature identifier: send element default value via characters() */ + protected static final String SCHEMA_ELEMENT_DEFAULT = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; + + /** Feature identifier: augment PSVI */ + protected static final String SCHEMA_AUGMENT_PSVI = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; + + /** Feature identifier: whether to recognize java encoding names */ + protected static final String ALLOW_JAVA_ENCODINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; + + /** Feature identifier: standard uri conformant feature. */ + protected static final String STANDARD_URI_CONFORMANT_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE; + + /** Feature: generate synthetic annotations */ + protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE; + + /** Feature identifier: validate annotations. */ + protected static final String VALIDATE_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE; + + /** Feature identifier: honour all schemaLocations */ + protected static final String HONOUR_ALL_SCHEMALOCATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; + + /** Feature identifier: use grammar pool only */ + protected static final String USE_GRAMMAR_POOL_ONLY = + Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + + /** Feature identifier: whether to continue parsing a schema after a fatal error is encountered */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + protected static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + /** Feature identifier: namespace growth */ + protected static final String NAMESPACE_GROWTH = + Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; + + /** Feature identifier: tolerate duplicates */ + protected static final String TOLERATE_DUPLICATES = + Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; + + /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */ + protected static final String IGNORE_XSI_TYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE; + + /** Feature identifier: whether to ignore ID/IDREF errors */ + protected static final String ID_IDREF_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore unparsed entity errors */ + protected static final String UNPARSED_ENTITY_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore identity constraint errors */ + protected static final String IDENTITY_CONSTRAINT_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE; + + // property identifiers + + /** Property identifier: symbol table. */ + public static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + public static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity resolver. */ + public static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: grammar pool. */ + public static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier: schema location. */ + protected static final String SCHEMA_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION; + + /** Property identifier: no namespace schema location. */ + protected static final String SCHEMA_NONS_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION; + + /** Property identifier: JAXP schema source. */ + protected static final String JAXP_SCHEMA_SOURCE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; + + /** Property identifier: JAXP schema language. */ + protected static final String JAXP_SCHEMA_LANGUAGE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE; + + /** Property identifier: root type definition. */ + protected static final String ROOT_TYPE_DEF = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY; + + /** Property identifier: root element declaration. */ + protected static final String ROOT_ELEMENT_DECL = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_ELEMENT_DECLARATION_PROPERTY; + + /** Property identifier: Schema DV Factory */ + protected static final String SCHEMA_DV_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY; + + // recognized features and properties + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = + { + VALIDATION, + SCHEMA_VALIDATION, + DYNAMIC_VALIDATION, + SCHEMA_FULL_CHECKING, + ALLOW_JAVA_ENCODINGS, + CONTINUE_AFTER_FATAL_ERROR, + STANDARD_URI_CONFORMANT_FEATURE, + GENERATE_SYNTHETIC_ANNOTATIONS, + VALIDATE_ANNOTATIONS, + HONOUR_ALL_SCHEMALOCATIONS, + USE_GRAMMAR_POOL_ONLY, + IGNORE_XSI_TYPE, + ID_IDREF_CHECKING, + IDENTITY_CONSTRAINT_CHECKING, + UNPARSED_ENTITY_CHECKING, + NAMESPACE_GROWTH, + TOLERATE_DUPLICATES + }; + + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { null, + // NOTE: The following defaults are nulled out on purpose. + // If they are set, then when the XML Schema validator + // is constructed dynamically, these values may override + // those set by the application. This goes against the + // whole purpose of XMLComponent#getFeatureDefault but + // it can't be helped in this case. -Ac + // NOTE: Instead of adding default values here, add them (and + // the corresponding recognized features) to the objects + // that have an XMLSchemaValidator instance as a member, + // such as the parser configurations. -PM + null, //Boolean.FALSE, + null, //Boolean.FALSE, + null, //Boolean.FALSE, + null, //Boolean.FALSE, + null, //Boolean.FALSE, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = + { + SYMBOL_TABLE, + ERROR_REPORTER, + ENTITY_RESOLVER, + VALIDATION_MANAGER, + SCHEMA_LOCATION, + SCHEMA_NONS_LOCATION, + JAXP_SCHEMA_SOURCE, + JAXP_SCHEMA_LANGUAGE, + ROOT_TYPE_DEF, + ROOT_ELEMENT_DECL, + SCHEMA_DV_FACTORY, + }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = + { null, null, null, null, null, null, null, null, null, null, null}; + + // this is the number of valuestores of each kind + // we expect an element to have. It's almost + // never > 1; so leave it at that. + protected static final int ID_CONSTRAINT_NUM = 1; + + // xsi:* attribute declarations + static final XSAttributeDecl XSI_TYPE = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_TYPE); + static final XSAttributeDecl XSI_NIL = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NIL); + static final XSAttributeDecl XSI_SCHEMALOCATION = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_SCHEMALOCATION); + static final XSAttributeDecl XSI_NONAMESPACESCHEMALOCATION = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION); + + // + private static final Hashtable EMPTY_TABLE = new Hashtable(); + + // + // Data + // + + /** current PSVI element info */ + protected ElementPSVImpl fCurrentPSVI = new ElementPSVImpl(); + + // since it is the responsibility of each component to an + // Augmentations parameter if one is null, to save ourselves from + // having to create this object continually, it is created here. + // If it is not present in calls that we're passing on, we *must* + // clear this before we introduce it into the pipeline. + protected final AugmentationsImpl fAugmentations = new AugmentationsImpl(); + + // this is included for the convenience of handleEndElement + protected XMLString fDefaultValue; + + // Validation features + protected boolean fDynamicValidation = false; + protected boolean fSchemaDynamicValidation = false; + protected boolean fDoValidation = false; + protected boolean fFullChecking = false; + protected boolean fNormalizeData = true; + protected boolean fSchemaElementDefault = true; + protected boolean fAugPSVI = true; + protected boolean fIdConstraint = false; + protected boolean fUseGrammarPoolOnly = false; + + // Namespace growth feature + protected boolean fNamespaceGrowth = false; + + /** Schema type: None, DTD, Schema */ + private String fSchemaType = null; + + // to indicate whether we are in the scope of entity reference or CData + protected boolean fEntityRef = false; + protected boolean fInCDATA = false; + + // properties + + /** Symbol table. */ + protected SymbolTable fSymbolTable; + + /** + * While parsing a document, keep the location of the document. + */ + private XMLLocator fLocator; + + /** + * A wrapper of the standard error reporter. We'll store all schema errors + * in this wrapper object, so that we can get all errors (error codes) of + * a specific element. This is useful for PSVI. + */ + protected final class XSIErrorReporter { + + // the error reporter property + XMLErrorReporter fErrorReporter; + + // store error codes; starting position of the errors for each element; + // number of element (depth); and whether to record error + Vector fErrors = new Vector(); + int[] fContext = new int[INITIAL_STACK_SIZE]; + int fContextCount; + + // set the external error reporter, clear errors + public void reset(XMLErrorReporter errorReporter) { + fErrorReporter = errorReporter; + fErrors.removeAllElements(); + fContextCount = 0; + } + + // should be called when starting process an element or an attribute. + // store the starting position for the current context + public void pushContext() { + if (!fAugPSVI) { + return; + } + // resize array if necessary + if (fContextCount == fContext.length) { + int newSize = fContextCount + INC_STACK_SIZE; + int[] newArray = new int[newSize]; + System.arraycopy(fContext, 0, newArray, 0, fContextCount); + fContext = newArray; + } + + fContext[fContextCount++] = fErrors.size(); + } + + // should be called on endElement: get all errors of the current element + public String[] popContext() { + if (!fAugPSVI) { + return null; + } + // get starting position of the current element + int contextPos = fContext[--fContextCount]; + // number of errors of the current element + int size = fErrors.size() - contextPos; + // if no errors, return null + if (size == 0) + return null; + // copy errors from the list to an string array + String[] errors = new String[size]; + for (int i = 0; i < size; i++) { + errors[i] = (String) fErrors.elementAt(contextPos + i); + } + // remove errors of the current element + fErrors.setSize(contextPos); + return errors; + } + + // should be called when an attribute is done: get all errors of + // this attribute, but leave the errors to the containing element + // also called after an element was strictly assessed. + public String[] mergeContext() { + if (!fAugPSVI) { + return null; + } + // get starting position of the current element + int contextPos = fContext[--fContextCount]; + // number of errors of the current element + int size = fErrors.size() - contextPos; + // if no errors, return null + if (size == 0) + return null; + // copy errors from the list to an string array + String[] errors = new String[size]; + for (int i = 0; i < size; i++) { + errors[i] = (String) fErrors.elementAt(contextPos + i); + } + // don't resize the vector: leave the errors for this attribute + // to the containing element + return errors; + } + + public void reportError(String domain, String key, Object[] arguments, short severity) + throws XNIException { + String message = fErrorReporter.reportError(domain, key, arguments, severity); + if (fAugPSVI) { + fErrors.addElement(key); + fErrors.addElement(message); + } + } // reportError(String,String,Object[],short) + + public void reportError( + XMLLocator location, + String domain, + String key, + Object[] arguments, + short severity) + throws XNIException { + String message = fErrorReporter.reportError(location, domain, key, arguments, severity); + if (fAugPSVI) { + fErrors.addElement(key); + fErrors.addElement(message); + } + } // reportError(XMLLocator,String,String,Object[],short) + } + + /** Error reporter. */ + protected final XSIErrorReporter fXSIErrorReporter = new XSIErrorReporter(); + + /** Entity resolver */ + protected XMLEntityResolver fEntityResolver; + + // updated during reset + protected ValidationManager fValidationManager = null; + protected ConfigurableValidationState fValidationState = new ConfigurableValidationState(); + protected XMLGrammarPool fGrammarPool; + + // schema location property values + protected String fExternalSchemas = null; + protected String fExternalNoNamespaceSchema = null; + + //JAXP Schema Source property + protected Object fJaxpSchemaSource = null; + + /** Schema Grammar Description passed, to give a chance to application to supply the Grammar */ + protected final XSDDescription fXSDDescription = new XSDDescription(); + protected final Hashtable fLocationPairs = new Hashtable(); + protected final Hashtable fExpandedLocationPairs = new Hashtable(); + protected final ArrayList fUnparsedLocations = new ArrayList(); + + + // handlers + + /** Document handler. */ + protected XMLDocumentHandler fDocumentHandler; + + protected XMLDocumentSource fDocumentSource; + + // + // XMLComponent methods + // + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[]) (RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

+ * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) throws XMLConfigurationException { + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[]) (RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) throws XMLConfigurationException { + if (propertyId.equals(ROOT_TYPE_DEF)) { + if (value == null) { + fRootTypeQName = null; + fRootTypeDefinition = null; + } + else if (value instanceof javax.xml.namespace.QName) { + fRootTypeQName = (javax.xml.namespace.QName) value; + fRootTypeDefinition = null; + } + else { + fRootTypeDefinition = (XSTypeDefinition) value; + fRootTypeQName = null; + } + } + else if (propertyId.equals(ROOT_ELEMENT_DECL)) { + if (value == null) { + fRootElementDeclQName = null; + fRootElementDeclaration = null; + } + else if (value instanceof javax.xml.namespace.QName) { + fRootElementDeclQName = (javax.xml.namespace.QName) value; + fRootElementDeclaration = null; + } + else { + fRootElementDeclaration = (XSElementDecl) value; + fRootElementDeclQName = null; + } + } + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + // + // XMLDocumentSource methods + // + + /** Sets the document handler to receive information about the document. */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + } // setDocumentHandler(XMLDocumentHandler) + + /** Returns the document handler */ + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } // setDocumentHandler(XMLDocumentHandler) + + // + // XMLDocumentHandler methods + // + + /** Sets the document source */ + public void setDocumentSource(XMLDocumentSource source) { + fDocumentSource = source; + } // setDocumentSource + + /** Returns the document source */ + public XMLDocumentSource getDocumentSource() { + return fDocumentSource; + } // getDocumentSource + + /** + * The start of the document. + * + * @param locator The system identifier of the entity if the entity + * is external, null otherwise. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param namespaceContext + * The namespace context in effect at the + * start of this document. + * This object represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDocument( + XMLLocator locator, + String encoding, + NamespaceContext namespaceContext, + Augmentations augs) + throws XNIException { + + fValidationState.setNamespaceSupport(namespaceContext); + fState4XsiType.setNamespaceSupport(namespaceContext); + fState4ApplyDefault.setNamespaceSupport(namespaceContext); + fLocator = locator; + + handleStartDocument(locator, encoding); + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); + } + + } // startDocument(XMLLocator,String) + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) + throws XNIException { + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.xmlDecl(version, encoding, standalone, augs); + } + + } // xmlDecl(String,String,String) + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * otherwise. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void doctypeDecl( + String rootElement, + String publicId, + String systemId, + Augmentations augs) + throws XNIException { + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); + } + + } // doctypeDecl(String,String,String) + + /** + * The start of an element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + Augmentations modifiedAugs = handleStartElement(element, attributes, augs); + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.startElement(element, attributes, modifiedAugs); + } + + } // startElement(QName,XMLAttributes, Augmentations) + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + Augmentations modifiedAugs = handleStartElement(element, attributes, augs); + + // in the case where there is a {value constraint}, and the element + // doesn't have any text content, change emptyElement call to + // start + characters + end + fDefaultValue = null; + // fElementDepth == -2 indicates that the schema validator was removed + // from the pipeline. then we don't need to call handleEndElement. + if (fElementDepth != -2) + modifiedAugs = handleEndElement(element, modifiedAugs); + + // call handlers + if (fDocumentHandler != null) { + if (!fSchemaElementDefault || fDefaultValue == null) { + fDocumentHandler.emptyElement(element, attributes, modifiedAugs); + } else { + fDocumentHandler.startElement(element, attributes, modifiedAugs); + fDocumentHandler.characters(fDefaultValue, null); + fDocumentHandler.endElement(element, modifiedAugs); + } + } + } // emptyElement(QName,XMLAttributes, Augmentations) + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException { + + text = handleCharacters(text); + // call handlers + if (fDocumentHandler != null) { + if (fNormalizeData && fUnionType) { + // for union types we can't normalize data + // thus we only need to send augs information if any; + // the normalized data for union will be send + // after normalization is performed (at the endElement()) + if (augs != null) + fDocumentHandler.characters(fEmptyXMLStr, augs); + } else { + fDocumentHandler.characters(text, augs); + } + } + + } // characters(XMLString) + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + + handleIgnorableWhitespace(text); + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.ignorableWhitespace(text, augs); + } + + } // ignorableWhitespace(XMLString) + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException { + + // in the case where there is a {value constraint}, and the element + // doesn't have any text content, add a characters call. + fDefaultValue = null; + Augmentations modifiedAugs = handleEndElement(element, augs); + // call handlers + if (fDocumentHandler != null) { + if (!fSchemaElementDefault || fDefaultValue == null) { + fDocumentHandler.endElement(element, modifiedAugs); + } else { + fDocumentHandler.characters(fDefaultValue, null); + fDocumentHandler.endElement(element, modifiedAugs); + } + } + } // endElement(QName, Augmentations) + + /** + * The start of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException { + + // REVISIT: what should we do here if schema normalization is on?? + fInCDATA = true; + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.startCDATA(augs); + } + + } // startCDATA() + + /** + * The end of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException { + + // call handlers + fInCDATA = false; + if (fDocumentHandler != null) { + fDocumentHandler.endCDATA(augs); + } + + } // endCDATA() + + /** + * The end of the document. + * + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDocument(Augmentations augs) throws XNIException { + + handleEndDocument(); + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.endDocument(augs); + } + fLocator = null; + + } // endDocument(Augmentations) + + // + // DOMRevalidationHandler methods + // + + + + + + public boolean characterData(String data, Augmentations augs) { + + fSawText = fSawText || data.length() > 0; + + // REVISIT: this methods basically duplicates implementation of + // handleCharacters(). We should be able to reuse some code + + // if whitespace == -1 skip normalization, because it is a complexType + // or a union type. + if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) { + // normalize data + normalizeWhitespace(data, fWhiteSpace == XSSimpleType.WS_COLLAPSE); + fBuffer.append(fNormalizedStr.ch, fNormalizedStr.offset, fNormalizedStr.length); + } else { + if (fAppendBuffer) + fBuffer.append(data); + } + + // When it's a complex type with element-only content, we need to + // find out whether the content contains any non-whitespace character. + boolean allWhiteSpace = true; + if (fCurrentType != null + && fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; + if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) { + // data outside of element content + for (int i = 0; i < data.length(); i++) { + if (!XMLChar.isSpace(data.charAt(i))) { + allWhiteSpace = false; + fSawCharacters = true; + break; + } + } + } + } + + return allWhiteSpace; + } + + public void elementDefault(String data) { + // no-op + } + + // + // XMLDocumentHandler and XMLDTDHandler methods + // + + /** + * This method notifies the start of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity( + String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) + throws XNIException { + + // REVISIT: what should happen if normalize_data_ is on?? + fEntityRef = true; + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); + } + + } // startEntity(String,String,String,String,String) + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

+ * Note: This method will never be called for the + * document entity; it is only called for external general entities + * referenced in document content. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.textDecl(version, encoding, augs); + } + + } // textDecl(String,String) + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException { + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.comment(text, augs); + } + + } // comment(XMLString) + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException { + + // call handlers + if (fDocumentHandler != null) { + fDocumentHandler.processingInstruction(target, data, augs); + } + + } // processingInstruction(String,XMLString) + + /** + * This method notifies the end of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augs) throws XNIException { + + // call handlers + fEntityRef = false; + if (fDocumentHandler != null) { + fDocumentHandler.endGeneralEntity(name, augs); + } + + } // endEntity(String) + + // constants + + static final int INITIAL_STACK_SIZE = 8; + static final int INC_STACK_SIZE = 8; + + // + // Data + // + + // Schema Normalization + + private static final boolean DEBUG_NORMALIZATION = false; + // temporary empty string buffer. + private final XMLString fEmptyXMLStr = new XMLString(null, 0, -1); + // temporary character buffer, and empty string buffer. + private static final int BUFFER_SIZE = 20; + private final XMLString fNormalizedStr = new XMLString(); + private boolean fFirstChunk = true; + // got first chunk in characters() (SAX) + private boolean fTrailing = false; // Previous chunk had a trailing space + private short fWhiteSpace = -1; //whiteSpace: preserve/replace/collapse + private boolean fUnionType = false; + + /** Schema grammar resolver. */ + private final XSGrammarBucket fGrammarBucket = new XSGrammarBucket(); + private final SubstitutionGroupHandler fSubGroupHandler = new SubstitutionGroupHandler(this); + + /** the DV usd to convert xsi:type to a QName */ + // REVISIT: in new simple type design, make things in DVs static, + // so that we can QNameDV.getCompiledForm() + private final XSSimpleType fQNameDV = + (XSSimpleType) SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME); + + private final CMNodeFactory nodeFactory = new CMNodeFactory(); + /** used to build content models */ + // REVISIT: create decl pool, and pass it to each traversers + private final CMBuilder fCMBuilder = new CMBuilder(nodeFactory); + + // Schema grammar loader + private final XMLSchemaLoader fSchemaLoader = + new XMLSchemaLoader( + fXSIErrorReporter.fErrorReporter, + fGrammarBucket, + fSubGroupHandler, + fCMBuilder); + + // state + + /** String representation of the validation root. */ + // REVISIT: what do we store here? QName, XPATH, some ID? use rawname now. + private String fValidationRoot; + + /** Skip validation: anything below this level should be skipped */ + private int fSkipValidationDepth; + + /** anything above this level has validation_attempted != full */ + private int fNFullValidationDepth; + + /** anything above this level has validation_attempted != none */ + private int fNNoneValidationDepth; + + /** Element depth: -2: validator not in pipeline; >= -1 current depth. */ + private int fElementDepth; + + /** Seen sub elements. */ + private boolean fSubElement; + + /** Seen sub elements stack. */ + private boolean[] fSubElementStack = new boolean[INITIAL_STACK_SIZE]; + + /** Current element declaration. */ + private XSElementDecl fCurrentElemDecl; + + /** Element decl stack. */ + private XSElementDecl[] fElemDeclStack = new XSElementDecl[INITIAL_STACK_SIZE]; + + /** nil value of the current element */ + private boolean fNil; + + /** nil value stack */ + private boolean[] fNilStack = new boolean[INITIAL_STACK_SIZE]; + + /** notation value of the current element */ + private XSNotationDecl fNotation; + + /** notation stack */ + private XSNotationDecl[] fNotationStack = new XSNotationDecl[INITIAL_STACK_SIZE]; + + /** Current type. */ + private XSTypeDefinition fCurrentType; + + /** type stack. */ + private XSTypeDefinition[] fTypeStack = new XSTypeDefinition[INITIAL_STACK_SIZE]; + + /** Current content model. */ + private XSCMValidator fCurrentCM; + + /** Content model stack. */ + private XSCMValidator[] fCMStack = new XSCMValidator[INITIAL_STACK_SIZE]; + + /** the current state of the current content model */ + private int[] fCurrCMState; + + /** stack to hold content model states */ + private int[][] fCMStateStack = new int[INITIAL_STACK_SIZE][]; + + /** whether the curret element is strictly assessed */ + private boolean fStrictAssess = true; + + /** strict assess stack */ + private boolean[] fStrictAssessStack = new boolean[INITIAL_STACK_SIZE]; + + /** Temporary string buffers. */ + private final StringBuffer fBuffer = new StringBuffer(); + + /** Whether need to append characters to fBuffer */ + private boolean fAppendBuffer = true; + + /** Did we see any character data? */ + private boolean fSawText = false; + + /** stack to record if we saw character data */ + private boolean[] fSawTextStack = new boolean[INITIAL_STACK_SIZE]; + + /** Did we see non-whitespace character data? */ + private boolean fSawCharacters = false; + + /** Stack to record if we saw character data outside of element content*/ + private boolean[] fStringContent = new boolean[INITIAL_STACK_SIZE]; + + /** temporary qname */ + private final QName fTempQName = new QName(); + + /** value of the "root-type-definition" property. */ + private javax.xml.namespace.QName fRootTypeQName = null; + private XSTypeDefinition fRootTypeDefinition = null; + + /** value of the "root-element-declaration" property. */ + private javax.xml.namespace.QName fRootElementDeclQName = null; + private XSElementDecl fRootElementDeclaration = null; + + private int fIgnoreXSITypeDepth; + + private boolean fIDCChecking; + + /** temporary validated info */ + private ValidatedInfo fValidatedInfo = new ValidatedInfo(); + + // used to validate default/fixed values against xsi:type + // only need to check facets, so we set extraChecking to false (in reset) + private ValidationState fState4XsiType = new ValidationState(); + + // used to apply default/fixed values + // only need to check id/idref/entity, so we set checkFacets to false + private ValidationState fState4ApplyDefault = new ValidationState(); + + // identity constraint information + + /** + * Stack of active XPath matchers for identity constraints. All + * active XPath matchers are notified of startElement + * and endElement callbacks in order to perform their matches. + *

+ * For each element with identity constraints, the selector of + * each identity constraint is activated. When the selector matches + * its XPath, then all the fields of the identity constraint are + * activated. + *

+ * Note: Once the activation scope is left, the + * XPath matchers are automatically removed from the stack of + * active matchers and no longer receive callbacks. + */ + protected XPathMatcherStack fMatcherStack = new XPathMatcherStack(); + + /** Cache of value stores for identity constraint fields. */ + protected ValueStoreCache fValueStoreCache = new ValueStoreCache(); + + // + // Constructors + // + + /** Default constructor. */ + public XMLSchemaValidator() { + fState4XsiType.setExtraChecking(false); + fState4ApplyDefault.setFacetChecking(false); + + } // () + + /* + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws SAXException Thrown by component on finitialization error. + * For example, if a feature or property is + * required for the operation of the component, the + * component manager may throw a + * SAXNotRecognizedException or a + * SAXNotSupportedException. + */ + public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { + + + fIdConstraint = false; + //reset XSDDescription + fLocationPairs.clear(); + fExpandedLocationPairs.clear(); + + // cleanup id table + fValidationState.resetIDTables(); + + // reset schema loader + fSchemaLoader.reset(componentManager); + + // initialize state + fCurrentElemDecl = null; + fCurrentCM = null; + fCurrCMState = null; + fSkipValidationDepth = -1; + fNFullValidationDepth = -1; + fNNoneValidationDepth = -1; + fElementDepth = -1; + fSubElement = false; + fSchemaDynamicValidation = false; + + // datatype normalization + fEntityRef = false; + fInCDATA = false; + + fMatcherStack.clear(); + + // get error reporter + fXSIErrorReporter.reset((XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER)); + + boolean parser_settings; + try { + parser_settings = componentManager.getFeature(PARSER_SETTINGS); + } + catch (XMLConfigurationException e){ + parser_settings = true; + } + + if (!parser_settings) { + // parser settings have not been changed + fValidationManager.addValidationState(fValidationState); + // the node limit on the SecurityManager may have changed so need to refresh. + nodeFactory.reset(); + // Re-parse external schema location properties. + XMLSchemaLoader.processExternalHints( + fExternalSchemas, + fExternalNoNamespaceSchema, + fLocationPairs, + fXSIErrorReporter.fErrorReporter); + return; + } + + // pass the component manager to the factory.. + nodeFactory.reset(componentManager); + + // get symbol table. if it's a new one, add symbols to it. + SymbolTable symbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE); + if (symbolTable != fSymbolTable) { + fSymbolTable = symbolTable; + } + + try { + fNamespaceGrowth = componentManager.getFeature(NAMESPACE_GROWTH); + } catch (XMLConfigurationException e) { + fNamespaceGrowth = false; + } + + try { + fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION); + } catch (XMLConfigurationException e) { + fDynamicValidation = false; + } + + if (fDynamicValidation) { + fDoValidation = true; + } else { + try { + fDoValidation = componentManager.getFeature(VALIDATION); + } catch (XMLConfigurationException e) { + fDoValidation = false; + } + } + + if (fDoValidation) { + try { + fDoValidation = componentManager.getFeature(XMLSchemaValidator.SCHEMA_VALIDATION); + } catch (XMLConfigurationException e) { + } + } + + try { + fFullChecking = componentManager.getFeature(SCHEMA_FULL_CHECKING); + } catch (XMLConfigurationException e) { + fFullChecking = false; + } + + try { + fNormalizeData = componentManager.getFeature(NORMALIZE_DATA); + } catch (XMLConfigurationException e) { + fNormalizeData = false; + } + + try { + fSchemaElementDefault = componentManager.getFeature(SCHEMA_ELEMENT_DEFAULT); + } catch (XMLConfigurationException e) { + fSchemaElementDefault = false; + } + + try { + fAugPSVI = componentManager.getFeature(SCHEMA_AUGMENT_PSVI); + } catch (XMLConfigurationException e) { + fAugPSVI = true; + } + try { + fSchemaType = + (String) componentManager.getProperty( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE); + } catch (XMLConfigurationException e) { + fSchemaType = null; + } + + try { + fUseGrammarPoolOnly = componentManager.getFeature(USE_GRAMMAR_POOL_ONLY); + } + catch (XMLConfigurationException e) { + fUseGrammarPoolOnly = false; + } + + fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER); + + fValidationManager = (ValidationManager) componentManager.getProperty(VALIDATION_MANAGER); + fValidationManager.addValidationState(fValidationState); + fValidationState.setSymbolTable(fSymbolTable); + + try { + final Object rootType = componentManager.getProperty(ROOT_TYPE_DEF); + if (rootType == null) { + fRootTypeQName = null; + fRootTypeDefinition = null; + } + else if (rootType instanceof javax.xml.namespace.QName) { + fRootTypeQName = (javax.xml.namespace.QName) rootType; + fRootTypeDefinition = null; + } + else { + fRootTypeDefinition = (XSTypeDefinition) rootType; + fRootTypeQName = null; + } + } + catch (XMLConfigurationException e) { + fRootTypeQName = null; + fRootTypeDefinition = null; + } + + try { + final Object rootDecl = componentManager.getProperty(ROOT_ELEMENT_DECL); + if (rootDecl == null) { + fRootElementDeclQName = null; + fRootElementDeclaration = null; + } + else if (rootDecl instanceof javax.xml.namespace.QName) { + fRootElementDeclQName = (javax.xml.namespace.QName) rootDecl; + fRootElementDeclaration = null; + } + else { + fRootElementDeclaration = (XSElementDecl) rootDecl; + fRootElementDeclQName = null; + } + } + catch (XMLConfigurationException e) { + fRootElementDeclQName = null; + fRootElementDeclaration = null; + } + + boolean ignoreXSIType; + try { + ignoreXSIType = componentManager.getFeature(IGNORE_XSI_TYPE); + } + catch (XMLConfigurationException e) { + ignoreXSIType = false; + } + // An initial value of -1 means that the root element considers itself + // below the depth where xsi:type stopped being ignored (which means that + // xsi:type attributes will not be ignored for the entire document) + fIgnoreXSITypeDepth = ignoreXSIType ? 0 : -1; + + try { + fIDCChecking = componentManager.getFeature(IDENTITY_CONSTRAINT_CHECKING); + } + catch (XMLConfigurationException e) { + fIDCChecking = true; + } + + try { + fValidationState.setIdIdrefChecking(componentManager.getFeature(ID_IDREF_CHECKING)); + } + catch (XMLConfigurationException e) { + fValidationState.setIdIdrefChecking(true); + } + + try { + fValidationState.setUnparsedEntityChecking(componentManager.getFeature(UNPARSED_ENTITY_CHECKING)); + } + catch (XMLConfigurationException e) { + fValidationState.setUnparsedEntityChecking(true); + } + + // get schema location properties + try { + fExternalSchemas = (String) componentManager.getProperty(SCHEMA_LOCATION); + fExternalNoNamespaceSchema = + (String) componentManager.getProperty(SCHEMA_NONS_LOCATION); + } catch (XMLConfigurationException e) { + fExternalSchemas = null; + fExternalNoNamespaceSchema = null; + } + + // store the external schema locations. they are set when reset is called, + // so any other schemaLocation declaration for the same namespace will be + // effectively ignored. becuase we choose to take first location hint + // available for a particular namespace. + XMLSchemaLoader.processExternalHints( + fExternalSchemas, + fExternalNoNamespaceSchema, + fLocationPairs, + fXSIErrorReporter.fErrorReporter); + + try { + fJaxpSchemaSource = componentManager.getProperty(JAXP_SCHEMA_SOURCE); + } catch (XMLConfigurationException e) { + fJaxpSchemaSource = null; + + } + + // clear grammars, and put the one for schema namespace there + try { + fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL); + } catch (XMLConfigurationException e) { + fGrammarPool = null; + } + + fState4XsiType.setSymbolTable(symbolTable); + fState4ApplyDefault.setSymbolTable(symbolTable); + + } // reset(XMLComponentManager) + + // + // FieldActivator methods + // + + /** + * Start the value scope for the specified identity constraint. This + * method is called when the selector matches in order to initialize + * the value store. + * + * @param identityConstraint The identity constraint. + */ + public void startValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) { + + ValueStoreBase valueStore = + fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth); + valueStore.startValueScope(); + + } // startValueScopeFor(IdentityConstraint identityConstraint) + + /** + * Request to activate the specified field. This method returns the + * matcher for the field. + * + * @param field The field to activate. + */ + public XPathMatcher activateField(Field field, int initialDepth) { + ValueStore valueStore = + fValueStoreCache.getValueStoreFor(field.getIdentityConstraint(), initialDepth); + XPathMatcher matcher = field.createMatcher(valueStore); + fMatcherStack.addMatcher(matcher); + matcher.startDocumentFragment(); + return matcher; + } // activateField(Field):XPathMatcher + + /** + * Ends the value scope for the specified identity constraint. + * + * @param identityConstraint The identity constraint. + */ + public void endValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) { + + ValueStoreBase valueStore = + fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth); + valueStore.endValueScope(); + + } // endValueScopeFor(IdentityConstraint) + + // a utility method for Identity constraints + private void activateSelectorFor(IdentityConstraint ic) { + Selector selector = ic.getSelector(); + FieldActivator activator = this; + if (selector == null) + return; + XPathMatcher matcher = selector.createMatcher(activator, fElementDepth); + fMatcherStack.addMatcher(matcher); + matcher.startDocumentFragment(); + } + + // Implements XSElementDeclHelper interface + public XSElementDecl getGlobalElementDecl(QName element) { + final SchemaGrammar sGrammar = + findSchemaGrammar( + XSDDescription.CONTEXT_ELEMENT, + element.uri, + null, + element, + null); + if (sGrammar != null) { + return sGrammar.getGlobalElementDecl(element.localpart); + } + return null; + } + + // + // Protected methods + // + + /** ensure element stack capacity */ + void ensureStackCapacity() { + + if (fElementDepth == fElemDeclStack.length) { + int newSize = fElementDepth + INC_STACK_SIZE; + boolean[] newArrayB = new boolean[newSize]; + System.arraycopy(fSubElementStack, 0, newArrayB, 0, fElementDepth); + fSubElementStack = newArrayB; + + XSElementDecl[] newArrayE = new XSElementDecl[newSize]; + System.arraycopy(fElemDeclStack, 0, newArrayE, 0, fElementDepth); + fElemDeclStack = newArrayE; + + newArrayB = new boolean[newSize]; + System.arraycopy(fNilStack, 0, newArrayB, 0, fElementDepth); + fNilStack = newArrayB; + + XSNotationDecl[] newArrayN = new XSNotationDecl[newSize]; + System.arraycopy(fNotationStack, 0, newArrayN, 0, fElementDepth); + fNotationStack = newArrayN; + + XSTypeDefinition[] newArrayT = new XSTypeDefinition[newSize]; + System.arraycopy(fTypeStack, 0, newArrayT, 0, fElementDepth); + fTypeStack = newArrayT; + + XSCMValidator[] newArrayC = new XSCMValidator[newSize]; + System.arraycopy(fCMStack, 0, newArrayC, 0, fElementDepth); + fCMStack = newArrayC; + + newArrayB = new boolean[newSize]; + System.arraycopy(fSawTextStack, 0, newArrayB, 0, fElementDepth); + fSawTextStack = newArrayB; + + newArrayB = new boolean[newSize]; + System.arraycopy(fStringContent, 0, newArrayB, 0, fElementDepth); + fStringContent = newArrayB; + + newArrayB = new boolean[newSize]; + System.arraycopy(fStrictAssessStack, 0, newArrayB, 0, fElementDepth); + fStrictAssessStack = newArrayB; + + int[][] newArrayIA = new int[newSize][]; + System.arraycopy(fCMStateStack, 0, newArrayIA, 0, fElementDepth); + fCMStateStack = newArrayIA; + } + + } // ensureStackCapacity + + // handle start document + void handleStartDocument(XMLLocator locator, String encoding) { + if (fIDCChecking) { + fValueStoreCache.startDocument(); + } + if (fAugPSVI) { + fCurrentPSVI.fGrammars = null; + fCurrentPSVI.fSchemaInformation = null; + } + } // handleStartDocument(XMLLocator,String) + + void handleEndDocument() { + if (fIDCChecking) { + fValueStoreCache.endDocument(); + } + } // handleEndDocument() + + // handle character contents + // returns the normalized string if possible, otherwise the original string + XMLString handleCharacters(XMLString text) { + + if (fSkipValidationDepth >= 0) + return text; + + fSawText = fSawText || text.length > 0; + + // Note: data in EntityRef and CDATA is normalized as well + // if whitespace == -1 skip normalization, because it is a complexType + // or a union type. + if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) { + // normalize data + normalizeWhitespace(text, fWhiteSpace == XSSimpleType.WS_COLLAPSE); + text = fNormalizedStr; + } + if (fAppendBuffer) + fBuffer.append(text.ch, text.offset, text.length); + + // When it's a complex type with element-only content, we need to + // find out whether the content contains any non-whitespace character. + if (fCurrentType != null + && fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; + if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) { + // data outside of element content + for (int i = text.offset; i < text.offset + text.length; i++) { + if (!XMLChar.isSpace(text.ch[i])) { + fSawCharacters = true; + break; + } + } + } + } + + return text; + } // handleCharacters(XMLString) + + /** + * Normalize whitespace in an XMLString according to the rules defined + * in XML Schema specifications. + * @param value The string to normalize. + * @param collapse replace or collapse + */ + private void normalizeWhitespace(XMLString value, boolean collapse) { + boolean skipSpace = collapse; + boolean sawNonWS = false; + boolean leading = false; + boolean trailing = false; + char c; + int size = value.offset + value.length; + + // ensure the ch array is big enough + if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < value.length + 1) { + fNormalizedStr.ch = new char[value.length + 1]; + } + // don't include the leading ' ' for now. might include it later. + fNormalizedStr.offset = 1; + fNormalizedStr.length = 1; + + for (int i = value.offset; i < size; i++) { + c = value.ch[i]; + if (XMLChar.isSpace(c)) { + if (!skipSpace) { + // take the first whitespace as a space and skip the others + fNormalizedStr.ch[fNormalizedStr.length++] = ' '; + skipSpace = collapse; + } + if (!sawNonWS) { + // this is a leading whitespace, record it + leading = true; + } + } else { + fNormalizedStr.ch[fNormalizedStr.length++] = c; + skipSpace = false; + sawNonWS = true; + } + } + if (skipSpace) { + if (fNormalizedStr.length > 1) { + // if we finished on a space trim it but also record it + fNormalizedStr.length--; + trailing = true; + } else if (leading && !fFirstChunk) { + // if all we had was whitespace we skipped record it as + // trailing whitespace as well + trailing = true; + } + } + + if (fNormalizedStr.length > 1) { + if (!fFirstChunk && (fWhiteSpace == XSSimpleType.WS_COLLAPSE)) { + if (fTrailing) { + // previous chunk ended on whitespace + // insert whitespace + fNormalizedStr.offset = 0; + fNormalizedStr.ch[0] = ' '; + } else if (leading) { + // previous chunk ended on character, + // this chunk starts with whitespace + fNormalizedStr.offset = 0; + fNormalizedStr.ch[0] = ' '; + } + } + } + + // The length includes the leading ' '. Now removing it. + fNormalizedStr.length -= fNormalizedStr.offset; + + fTrailing = trailing; + + if (trailing || sawNonWS) + fFirstChunk = false; + } + + private void normalizeWhitespace(String value, boolean collapse) { + boolean skipSpace = collapse; + char c; + int size = value.length(); + + // ensure the ch array is big enough + if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < size) { + fNormalizedStr.ch = new char[size]; + } + fNormalizedStr.offset = 0; + fNormalizedStr.length = 0; + + for (int i = 0; i < size; i++) { + c = value.charAt(i); + if (XMLChar.isSpace(c)) { + if (!skipSpace) { + // take the first whitespace as a space and skip the others + fNormalizedStr.ch[fNormalizedStr.length++] = ' '; + skipSpace = collapse; + } + } else { + fNormalizedStr.ch[fNormalizedStr.length++] = c; + skipSpace = false; + } + } + if (skipSpace) { + if (fNormalizedStr.length != 0) + // if we finished on a space trim it but also record it + fNormalizedStr.length--; + } + } + + // handle ignorable whitespace + void handleIgnorableWhitespace(XMLString text) { + + if (fSkipValidationDepth >= 0) + return; + + // REVISIT: the same process needs to be performed as handleCharacters. + // only it's simpler here: we know all characters are whitespaces. + + } // handleIgnorableWhitespace(XMLString) + + /** Handle element. */ + Augmentations handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) { + + if (DEBUG) { + System.out.println("==>handleStartElement: " + element); + } + + // root element + if (fElementDepth == -1 && fValidationManager.isGrammarFound()) { + if (fSchemaType == null) { + // schemaType is not specified + // if a DTD grammar is found, we do the same thing as Dynamic: + // if a schema grammar is found, validation is performed; + // otherwise, skip the whole document. + fSchemaDynamicValidation = true; + } else { + // [1] Either schemaType is DTD, and in this case validate/schema is turned off + // [2] Validating against XML Schemas only + // [a] dynamic validation is false: report error if SchemaGrammar is not found + // [b] dynamic validation is true: if grammar is not found ignore. + } + + } + + // get xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes, + // parse them to get the grammars. But only do this if the grammar can grow. + if (!fUseGrammarPoolOnly) { + String sLocation = + attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_SCHEMALOCATION); + String nsLocation = + attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION); + //store the location hints.. we need to do it so that we can defer the loading of grammar until + //there is a reference to a component from that namespace. To provide location hints to the + //application for a namespace + storeLocations(sLocation, nsLocation); + } + + // if we are in the content of "skip", then just skip this element + // REVISIT: is this the correct behaviour for ID constraints? -NG + if (fSkipValidationDepth >= 0) { + fElementDepth++; + if (fAugPSVI) + augs = getEmptyAugs(augs); + return augs; + } + + // if we are not skipping this element, and there is a content model, + // we try to find the corresponding decl object for this element. + // the reason we move this part of code here is to make sure the + // error reported here (if any) is stored within the parent element's + // context, instead of that of the current element. + Object decl = null; + if (fCurrentCM != null) { + decl = fCurrentCM.oneTransition(element, fCurrCMState, fSubGroupHandler); + // it could be an element decl or a wildcard decl + if (fCurrCMState[0] == XSCMValidator.FIRST_ERROR) { + XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; + //REVISIT: is it the only case we will have particle = null? + Vector next; + if (ctype.fParticle != null + && (next = fCurrentCM.whatCanGoHere(fCurrCMState)).size() > 0) { + String expected = expectedStr(next); + final int[] occurenceInfo = fCurrentCM.occurenceInfo(fCurrCMState); + String elemExpandedQname = (element.uri != null) ? "{"+'"'+element.uri+'"'+":"+element.localpart+"}" : element.localpart; + if (occurenceInfo != null) { + final int minOccurs = occurenceInfo[0]; + final int maxOccurs = occurenceInfo[1]; + final int count = occurenceInfo[2]; + // Check if this is a violation of minOccurs + if (count < minOccurs) { + final int required = minOccurs - count; + if (required > 1) { + reportSchemaError("cvc-complex-type.2.4.h", new Object[] { element.rawname, + fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(minOccurs), Integer.toString(required) }); + } + else { + reportSchemaError("cvc-complex-type.2.4.g", new Object[] { element.rawname, + fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(minOccurs) }); + } + } + // Check if this is a violation of maxOccurs + else if (count >= maxOccurs && maxOccurs != SchemaSymbols.OCCURRENCE_UNBOUNDED) { + reportSchemaError("cvc-complex-type.2.4.e", new Object[] { element.rawname, + expected, Integer.toString(maxOccurs) }); + } + else { + reportSchemaError("cvc-complex-type.2.4.a", new Object[] { elemExpandedQname, expected }); + } + } + else { + reportSchemaError("cvc-complex-type.2.4.a", new Object[] { elemExpandedQname, expected }); + } + } + else { + final int[] occurenceInfo = fCurrentCM.occurenceInfo(fCurrCMState); + if (occurenceInfo != null) { + final int maxOccurs = occurenceInfo[1]; + final int count = occurenceInfo[2]; + // Check if this is a violation of maxOccurs + if (count >= maxOccurs && maxOccurs != SchemaSymbols.OCCURRENCE_UNBOUNDED) { + reportSchemaError("cvc-complex-type.2.4.f", new Object[] { fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(maxOccurs) }); + } + else { + reportSchemaError("cvc-complex-type.2.4.d", new Object[] { element.rawname }); + } + } + else { + reportSchemaError("cvc-complex-type.2.4.d", new Object[] { element.rawname }); + } + } + } + } + + // if it's not the root element, we push the current states in the stacks + if (fElementDepth != -1) { + ensureStackCapacity(); + fSubElementStack[fElementDepth] = true; + fSubElement = false; + fElemDeclStack[fElementDepth] = fCurrentElemDecl; + fNilStack[fElementDepth] = fNil; + fNotationStack[fElementDepth] = fNotation; + fTypeStack[fElementDepth] = fCurrentType; + fStrictAssessStack[fElementDepth] = fStrictAssess; + fCMStack[fElementDepth] = fCurrentCM; + fCMStateStack[fElementDepth] = fCurrCMState; + fSawTextStack[fElementDepth] = fSawText; + fStringContent[fElementDepth] = fSawCharacters; + } + + // increase the element depth after we've saved + // all states for the parent element + fElementDepth++; + fCurrentElemDecl = null; + XSWildcardDecl wildcard = null; + fCurrentType = null; + fStrictAssess = true; + fNil = false; + fNotation = null; + + // and the buffer to hold the value of the element + fBuffer.setLength(0); + fSawText = false; + fSawCharacters = false; + + // check what kind of declaration the "decl" from + // oneTransition() maps to + if (decl != null) { + if (decl instanceof XSElementDecl) { + fCurrentElemDecl = (XSElementDecl) decl; + } else { + wildcard = (XSWildcardDecl) decl; + } + } + + // if the wildcard is skip, then return + if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_SKIP) { + fSkipValidationDepth = fElementDepth; + if (fAugPSVI) + augs = getEmptyAugs(augs); + return augs; + } + + if (fElementDepth == 0) { + // 1.1.1.1 An element declaration was stipulated by the processor + if (fRootElementDeclaration != null) { + fCurrentElemDecl = fRootElementDeclaration; + checkElementMatchesRootElementDecl(fCurrentElemDecl, element); + } + else if (fRootElementDeclQName != null) { + processRootElementDeclQName(fRootElementDeclQName, element); + } + // 1.2.1.1 A type definition was stipulated by the processor + else if (fRootTypeDefinition != null) { + fCurrentType = fRootTypeDefinition; + } + else if (fRootTypeQName != null) { + processRootTypeQName(fRootTypeQName); + } + } + + // if there was no processor stipulated type + if (fCurrentType == null) { + // try again to get the element decl: + // case 1: find declaration for root element + // case 2: find declaration for element from another namespace + if (fCurrentElemDecl == null) { + // try to find schema grammar by different means.. + SchemaGrammar sGrammar = + findSchemaGrammar( + XSDDescription.CONTEXT_ELEMENT, + element.uri, + null, + element, + attributes); + if (sGrammar != null) { + fCurrentElemDecl = sGrammar.getGlobalElementDecl(element.localpart); + } + } + + if (fCurrentElemDecl != null) { + // then get the type + fCurrentType = fCurrentElemDecl.fType; + } + } + + // check if we should be ignoring xsi:type on this element + if (fElementDepth == fIgnoreXSITypeDepth && fCurrentElemDecl == null) { + fIgnoreXSITypeDepth++; + } + + // process xsi:type attribute information + String xsiType = null; + if (fElementDepth >= fIgnoreXSITypeDepth) { + xsiType = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_TYPE); + } + + // if no decl/type found for the current element + if (fCurrentType == null && xsiType == null) { + // if this is the validation root, report an error, because + // we can't find eith decl or type for this element + // REVISIT: should we report error, or warning? + if (fElementDepth == 0) { + // for dynamic validation, skip the whole content, + // because no grammar was found. + if (fDynamicValidation || fSchemaDynamicValidation) { + // no schema grammar was found, but it's either dynamic + // validation, or another kind of grammar was found (DTD, + // for example). The intended behavior here is to skip + // the whole document. To improve performance, we try to + // remove the validator from the pipeline, since it's not + // supposed to do anything. + if (fDocumentSource != null) { + fDocumentSource.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) + fDocumentHandler.setDocumentSource(fDocumentSource); + // indicate that the validator was removed. + fElementDepth = -2; + return augs; + } + + fSkipValidationDepth = fElementDepth; + if (fAugPSVI) + augs = getEmptyAugs(augs); + return augs; + } + // We don't call reportSchemaError here, because the spec + // doesn't think it's invalid not to be able to find a + // declaration or type definition for an element. Xerces is + // reporting it as an error for historical reasons, but in + // PSVI, we shouldn't mark this element as invalid because + // of this. - SG + fXSIErrorReporter.fErrorReporter.reportError( + XSMessageFormatter.SCHEMA_DOMAIN, + "cvc-elt.1.a", + new Object[] { element.rawname }, + XMLErrorReporter.SEVERITY_ERROR); + } + // if wildcard = strict, report error. + // needs to be called before fXSIErrorReporter.pushContext() + // so that the error belongs to the parent element. + else if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_STRICT) { + // report error, because wilcard = strict + reportSchemaError("cvc-complex-type.2.4.c", new Object[] { element.rawname }); + } + // no element decl or type found for this element. + // Allowed by the spec, we can choose to either laxly assess this + // element, or to skip it. Now we choose lax assessment. + fCurrentType = SchemaGrammar.fAnyType; + fStrictAssess = false; + fNFullValidationDepth = fElementDepth; + // any type has mixed content, so we don't need to append buffer + fAppendBuffer = false; + + // push error reporter context: record the current position + // This has to happen after we process skip contents, + // otherwise push and pop won't be correctly paired. + fXSIErrorReporter.pushContext(); + } else { + // push error reporter context: record the current position + // This has to happen after we process skip contents, + // otherwise push and pop won't be correctly paired. + fXSIErrorReporter.pushContext(); + + // get xsi:type + if (xsiType != null) { + XSTypeDefinition oldType = fCurrentType; + fCurrentType = getAndCheckXsiType(element, xsiType, attributes); + // If it fails, use the old type. Use anyType if ther is no old type. + if (fCurrentType == null) { + if (oldType == null) + fCurrentType = SchemaGrammar.fAnyType; + else + fCurrentType = oldType; + } + } + + fNNoneValidationDepth = fElementDepth; + // if the element has a fixed value constraint, we need to append + if (fCurrentElemDecl != null + && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED) { + fAppendBuffer = true; + } + // if the type is simple, we need to append + else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { + fAppendBuffer = true; + } else { + // if the type is simple content complex type, we need to append + XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; + fAppendBuffer = (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE); + } + } + + // Element Locally Valid (Element) + // 2 Its {abstract} must be false. + if (fCurrentElemDecl != null && fCurrentElemDecl.getAbstract()) + reportSchemaError("cvc-elt.2", new Object[] { element.rawname }); + + // make the current element validation root + if (fElementDepth == 0) { + fValidationRoot = element.rawname; + } + + // update normalization flags + if (fNormalizeData) { + // reset values + fFirstChunk = true; + fTrailing = false; + fUnionType = false; + fWhiteSpace = -1; + } + + // Element Locally Valid (Type) + // 2 Its {abstract} must be false. + if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; + if (ctype.getAbstract()) { + reportSchemaError("cvc-type.2", new Object[] { element.rawname }); + } + if (fNormalizeData) { + // find out if the content type is simple and if variety is union + // to be able to do character normalization + if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { + if (ctype.fXSSimpleType.getVariety() == XSSimpleType.VARIETY_UNION) { + fUnionType = true; + } else { + try { + fWhiteSpace = ctype.fXSSimpleType.getWhitespace(); + } catch (DatatypeException e) { + // do nothing + } + } + } + } + } + // normalization: simple type + else if (fNormalizeData) { + // if !union type + XSSimpleType dv = (XSSimpleType) fCurrentType; + if (dv.getVariety() == XSSimpleType.VARIETY_UNION) { + fUnionType = true; + } else { + try { + fWhiteSpace = dv.getWhitespace(); + } catch (DatatypeException e) { + // do nothing + } + } + } + + // then try to get the content model + fCurrentCM = null; + if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + fCurrentCM = ((XSComplexTypeDecl) fCurrentType).getContentModel(fCMBuilder); + } + + // and get the initial content model state + fCurrCMState = null; + if (fCurrentCM != null) + fCurrCMState = fCurrentCM.startContentModel(); + + // get information about xsi:nil + String xsiNil = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NIL); + // only deal with xsi:nil when there is an element declaration + if (xsiNil != null && fCurrentElemDecl != null) + fNil = getXsiNil(element, xsiNil); + + // now validate everything related with the attributes + // first, get the attribute group + XSAttributeGroupDecl attrGrp = null; + if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; + attrGrp = ctype.getAttrGrp(); + } + + if (fIDCChecking) { + // activate identity constraints + fValueStoreCache.startElement(); + fMatcherStack.pushContext(); + //if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0 && !fIgnoreIDC) { + if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0) { + fIdConstraint = true; + // initialize when identity constrains are defined for the elem + fValueStoreCache.initValueStoresFor(fCurrentElemDecl, this); + } + } + processAttributes(element, attributes, attrGrp); + + // add default attributes + if (attrGrp != null) { + addDefaultAttributes(element, attributes, attrGrp); + } + + // call all active identity constraints + int count = fMatcherStack.getMatcherCount(); + for (int i = 0; i < count; i++) { + XPathMatcher matcher = fMatcherStack.getMatcherAt(i); + matcher.startElement( element, attributes); + } + + if (fAugPSVI) { + augs = getEmptyAugs(augs); + + // PSVI: add validation context + fCurrentPSVI.fValidationContext = fValidationRoot; + // PSVI: add element declaration + fCurrentPSVI.fDeclaration = fCurrentElemDecl; + // PSVI: add element type + fCurrentPSVI.fTypeDecl = fCurrentType; + // PSVI: add notation attribute + fCurrentPSVI.fNotation = fNotation; + // PSVI: add nil + fCurrentPSVI.fNil = fNil; + } + + return augs; + + } // handleStartElement(QName,XMLAttributes,boolean) + + /** + * Handle end element. If there is not text content, and there is a + * {value constraint} on the corresponding element decl, then + * set the fDefaultValue XMLString representing the default value. + */ + Augmentations handleEndElement(QName element, Augmentations augs) { + + if (DEBUG) { + System.out.println("==>handleEndElement:" + element); + } + // if we are skipping, return + if (fSkipValidationDepth >= 0) { + // but if this is the top element that we are skipping, + // restore the states. + if (fSkipValidationDepth == fElementDepth && fSkipValidationDepth > 0) { + // set the partial validation depth to the depth of parent + fNFullValidationDepth = fSkipValidationDepth - 1; + fSkipValidationDepth = -1; + fElementDepth--; + fSubElement = fSubElementStack[fElementDepth]; + fCurrentElemDecl = fElemDeclStack[fElementDepth]; + fNil = fNilStack[fElementDepth]; + fNotation = fNotationStack[fElementDepth]; + fCurrentType = fTypeStack[fElementDepth]; + fCurrentCM = fCMStack[fElementDepth]; + fStrictAssess = fStrictAssessStack[fElementDepth]; + fCurrCMState = fCMStateStack[fElementDepth]; + fSawText = fSawTextStack[fElementDepth]; + fSawCharacters = fStringContent[fElementDepth]; + } + else { + fElementDepth--; + } + + // PSVI: validation attempted: + // use default values in psvi item for + // validation attempted, validity, and error codes + + // check extra schema constraints on root element + if (fElementDepth == -1 && fFullChecking && !fUseGrammarPoolOnly) { + XSConstraints.fullSchemaChecking( + fGrammarBucket, + fSubGroupHandler, + fCMBuilder, + fXSIErrorReporter.fErrorReporter); + } + + if (fAugPSVI) + augs = getEmptyAugs(augs); + return augs; + } + + // now validate the content of the element + processElementContent(element); + + if (fIDCChecking) { + // Element Locally Valid (Element) + // 6 The element information item must be valid with respect to each of the {identity-constraint definitions} as per Identity-constraint Satisfied (3.11.4). + + // call matchers and de-activate context + int oldCount = fMatcherStack.getMatcherCount(); + for (int i = oldCount - 1; i >= 0; i--) { + XPathMatcher matcher = fMatcherStack.getMatcherAt(i); + if (fCurrentElemDecl == null) { + matcher.endElement(element, fCurrentType, false, fValidatedInfo.actualValue, fValidatedInfo.actualValueType, fValidatedInfo.itemValueTypes); + } + else { + matcher.endElement( + element, + fCurrentType, + fCurrentElemDecl.getNillable(), + fDefaultValue == null + ? fValidatedInfo.actualValue + : fCurrentElemDecl.fDefault.actualValue, + fDefaultValue == null + ? fValidatedInfo.actualValueType + : fCurrentElemDecl.fDefault.actualValueType, + fDefaultValue == null + ? fValidatedInfo.itemValueTypes + : fCurrentElemDecl.fDefault.itemValueTypes); + } + } + + if (fMatcherStack.size() > 0) { + fMatcherStack.popContext(); + } + + int newCount = fMatcherStack.getMatcherCount(); + // handle everything *but* keyref's. + for (int i = oldCount - 1; i >= newCount; i--) { + XPathMatcher matcher = fMatcherStack.getMatcherAt(i); + if (matcher instanceof Selector.Matcher) { + Selector.Matcher selMatcher = (Selector.Matcher) matcher; + IdentityConstraint id; + if ((id = selMatcher.getIdentityConstraint()) != null + && id.getCategory() != IdentityConstraint.IC_KEYREF) { + fValueStoreCache.transplant(id, selMatcher.getInitialDepth()); + } + } + } + + // now handle keyref's/... + for (int i = oldCount - 1; i >= newCount; i--) { + XPathMatcher matcher = fMatcherStack.getMatcherAt(i); + if (matcher instanceof Selector.Matcher) { + Selector.Matcher selMatcher = (Selector.Matcher) matcher; + IdentityConstraint id; + if ((id = selMatcher.getIdentityConstraint()) != null + && id.getCategory() == IdentityConstraint.IC_KEYREF) { + ValueStoreBase values = + fValueStoreCache.getValueStoreFor(id, selMatcher.getInitialDepth()); + // nothing to do if nothing matched, or if not all + // fields are present. + if (values != null && values.fValuesCount == values.fFieldCount) + values.endDocumentFragment(); + } + } + } + fValueStoreCache.endElement(); + } + + // Check if we should modify the xsi:type ignore depth + // This check is independent of whether this is the validation root, + // and should be done before the element depth is decremented. + if (fElementDepth < fIgnoreXSITypeDepth) { + fIgnoreXSITypeDepth--; + } + + SchemaGrammar[] grammars = null; + // have we reached the end tag of the validation root? + if (fElementDepth == 0) { + // 7 If the element information item is the validation root, it must be valid per Validation Root Valid (ID/IDREF) (3.3.4). + Iterator invIdRefs = fValidationState.checkIDRefID(); + fValidationState.resetIDTables(); + if (invIdRefs != null) { + while (invIdRefs.hasNext()) { + reportSchemaError("cvc-id.1", new Object[] { invIdRefs.next() }); + } + } + // check extra schema constraints + if (fFullChecking && !fUseGrammarPoolOnly) { + XSConstraints.fullSchemaChecking( + fGrammarBucket, + fSubGroupHandler, + fCMBuilder, + fXSIErrorReporter.fErrorReporter); + } + + grammars = fGrammarBucket.getGrammars(); + // return the final set of grammars validator ended up with + if (fGrammarPool != null) { + // Set grammars as immutable + for (int k=0; k < grammars.length; k++) { + grammars[k].setImmutable(true); + } + fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_SCHEMA, grammars); + } + augs = endElementPSVI(true, grammars, augs); + } else { + augs = endElementPSVI(false, grammars, augs); + + // decrease element depth and restore states + fElementDepth--; + + // get the states for the parent element. + fSubElement = fSubElementStack[fElementDepth]; + fCurrentElemDecl = fElemDeclStack[fElementDepth]; + fNil = fNilStack[fElementDepth]; + fNotation = fNotationStack[fElementDepth]; + fCurrentType = fTypeStack[fElementDepth]; + fCurrentCM = fCMStack[fElementDepth]; + fStrictAssess = fStrictAssessStack[fElementDepth]; + fCurrCMState = fCMStateStack[fElementDepth]; + fSawText = fSawTextStack[fElementDepth]; + fSawCharacters = fStringContent[fElementDepth]; + + // We should have a stack for whitespace value, and pop it up here. + // But when fWhiteSpace != -1, and we see a sub-element, it must be + // an error (at least for Schema 1.0). So for valid documents, the + // only value we are going to push/pop in the stack is -1. + // Here we just mimic the effect of popping -1. -SG + fWhiteSpace = -1; + // Same for append buffer. Simple types and elements with fixed + // value constraint don't allow sub-elements. -SG + fAppendBuffer = false; + // same here. + fUnionType = false; + } + + return augs; + } // handleEndElement(QName,boolean)*/ + + final Augmentations endElementPSVI( + boolean root, + SchemaGrammar[] grammars, + Augmentations augs) { + + if (fAugPSVI) { + augs = getEmptyAugs(augs); + + // the 5 properties sent on startElement calls + fCurrentPSVI.fDeclaration = this.fCurrentElemDecl; + fCurrentPSVI.fTypeDecl = this.fCurrentType; + fCurrentPSVI.fNotation = this.fNotation; + fCurrentPSVI.fValidationContext = this.fValidationRoot; + fCurrentPSVI.fNil = this.fNil; + // PSVI: validation attempted + // nothing below or at the same level has none or partial + // (which means this level is strictly assessed, and all chidren + // are full), so this one has full + if (fElementDepth > fNFullValidationDepth) { + fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_FULL; + } + // nothing below or at the same level has full or partial + // (which means this level is not strictly assessed, and all chidren + // are none), so this one has none + else if (fElementDepth > fNNoneValidationDepth) { + fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_NONE; + } + // otherwise partial, and anything above this level will be partial + else { + fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_PARTIAL; + } + + // this guarantees that depth settings do not cross-over between sibling nodes + if (fNFullValidationDepth == fElementDepth) { + fNFullValidationDepth = fElementDepth - 1; + } + if (fNNoneValidationDepth == fElementDepth) { + fNNoneValidationDepth = fElementDepth - 1; + } + + if (fDefaultValue != null) + fCurrentPSVI.fSpecified = true; + fCurrentPSVI.fValue.copyFrom(fValidatedInfo); + + if (fStrictAssess) { + // get all errors for the current element, its attribute, + // and subelements (if they were strictly assessed). + // any error would make this element invalid. + // and we merge these errors to the parent element. + String[] errors = fXSIErrorReporter.mergeContext(); + + // PSVI: error codes + fCurrentPSVI.fErrors = errors; + // PSVI: validity + fCurrentPSVI.fValidity = + (errors == null) ? ElementPSVI.VALIDITY_VALID : ElementPSVI.VALIDITY_INVALID; + } else { + // PSVI: validity + fCurrentPSVI.fValidity = ElementPSVI.VALIDITY_NOTKNOWN; + // Discard the current context: ignore any error happened within + // the sub-elements/attributes of this element, because those + // errors won't affect the validity of the parent elements. + fXSIErrorReporter.popContext(); + } + + if (root) { + // store [schema information] in the PSVI + fCurrentPSVI.fGrammars = grammars; + fCurrentPSVI.fSchemaInformation = null; + } + } + + return augs; + + } + + Augmentations getEmptyAugs(Augmentations augs) { + if (augs == null) { + augs = fAugmentations; + augs.removeAllItems(); + } + augs.putItem(Constants.ELEMENT_PSVI, fCurrentPSVI); + fCurrentPSVI.reset(); + + return augs; + } + + void storeLocations(String sLocation, String nsLocation) { + if (sLocation != null) { + if (!XMLSchemaLoader.tokenizeSchemaLocationStr(sLocation, fLocationPairs, fLocator == null ? null : fLocator.getExpandedSystemId())) { + // error! + fXSIErrorReporter.reportError( + XSMessageFormatter.SCHEMA_DOMAIN, + "SchemaLocation", + new Object[] { sLocation }, + XMLErrorReporter.SEVERITY_WARNING); + } + } + if (nsLocation != null) { + XMLSchemaLoader.LocationArray la = + ((XMLSchemaLoader.LocationArray) fLocationPairs.get(XMLSymbols.EMPTY_STRING)); + if (la == null) { + la = new XMLSchemaLoader.LocationArray(); + fLocationPairs.put(XMLSymbols.EMPTY_STRING, la); + } + if (fLocator != null) { + try { + nsLocation = XMLEntityManager.expandSystemId(nsLocation, fLocator.getExpandedSystemId(), false); + } catch (MalformedURIException e) { + } + } + la.addLocation(nsLocation); + } + + } //storeLocations + + //this is the function where logic of retrieving grammar is written , parser first tries to get the grammar from + //the local pool, if not in local pool, it gives chance to application to be able to retrieve the grammar, then it + //tries to parse the grammar using location hints from the give namespace. + SchemaGrammar findSchemaGrammar( + short contextType, + String namespace, + QName enclosingElement, + QName triggeringComponent, + XMLAttributes attributes) { + SchemaGrammar grammar = null; + //get the grammar from local pool... + grammar = fGrammarBucket.getGrammar(namespace); + + if (grammar == null) { + fXSDDescription.setNamespace(namespace); + if (fGrammarPool != null) { + grammar = (SchemaGrammar) fGrammarPool.retrieveGrammar(fXSDDescription); + if (grammar != null) { + // put this grammar into the bucket, along with grammars + // imported by it (directly or indirectly) + if (!fGrammarBucket.putGrammar(grammar, true, fNamespaceGrowth)) { + // REVISIT: a conflict between new grammar(s) and grammars + // in the bucket. What to do? A warning? An exception? + fXSIErrorReporter.fErrorReporter.reportError( + XSMessageFormatter.SCHEMA_DOMAIN, + "GrammarConflict", + null, + XMLErrorReporter.SEVERITY_WARNING); + grammar = null; + } + } + } + } + + if (!fUseGrammarPoolOnly && (grammar == null || + (fNamespaceGrowth && !hasSchemaComponent(grammar, contextType, triggeringComponent)))) { + fXSDDescription.reset(); + fXSDDescription.fContextType = contextType; + fXSDDescription.setNamespace(namespace); + fXSDDescription.fEnclosedElementName = enclosingElement; + fXSDDescription.fTriggeringComponent = triggeringComponent; + fXSDDescription.fAttributes = attributes; + if (fLocator != null) { + fXSDDescription.setBaseSystemId(fLocator.getExpandedSystemId()); + } + + Hashtable locationPairs = fLocationPairs; + Object locationArray = + locationPairs.get(namespace == null ? XMLSymbols.EMPTY_STRING : namespace); + if (locationArray != null) { + String[] temp = ((XMLSchemaLoader.LocationArray) locationArray).getLocationArray(); + if (temp.length != 0) { + setLocationHints(fXSDDescription, temp, grammar); + } + } + + if (grammar == null || fXSDDescription.fLocationHints != null) { + boolean toParseSchema = true; + if (grammar != null) { + // use location hints instead + locationPairs = EMPTY_TABLE; + } + + // try to parse the grammar using location hints from that namespace.. + try { + XMLInputSource xis = + XMLSchemaLoader.resolveDocument( + fXSDDescription, + locationPairs, + fEntityResolver); + if (grammar != null && fNamespaceGrowth) { + try { + // if we are dealing with a different schema location, then include the new schema + // into the existing grammar + if (grammar.getDocumentLocations().contains(XMLEntityManager.expandSystemId(xis.getSystemId(), xis.getBaseSystemId(), false))) { + toParseSchema = false; + } + } + catch (MalformedURIException e) { + } + } + if (toParseSchema) { + grammar = fSchemaLoader.loadSchema(fXSDDescription, xis, fLocationPairs); + } + } + catch (IOException ex) { + final String [] locationHints = fXSDDescription.getLocationHints(); + fXSIErrorReporter.fErrorReporter.reportError( + XSMessageFormatter.SCHEMA_DOMAIN, + "schema_reference.4", + new Object[] { locationHints != null ? locationHints[0] : XMLSymbols.EMPTY_STRING }, + XMLErrorReporter.SEVERITY_WARNING, ex); + } + } + } + + return grammar; + + } //findSchemaGrammar + + private boolean hasSchemaComponent(SchemaGrammar grammar, short contextType, QName triggeringComponent) { + if (grammar != null && triggeringComponent != null) { + String localName = triggeringComponent.localpart; + if (localName != null && localName.length() > 0) { + switch (contextType) { + case XSDDescription.CONTEXT_ELEMENT: + return grammar.getElementDeclaration(localName) != null; + case XSDDescription.CONTEXT_ATTRIBUTE: + return grammar.getAttributeDeclaration(localName) != null; + case XSDDescription.CONTEXT_XSITYPE: + return grammar.getTypeDefinition(localName) != null; + } + } + } + return false; + } + + private void setLocationHints(XSDDescription desc, String[] locations, SchemaGrammar grammar) { + int length = locations.length; + if (grammar == null) { + fXSDDescription.fLocationHints = new String[length]; + System.arraycopy(locations, 0, fXSDDescription.fLocationHints, 0, length); + } + else { + setLocationHints(desc, locations, grammar.getDocumentLocations()); + } + } + + private void setLocationHints(XSDDescription desc, String[] locations, StringList docLocations) { + int length = locations.length; + String[] hints = new String[length]; + int counter = 0; + + for (int i=0; i 0) { + if (counter == length) { + fXSDDescription.fLocationHints = hints; + } + else { + fXSDDescription.fLocationHints = new String[counter]; + System.arraycopy(hints, 0, fXSDDescription.fLocationHints, 0, counter); + } + } + } + + XSTypeDefinition getAndCheckXsiType(QName element, String xsiType, XMLAttributes attributes) { + // This method also deals with clause 1.2.1.2 of the constraint + // Validation Rule: Schema-Validity Assessment (Element) + + // Element Locally Valid (Element) + // 4 If there is an attribute information item among the element information item's [attributes] whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is type, then all of the following must be true: + // 4.1 The normalized value of that attribute information item must be valid with respect to the built-in QName simple type, as defined by String Valid (3.14.4); + QName typeName = null; + try { + typeName = (QName) fQNameDV.validate(xsiType, fValidationState, null); + } catch (InvalidDatatypeValueException e) { + reportSchemaError(e.getKey(), e.getArgs()); + reportSchemaError( + "cvc-elt.4.1", + new Object[] { + element.rawname, + SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_TYPE, + xsiType }); + return null; + } + + // 4.2 The local name and namespace name (as defined in QName Interpretation (3.15.3)), of the actual value of that attribute information item must resolve to a type definition, as defined in QName resolution (Instance) (3.15.4) + XSTypeDefinition type = null; + // if the namespace is schema namespace, first try built-in types + if (typeName.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) { + type = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(typeName.localpart); + } + // if it's not schema built-in types, then try to get a grammar + if (type == null) { + //try to find schema grammar by different means.... + SchemaGrammar grammar = + findSchemaGrammar( + XSDDescription.CONTEXT_XSITYPE, + typeName.uri, + element, + typeName, + attributes); + + if (grammar != null) + type = grammar.getGlobalTypeDecl(typeName.localpart); + } + // still couldn't find the type, report an error + if (type == null) { + reportSchemaError("cvc-elt.4.2", new Object[] { element.rawname, xsiType }); + return null; + } + + // if there is no current type, set this one as current. + // and we don't need to do extra checking + if (fCurrentType != null) { + short block = XSConstants.DERIVATION_NONE; + // 4.3 The local type definition must be validly derived from the {type definition} given the union of the {disallowed substitutions} and the {type definition}'s {prohibited substitutions}, as defined in Type Derivation OK (Complex) (3.4.6) (if it is a complex type definition), or given {disallowed substitutions} as defined in Type Derivation OK (Simple) (3.14.6) (if it is a simple type definition). + // Note: It's possible to have fCurrentType be non-null and fCurrentElemDecl + // be null, if the current type is set using the property "root-type-definition". + // In that case, we don't disallow any substitutions. -PM + if (fCurrentElemDecl != null) { + block = fCurrentElemDecl.fBlock; + } + if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + block |= ((XSComplexTypeDecl) fCurrentType).fBlock; + } + if (!XSConstraints.checkTypeDerivationOk(type, fCurrentType, block)) { + reportSchemaError( + "cvc-elt.4.3", + new Object[] { element.rawname, xsiType, XS10TypeHelper.getSchemaTypeName(fCurrentType)}); + } + } + + return type; + } //getAndCheckXsiType + + boolean getXsiNil(QName element, String xsiNil) { + // Element Locally Valid (Element) + // 3 The appropriate case among the following must be true: + // 3.1 If {nillable} is false, then there must be no attribute information item among the element information item's [attributes] whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is nil. + if (fCurrentElemDecl != null && !fCurrentElemDecl.getNillable()) { + reportSchemaError( + "cvc-elt.3.1", + new Object[] { + element.rawname, + SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL }); + } + // 3.2 If {nillable} is true and there is such an attribute information item and its actual value is true , then all of the following must be true: + // 3.2.2 There must be no fixed {value constraint}. + else { + String value = XMLChar.trim(xsiNil); + if (value.equals(SchemaSymbols.ATTVAL_TRUE) + || value.equals(SchemaSymbols.ATTVAL_TRUE_1)) { + if (fCurrentElemDecl != null + && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED) { + reportSchemaError( + "cvc-elt.3.2.2", + new Object[] { + element.rawname, + SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL }); + } + return true; + } + } + return false; + } + + void processAttributes(QName element, XMLAttributes attributes, XSAttributeGroupDecl attrGrp) { + + if (DEBUG) { + System.out.println("==>processAttributes: " + attributes.getLength()); + } + + // whether we have seen a Wildcard ID. + String wildcardIDName = null; + + // for each present attribute + int attCount = attributes.getLength(); + + Augmentations augs = null; + AttributePSVImpl attrPSVI = null; + + boolean isSimple = + fCurrentType == null || fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE; + + XSObjectList attrUses = null; + int useCount = 0; + XSWildcardDecl attrWildcard = null; + if (!isSimple) { + attrUses = attrGrp.getAttributeUses(); + useCount = attrUses.getLength(); + attrWildcard = attrGrp.fAttributeWC; + } + + // Element Locally Valid (Complex Type) + // 3 For each attribute information item in the element information item's [attributes] excepting those whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is one of type, nil, schemaLocation or noNamespaceSchemaLocation, the appropriate case among the following must be true: + // get the corresponding attribute decl + for (int index = 0; index < attCount; index++) { + + attributes.getName(index, fTempQName); + + if (DEBUG) { + System.out.println("==>process attribute: " + fTempQName); + } + + if (fAugPSVI || fIdConstraint) { + augs = attributes.getAugmentations(index); + attrPSVI = (AttributePSVImpl) augs.getItem(Constants.ATTRIBUTE_PSVI); + if (attrPSVI != null) { + attrPSVI.reset(); + } else { + attrPSVI = new AttributePSVImpl(); + augs.putItem(Constants.ATTRIBUTE_PSVI, attrPSVI); + } + // PSVI attribute: validation context + attrPSVI.fValidationContext = fValidationRoot; + } + + // Element Locally Valid (Type) + // 3.1.1 The element information item's [attributes] must be empty, excepting those + // whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and + // whose [local name] is one of type, nil, schemaLocation or noNamespaceSchemaLocation. + + // for the 4 xsi attributes, get appropriate decl, and validate + if (fTempQName.uri == SchemaSymbols.URI_XSI) { + XSAttributeDecl attrDecl = null; + if (fTempQName.localpart == SchemaSymbols.XSI_TYPE) { + attrDecl = XSI_TYPE; + } + else if (fTempQName.localpart == SchemaSymbols.XSI_NIL) { + attrDecl = XSI_NIL; + } + else if (fTempQName.localpart == SchemaSymbols.XSI_SCHEMALOCATION) { + attrDecl = XSI_SCHEMALOCATION; + } + else if (fTempQName.localpart == SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION) { + attrDecl = XSI_NONAMESPACESCHEMALOCATION; + } + if (attrDecl != null) { + processOneAttribute(element, attributes, index, attrDecl, null, attrPSVI); + continue; + } + } + + // for namespace attributes, no_validation/unknow_validity + if (fTempQName.rawname == XMLSymbols.PREFIX_XMLNS + || fTempQName.rawname.startsWith("xmlns:")) { + continue; + } + + // simple type doesn't allow any other attributes + if (isSimple) { + reportSchemaError( + "cvc-type.3.1.1", + new Object[] { element.rawname, fTempQName.rawname }); + continue; + } + + // it's not xmlns, and not xsi, then we need to find a decl for it + XSAttributeUseImpl currUse = null, oneUse; + for (int i = 0; i < useCount; i++) { + oneUse = (XSAttributeUseImpl) attrUses.item(i); + if (oneUse.fAttrDecl.fName == fTempQName.localpart + && oneUse.fAttrDecl.fTargetNamespace == fTempQName.uri) { + currUse = oneUse; + break; + } + } + + // 3.2 otherwise all of the following must be true: + // 3.2.1 There must be an {attribute wildcard}. + // 3.2.2 The attribute information item must be valid with respect to it as defined in Item Valid (Wildcard) (3.10.4). + + // if failed, get it from wildcard + if (currUse == null) { + //if (attrWildcard == null) + // reportSchemaError("cvc-complex-type.3.2.1", new Object[]{element.rawname, fTempQName.rawname}); + if (attrWildcard == null || !attrWildcard.allowNamespace(fTempQName.uri)) { + // so this attribute is not allowed + reportSchemaError( + "cvc-complex-type.3.2.2", + new Object[] { element.rawname, fTempQName.rawname }); + + // We have seen an attribute that was not declared + fNFullValidationDepth = fElementDepth; + + continue; + } + } + + XSAttributeDecl currDecl = null; + if (currUse != null) { + currDecl = currUse.fAttrDecl; + } else { + // which means it matches a wildcard + // skip it if processContents is skip + if (attrWildcard.fProcessContents == XSWildcardDecl.PC_SKIP) + continue; + + //try to find grammar by different means... + SchemaGrammar grammar = + findSchemaGrammar( + XSDDescription.CONTEXT_ATTRIBUTE, + fTempQName.uri, + element, + fTempQName, + attributes); + + if (grammar != null) { + currDecl = grammar.getGlobalAttributeDecl(fTempQName.localpart); + } + + // if can't find + if (currDecl == null) { + // if strict, report error + if (attrWildcard.fProcessContents == XSWildcardDecl.PC_STRICT) { + reportSchemaError( + "cvc-complex-type.3.2.2", + new Object[] { element.rawname, fTempQName.rawname }); + } + + // then continue to the next attribute + continue; + } else { + // 5 Let [Definition:] the wild IDs be the set of all attribute information item to which clause 3.2 applied and whose validation resulted in a context-determined declaration of mustFind or no context-determined declaration at all, and whose [local name] and [namespace name] resolve (as defined by QName resolution (Instance) (3.15.4)) to an attribute declaration whose {type definition} is or is derived from ID. Then all of the following must be true: + // 5.1 There must be no more than one item in wild IDs. + if (currDecl.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE + && ((XSSimpleType) currDecl.fType).isIDType()) { + if (wildcardIDName != null) { + reportSchemaError( + "cvc-complex-type.5.1", + new Object[] { element.rawname, currDecl.fName, wildcardIDName }); + } else + wildcardIDName = currDecl.fName; + } + } + } + + processOneAttribute(element, attributes, index, currDecl, currUse, attrPSVI); + } // end of for (all attributes) + + // 5.2 If wild IDs is non-empty, there must not be any attribute uses among the {attribute uses} whose {attribute declaration}'s {type definition} is or is derived from ID. + if (!isSimple && attrGrp.fIDAttrName != null && wildcardIDName != null) { + reportSchemaError( + "cvc-complex-type.5.2", + new Object[] { element.rawname, wildcardIDName, attrGrp.fIDAttrName }); + } + + } //processAttributes + + void processOneAttribute( + QName element, + XMLAttributes attributes, + int index, + XSAttributeDecl currDecl, + XSAttributeUseImpl currUse, + AttributePSVImpl attrPSVI) { + + String attrValue = attributes.getValue(index); + fXSIErrorReporter.pushContext(); + + // Attribute Locally Valid + // For an attribute information item to be locally valid with respect to an attribute declaration all of the following must be true: + // 1 The declaration must not be absent (see Missing Sub-components (5.3) for how this can fail to be the case). + // 2 Its {type definition} must not be absent. + // 3 The item's normalized value must be locally valid with respect to that {type definition} as per String Valid (3.14.4). + // get simple type + XSSimpleType attDV = currDecl.fType; + + Object actualValue = null; + try { + actualValue = attDV.validate(attrValue, fValidationState, fValidatedInfo); + // store the normalized value + if (fNormalizeData) { + attributes.setValue(index, fValidatedInfo.normalizedValue); + } + // PSVI: element notation + if (attDV.getVariety() == XSSimpleType.VARIETY_ATOMIC + && attDV.getPrimitiveKind() == XSSimpleType.PRIMITIVE_NOTATION) { + QName qName = (QName) actualValue; + SchemaGrammar grammar = fGrammarBucket.getGrammar(qName.uri); + + //REVISIT: is it possible for the notation to be in different namespace than the attribute + //with which it is associated, CHECK !! + // should we give chance to the application to be able to retrieve a grammar - nb + //REVISIT: what would be the triggering component here.. if it is attribute value that + // triggered the loading of grammar ?? -nb + + if (grammar != null) { + fNotation = grammar.getGlobalNotationDecl(qName.localpart); + } + } + } + catch (InvalidDatatypeValueException idve) { + reportSchemaError(idve.getKey(), idve.getArgs()); + reportSchemaError( + "cvc-attribute.3", + new Object[] { element.rawname, fTempQName.rawname, attrValue, + (attDV instanceof XSSimpleTypeDecl) ? + ((XSSimpleTypeDecl) attDV).getTypeName() : attDV.getName()}); + } + + // get the value constraint from use or decl + // 4 The item's actual value must match the value of the {value constraint}, if it is present and fixed. // now check the value against the simpleType + if (actualValue != null && currDecl.getConstraintType() == XSConstants.VC_FIXED) { + if (!ValidatedInfo.isComparable(fValidatedInfo, currDecl.fDefault) || !actualValue.equals(currDecl.fDefault.actualValue)) { + reportSchemaError( + "cvc-attribute.4", + new Object[] { + element.rawname, + fTempQName.rawname, + attrValue, + currDecl.fDefault.stringValue()}); + } + } + + // 3.1 If there is among the {attribute uses} an attribute use with an {attribute declaration} whose {name} matches the attribute information item's [local name] and whose {target namespace} is identical to the attribute information item's [namespace name] (where an absent {target namespace} is taken to be identical to a [namespace name] with no value), then the attribute information must be valid with respect to that attribute use as per Attribute Locally Valid (Use) (3.5.4). In this case the {attribute declaration} of that attribute use is the context-determined declaration for the attribute information item with respect to Schema-Validity Assessment (Attribute) (3.2.4) and Assessment Outcome (Attribute) (3.2.5). + if (actualValue != null + && currUse != null + && currUse.fConstraintType == XSConstants.VC_FIXED) { + if (!ValidatedInfo.isComparable(fValidatedInfo, currUse.fDefault) || !actualValue.equals(currUse.fDefault.actualValue)) { + reportSchemaError( + "cvc-complex-type.3.1", + new Object[] { + element.rawname, + fTempQName.rawname, + attrValue, + currUse.fDefault.stringValue()}); + } + } + if (fIdConstraint) { + attrPSVI.fValue.copyFrom(fValidatedInfo); + } + + if (fAugPSVI) { + // PSVI: attribute declaration + attrPSVI.fDeclaration = currDecl; + // PSVI: attribute type + attrPSVI.fTypeDecl = attDV; + + // PSVI: attribute normalized value + // NOTE: we always store the normalized value, even if it's invlid, + // because it might still be useful to the user. But when the it's + // not valid, the normalized value is not trustable. + attrPSVI.fValue.copyFrom(fValidatedInfo); + + // PSVI: validation attempted: + attrPSVI.fValidationAttempted = AttributePSVI.VALIDATION_FULL; + + // We have seen an attribute that was declared. + fNNoneValidationDepth = fElementDepth; + + String[] errors = fXSIErrorReporter.mergeContext(); + // PSVI: error codes + attrPSVI.fErrors = errors; + // PSVI: validity + attrPSVI.fValidity = + (errors == null) ? AttributePSVI.VALIDITY_VALID : AttributePSVI.VALIDITY_INVALID; + } + } + + void addDefaultAttributes( + QName element, + XMLAttributes attributes, + XSAttributeGroupDecl attrGrp) { + // Check after all specified attrs are scanned + // (1) report error for REQUIRED attrs that are missing (V_TAGc) + // REVISIT: should we check prohibited attributes? + // (2) report error for PROHIBITED attrs that are present (V_TAGc) + // (3) add default attrs (FIXED and NOT_FIXED) + // + if (DEBUG) { + System.out.println("==>addDefaultAttributes: " + element); + } + XSObjectList attrUses = attrGrp.getAttributeUses(); + int useCount = attrUses.getLength(); + XSAttributeUseImpl currUse; + XSAttributeDecl currDecl; + short constType; + ValidatedInfo defaultValue; + boolean isSpecified; + QName attName; + // for each attribute use + for (int i = 0; i < useCount; i++) { + + currUse = (XSAttributeUseImpl) attrUses.item(i); + currDecl = currUse.fAttrDecl; + // get value constraint + constType = currUse.fConstraintType; + defaultValue = currUse.fDefault; + if (constType == XSConstants.VC_NONE) { + constType = currDecl.getConstraintType(); + defaultValue = currDecl.fDefault; + } + // whether this attribute is specified + isSpecified = attributes.getValue(currDecl.fTargetNamespace, currDecl.fName) != null; + + // Element Locally Valid (Complex Type) + // 4 The {attribute declaration} of each attribute use in the {attribute uses} whose + // {required} is true matches one of the attribute information items in the element + // information item's [attributes] as per clause 3.1 above. + if (currUse.fUse == SchemaSymbols.USE_REQUIRED) { + if (!isSpecified) + reportSchemaError( + "cvc-complex-type.4", + new Object[] { element.rawname, currDecl.fName }); + } + // if the attribute is not specified, then apply the value constraint + if (!isSpecified && constType != XSConstants.VC_NONE) { + attName = + new QName(null, currDecl.fName, currDecl.fName, currDecl.fTargetNamespace); + String normalized = (defaultValue != null) ? defaultValue.stringValue() : ""; + int attrIndex; + if (attributes instanceof XMLAttributesImpl) { + XMLAttributesImpl attrs = (XMLAttributesImpl) attributes; + attrIndex = attrs.getLength(); + attrs.addAttributeNS(attName, "CDATA", normalized); + } + else { + attrIndex = attributes.addAttribute(attName, "CDATA", normalized); + } + + if (fAugPSVI) { + + // PSVI: attribute is "schema" specified + Augmentations augs = attributes.getAugmentations(attrIndex); + AttributePSVImpl attrPSVI = new AttributePSVImpl(); + augs.putItem(Constants.ATTRIBUTE_PSVI, attrPSVI); + + attrPSVI.fDeclaration = currDecl; + attrPSVI.fTypeDecl = currDecl.fType; + attrPSVI.fValue.copyFrom(defaultValue); + attrPSVI.fValidationContext = fValidationRoot; + attrPSVI.fValidity = AttributePSVI.VALIDITY_VALID; + attrPSVI.fValidationAttempted = AttributePSVI.VALIDATION_FULL; + attrPSVI.fSpecified = true; + } + } + + } // for + } // addDefaultAttributes + + /** + * If there is not text content, and there is a + * {value constraint} on the corresponding element decl, then return + * an XMLString representing the default value. + */ + void processElementContent(QName element) { + // 1 If the item is ?valid? with respect to an element declaration as per Element Locally Valid (Element) (?3.3.4) and the {value constraint} is present, but clause 3.2 of Element Locally Valid (Element) (?3.3.4) above is not satisfied and the item has no element or character information item [children], then schema. Furthermore, the post-schema-validation infoset has the canonical lexical representation of the {value constraint} value as the item's [schema normalized value] property. + if (fCurrentElemDecl != null + && fCurrentElemDecl.fDefault != null + && !fSawText + && !fSubElement + && !fNil) { + + String strv = fCurrentElemDecl.fDefault.stringValue(); + int bufLen = strv.length(); + if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < bufLen) { + fNormalizedStr.ch = new char[bufLen]; + } + strv.getChars(0, bufLen, fNormalizedStr.ch, 0); + fNormalizedStr.offset = 0; + fNormalizedStr.length = bufLen; + fDefaultValue = fNormalizedStr; + } + // fixed values are handled later, after xsi:type determined. + + fValidatedInfo.normalizedValue = null; + + // Element Locally Valid (Element) + // 3.2.1 The element information item must have no character or element information item [children]. + if (fNil) { + if (fSubElement || fSawText) { + reportSchemaError( + "cvc-elt.3.2.1", + new Object[] { + element.rawname, + SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL }); + } + } + + this.fValidatedInfo.reset(); + + // 5 The appropriate case among the following must be true: + // 5.1 If the declaration has a {value constraint}, the item has neither element nor character [children] and clause 3.2 has not applied, then all of the following must be true: + if (fCurrentElemDecl != null + && fCurrentElemDecl.getConstraintType() != XSConstants.VC_NONE + && !fSubElement + && !fSawText + && !fNil) { + // 5.1.1 If the actual type definition is a local type definition then the canonical lexical representation of the {value constraint} value must be a valid default for the actual type definition as defined in Element Default Valid (Immediate) (3.3.6). + if (fCurrentType != fCurrentElemDecl.fType) { + //REVISIT:we should pass ValidatedInfo here. + if (XSConstraints + .ElementDefaultValidImmediate( + fCurrentType, + fCurrentElemDecl.fDefault.stringValue(), + fState4XsiType, + null) + == null) + reportSchemaError( + "cvc-elt.5.1.1", + new Object[] { + element.rawname, + fCurrentType.getName(), + fCurrentElemDecl.fDefault.stringValue()}); + } + // 5.1.2 The element information item with the canonical lexical representation of the {value constraint} value used as its normalized value must be valid with respect to the actual type definition as defined by Element Locally Valid (Type) (3.3.4). + // REVISIT: don't use toString, but validateActualValue instead + // use the fState4ApplyDefault + elementLocallyValidType(element, fCurrentElemDecl.fDefault.stringValue()); + } else { + // The following method call also deal with clause 1.2.2 of the constraint + // Validation Rule: Schema-Validity Assessment (Element) + + // 5.2 If the declaration has no {value constraint} or the item has either element or character [children] or clause 3.2 has applied, then all of the following must be true: + // 5.2.1 The element information item must be valid with respect to the actual type definition as defined by Element Locally Valid (Type) (3.3.4). + Object actualValue = elementLocallyValidType(element, fBuffer); + // 5.2.2 If there is a fixed {value constraint} and clause 3.2 has not applied, all of the following must be true: + if (fCurrentElemDecl != null + && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED + && !fNil) { + String content = fBuffer.toString(); + // 5.2.2.1 The element information item must have no element information item [children]. + if (fSubElement) + reportSchemaError("cvc-elt.5.2.2.1", new Object[] { element.rawname }); + // 5.2.2.2 The appropriate case among the following must be true: + if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; + // 5.2.2.2.1 If the {content type} of the actual type definition is mixed, then the initial value of the item must match the canonical lexical representation of the {value constraint} value. + if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) { + // REVISIT: how to get the initial value, does whiteSpace count? + if (!fCurrentElemDecl.fDefault.normalizedValue.equals(content)) + reportSchemaError( + "cvc-elt.5.2.2.2.1", + new Object[] { + element.rawname, + content, + fCurrentElemDecl.fDefault.normalizedValue }); + } + // 5.2.2.2.2 If the {content type} of the actual type definition is a simple type definition, then the actual value of the item must match the canonical lexical representation of the {value constraint} value. + else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { + if (actualValue != null && (!ValidatedInfo.isComparable(fValidatedInfo, fCurrentElemDecl.fDefault) + || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) { + reportSchemaError( + "cvc-elt.5.2.2.2.2", + new Object[] { + element.rawname, + content, + fCurrentElemDecl.fDefault.stringValue()}); + } + } + } else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { + if (actualValue != null && (!ValidatedInfo.isComparable(fValidatedInfo, fCurrentElemDecl.fDefault) + || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) { + // REVISIT: the spec didn't mention this case: fixed + // value with simple type + reportSchemaError( + "cvc-elt.5.2.2.2.2", + new Object[] { + element.rawname, + content, + fCurrentElemDecl.fDefault.stringValue()}); + } + } + } + } + + if (fDefaultValue == null && fNormalizeData && fDocumentHandler != null && fUnionType) { + // for union types we need to send data because we delayed sending + // this data when we received it in the characters() call. + String content = fValidatedInfo.normalizedValue; + if (content == null) + content = fBuffer.toString(); + + int bufLen = content.length(); + if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < bufLen) { + fNormalizedStr.ch = new char[bufLen]; + } + content.getChars(0, bufLen, fNormalizedStr.ch, 0); + fNormalizedStr.offset = 0; + fNormalizedStr.length = bufLen; + fDocumentHandler.characters(fNormalizedStr, null); + } + } // processElementContent + + Object elementLocallyValidType(QName element, Object textContent) { + if (fCurrentType == null) + return null; + + Object retValue = null; + // Element Locally Valid (Type) + // 3 The appropriate case among the following must be true: + // 3.1 If the type definition is a simple type definition, then all of the following must be true: + if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { + // 3.1.2 The element information item must have no element information item [children]. + if (fSubElement) + reportSchemaError("cvc-type.3.1.2", new Object[] { element.rawname }); + // 3.1.3 If clause 3.2 of Element Locally Valid (Element) (3.3.4) did not apply, then the normalized value must be valid with respect to the type definition as defined by String Valid (3.14.4). + if (!fNil) { + XSSimpleType dv = (XSSimpleType) fCurrentType; + try { + if (!fNormalizeData || fUnionType) { + fValidationState.setNormalizationRequired(true); + } + retValue = dv.validate(textContent, fValidationState, fValidatedInfo); + } catch (InvalidDatatypeValueException e) { + reportSchemaError(e.getKey(), e.getArgs()); + reportSchemaError( + "cvc-type.3.1.3", + new Object[] { element.rawname, textContent }); + } + } + } else { + // 3.2 If the type definition is a complex type definition, then the element information item must be valid with respect to the type definition as per Element Locally Valid (Complex Type) (3.4.4); + retValue = elementLocallyValidComplexType(element, textContent); + } + + return retValue; + } // elementLocallyValidType + + Object elementLocallyValidComplexType(QName element, Object textContent) { + Object actualValue = null; + XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType; + + // Element Locally Valid (Complex Type) + // For an element information item to be locally valid with respect to a complex type definition all of the following must be true: + // 1 {abstract} is false. + // 2 If clause 3.2 of Element Locally Valid (Element) (3.3.4) did not apply, then the appropriate case among the following must be true: + if (!fNil) { + // 2.1 If the {content type} is empty, then the element information item has no character or element information item [children]. + if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_EMPTY + && (fSubElement || fSawText)) { + reportSchemaError("cvc-complex-type.2.1", new Object[] { element.rawname }); + } + // 2.2 If the {content type} is a simple type definition, then the element information item has no element information item [children], and the normalized value of the element information item is valid with respect to that simple type definition as defined by String Valid (3.14.4). + else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { + if (fSubElement) + reportSchemaError("cvc-complex-type.2.2", new Object[] { element.rawname }); + XSSimpleType dv = ctype.fXSSimpleType; + try { + if (!fNormalizeData || fUnionType) { + fValidationState.setNormalizationRequired(true); + } + actualValue = dv.validate(textContent, fValidationState, fValidatedInfo); + } catch (InvalidDatatypeValueException e) { + reportSchemaError(e.getKey(), e.getArgs()); + reportSchemaError("cvc-complex-type.2.2", new Object[] { element.rawname }); + } + // REVISIT: eventually, this method should return the same actualValue as elementLocallyValidType... + // obviously it'll return null when the content is complex. + } + // 2.3 If the {content type} is element-only, then the element information item has no character information item [children] other than those whose [character code] is defined as a white space in [XML 1.0 (Second Edition)]. + else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) { + if (fSawCharacters) { + reportSchemaError("cvc-complex-type.2.3", new Object[] { element.rawname }); + } + } + // 2.4 If the {content type} is element-only or mixed, then the sequence of the element information item's element information item [children], if any, taken in order, is valid with respect to the {content type}'s particle, as defined in Element Sequence Locally Valid (Particle) (3.9.4). + if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT + || ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) { + // if the current state is a valid state, check whether + // it's one of the final states. + if (DEBUG) { + System.out.println(fCurrCMState); + } + if (fCurrCMState[0] >= 0 && !fCurrentCM.endContentModel(fCurrCMState)) { + String expected = expectedStr(fCurrentCM.whatCanGoHere(fCurrCMState)); + final int[] occurenceInfo = fCurrentCM.occurenceInfo(fCurrCMState); + if (occurenceInfo != null) { + final int minOccurs = occurenceInfo[0]; + final int count = occurenceInfo[2]; + // Check if this is a violation of minOccurs + if (count < minOccurs) { + final int required = minOccurs - count; + if (required > 1) { + reportSchemaError("cvc-complex-type.2.4.j", new Object[] { element.rawname, + fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(minOccurs), Integer.toString(required) }); + } + else { + reportSchemaError("cvc-complex-type.2.4.i", new Object[] { element.rawname, + fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(minOccurs) }); + } + } + else { + reportSchemaError("cvc-complex-type.2.4.b", new Object[] { element.rawname, expected }); + } + } + else { + reportSchemaError("cvc-complex-type.2.4.b", new Object[] { element.rawname, expected }); + } + } + } + } + return actualValue; + } // elementLocallyValidComplexType + + void processRootTypeQName(final javax.xml.namespace.QName rootTypeQName) { + String rootTypeNamespace = rootTypeQName.getNamespaceURI(); + // Add namespace to symbol table, to make sure it's interned. + // This namespace may be later compared with other values using ==. + rootTypeNamespace = fSymbolTable.addSymbol(rootTypeNamespace); + if (rootTypeNamespace != null && rootTypeNamespace.equals(XMLConstants.NULL_NS_URI)) { + rootTypeNamespace = null; + } + if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(rootTypeNamespace)) { + fCurrentType = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(rootTypeQName.getLocalPart()); + } + else { + final SchemaGrammar grammarForRootType = findSchemaGrammar( + XSDDescription.CONTEXT_ELEMENT, rootTypeNamespace, null, null, null); + if (grammarForRootType != null) { + fCurrentType = grammarForRootType.getGlobalTypeDecl(rootTypeQName.getLocalPart()); + } + } + if (fCurrentType == null) { + String typeName = (rootTypeQName.getPrefix().equals(XMLConstants.DEFAULT_NS_PREFIX)) ? + rootTypeQName.getLocalPart() : + rootTypeQName.getPrefix()+":"+rootTypeQName.getLocalPart(); + reportSchemaError("cvc-type.1", new Object[] {typeName}); + } + } // processRootTypeQName + + void processRootElementDeclQName(final javax.xml.namespace.QName rootElementDeclQName, final QName element) { + String rootElementDeclNamespace = rootElementDeclQName.getNamespaceURI(); + // Add namespace to symbol table, to make sure it's interned. + // This namespace may be later compared with other values using ==. + rootElementDeclNamespace = fSymbolTable.addSymbol(rootElementDeclNamespace); + if (rootElementDeclNamespace != null && rootElementDeclNamespace.equals(XMLConstants.NULL_NS_URI)) { + rootElementDeclNamespace = null; + } + final SchemaGrammar grammarForRootElement = findSchemaGrammar( + XSDDescription.CONTEXT_ELEMENT, rootElementDeclNamespace, null, null, null); + if (grammarForRootElement != null) { + fCurrentElemDecl = grammarForRootElement.getGlobalElementDecl(rootElementDeclQName.getLocalPart()); + } + if (fCurrentElemDecl == null) { + String declName = (rootElementDeclQName.getPrefix().equals(XMLConstants.DEFAULT_NS_PREFIX)) ? + rootElementDeclQName.getLocalPart() : + rootElementDeclQName.getPrefix()+":"+rootElementDeclQName.getLocalPart(); + reportSchemaError("cvc-elt.1.a", new Object[] {declName}); + } + else { + checkElementMatchesRootElementDecl(fCurrentElemDecl, element); + } + } // processRootElementDeclQName + + void checkElementMatchesRootElementDecl(final XSElementDecl rootElementDecl, final QName element) { + // Report an error if the name of the element does + // not match the name of the specified element declaration. + if (element.localpart != rootElementDecl.fName || + element.uri != rootElementDecl.fTargetNamespace) { + reportSchemaError("cvc-elt.1.b", new Object[] {element.rawname, rootElementDecl.fName}); + } + } // checkElementMatchesRootElementDecl + + void reportSchemaError(String key, Object[] arguments) { + if (fDoValidation) + fXSIErrorReporter.reportError( + XSMessageFormatter.SCHEMA_DOMAIN, + key, + arguments, + XMLErrorReporter.SEVERITY_ERROR); + } + + private String expectedStr(Vector expected) { + StringBuffer ret = new StringBuffer("{"); + int size = expected.size(); + for (int i = 0; i < size; i++) { + if (i > 0) + ret.append(", "); + ret.append(expected.elementAt(i).toString()); + } + ret.append('}'); + return ret.toString(); + } + + /**********************************/ + + // xpath matcher information + + /** + * Stack of XPath matchers for identity constraints. + * + * @author Andy Clark, IBM + */ + protected static class XPathMatcherStack { + + // + // Data + // + + /** Active matchers. */ + protected XPathMatcher[] fMatchers = new XPathMatcher[4]; + + /** Count of active matchers. */ + protected int fMatchersCount; + + /** Offset stack for contexts. */ + protected IntStack fContextStack = new IntStack(); + + // + // Constructors + // + + public XPathMatcherStack() { + } // () + + // + // Public methods + // + + /** Resets the XPath matcher stack. */ + public void clear() { + for (int i = 0; i < fMatchersCount; i++) { + fMatchers[i] = null; + } + fMatchersCount = 0; + fContextStack.clear(); + } // clear() + + /** Returns the size of the stack. */ + public int size() { + return fContextStack.size(); + } // size():int + + /** Returns the count of XPath matchers. */ + public int getMatcherCount() { + return fMatchersCount; + } // getMatcherCount():int + + /** Adds a matcher. */ + public void addMatcher(XPathMatcher matcher) { + ensureMatcherCapacity(); + fMatchers[fMatchersCount++] = matcher; + } // addMatcher(XPathMatcher) + + /** Returns the XPath matcher at the specified index. */ + public XPathMatcher getMatcherAt(int index) { + return fMatchers[index]; + } // getMatcherAt(index):XPathMatcher + + /** Pushes a new context onto the stack. */ + public void pushContext() { + fContextStack.push(fMatchersCount); + } // pushContext() + + /** Pops a context off of the stack. */ + public void popContext() { + fMatchersCount = fContextStack.pop(); + } // popContext() + + // + // Private methods + // + + /** Ensures the size of the matchers array. */ + private void ensureMatcherCapacity() { + if (fMatchersCount == fMatchers.length) { + XPathMatcher[] array = new XPathMatcher[fMatchers.length * 2]; + System.arraycopy(fMatchers, 0, array, 0, fMatchers.length); + fMatchers = array; + } + } // ensureMatcherCapacity() + + } // class XPathMatcherStack + + // value store implementations + + /** + * Value store implementation base class. There are specific subclasses + * for handling unique, key, and keyref. + * + * @author Andy Clark, IBM + */ + protected abstract class ValueStoreBase implements ValueStore { + + // + // Data + // + + /** Identity constraint. */ + protected IdentityConstraint fIdentityConstraint; + protected int fFieldCount = 0; + protected Field[] fFields = null; + /** current data */ + protected Object[] fLocalValues = null; + protected short[] fLocalValueTypes = null; + protected ShortList[] fLocalItemValueTypes = null; + + /** Current data value count. */ + protected int fValuesCount; + + /** global data */ + public final Vector fValues = new Vector(); + public ShortVector fValueTypes = null; + public Vector fItemValueTypes = null; + + private boolean fUseValueTypeVector = false; + private int fValueTypesLength = 0; + private short fValueType = 0; + + private boolean fUseItemValueTypeVector = false; + private int fItemValueTypesLength = 0; + private ShortList fItemValueType = null; + + /** buffer for error messages */ + final StringBuffer fTempBuffer = new StringBuffer(); + + // + // Constructors + // + + /** Constructs a value store for the specified identity constraint. */ + protected ValueStoreBase(IdentityConstraint identityConstraint) { + fIdentityConstraint = identityConstraint; + fFieldCount = fIdentityConstraint.getFieldCount(); + fFields = new Field[fFieldCount]; + fLocalValues = new Object[fFieldCount]; + fLocalValueTypes = new short[fFieldCount]; + fLocalItemValueTypes = new ShortList[fFieldCount]; + for (int i = 0; i < fFieldCount; i++) { + fFields[i] = fIdentityConstraint.getFieldAt(i); + } + } // (IdentityConstraint) + + // + // Public methods + // + + // destroys this ValueStore; useful when, for instance, a + // locally-scoped ID constraint is involved. + public void clear() { + fValuesCount = 0; + fUseValueTypeVector = false; + fValueTypesLength = 0; + fValueType = 0; + fUseItemValueTypeVector = false; + fItemValueTypesLength = 0; + fItemValueType = null; + fValues.setSize(0); + if (fValueTypes != null) { + fValueTypes.clear(); + } + if (fItemValueTypes != null) { + fItemValueTypes.setSize(0); + } + } // end clear():void + + // appends the contents of one ValueStore to those of us. + public void append(ValueStoreBase newVal) { + for (int i = 0; i < newVal.fValues.size(); i++) { + fValues.addElement(newVal.fValues.elementAt(i)); + } + } // append(ValueStoreBase) + + /** Start scope for value store. */ + public void startValueScope() { + fValuesCount = 0; + for (int i = 0; i < fFieldCount; i++) { + fLocalValues[i] = null; + fLocalValueTypes[i] = 0; + fLocalItemValueTypes[i] = null; + } + } // startValueScope() + + /** Ends scope for value store. */ + public void endValueScope() { + + if (fValuesCount == 0) { + if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) { + String code = "AbsentKeyValue"; + String eName = fIdentityConstraint.getElementName(); + String cName = fIdentityConstraint.getIdentityConstraintName(); + reportSchemaError(code, new Object[] { eName, cName }); + } + return; + } + + // Validation Rule: Identity-constraint Satisfied + // 4.2 If the {identity-constraint category} is key, then all of the following must be true: + // 4.2.1 The target node set and the qualified node set are equal, that is, every member of the + // target node set is also a member of the qualified node set and vice versa. + // + // If the IDC is a key check whether we have all the fields. + if (fValuesCount != fFieldCount) { + if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) { + String code = "KeyNotEnoughValues"; + UniqueOrKey key = (UniqueOrKey) fIdentityConstraint; + String eName = fIdentityConstraint.getElementName(); + String cName = key.getIdentityConstraintName(); + reportSchemaError(code, new Object[] { eName, cName }); + } + return; + } + + } // endValueScope() + + // This is needed to allow keyref's to look for matched keys + // in the correct scope. Unique and Key may also need to + // override this method for purposes of their own. + // This method is called whenever the DocumentFragment + // of an ID Constraint goes out of scope. + public void endDocumentFragment() { + } // endDocumentFragment():void + + /** + * Signals the end of the document. This is where the specific + * instances of value stores can verify the integrity of the + * identity constraints. + */ + public void endDocument() { + } // endDocument() + + // + // ValueStore methods + // + + /* reports an error if an element is matched + * has nillable true and is matched by a key. + */ + + public void reportError(String key, Object[] args) { + reportSchemaError(key, args); + } // reportError(String,Object[]) + + /** + * Adds the specified value to the value store. + * + * @param field The field associated to the value. This reference + * is used to ensure that each field only adds a value + * once within a selection scope. + * @param mayMatch a flag indiciating whether the field may be matched. + * @param actualValue The value to add. + * @param valueType Type of the value to add. + * @param itemValueType If the value is a list, a list of types for each of the values in the list. + */ + public void addValue(Field field, boolean mayMatch, Object actualValue, short valueType, ShortList itemValueType) { + int i; + for (i = fFieldCount - 1; i > -1; i--) { + if (fFields[i] == field) { + break; + } + } + // do we even know this field? + if (i == -1) { + String code = "UnknownField"; + String eName = fIdentityConstraint.getElementName(); + String cName = fIdentityConstraint.getIdentityConstraintName(); + reportSchemaError(code, new Object[] { field.toString(), eName, cName }); + return; + } + if (!mayMatch) { + String code = "FieldMultipleMatch"; + String cName = fIdentityConstraint.getIdentityConstraintName(); + reportSchemaError(code, new Object[] { field.toString(), cName }); + } + else { + fValuesCount++; + } + fLocalValues[i] = actualValue; + fLocalValueTypes[i] = valueType; + fLocalItemValueTypes[i] = itemValueType; + if (fValuesCount == fFieldCount) { + checkDuplicateValues(); + // store values + for (i = 0; i < fFieldCount; i++) { + fValues.addElement(fLocalValues[i]); + addValueType(fLocalValueTypes[i]); + addItemValueType(fLocalItemValueTypes[i]); + } + } + } // addValue(String,Field) + + /** + * Returns true if this value store contains the locally scoped value stores + */ + public boolean contains() { + // REVISIT: we can improve performance by using hash codes, instead of + // traversing global vector that could be quite large. + int next = 0; + final int size = fValues.size(); + LOOP : for (int i = 0; i < size; i = next) { + next = i + fFieldCount; + for (int j = 0; j < fFieldCount; j++) { + Object value1 = fLocalValues[j]; + Object value2 = fValues.elementAt(i); + short valueType1 = fLocalValueTypes[j]; + short valueType2 = getValueTypeAt(i); + if (value1 == null || value2 == null || valueType1 != valueType2 || !(value1.equals(value2))) { + continue LOOP; + } + else if(valueType1 == XSConstants.LIST_DT || valueType1 == XSConstants.LISTOFUNION_DT) { + ShortList list1 = fLocalItemValueTypes[j]; + ShortList list2 = getItemValueTypeAt(i); + if(list1 == null || list2 == null || !list1.equals(list2)) + continue LOOP; + } + i++; + } + // found it + return true; + } + // didn't find it + return false; + } // contains():boolean + + /** + * Returns -1 if this value store contains the specified + * values, otherwise the index of the first field in the + * key sequence. + */ + public int contains(ValueStoreBase vsb) { + + final Vector values = vsb.fValues; + final int size1 = values.size(); + if (fFieldCount <= 1) { + for (int i = 0; i < size1; ++i) { + short val = vsb.getValueTypeAt(i); + if (!valueTypeContains(val) || !fValues.contains(values.elementAt(i))) { + return i; + } + else if(val == XSConstants.LIST_DT || val == XSConstants.LISTOFUNION_DT) { + ShortList list1 = vsb.getItemValueTypeAt(i); + if (!itemValueTypeContains(list1)) { + return i; + } + } + } + } + /** Handle n-tuples. **/ + else { + final int size2 = fValues.size(); + /** Iterate over each set of fields. **/ + OUTER: for (int i = 0; i < size1; i += fFieldCount) { + /** Check whether this set is contained in the value store. **/ + INNER: for (int j = 0; j < size2; j += fFieldCount) { + for (int k = 0; k < fFieldCount; ++k) { + final Object value1 = values.elementAt(i+k); + final Object value2 = fValues.elementAt(j+k); + final short valueType1 = vsb.getValueTypeAt(i+k); + final short valueType2 = getValueTypeAt(j+k); + if (value1 != value2 && (valueType1 != valueType2 || value1 == null || !value1.equals(value2))) { + continue INNER; + } + else if(valueType1 == XSConstants.LIST_DT || valueType1 == XSConstants.LISTOFUNION_DT) { + ShortList list1 = vsb.getItemValueTypeAt(i+k); + ShortList list2 = getItemValueTypeAt(j+k); + if (list1 == null || list2 == null || !list1.equals(list2)) { + continue INNER; + } + } + } + continue OUTER; + } + return i; + } + } + return -1; + + } // contains(Vector):Object + + // + // Protected methods + // + + protected void checkDuplicateValues() { + // no-op + } // duplicateValue(Hashtable) + + /** Returns a string of the specified values. */ + protected String toString(Object[] values) { + + // no values + int size = values.length; + if (size == 0) { + return ""; + } + + fTempBuffer.setLength(0); + + // construct value string + for (int i = 0; i < size; i++) { + if (i > 0) { + fTempBuffer.append(','); + } + fTempBuffer.append(values[i]); + } + return fTempBuffer.toString(); + + } // toString(Object[]):String + + /** Returns a string of the specified values. */ + protected String toString(Vector values, int start, int length) { + + // no values + if (length == 0) { + return ""; + } + + // one value + if (length == 1) { + return String.valueOf(values.elementAt(start)); + } + + // construct value string + StringBuffer str = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i > 0) { + str.append(','); + } + str.append(values.elementAt(start + i)); + } + return str.toString(); + + } // toString(Vector,int,int):String + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + String s = super.toString(); + int index1 = s.lastIndexOf('$'); + if (index1 != -1) { + s = s.substring(index1 + 1); + } + int index2 = s.lastIndexOf('.'); + if (index2 != -1) { + s = s.substring(index2 + 1); + } + return s + '[' + fIdentityConstraint + ']'; + } // toString():String + + // + // Private methods + // + + private void addValueType(short type) { + if (fUseValueTypeVector) { + fValueTypes.add(type); + } + else if (fValueTypesLength++ == 0) { + fValueType = type; + } + else if (fValueType != type) { + fUseValueTypeVector = true; + if (fValueTypes == null) { + fValueTypes = new ShortVector(fValueTypesLength * 2); + } + for (int i = 1; i < fValueTypesLength; ++i) { + fValueTypes.add(fValueType); + } + fValueTypes.add(type); + } + } + + private short getValueTypeAt(int index) { + if (fUseValueTypeVector) { + return fValueTypes.valueAt(index); + } + return fValueType; + } + + private boolean valueTypeContains(short value) { + if (fUseValueTypeVector) { + return fValueTypes.contains(value); + } + return fValueType == value; + } + + private void addItemValueType(ShortList itemValueType) { + if (fUseItemValueTypeVector) { + fItemValueTypes.add(itemValueType); + } + else if (fItemValueTypesLength++ == 0) { + fItemValueType = itemValueType; + } + else if (!(fItemValueType == itemValueType || + (fItemValueType != null && fItemValueType.equals(itemValueType)))) { + fUseItemValueTypeVector = true; + if (fItemValueTypes == null) { + fItemValueTypes = new Vector(fItemValueTypesLength * 2); + } + for (int i = 1; i < fItemValueTypesLength; ++i) { + fItemValueTypes.add(fItemValueType); + } + fItemValueTypes.add(itemValueType); + } + } + + private ShortList getItemValueTypeAt(int index) { + if (fUseItemValueTypeVector) { + return (ShortList) fItemValueTypes.elementAt(index); + } + return fItemValueType; + } + + private boolean itemValueTypeContains(ShortList value) { + if (fUseItemValueTypeVector) { + return fItemValueTypes.contains(value); + } + return fItemValueType == value || + (fItemValueType != null && fItemValueType.equals(value)); + } + + } // class ValueStoreBase + + /** + * Unique value store. + * + * @author Andy Clark, IBM + */ + protected class UniqueValueStore extends ValueStoreBase { + + // + // Constructors + // + + /** Constructs a unique value store. */ + public UniqueValueStore(UniqueOrKey unique) { + super(unique); + } // (Unique) + + // + // ValueStoreBase protected methods + // + + /** + * Called when a duplicate value is added. + */ + protected void checkDuplicateValues() { + // is this value as a group duplicated? + if (contains()) { + String code = "DuplicateUnique"; + String value = toString(fLocalValues); + String eName = fIdentityConstraint.getElementName(); + String cName = fIdentityConstraint.getIdentityConstraintName(); + reportSchemaError(code, new Object[] { value, eName, cName }); + } + } // duplicateValue(Hashtable) + + } // class UniqueValueStore + + /** + * Key value store. + * + * @author Andy Clark, IBM + */ + protected class KeyValueStore extends ValueStoreBase { + + // REVISIT: Implement a more efficient storage mechanism. -Ac + + // + // Constructors + // + + /** Constructs a key value store. */ + public KeyValueStore(UniqueOrKey key) { + super(key); + } // (Key) + + // + // ValueStoreBase protected methods + // + + /** + * Called when a duplicate value is added. + */ + protected void checkDuplicateValues() { + if (contains()) { + String code = "DuplicateKey"; + String value = toString(fLocalValues); + String eName = fIdentityConstraint.getElementName(); + String cName = fIdentityConstraint.getIdentityConstraintName(); + reportSchemaError(code, new Object[] { value, eName, cName }); + } + } // duplicateValue(Hashtable) + + } // class KeyValueStore + + /** + * Key reference value store. + * + * @author Andy Clark, IBM + */ + protected class KeyRefValueStore extends ValueStoreBase { + + // + // Data + // + + /** Key value store. */ + protected ValueStoreBase fKeyValueStore; + + // + // Constructors + // + + /** Constructs a key value store. */ + public KeyRefValueStore(KeyRef keyRef, KeyValueStore keyValueStore) { + super(keyRef); + fKeyValueStore = keyValueStore; + } // (KeyRef) + + // + // ValueStoreBase methods + // + + // end the value Scope; here's where we have to tie + // up keyRef loose ends. + public void endDocumentFragment() { + + // do all the necessary management... + super.endDocumentFragment(); + + // verify references + // get the key store corresponding (if it exists): + fKeyValueStore = + (ValueStoreBase) fValueStoreCache.fGlobalIDConstraintMap.get( + ((KeyRef) fIdentityConstraint).getKey()); + + if (fKeyValueStore == null) { + // report error + String code = "KeyRefOutOfScope"; + String value = fIdentityConstraint.toString(); + reportSchemaError(code, new Object[] { value }); + return; + } + int errorIndex = fKeyValueStore.contains(this); + if (errorIndex != -1) { + String code = "KeyNotFound"; + String values = toString(fValues, errorIndex, fFieldCount); + String element = fIdentityConstraint.getElementName(); + String name = fIdentityConstraint.getName(); + reportSchemaError(code, new Object[] { name, values, element }); + } + + } // endDocumentFragment() + + /** End document. */ + public void endDocument() { + super.endDocument(); + + } // endDocument() + + } // class KeyRefValueStore + + // value store management + + /** + * Value store cache. This class is used to store the values for + * identity constraints. + * + * @author Andy Clark, IBM + */ + protected class ValueStoreCache { + + // + // Data + // + final LocalIDKey fLocalId = new LocalIDKey(); + // values stores + + /** stores all global Values stores. */ + protected final ArrayList fValueStores = new ArrayList(); + + /** + * Values stores associated to specific identity constraints. + * This hashtable maps IdentityConstraints and + * the 0-based element on which their selectors first matched to + * a corresponding ValueStore. This should take care + * of all cases, including where ID constraints with + * descendant-or-self axes occur on recursively-defined + * elements. + */ + protected final HashMap fIdentityConstraint2ValueStoreMap = new HashMap(); + + // sketch of algorithm: + // - when a constraint is first encountered, its + // values are stored in the (local) fIdentityConstraint2ValueStoreMap; + // - Once it is validated (i.e., when it goes out of scope), + // its values are merged into the fGlobalIDConstraintMap; + // - as we encounter keyref's, we look at the global table to + // validate them. + // + // The fGlobalIDMapStack has the following structure: + // - validation always occurs against the fGlobalIDConstraintMap + // (which comprises all the "eligible" id constraints); + // When an endElement is found, this Hashtable is merged with the one + // below in the stack. + // When a start tag is encountered, we create a new + // fGlobalIDConstraintMap. + // i.e., the top of the fGlobalIDMapStack always contains + // the preceding siblings' eligible id constraints; + // the fGlobalIDConstraintMap contains descendants+self. + // keyrefs can only match descendants+self. + protected final Stack fGlobalMapStack = new Stack(); + protected final HashMap fGlobalIDConstraintMap = new HashMap(); + + // + // Constructors + // + + /** Default constructor. */ + public ValueStoreCache() { + } // () + + // + // Public methods + // + + /** Resets the identity constraint cache. */ + public void startDocument() { + fValueStores.clear(); + fIdentityConstraint2ValueStoreMap.clear(); + fGlobalIDConstraintMap.clear(); + fGlobalMapStack.removeAllElements(); + } // startDocument() + + // startElement: pushes the current fGlobalIDConstraintMap + // onto fGlobalMapStack and clears fGlobalIDConstraint map. + public void startElement() { + // only clone the map when there are elements + if (fGlobalIDConstraintMap.size() > 0) + fGlobalMapStack.push(fGlobalIDConstraintMap.clone()); + else + fGlobalMapStack.push(null); + fGlobalIDConstraintMap.clear(); + } // startElement(void) + + /** endElement(): merges contents of fGlobalIDConstraintMap with the + * top of fGlobalMapStack into fGlobalIDConstraintMap. + */ + public void endElement() { + if (fGlobalMapStack.isEmpty()) { + return; // must be an invalid doc! + } + HashMap oldMap = (HashMap) fGlobalMapStack.pop(); + // return if there is no element + if (oldMap == null) { + return; + } + + Iterator entries = oldMap.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + IdentityConstraint id = (IdentityConstraint) entry.getKey(); + ValueStoreBase oldVal = (ValueStoreBase) entry.getValue(); + if (oldVal != null) { + ValueStoreBase currVal = (ValueStoreBase) fGlobalIDConstraintMap.get(id); + if (currVal == null) { + fGlobalIDConstraintMap.put(id, oldVal); + } + else if (currVal != oldVal) { + currVal.append(oldVal); + } + } + } + } // endElement() + + /** + * Initializes the value stores for the specified element + * declaration. + */ + public void initValueStoresFor(XSElementDecl eDecl, FieldActivator activator) { + // initialize value stores for unique fields + IdentityConstraint[] icArray = eDecl.fIDConstraints; + int icCount = eDecl.fIDCPos; + for (int i = 0; i < icCount; i++) { + switch (icArray[i].getCategory()) { + case (IdentityConstraint.IC_UNIQUE) : + // initialize value stores for unique fields + UniqueOrKey unique = (UniqueOrKey) icArray[i]; + LocalIDKey toHash = new LocalIDKey(unique, fElementDepth); + UniqueValueStore uniqueValueStore = + (UniqueValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); + if (uniqueValueStore == null) { + uniqueValueStore = new UniqueValueStore(unique); + fIdentityConstraint2ValueStoreMap.put(toHash, uniqueValueStore); + } else { + uniqueValueStore.clear(); + } + fValueStores.add(uniqueValueStore); + activateSelectorFor(icArray[i]); + break; + case (IdentityConstraint.IC_KEY) : + // initialize value stores for key fields + UniqueOrKey key = (UniqueOrKey) icArray[i]; + toHash = new LocalIDKey(key, fElementDepth); + KeyValueStore keyValueStore = + (KeyValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); + if (keyValueStore == null) { + keyValueStore = new KeyValueStore(key); + fIdentityConstraint2ValueStoreMap.put(toHash, keyValueStore); + } else { + keyValueStore.clear(); + } + fValueStores.add(keyValueStore); + activateSelectorFor(icArray[i]); + break; + case (IdentityConstraint.IC_KEYREF) : + // initialize value stores for keyRef fields + KeyRef keyRef = (KeyRef) icArray[i]; + toHash = new LocalIDKey(keyRef, fElementDepth); + KeyRefValueStore keyRefValueStore = + (KeyRefValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); + if (keyRefValueStore == null) { + keyRefValueStore = new KeyRefValueStore(keyRef, null); + fIdentityConstraint2ValueStoreMap.put(toHash, keyRefValueStore); + } else { + keyRefValueStore.clear(); + } + fValueStores.add(keyRefValueStore); + activateSelectorFor(icArray[i]); + break; + } + } + } // initValueStoresFor(XSElementDecl) + + /** Returns the value store associated to the specified IdentityConstraint. */ + public ValueStoreBase getValueStoreFor(IdentityConstraint id, int initialDepth) { + fLocalId.fDepth = initialDepth; + fLocalId.fId = id; + return (ValueStoreBase) fIdentityConstraint2ValueStoreMap.get(fLocalId); + } // getValueStoreFor(IdentityConstraint, int):ValueStoreBase + + /** Returns the global value store associated to the specified IdentityConstraint. */ + public ValueStoreBase getGlobalValueStoreFor(IdentityConstraint id) { + return (ValueStoreBase) fGlobalIDConstraintMap.get(id); + } // getValueStoreFor(IdentityConstraint):ValueStoreBase + + // This method takes the contents of the (local) ValueStore + // associated with id and moves them into the global + // hashtable, if id is a or a . + // If it's a , then we leave it for later. + public void transplant(IdentityConstraint id, int initialDepth) { + fLocalId.fDepth = initialDepth; + fLocalId.fId = id; + ValueStoreBase newVals = + (ValueStoreBase) fIdentityConstraint2ValueStoreMap.get(fLocalId); + if (id.getCategory() == IdentityConstraint.IC_KEYREF) + return; + ValueStoreBase currVals = (ValueStoreBase) fGlobalIDConstraintMap.get(id); + if (currVals != null) { + currVals.append(newVals); + fGlobalIDConstraintMap.put(id, currVals); + } else + fGlobalIDConstraintMap.put(id, newVals); + + } // transplant(id) + + /** Check identity constraints. */ + public void endDocument() { + + int count = fValueStores.size(); + for (int i = 0; i < count; i++) { + ValueStoreBase valueStore = (ValueStoreBase) fValueStores.get(i); + valueStore.endDocument(); + } + + } // endDocument() + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + String s = super.toString(); + int index1 = s.lastIndexOf('$'); + if (index1 != -1) { + return s.substring(index1 + 1); + } + int index2 = s.lastIndexOf('.'); + if (index2 != -1) { + return s.substring(index2 + 1); + } + return s; + } // toString():String + + } // class ValueStoreCache + + // the purpose of this class is to enable IdentityConstraint,int + // pairs to be used easily as keys in Hashtables. + protected static final class LocalIDKey { + + public IdentityConstraint fId; + public int fDepth; + + public LocalIDKey() { + } + + public LocalIDKey(IdentityConstraint id, int depth) { + fId = id; + fDepth = depth; + } // init(IdentityConstraint, int) + + // object method + public int hashCode() { + return fId.hashCode() + fDepth; + } + + public boolean equals(Object localIDKey) { + if (localIDKey instanceof LocalIDKey) { + LocalIDKey lIDKey = (LocalIDKey) localIDKey; + return (lIDKey.fId == fId && lIDKey.fDepth == fDepth); + } + return false; + } + } // class LocalIDKey + + /** + * A simple vector for shorts. + */ + protected static final class ShortVector { + + // + // Data + // + + /** Current length. */ + private int fLength; + + /** Data. */ + private short[] fData; + + // + // Constructors + // + + public ShortVector() {} + + public ShortVector(int initialCapacity) { + fData = new short[initialCapacity]; + } + + // + // Public methods + // + + /** Returns the length of the vector. */ + public int length() { + return fLength; + } + + /** Adds the value to the vector. */ + public void add(short value) { + ensureCapacity(fLength + 1); + fData[fLength++] = value; + } + + /** Returns the short value at the specified position in the vector. */ + public short valueAt(int position) { + return fData[position]; + } + + /** Clears the vector. */ + public void clear() { + fLength = 0; + } + + /** Returns whether the short is contained in the vector. */ + public boolean contains(short value) { + for (int i = 0; i < fLength; ++i) { + if (fData[i] == value) { + return true; + } + } + return false; + } + + // + // Private methods + // + + /** Ensures capacity. */ + private void ensureCapacity(int size) { + if (fData == null) { + fData = new short[8]; + } + else if (fData.length <= size) { + short[] newdata = new short[fData.length * 2]; + System.arraycopy(fData, 0, newdata, 0, fData.length); + fData = newdata; + } + } + } + +} // class SchemaValidator diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAnnotationImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAnnotationImpl.java new file mode 100644 index 0000000..7051870 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAnnotationImpl.java @@ -0,0 +1,186 @@ +/* + * 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. + */ +package org.apache.xerces.impl.xs; + +import java.io.IOException; +import java.io.StringReader; + +import org.apache.xerces.dom.CoreDocumentImpl; +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.parsers.SAXParser; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSNamespaceItem; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * This is an implementation of the XSAnnotation schema component. + * + * @xerces.internal + * + * @version $Id$ + */ +public class XSAnnotationImpl implements XSAnnotation { + + // Data + + // the content of the annotation node, including all children, along + // with any non-schema attributes from its parent + private String fData = null; + + // the grammar which owns this annotation; we get parsers + // from here when we need them + private SchemaGrammar fGrammar = null; + + // constructors + public XSAnnotationImpl(String contents, SchemaGrammar grammar) { + fData = contents; + fGrammar = grammar; + } + + /** + * Write contents of the annotation to the specified DOM object. If the + * specified target object is a DOM in-scope namespace + * declarations for annotation element are added as + * attributes nodes of the serialized annotation, otherwise + * the corresponding events for all in-scope namespace declaration are + * sent via specified document handler. + * @param target A target pointer to the annotation target object, i.e. + * org.w3c.dom.Document, + * org.xml.sax.ContentHandler. + * @param targetType A target type. + * @return If the target is recognized type and supported by + * this implementation return true, otherwise return false. + */ + public boolean writeAnnotation(Object target, + short targetType) { + if(targetType == XSAnnotation.W3C_DOM_ELEMENT || targetType == XSAnnotation.W3C_DOM_DOCUMENT) { + writeToDOM((Node)target, targetType); + return true; + } else if (targetType == SAX_CONTENTHANDLER) { + writeToSAX((ContentHandler)target); + return true; + } + return false; + } + + /** + * A text representation of annotation. + */ + public String getAnnotationString() { + return fData; + } + + // XSObject methods + + /** + * The type of this object, i.e. + * ELEMENT_DECLARATION. + */ + public short getType() { + return XSConstants.ANNOTATION; + } + + /** + * The name of type NCName of this declaration as defined in + * XML Namespaces. + */ + public String getName() { + return null; + } + + /** + * The [target namespace] of this object, or null if it is + * unspecified. + */ + public String getNamespace() { + return null; + } + + /** + * A namespace schema information item corresponding to the target + * namespace of the component, if it's globally declared; or null + * otherwise. + */ + public XSNamespaceItem getNamespaceItem() { + return null; + } + + // private methods + private synchronized void writeToSAX(ContentHandler handler) { + // nothing must go wrong with this parse... + SAXParser parser = fGrammar.getSAXParser(); + StringReader aReader = new StringReader(fData); + InputSource aSource = new InputSource(aReader); + parser.setContentHandler(handler); + try { + parser.parse(aSource); + } + catch (SAXException e) { + // this should never happen! + // REVISIT: what to do with this?; should really not + // eat it... + } + catch (IOException i) { + // ditto with above + } + // Release the reference to the user's ContentHandler. + parser.setContentHandler(null); + } + + // this creates the new Annotation element as the first child + // of the Node + private synchronized void writeToDOM(Node target, short type) { + Document futureOwner = (type == XSAnnotation.W3C_DOM_ELEMENT) ? + target.getOwnerDocument() : (Document)target; + DOMParser parser = fGrammar.getDOMParser(); + StringReader aReader = new StringReader(fData); + InputSource aSource = new InputSource(aReader); + try { + parser.parse(aSource); + } + catch (SAXException e) { + // this should never happen! + // REVISIT: what to do with this?; should really not + // eat it... + } + catch (IOException i) { + // ditto with above + } + Document aDocument = parser.getDocument(); + parser.dropDocumentReferences(); + Element annotation = aDocument.getDocumentElement(); + Node newElem = null; + if (futureOwner instanceof CoreDocumentImpl) { + newElem = futureOwner.adoptNode(annotation); + // adoptNode will return null when the DOM implementations are not compatible. + if (newElem == null) { + newElem = futureOwner.importNode(annotation, true); + } + } + else { + newElem = futureOwner.importNode(annotation, true); + } + target.insertBefore(newElem, target.getFirstChild()); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeDecl.java new file mode 100644 index 0000000..d1316fe --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeDecl.java @@ -0,0 +1,217 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSAttributeDeclaration; +import org.apache.xerces.xs.XSComplexTypeDefinition; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSValue; + +/** + * The XML representation for an attribute declaration + * schema component is an <attribute> element information item + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Sandy Gao, IBM + * @version $Id$ + */ +public class XSAttributeDecl implements XSAttributeDeclaration { + + // scopes + public final static short SCOPE_ABSENT = 0; + public final static short SCOPE_GLOBAL = 1; + public final static short SCOPE_LOCAL = 2; + + // the name of the attribute + String fName = null; + // the target namespace of the attribute + String fTargetNamespace = null; + // the simple type of the attribute + XSSimpleType fType = null; + public QName fUnresolvedTypeName = null; + // value constraint type: default, fixed or !specified + short fConstraintType = XSConstants.VC_NONE; + // scope + short fScope = XSConstants.SCOPE_ABSENT; + // enclosing complex type, when the scope is local + XSComplexTypeDecl fEnclosingCT = null; + // optional annotations + XSObjectList fAnnotations = null; + // value constraint value + ValidatedInfo fDefault = null; + // The namespace schema information item corresponding to the target namespace + // of the attribute declaration, if it is globally declared; or null otherwise. + private XSNamespaceItem fNamespaceItem = null; + + public void setValues(String name, String targetNamespace, + XSSimpleType simpleType, short constraintType, short scope, + ValidatedInfo valInfo, XSComplexTypeDecl enclosingCT, + XSObjectList annotations) { + fName = name; + fTargetNamespace = targetNamespace; + fType = simpleType; + fConstraintType = constraintType; + fScope = scope; + fDefault = valInfo; + fEnclosingCT = enclosingCT; + fAnnotations = annotations; + } + + public void reset(){ + fName = null; + fTargetNamespace = null; + fType = null; + fUnresolvedTypeName = null; + fConstraintType = XSConstants.VC_NONE; + fScope = XSConstants.SCOPE_ABSENT; + fDefault = null; + fAnnotations = null; + } + + /** + * Get the type of the object, i.e ELEMENT_DECLARATION. + */ + public short getType() { + return XSConstants.ATTRIBUTE_DECLARATION; + } + + /** + * The name of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return fName; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return fTargetNamespace; + } + + /** + * A simple type definition + */ + public XSSimpleTypeDefinition getTypeDefinition() { + return fType; + } + + /** + * Optional. Either global or a complex type definition ( + * ctDefinition). This property is absent in the case of + * declarations within attribute group definitions: their scope will be + * determined when they are used in the construction of complex type + * definitions. + */ + public short getScope() { + return fScope; + } + + /** + * Locally scoped declarations are available for use only within the + * complex type definition identified by the scope + * property. + */ + public XSComplexTypeDefinition getEnclosingCTDefinition() { + return fEnclosingCT; + } + + /** + * Value constraint: one of default, fixed. + */ + public short getConstraintType() { + return fConstraintType; + } + + /** + * Value constraint: The actual value (with respect to the {type + * definition}) Should we return Object instead of DOMString? + */ + public String getConstraintValue() { + // REVISIT: SCAPI: what's the proper representation + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.stringValue(); + } + + /** + * Optional. Annotation. + */ + public XSAnnotation getAnnotation() { + return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + public ValidatedInfo getValInfo() { + return fDefault; + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return fNamespaceItem; + } + + void setNamespaceItem(XSNamespaceItem namespaceItem) { + fNamespaceItem = namespaceItem; + } + + public Object getActualVC() { + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.actualValue; + } + + public short getActualVCType() { + return getConstraintType() == XSConstants.VC_NONE ? + XSConstants.UNAVAILABLE_DT : + fDefault.actualValueType; + } + + public ShortList getItemValueTypes() { + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.itemValueTypes; + } + + public XSValue getValueConstraintValue() { + return fDefault; + } + +} // class XSAttributeDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeGroupDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeGroupDecl.java new file mode 100644 index 0000000..c868047 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeGroupDecl.java @@ -0,0 +1,404 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSAttributeGroupDefinition; +import org.apache.xerces.xs.XSAttributeUse; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSWildcard; + +/** + * The XML representation for an attribute group declaration + * schema component is a global <attributeGroup> element information item + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id$ + */ +public class XSAttributeGroupDecl implements XSAttributeGroupDefinition { + + // name of the attribute group + public String fName = null; + // target namespace of the attribute group + public String fTargetNamespace = null; + // number of attribute uses included by this attribute group + int fAttrUseNum = 0; + // attribute uses included by this attribute group + private static final int INITIAL_SIZE = 5; + XSAttributeUseImpl[] fAttributeUses = new XSAttributeUseImpl[INITIAL_SIZE]; + // attribute wildcard included by this attribute group + public XSWildcardDecl fAttributeWC = null; + // whether there is an attribute use whose type is or is derived from ID. + public String fIDAttrName = null; + + // optional annotation + public XSObjectList fAnnotations; + + protected XSObjectListImpl fAttrUses = null; + + // The namespace schema information item corresponding to the target namespace + // of the attribute group definition, if it is globally declared; or null otherwise. + private XSNamespaceItem fNamespaceItem = null; + + // add an attribute use + // if the type is derived from ID, but there is already another attribute + // use of type ID, then return the name of the other attribute use; + // otherwise, return null + public String addAttributeUse(XSAttributeUseImpl attrUse) { + + // if this attribute use is prohibited, then don't check whether it's + // of type ID + if (attrUse.fUse != SchemaSymbols.USE_PROHIBITED) { + if (attrUse.fAttrDecl.fType.isIDType()) { + // if there is already an attribute use of type ID, + // return its name (and don't add it to the list, to avoid + // interruption to instance validation. + if (fIDAttrName == null) + fIDAttrName = attrUse.fAttrDecl.fName; + else + return fIDAttrName; + } + } + + if (fAttrUseNum == fAttributeUses.length) { + fAttributeUses = resize(fAttributeUses, fAttrUseNum*2); + } + fAttributeUses[fAttrUseNum++] = attrUse; + + return null; + } + + public void replaceAttributeUse(XSAttributeUse oldUse, XSAttributeUseImpl newUse) { + for (int i=0; i 0) { +// OUTER: for (int i = 0; i < fAttrUseNum; i++) { +// if (fAttributeUses[i].fUse == SchemaSymbols.USE_PROHIBITED) +// continue; +// for (int j = 1; j <= pCount; j++) { +// if (fAttributeUses[i].fAttrDecl.fName == pUses[fAttrUseNum-pCount].fAttrDecl.fName && +// fAttributeUses[i].fAttrDecl.fTargetNamespace == pUses[fAttrUseNum-pCount].fAttrDecl.fTargetNamespace) { +// continue OUTER; +// } +// } +// pUses[newCount++] = fAttributeUses[i]; +// } +// fAttributeUses = pUses; +// fAttrUseNum = newCount; +// } + } + + /** + * Check that the attributes in this group validly restrict those from a base group. + * If an error is found, an Object[] is returned. This contains the arguments for the error message + * describing the error. The last element in the array (at index arr.length - 1) is the the error code. + * Returns null if there is no error. + * + * REVISIT: is there a better way of returning the appropriate information for the error? + * + * @param typeName the name of the type containing this attribute group, used for error reporting purposes + * @param baseGroup the XSAttributeGroupDecl that is the base we are checking against + */ + public Object[] validRestrictionOf(String typeName, XSAttributeGroupDecl baseGroup) { + + Object[] errorArgs = null; + XSAttributeUseImpl attrUse = null; + XSAttributeDecl attrDecl = null; + XSAttributeUseImpl baseAttrUse = null; + XSAttributeDecl baseAttrDecl = null; + + for (int i=0; iname of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return fName; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return fTargetNamespace; + } + + /** + * {attribute uses} A set of attribute uses. + */ + public XSObjectList getAttributeUses() { + if (fAttrUses == null) { + if (fAttrUseNum > 0) { + fAttrUses = new XSObjectListImpl(fAttributeUses, fAttrUseNum); + } + else { + fAttrUses = XSObjectListImpl.EMPTY_LIST; + } + } + return fAttrUses; + } + + /** + * {attribute wildcard} Optional. A wildcard. + */ + public XSWildcard getAttributeWildcard() { + return fAttributeWC; + } + + /** + * Optional. Annotation. + */ + public XSAnnotation getAnnotation() { + return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return fNamespaceItem; + } + + void setNamespaceItem(XSNamespaceItem namespaceItem) { + fNamespaceItem = namespaceItem; + } + +} // class XSAttributeGroupDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeUseImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeUseImpl.java new file mode 100644 index 0000000..771f326 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSAttributeUseImpl.java @@ -0,0 +1,155 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.XSAttributeDeclaration; +import org.apache.xerces.xs.XSAttributeUse; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSValue; + +/** + * The XML representation for an attribute use + * schema component is a local <attribute> element information item + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @version $Id$ + */ +public class XSAttributeUseImpl implements XSAttributeUse { + + // the referred attribute decl + public XSAttributeDecl fAttrDecl = null; + // use information: SchemaSymbols.USE_OPTIONAL, REQUIRED, PROHIBITED + public short fUse = SchemaSymbols.USE_OPTIONAL; + // value constraint type: default, fixed or !specified + public short fConstraintType = XSConstants.VC_NONE; + // value constraint value + public ValidatedInfo fDefault = null; + // optional annotation + public XSObjectList fAnnotations = null; + + public void reset(){ + fDefault = null; + fAttrDecl = null; + fUse = SchemaSymbols.USE_OPTIONAL; + fConstraintType = XSConstants.VC_NONE; + fAnnotations = null; + } + + /** + * Get the type of the object, i.e ELEMENT_DECLARATION. + */ + public short getType() { + return XSConstants.ATTRIBUTE_USE; + } + + /** + * The name of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return null; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return null; + } + + /** + * {required} determines whether this use of an attribute declaration + * requires an appropriate attribute information item to be present, or + * merely allows it. + */ + public boolean getRequired() { + return fUse == SchemaSymbols.USE_REQUIRED; + } + + /** + * {attribute declaration} provides the attribute declaration itself, + * which will in turn determine the simple type definition used. + */ + public XSAttributeDeclaration getAttrDeclaration() { + return fAttrDecl; + } + + /** + * Value Constraint: one of default, fixed. + */ + public short getConstraintType() { + return fConstraintType; + } + + /** + * Value Constraint: The actual value (with respect to the {type + * definition}). + */ + public String getConstraintValue() { + // REVISIT: SCAPI: what's the proper representation + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.stringValue(); + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return null; + } + + public Object getActualVC() { + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.actualValue; + } + + public short getActualVCType() { + return getConstraintType() == XSConstants.VC_NONE ? + XSConstants.UNAVAILABLE_DT : + fDefault.actualValueType; + } + + public ShortList getItemValueTypes() { + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.itemValueTypes; + } + + public XSValue getValueConstraintValue() { + return fDefault; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + +} // class XSAttributeUseImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSComplexTypeDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSComplexTypeDecl.java new file mode 100644 index 0000000..fcd5066 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSComplexTypeDecl.java @@ -0,0 +1,732 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.xs.models.CMBuilder; +import org.apache.xerces.impl.xs.models.XSCMValidator; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.XSAttributeUse; +import org.apache.xerces.xs.XSComplexTypeDefinition; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSParticle; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; +import org.apache.xerces.xs.XSWildcard; +import org.w3c.dom.TypeInfo; + +/** + * The XML representation for a complexType + * schema component is a <complexType> element information item + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Sandy Gao, IBM + * @version $Id$ + */ +public class XSComplexTypeDecl implements XSComplexTypeDefinition, TypeInfo { + + // name of the complexType + String fName = null; + + // target namespace of the complexType + String fTargetNamespace = null; + + // base type of the complexType + XSTypeDefinition fBaseType = null; + + // derivation method of the complexType + short fDerivedBy = XSConstants.DERIVATION_RESTRICTION; + + // final set of the complexType + short fFinal = XSConstants.DERIVATION_NONE; + + // block set (prohibited substitution) of the complexType + short fBlock = XSConstants.DERIVATION_NONE; + + // flags: whether is abstract; whether contains ID type; + // whether it's an anonymous tpye + short fMiscFlags = 0; + + // the attribute group that holds the attribute uses and attribute wildcard + XSAttributeGroupDecl fAttrGrp = null; + + // the content type of the complexType + short fContentType = CONTENTTYPE_EMPTY; + + // if the content type is simple, then the corresponding simpleType + XSSimpleType fXSSimpleType = null; + + // if the content type is element or mixed, the particle + XSParticleDecl fParticle = null; + + // if there is a particle, the content model corresponding to that particle + XSCMValidator fCMValidator = null; + + // the content model that's sufficient for computing UPA + XSCMValidator fUPACMValidator = null; + + // list of annotations affiliated with this type + XSObjectListImpl fAnnotations = null; + + // The namespace schema information item corresponding to the target namespace + // of the complex type definition, if it is globally declared; or null otherwise. + private XSNamespaceItem fNamespaceItem = null; + + // DOM Level 3 TypeInfo Derivation Method constants + static final int DERIVATION_ANY = 0; + static final int DERIVATION_RESTRICTION = 1; + static final int DERIVATION_EXTENSION = 2; + static final int DERIVATION_UNION = 4; + static final int DERIVATION_LIST = 8; + + public XSComplexTypeDecl() { + // do-nothing constructor for now. + } + + public void setValues(String name, String targetNamespace, + XSTypeDefinition baseType, short derivedBy, short schemaFinal, + short block, short contentType, + boolean isAbstract, XSAttributeGroupDecl attrGrp, + XSSimpleType simpleType, XSParticleDecl particle, + XSObjectListImpl annotations) { + fTargetNamespace = targetNamespace; + fBaseType = baseType; + fDerivedBy = derivedBy; + fFinal = schemaFinal; + fBlock = block; + fContentType = contentType; + if(isAbstract) + fMiscFlags |= CT_IS_ABSTRACT; + fAttrGrp = attrGrp; + fXSSimpleType = simpleType; + fParticle = particle; + fAnnotations = annotations; + } + + public void setName(String name) { + fName = name; + } + + public short getTypeCategory() { + return COMPLEX_TYPE; + } + + public String getTypeName() { + return fName; + } + + public short getFinalSet(){ + return fFinal; + } + + public String getTargetNamespace(){ + return fTargetNamespace; + } + + // flags for the misc flag + private static final short CT_IS_ABSTRACT = 1; + private static final short CT_HAS_TYPE_ID = 2; + private static final short CT_IS_ANONYMOUS = 4; + + // methods to get/set misc flag + + public boolean containsTypeID () { + return((fMiscFlags & CT_HAS_TYPE_ID) != 0); + } + + public void setIsAbstractType() { + fMiscFlags |= CT_IS_ABSTRACT; + } + public void setContainsTypeID() { + fMiscFlags |= CT_HAS_TYPE_ID; + } + public void setIsAnonymous() { + fMiscFlags |= CT_IS_ANONYMOUS; + } + + public XSCMValidator getContentModel(CMBuilder cmBuilder) { + return getContentModel(cmBuilder, false); + } + + public synchronized XSCMValidator getContentModel(CMBuilder cmBuilder, boolean forUPA) { + if (fCMValidator == null) { + if (forUPA) { + if (fUPACMValidator == null) { + fUPACMValidator = cmBuilder.getContentModel(this, true); + + if (fUPACMValidator != null && !fUPACMValidator.isCompactedForUPA()) { + fCMValidator = fUPACMValidator; + } + } + return fUPACMValidator; + } + else { + fCMValidator = cmBuilder.getContentModel(this, false); + } + } + + return fCMValidator; + } + + // some utility methods: + + // return the attribute group for this complex type + public XSAttributeGroupDecl getAttrGrp() { + return fAttrGrp; + } + + public String toString() { + StringBuffer str = new StringBuffer(); + appendTypeInfo(str); + return str.toString(); + } + + void appendTypeInfo(StringBuffer str) { + String contentType[] = {"EMPTY", "SIMPLE", "ELEMENT", "MIXED"}; + String derivedBy[] = {"EMPTY", "EXTENSION", "RESTRICTION"}; + + str.append("Complex type name='").append(fTargetNamespace).append(',').append(getTypeName()).append("', "); + if (fBaseType != null) { + str.append(" base type name='").append(fBaseType.getName()).append("', "); + } + str.append(" content type='").append(contentType[fContentType]).append("', "); + str.append(" isAbstract='").append(getAbstract()).append("', "); + str.append(" hasTypeId='").append(containsTypeID()).append("', "); + str.append(" final='").append(fFinal).append("', "); + str.append(" block='").append(fBlock).append("', "); + if (fParticle != null) { + str.append(" particle='").append(fParticle.toString()).append("', "); + } + str.append(" derivedBy='").append(derivedBy[fDerivedBy]).append("'. "); + + } + + public boolean derivedFromType(XSTypeDefinition ancestor, short derivationMethod) { + // ancestor is null, retur false + if (ancestor == null) + return false; + // ancestor is anyType, return true + if (ancestor == SchemaGrammar.fAnyType) + return true; + // recursively get base, and compare it with ancestor + XSTypeDefinition type = this; + while (type != ancestor && // compare with ancestor + type != SchemaGrammar.fAnySimpleType && // reached anySimpleType + type != SchemaGrammar.fAnyType) { // reached anyType + type = type.getBaseType(); + } + + return type == ancestor; + } + + public boolean derivedFrom(String ancestorNS, String ancestorName, short derivationMethod) { + // ancestor is null, retur false + if (ancestorName == null) + return false; + // ancestor is anyType, return true + if (ancestorNS != null && + ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) && + ancestorName.equals(SchemaSymbols.ATTVAL_ANYTYPE)) { + return true; + } + + // recursively get base, and compare it with ancestor + XSTypeDefinition type = this; + while (!(ancestorName.equals(type.getName()) && + ((ancestorNS == null && type.getNamespace() == null) || + (ancestorNS != null && ancestorNS.equals(type.getNamespace())))) && // compare with ancestor + type != SchemaGrammar.fAnySimpleType && // reached anySimpleType + type != SchemaGrammar.fAnyType) { // reached anyType + type = (XSTypeDefinition)type.getBaseType(); + } + + return type != SchemaGrammar.fAnySimpleType && + type != SchemaGrammar.fAnyType; + } + + /** + * Checks if a type is derived from another given the the name, namespace + * and derivation method. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param derivationMethod + * The derivation method + * + * @return boolean True if the ancestor type is derived from the reference + * type by the specifiied derivation method. + */ + public boolean isDOMDerivedFrom(String ancestorNS, String ancestorName, + int derivationMethod) { + // ancestor is null, retur false + if (ancestorName == null) + return false; + + // ancestor is anyType, return true + if (ancestorNS != null + && ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) + && ancestorName.equals(SchemaSymbols.ATTVAL_ANYTYPE) + && (derivationMethod == DERIVATION_RESTRICTION + && derivationMethod == DERIVATION_EXTENSION)) { + return true; + } + + // restriction + if ((derivationMethod & DERIVATION_RESTRICTION) != 0) { + if (isDerivedByRestriction(ancestorNS, ancestorName, + derivationMethod, this)) { + return true; + } + } + + // extension + if ((derivationMethod & DERIVATION_EXTENSION) != 0) { + if (isDerivedByExtension(ancestorNS, ancestorName, + derivationMethod, this)) { + return true; + } + } + + // list or union + if ((((derivationMethod & DERIVATION_LIST) != 0) || ((derivationMethod & DERIVATION_UNION) != 0)) + && ((derivationMethod & DERIVATION_RESTRICTION) == 0) + && ((derivationMethod & DERIVATION_EXTENSION) == 0)) { + + if (ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) + && ancestorName.equals(SchemaSymbols.ATTVAL_ANYTYPE)) { + ancestorName = SchemaSymbols.ATTVAL_ANYSIMPLETYPE; + } + + if(!(fName.equals(SchemaSymbols.ATTVAL_ANYTYPE) + && fTargetNamespace.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA))){ + if (fBaseType != null && fBaseType instanceof XSSimpleTypeDecl) { + + return ((XSSimpleTypeDecl) fBaseType).isDOMDerivedFrom(ancestorNS, + ancestorName, derivationMethod); + } else if (fBaseType != null + && fBaseType instanceof XSComplexTypeDecl) { + return ((XSComplexTypeDecl) fBaseType).isDOMDerivedFrom( + ancestorNS, ancestorName, derivationMethod); + } + } + } + + // If the value of the parameter is 0 i.e. no bit (corresponding to + // restriction, list, extension or union) is set to 1 for the + // derivationMethod parameter. + if (((derivationMethod & DERIVATION_EXTENSION) == 0) + && (((derivationMethod & DERIVATION_RESTRICTION) == 0) + && ((derivationMethod & DERIVATION_LIST) == 0) + && ((derivationMethod & DERIVATION_UNION) == 0))) { + return isDerivedByAny(ancestorNS, ancestorName, derivationMethod, this); + } + + return false; + } + + /** + * Checks if a type is derived from another by any combination of + * restriction, list ir union. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param derivationMethod + * A short indication the method of derivation + * @param type + * The reference type definition + * + * @return boolean True if the type is derived by any method for the + * reference type + */ + private boolean isDerivedByAny(String ancestorNS, String ancestorName, + int derivationMethod, XSTypeDefinition type) { + XSTypeDefinition oldType = null; + boolean derivedFrom = false; + while (type != null && type != oldType) { + + // If the ancestor type is reached or is the same as this type. + if ((ancestorName.equals(type.getName())) + && ((ancestorNS == null && type.getNamespace() == null) + || (ancestorNS != null && ancestorNS.equals(type.getNamespace())))) { + derivedFrom = true; + break; + } + + // Check if this type is derived from the base by restriction or + // extension + if (isDerivedByRestriction(ancestorNS, ancestorName, + derivationMethod, type)) { + return true; + } else if (!isDerivedByExtension(ancestorNS, ancestorName, + derivationMethod, type)) { + return true; + } + oldType = type; + type = type.getBaseType(); + } + + return derivedFrom; + } + + /** + * Checks if a type is derived from another by restriction. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param derivationMethod + * A short indication the method of derivation * + * @param type + * The reference type definition + * + * @return boolean True if the type is derived by restriciton for the + * reference type + */ + private boolean isDerivedByRestriction(String ancestorNS, + String ancestorName, int derivationMethod, XSTypeDefinition type) { + + XSTypeDefinition oldType = null; + while (type != null && type != oldType) { + + // ancestor is anySimpleType, return false + if (ancestorNS != null + && ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) + && ancestorName.equals(SchemaSymbols.ATTVAL_ANYSIMPLETYPE)) { + return false; + } + + // if the name and namespace of this type is the same as the + // ancestor return true + if ((ancestorName.equals(type.getName())) + && (ancestorNS != null && ancestorNS.equals(type.getNamespace())) + || ((type.getNamespace() == null && ancestorNS == null))) { + + return true; + } + + // If the base type is a complexType with simpleContent + if (type instanceof XSSimpleTypeDecl) { + if (ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) + && ancestorName.equals(SchemaSymbols.ATTVAL_ANYTYPE)) { + ancestorName = SchemaSymbols.ATTVAL_ANYSIMPLETYPE; + } + return ((XSSimpleTypeDecl) type).isDOMDerivedFrom(ancestorNS, + ancestorName, derivationMethod); + } else { + // If the base type is a complex type + // Every derivation step till the base type should be + // restriction. If not return false + if (((XSComplexTypeDecl) type).getDerivationMethod() != XSConstants.DERIVATION_RESTRICTION) { + return false; + } + } + oldType = type; + type = type.getBaseType(); + + } + + return false; + } + + /** + * Checks if a type is derived from another by extension. See: + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#TypeInfo-isDerivedFrom + * + * @param ancestorNS + * The namspace of the ancestor type declaration + * @param ancestorName + * The name of the ancestor type declaration + * @param derivationMethod + * A short indication the method of derivation + * @param type + * The reference type definition + * + * @return boolean True if the type is derived by extension for the + * reference type + */ + private boolean isDerivedByExtension(String ancestorNS, + String ancestorName, int derivationMethod, XSTypeDefinition type) { + + boolean extension = false; + XSTypeDefinition oldType = null; + while (type != null && type != oldType) { + // If ancestor is anySimpleType return false. + if (ancestorNS != null + && ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) + && ancestorName.equals(SchemaSymbols.ATTVAL_ANYSIMPLETYPE) + && SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(type.getNamespace()) + && SchemaSymbols.ATTVAL_ANYTYPE.equals(type.getName())) { + break; + } + + if ((ancestorName.equals(type.getName())) + && ((ancestorNS == null && type.getNamespace() == null) + || (ancestorNS != null && ancestorNS.equals(type.getNamespace())))) { + // returns true if atleast one derivation step was extension + return extension; + } + + // If the base type is a complexType with simpleContent + if (type instanceof XSSimpleTypeDecl) { + if (ancestorNS.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) + && ancestorName.equals(SchemaSymbols.ATTVAL_ANYTYPE)) { + ancestorName = SchemaSymbols.ATTVAL_ANYSIMPLETYPE; + } + + // derivationMethod extension will always return false for a + // simpleType, + // we treat it like a restriction + if ((derivationMethod & DERIVATION_EXTENSION) != 0) { + return extension + & ((XSSimpleTypeDecl) type).isDOMDerivedFrom( + ancestorNS, ancestorName, + (derivationMethod & DERIVATION_RESTRICTION)); + } else { + return extension + & ((XSSimpleTypeDecl) type).isDOMDerivedFrom( + ancestorNS, ancestorName, derivationMethod); + } + + } else { + // If the base type is a complex type + // At least one derivation step upto the ancestor type should be + // extension. + if (((XSComplexTypeDecl) type).getDerivationMethod() == XSConstants.DERIVATION_EXTENSION) { + extension = extension | true; + } + } + oldType = type; + type = type.getBaseType(); + } + + return false; + } + + + + public void reset(){ + fName = null; + fTargetNamespace = null; + fBaseType = null; + fDerivedBy = XSConstants.DERIVATION_RESTRICTION; + fFinal = XSConstants.DERIVATION_NONE; + fBlock = XSConstants.DERIVATION_NONE; + + fMiscFlags = 0; + + // reset attribute group + fAttrGrp.reset(); + fContentType = CONTENTTYPE_EMPTY; + fXSSimpleType = null; + fParticle = null; + fCMValidator = null; + fUPACMValidator = null; + if(fAnnotations != null) { + // help out the garbage collector + fAnnotations.clearXSObjectList(); + } + fAnnotations = null; + } + + /** + * Get the type of the object, i.e ELEMENT_DECLARATION. + */ + public short getType() { + return XSConstants.TYPE_DEFINITION; + } + + /** + * The name of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return getAnonymous() ? null : fName; + } + + /** + * A boolean that specifies if the type definition is anonymous. + * Convenience attribute. This is a field is not part of + * XML Schema component model. + */ + public boolean getAnonymous() { + return((fMiscFlags & CT_IS_ANONYMOUS) != 0); + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return fTargetNamespace; + } + + /** + * {base type definition} Either a simple type definition or a complex + * type definition. + */ + public XSTypeDefinition getBaseType() { + return fBaseType; + } + + /** + * {derivation method} Either extension or restriction. The valid constant + * value for this XSConstants EXTENTION, RESTRICTION. + */ + public short getDerivationMethod() { + return fDerivedBy; + } + + /** + * {final} For complex type definition it is a subset of {extension, + * restriction}. For simple type definition it is a subset of + * {extension, list, restriction, union}. + * @param derivation Extension, restriction, list, union constants + * (defined in XSConstants). + * @return True if derivation is in the final set, otherwise false. + */ + public boolean isFinal(short derivation) { + return (fFinal & derivation) != 0; + } + + /** + * {final} For complex type definition it is a subset of {extension, restriction}. + * + * @return A bit flag that represents: + * {extension, restriction) or none for complexTypes; + * {extension, list, restriction, union} or none for simpleTypes; + */ + public short getFinal() { + return fFinal; + } + + /** + * {abstract} A boolean. Complex types for which {abstract} is true must + * not be used as the {type definition} for the validation of element + * information items. + */ + public boolean getAbstract() { + return((fMiscFlags & CT_IS_ABSTRACT) != 0); + } + + /** + * {attribute uses} A set of attribute uses. + */ + public XSObjectList getAttributeUses() { + return fAttrGrp.getAttributeUses(); + } + + /** + * {attribute wildcard} Optional. A wildcard. + */ + public XSWildcard getAttributeWildcard() { + return fAttrGrp.getAttributeWildcard(); + } + + /** + * {content type} One of empty, a simple type definition (see + * simpleType, or mixed, element-only (see + * cmParticle). + */ + public short getContentType() { + return fContentType; + } + + /** + * A simple type definition corresponding to simple content model, + * otherwise null + */ + public XSSimpleTypeDefinition getSimpleType() { + return fXSSimpleType; + } + + /** + * A particle for mixed or element-only content model, otherwise + * null + */ + public XSParticle getParticle() { + return fParticle; + } + + /** + * {prohibited substitutions} A subset of {extension, restriction}. + * @param prohibited extention or restriction constants (defined in + * XSConstants). + * @return True if prohibited is a prohibited substitution, otherwise + * false. + */ + public boolean isProhibitedSubstitution(short prohibited) { + return (fBlock & prohibited) != 0; + } + + /** + * {prohibited substitutions} + * + * @return A bit flag corresponding to prohibited substitutions + */ + public short getProhibitedSubstitutions() { + return fBlock; + } + + /** + * Optional. Annotation. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return fNamespaceItem; + } + + void setNamespaceItem(XSNamespaceItem namespaceItem) { + fNamespaceItem = namespaceItem; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSComplexTypeDefinition#getAttributeUse(java.lang.String, java.lang.String) + */ + public XSAttributeUse getAttributeUse(String namespace, String name) { + return fAttrGrp.getAttributeUse(namespace, name); + } + + public String getTypeNamespace() { + return getNamespace(); + } + + public boolean isDerivedFrom(String typeNamespaceArg, String typeNameArg, int derivationMethod) { + return isDOMDerivedFrom(typeNamespaceArg, typeNameArg, derivationMethod); + } + +} // class XSComplexTypeDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSConstraints.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSConstraints.java new file mode 100644 index 0000000..383c7c2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSConstraints.java @@ -0,0 +1,1530 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Vector; + +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.dv.ValidationContext; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xs.models.CMBuilder; +import org.apache.xerces.impl.xs.models.XSCMValidator; +import org.apache.xerces.impl.xs.util.SimpleLocator; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * Constraints shared by traversers and validator + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class XSConstraints { + + // IHR: Visited on 2006-11-17 + // Added a boolean return value to particleValidRestriction (it was a void function) + // to help the checkRecurseLax to know when expansion has happened and no order is required + // (IHR@xbrl.org) (Ignacio@Hernandez-Ros.com) + + static final int OCCURRENCE_UNKNOWN = SchemaSymbols.OCCURRENCE_UNBOUNDED-1; + static final XSSimpleType STRING_TYPE = (XSSimpleType)SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_STRING); + + private static XSParticleDecl fEmptyParticle = null; + public static XSParticleDecl getEmptySequence() { + if (fEmptyParticle == null) { + XSModelGroupImpl group = new XSModelGroupImpl(); + group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE; + group.fParticleCount = 0; + group.fParticles = null; + group.fAnnotations = XSObjectListImpl.EMPTY_LIST; + XSParticleDecl particle = new XSParticleDecl(); + particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; + particle.fValue = group; + particle.fAnnotations = XSObjectListImpl.EMPTY_LIST; + fEmptyParticle = particle; + } + return fEmptyParticle; + } + + private static final Comparator ELEMENT_PARTICLE_COMPARATOR = new Comparator() { + + public int compare(Object o1, Object o2) { + XSParticleDecl pDecl1 = (XSParticleDecl) o1; + XSParticleDecl pDecl2 = (XSParticleDecl) o2; + XSElementDecl decl1 = (XSElementDecl) pDecl1.fValue; + XSElementDecl decl2 = (XSElementDecl) pDecl2.fValue; + + String namespace1 = decl1.getNamespace(); + String namespace2 = decl2.getNamespace(); + String name1 = decl1.getName(); + String name2 = decl2.getName(); + + boolean sameNamespace = (namespace1 == namespace2); + int namespaceComparison = 0; + + if (!sameNamespace) { + if (namespace1 != null) { + if (namespace2 != null){ + namespaceComparison = namespace1.compareTo(namespace2); + } + else { + namespaceComparison = 1; + } + } + else { + namespaceComparison = -1; + } + } + //This assumes that the names are never null. + return namespaceComparison != 0 ? namespaceComparison : name1.compareTo(name2); + } + }; + + /** + * check whether derived is valid derived from base, given a subset + * of {restriction, extension}.B + */ + public static boolean checkTypeDerivationOk(XSTypeDefinition derived, XSTypeDefinition base, short block) { + // if derived is anyType, then it's valid only if base is anyType too + if (derived == SchemaGrammar.fAnyType) + return derived == base; + // if derived is anySimpleType, then it's valid only if the base + // is ur-type + if (derived == SchemaGrammar.fAnySimpleType) { + return (base == SchemaGrammar.fAnyType || + base == SchemaGrammar.fAnySimpleType); + } + + // if derived is simple type + if (derived.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { + // if base is complex type + if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + // if base is anyType, change base to anySimpleType, + // otherwise, not valid + if (base == SchemaGrammar.fAnyType) + base = SchemaGrammar.fAnySimpleType; + else + return false; + } + return checkSimpleDerivation((XSSimpleType)derived, + (XSSimpleType)base, block); + } + else { + return checkComplexDerivation((XSComplexTypeDecl)derived, base, block); + } + } + + /** + * check whether simple type derived is valid derived from base, + * given a subset of {restriction, extension}. + */ + public static boolean checkSimpleDerivationOk(XSSimpleType derived, XSTypeDefinition base, short block) { + // if derived is anySimpleType, then it's valid only if the base + // is ur-type + if (derived == SchemaGrammar.fAnySimpleType) { + return (base == SchemaGrammar.fAnyType || + base == SchemaGrammar.fAnySimpleType); + } + + // if base is complex type + if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { + // if base is anyType, change base to anySimpleType, + // otherwise, not valid + if (base == SchemaGrammar.fAnyType) + base = SchemaGrammar.fAnySimpleType; + else + return false; + } + return checkSimpleDerivation((XSSimpleType)derived, + (XSSimpleType)base, block); + } + + /** + * check whether complex type derived is valid derived from base, + * given a subset of {restriction, extension}. + */ + public static boolean checkComplexDerivationOk(XSComplexTypeDecl derived, XSTypeDefinition base, short block) { + // if derived is anyType, then it's valid only if base is anyType too + if (derived == SchemaGrammar.fAnyType) + return derived == base; + return checkComplexDerivation((XSComplexTypeDecl)derived, base, block); + } + + /** + * Note: this will be a private method, and it assumes that derived is not + * anySimpleType, and base is not anyType. Another method will be + * introduced for public use, which will call this method. + */ + private static boolean checkSimpleDerivation(XSSimpleType derived, XSSimpleType base, short block) { + // 1 They are the same type definition. + if (derived == base) + return true; + + // 2 All of the following must be true: + // 2.1 restriction is not in the subset, or in the {final} of its own {base type definition}; + if ((block & XSConstants.DERIVATION_RESTRICTION) != 0 || + (derived.getBaseType().getFinal() & XSConstants.DERIVATION_RESTRICTION) != 0) { + return false; + } + + // 2.2 One of the following must be true: + // 2.2.1 D's base type definition is B. + XSSimpleType directBase = (XSSimpleType)derived.getBaseType(); + if (directBase == base) + return true; + + // 2.2.2 D's base type definition is not the simple ur-type definition and is validly derived from B given the subset, as defined by this constraint. + if (directBase != SchemaGrammar.fAnySimpleType && + checkSimpleDerivation(directBase, base, block)) { + return true; + } + + // 2.2.3 D's {variety} is list or union and B is the simple ur-type definition. + if ((derived.getVariety() == XSSimpleType.VARIETY_LIST || + derived.getVariety() == XSSimpleType.VARIETY_UNION) && + base == SchemaGrammar.fAnySimpleType) { + return true; + } + + // 2.2.4 B's {variety} is union and D is validly derived from a type definition in B's {member type definitions} given the subset, as defined by this constraint. + if (base.getVariety() == XSSimpleType.VARIETY_UNION) { + XSObjectList subUnionMemberDV = base.getMemberTypes(); + int subUnionSize = subUnionMemberDV.getLength(); + for (int i=0; i= 0; i--) { + SGHandler.addSubstitutionGroup(grammars[i].getSubstitutionGroups()); + } + + XSParticleDecl fakeDerived = new XSParticleDecl(); + XSParticleDecl fakeBase = new XSParticleDecl(); + fakeDerived.fType = XSParticleDecl.PARTICLE_MODELGROUP; + fakeBase.fType = XSParticleDecl.PARTICLE_MODELGROUP; + // before worrying about complexTypes, let's get + // groups redefined by restriction out of the way. + for (int g = grammars.length-1; g >= 0; g--) { + XSGroupDecl [] redefinedGroups = grammars[g].getRedefinedGroupDecls(); + SimpleLocator [] rgLocators = grammars[g].getRGLocators(); + for(int i=0; i= 0; i--) { + // get whether to skip EDC, and types need to be checked + keepType = 0; + fullChecked = grammars[i].fFullChecked; + types = grammars[i].getUncheckedComplexTypeDecls(); + ctLocators = grammars[i].getUncheckedCTLocators(); + // for each type + for (j = 0; j < types.length; j++) { + // if we've already full-checked this grammar, then + // skip the EDC constraint + if (!fullChecked) { + // 1. Element Decl Consistent + if (types[j].fParticle!=null) { + elemTable.clear(); + try { + checkElementDeclsConsistent(types[j], types[j].fParticle, + elemTable, SGHandler); + } + catch (XMLSchemaException e) { + reportSchemaError(errorReporter, ctLocators[j], + e.getKey(), + e.getArgs()); + } + } + } + + // 2. Particle Derivation + + if (types[j].fBaseType != null && + types[j].fBaseType != SchemaGrammar.fAnyType && + types[j].fDerivedBy == XSConstants.DERIVATION_RESTRICTION && + (types[j].fBaseType instanceof XSComplexTypeDecl)) { + + XSParticleDecl derivedParticle=types[j].fParticle; + XSParticleDecl baseParticle= + ((XSComplexTypeDecl)(types[j].fBaseType)).fParticle; + if (derivedParticle==null) { + if (baseParticle!=null && !baseParticle.emptiable()) { + reportSchemaError(errorReporter,ctLocators[j], + "derivation-ok-restriction.5.3.2", + new Object[]{types[j].fName, types[j].fBaseType.getName()}); + } + } + else if (baseParticle!=null) { + try { + particleValidRestriction(types[j].fParticle, + SGHandler, + ((XSComplexTypeDecl)(types[j].fBaseType)).fParticle, + SGHandler); + } catch (XMLSchemaException e) { + reportSchemaError(errorReporter, ctLocators[j], + e.getKey(), + e.getArgs()); + reportSchemaError(errorReporter, ctLocators[j], + "derivation-ok-restriction.5.4.2", + new Object[]{types[j].fName}); + } + } + else { + reportSchemaError(errorReporter, ctLocators[j], + "derivation-ok-restriction.5.4.2", + new Object[]{types[j].fName}); + } + } + // 3. UPA + // get the content model and check UPA + XSCMValidator cm = types[j].getContentModel(cmBuilder, true); + further = false; + if (cm != null) { + try { + further = cm.checkUniqueParticleAttribution(SGHandler); + } catch (XMLSchemaException e) { + reportSchemaError(errorReporter, ctLocators[j], + e.getKey(), + e.getArgs()); + } + } + // now report all errors + // REVISIT: do we want to report all errors? or just one? + /*for (k = errors.getErrorCodeNum()-1; k >= 0; k--) { + reportSchemaError(errorReporter, ctLocators[j], + errors.getErrorCode(k), + errors.getArgs(k)); + }*/ + + // if we are doing all checkings, and this one needs further + // checking, store it in the type array. + if (!fullChecked && further) + types[keepType++] = types[j]; + + // clear errors for the next type. + // REVISIT: do we want to report all errors? or just one? + //errors.clear(); + } + // we've done with the types in this grammar. if we are checking + // all constraints, need to trim type array to a proper size: + // only contain those need further checking. + // and mark this grammar that it only needs UPA checking. + if (!fullChecked) { + grammars[i].setUncheckedTypeNum(keepType); + grammars[i].fFullChecked = true; + } + } + } + + /* + Check that a given particle is a valid restriction of a base particle. + */ + + public static void checkElementDeclsConsistent(XSComplexTypeDecl type, + XSParticleDecl particle, + SymbolHash elemDeclHash, + SubstitutionGroupHandler sgHandler) + throws XMLSchemaException { + + // check for elements in the tree with the same name and namespace + + int pType = particle.fType; + + if (pType == XSParticleDecl.PARTICLE_WILDCARD) + return; + + if (pType == XSParticleDecl.PARTICLE_ELEMENT) { + XSElementDecl elem = (XSElementDecl)(particle.fValue); + findElemInTable(type, elem, elemDeclHash); + + if (elem.fScope == XSConstants.SCOPE_GLOBAL) { + // Check for subsitution groups. + XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(elem); + for (int i = 0; i < subGroup.length; i++) { + findElemInTable(type, subGroup[i], elemDeclHash); + } + } + return; + } + + XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue; + for (int i = 0; i < group.fParticleCount; i++) + checkElementDeclsConsistent(type, group.fParticles[i], elemDeclHash, sgHandler); + } + + public static void findElemInTable(XSComplexTypeDecl type, XSElementDecl elem, + SymbolHash elemDeclHash) + throws XMLSchemaException { + + // How can we avoid this concat? LM. + String name = elem.fName + "," + elem.fTargetNamespace; + + XSElementDecl existingElem = null; + if ((existingElem = (XSElementDecl)(elemDeclHash.get(name))) == null) { + // just add it in + elemDeclHash.put(name, elem); + } + else { + // If this is the same check element, we're O.K. + if (elem == existingElem) + return; + + if (elem.fType != existingElem.fType) { + // Types are not the same + throw new XMLSchemaException("cos-element-consistent", + new Object[] {type.fName, elem.fName}); + + } + } + } + + // Check that a given particle is a valid restriction of a base particle. + // + // IHR: 2006/11/17 + // Returns a boolean indicating if there has been expansion of substitution group + // in the bParticle. + // With this information the checkRecurseLax function knows when is + // to keep the order and when to ignore it. + private static boolean particleValidRestriction(XSParticleDecl dParticle, + SubstitutionGroupHandler dSGHandler, + XSParticleDecl bParticle, + SubstitutionGroupHandler bSGHandler) + throws XMLSchemaException { + return particleValidRestriction(dParticle, dSGHandler, bParticle, bSGHandler, true); + } + + private static boolean particleValidRestriction(XSParticleDecl dParticle, + SubstitutionGroupHandler dSGHandler, + XSParticleDecl bParticle, + SubstitutionGroupHandler bSGHandler, + boolean checkWCOccurrence) + throws XMLSchemaException { + + Vector dChildren = null; + Vector bChildren = null; + int dMinEffectiveTotalRange=OCCURRENCE_UNKNOWN; + int dMaxEffectiveTotalRange=OCCURRENCE_UNKNOWN; + + // By default there has been no expansion + boolean bExpansionHappened = false; + + // Check for empty particles. If either base or derived particle is empty, + // (and the other isn't) it's an error. + if (dParticle.isEmpty() && !bParticle.emptiable()) { + throw new XMLSchemaException("cos-particle-restrict.a", null); + } + else if (!dParticle.isEmpty() && bParticle.isEmpty()) { + throw new XMLSchemaException("cos-particle-restrict.b", null); + } + + // + // Do setup prior to invoking the Particle (Restriction) cases. + // This involves: + // - removing pointless occurrences for groups, and retrieving a vector of + // non-pointless children + // - turning top-level elements with substitution groups into CHOICE groups. + // + + short dType = dParticle.fType; + // + // Handle pointless groups for the derived particle + // + if (dType == XSParticleDecl.PARTICLE_MODELGROUP) { + dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor; + + // Find a group, starting with this particle, with more than 1 child. There + // may be none, and the particle of interest trivially becomes an element or + // wildcard. + XSParticleDecl dtmp = getNonUnaryGroup(dParticle); + if (dtmp != dParticle) { + // Particle has been replaced. Retrieve new type info. + dParticle = dtmp; + dType = dParticle.fType; + if (dType == XSParticleDecl.PARTICLE_MODELGROUP) + dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor; + } + + // Fill in a vector with the children of the particle, removing any + // pointless model groups in the process. + dChildren = removePointlessChildren(dParticle); + } + + int dMinOccurs = dParticle.fMinOccurs; + int dMaxOccurs = dParticle.fMaxOccurs; + + // + // For elements which are the heads of substitution groups, treat as CHOICE + // + if (dSGHandler != null && dType == XSParticleDecl.PARTICLE_ELEMENT) { + XSElementDecl dElement = (XSElementDecl)dParticle.fValue; + + if (dElement.fScope == XSConstants.SCOPE_GLOBAL) { + // Check for subsitution groups. Treat any element that has a + // subsitution group as a choice. Fill in the children vector with the + // members of the substitution group + XSElementDecl[] subGroup = dSGHandler.getSubstitutionGroup(dElement); + if (subGroup.length >0 ) { + // Now, set the type to be CHOICE. The "group" will have the same + // occurrence information as the original particle. + dType = XSModelGroupImpl.MODELGROUP_CHOICE; + dMinEffectiveTotalRange = dMinOccurs; + dMaxEffectiveTotalRange = dMaxOccurs; + + // Fill in the vector of children + dChildren = new Vector(subGroup.length+1); + for (int i = 0; i < subGroup.length; i++) { + addElementToParticleVector(dChildren, subGroup[i]); + } + addElementToParticleVector(dChildren, dElement); + Collections.sort(dChildren, ELEMENT_PARTICLE_COMPARATOR); + + // Set the handler to null, to indicate that we've finished handling + // substitution groups for this particle. + dSGHandler = null; + } + } + } + + short bType = bParticle.fType; + // + // Handle pointless groups for the base particle + // + if (bType == XSParticleDecl.PARTICLE_MODELGROUP) { + bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor; + + // Find a group, starting with this particle, with more than 1 child. There + // may be none, and the particle of interest trivially becomes an element or + // wildcard. + XSParticleDecl btmp = getNonUnaryGroup(bParticle); + if (btmp != bParticle) { + // Particle has been replaced. Retrieve new type info. + bParticle = btmp; + bType = bParticle.fType; + if (bType == XSParticleDecl.PARTICLE_MODELGROUP) + bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor; + } + + // Fill in a vector with the children of the particle, removing any + // pointless model groups in the process. + bChildren = removePointlessChildren(bParticle); + } + + int bMinOccurs = bParticle.fMinOccurs; + int bMaxOccurs = bParticle.fMaxOccurs; + + if (bSGHandler != null && bType == XSParticleDecl.PARTICLE_ELEMENT) { + XSElementDecl bElement = (XSElementDecl)bParticle.fValue; + + if (bElement.fScope == XSConstants.SCOPE_GLOBAL) { + // Check for subsitution groups. Treat any element that has a + // subsitution group as a choice. Fill in the children vector with the + // members of the substitution group + XSElementDecl[] bsubGroup = bSGHandler.getSubstitutionGroup(bElement); + if (bsubGroup.length >0 ) { + // Now, set the type to be CHOICE + bType = XSModelGroupImpl.MODELGROUP_CHOICE; + + bChildren = new Vector(bsubGroup.length+1); + for (int i = 0; i < bsubGroup.length; i++) { + addElementToParticleVector(bChildren, bsubGroup[i]); + } + addElementToParticleVector(bChildren, bElement); + Collections.sort(bChildren, ELEMENT_PARTICLE_COMPARATOR); + // Set the handler to null, to indicate that we've finished handling + // substitution groups for this particle. + bSGHandler = null; + + // if we are here expansion of bParticle happened + bExpansionHappened = true; + } + } + } + + // + // O.K. - Figure out which particle derivation rule applies and call it + // + switch (dType) { + case XSParticleDecl.PARTICLE_ELEMENT: + { + switch (bType) { + + // Elt:Elt NameAndTypeOK + case XSParticleDecl.PARTICLE_ELEMENT: + { + checkNameAndTypeOK((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs, + (XSElementDecl)bParticle.fValue,bMinOccurs,bMaxOccurs); + return bExpansionHappened; + } + + // Elt:Any NSCompat + case XSParticleDecl.PARTICLE_WILDCARD: + { + checkNSCompat((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs, + (XSWildcardDecl)bParticle.fValue,bMinOccurs,bMaxOccurs, + checkWCOccurrence); + return bExpansionHappened; + } + + // Elt:All RecurseAsIfGroup + case XSModelGroupImpl.MODELGROUP_CHOICE: + { + // Treat the element as if it were in a group of the same type + // as the base Particle + dChildren = new Vector(); + dChildren.addElement(dParticle); + + checkRecurseLax(dChildren, 1, 1, dSGHandler, + bChildren, bMinOccurs, bMaxOccurs, bSGHandler); + return bExpansionHappened; + } + case XSModelGroupImpl.MODELGROUP_SEQUENCE: + case XSModelGroupImpl.MODELGROUP_ALL: + { + // Treat the element as if it were in a group of the same type + // as the base Particle + dChildren = new Vector(); + dChildren.addElement(dParticle); + + checkRecurse(dChildren, 1, 1, dSGHandler, + bChildren, bMinOccurs, bMaxOccurs, bSGHandler); + return bExpansionHappened; + } + + default: + { + throw new XMLSchemaException("Internal-Error", + new Object[]{"in particleValidRestriction"}); + } + } + } + + case XSParticleDecl.PARTICLE_WILDCARD: + { + switch (bType) { + + // Any:Any NSSubset + case XSParticleDecl.PARTICLE_WILDCARD: + { + checkNSSubset((XSWildcardDecl)dParticle.fValue, dMinOccurs, dMaxOccurs, + (XSWildcardDecl)bParticle.fValue, bMinOccurs, bMaxOccurs); + return bExpansionHappened; + } + + case XSModelGroupImpl.MODELGROUP_CHOICE: + case XSModelGroupImpl.MODELGROUP_SEQUENCE: + case XSModelGroupImpl.MODELGROUP_ALL: + case XSParticleDecl.PARTICLE_ELEMENT: + { + throw new XMLSchemaException("cos-particle-restrict.2", + new Object[]{"any:choice,sequence,all,elt"}); + } + + default: + { + throw new XMLSchemaException("Internal-Error", + new Object[]{"in particleValidRestriction"}); + } + } + } + + case XSModelGroupImpl.MODELGROUP_ALL: + { + switch (bType) { + + // All:Any NSRecurseCheckCardinality + case XSParticleDecl.PARTICLE_WILDCARD: + { + if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) + dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); + if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) + dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); + + checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, + dMaxEffectiveTotalRange, + dSGHandler, + bParticle,bMinOccurs,bMaxOccurs, + checkWCOccurrence); + + return bExpansionHappened; + } + + case XSModelGroupImpl.MODELGROUP_ALL: + { + checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, + bChildren, bMinOccurs, bMaxOccurs, bSGHandler); + return bExpansionHappened; + } + + case XSModelGroupImpl.MODELGROUP_CHOICE: + case XSModelGroupImpl.MODELGROUP_SEQUENCE: + case XSParticleDecl.PARTICLE_ELEMENT: + { + throw new XMLSchemaException("cos-particle-restrict.2", + new Object[]{"all:choice,sequence,elt"}); + } + + default: + { + throw new XMLSchemaException("Internal-Error", + new Object[]{"in particleValidRestriction"}); + } + } + } + + case XSModelGroupImpl.MODELGROUP_CHOICE: + { + switch (bType) { + + // Choice:Any NSRecurseCheckCardinality + case XSParticleDecl.PARTICLE_WILDCARD: + { + if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) + dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); + if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) + dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); + + checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, + dMaxEffectiveTotalRange, + dSGHandler, + bParticle,bMinOccurs,bMaxOccurs, + checkWCOccurrence); + return bExpansionHappened; + } + + case XSModelGroupImpl.MODELGROUP_CHOICE: + { + checkRecurseLax(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, + bChildren, bMinOccurs, bMaxOccurs, bSGHandler); + return bExpansionHappened; + } + + case XSModelGroupImpl.MODELGROUP_ALL: + case XSModelGroupImpl.MODELGROUP_SEQUENCE: + case XSParticleDecl.PARTICLE_ELEMENT: + { + throw new XMLSchemaException("cos-particle-restrict.2", + new Object[]{"choice:all,sequence,elt"}); + } + + default: + { + throw new XMLSchemaException("Internal-Error", + new Object[]{"in particleValidRestriction"}); + } + } + } + + + case XSModelGroupImpl.MODELGROUP_SEQUENCE: + { + switch (bType) { + + // Choice:Any NSRecurseCheckCardinality + case XSParticleDecl.PARTICLE_WILDCARD: + { + if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) + dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); + if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) + dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); + + checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, + dMaxEffectiveTotalRange, + dSGHandler, + bParticle,bMinOccurs,bMaxOccurs, + checkWCOccurrence); + return bExpansionHappened; + } + + case XSModelGroupImpl.MODELGROUP_ALL: + { + checkRecurseUnordered(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, + bChildren, bMinOccurs, bMaxOccurs, bSGHandler); + return bExpansionHappened; + } + + case XSModelGroupImpl.MODELGROUP_SEQUENCE: + { + checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, + bChildren, bMinOccurs, bMaxOccurs, bSGHandler); + return bExpansionHappened; + } + + case XSModelGroupImpl.MODELGROUP_CHOICE: + { + int min1 = dMinOccurs * dChildren.size(); + int max1 = (dMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED)? + dMaxOccurs : dMaxOccurs * dChildren.size(); + checkMapAndSum(dChildren, min1, max1, dSGHandler, + bChildren, bMinOccurs, bMaxOccurs, bSGHandler); + return bExpansionHappened; + } + + case XSParticleDecl.PARTICLE_ELEMENT: + { + throw new XMLSchemaException("cos-particle-restrict.2", + new Object[]{"seq:elt"}); + } + + default: + { + throw new XMLSchemaException("Internal-Error", + new Object[]{"in particleValidRestriction"}); + } + } + } + + } + + return bExpansionHappened; + } + + private static void addElementToParticleVector (Vector v, XSElementDecl d) { + + XSParticleDecl p = new XSParticleDecl(); + p.fValue = d; + p.fType = XSParticleDecl.PARTICLE_ELEMENT; + v.addElement(p); + + } + + private static XSParticleDecl getNonUnaryGroup(XSParticleDecl p) { + + if (p.fType == XSParticleDecl.PARTICLE_ELEMENT || + p.fType == XSParticleDecl.PARTICLE_WILDCARD) + return p; + + if (p.fMinOccurs==1 && p.fMaxOccurs==1 && + p.fValue!=null && ((XSModelGroupImpl)p.fValue).fParticleCount == 1) + return getNonUnaryGroup(((XSModelGroupImpl)p.fValue).fParticles[0]); + else + return p; + } + + private static Vector removePointlessChildren(XSParticleDecl p) { + + if (p.fType == XSParticleDecl.PARTICLE_ELEMENT || + p.fType == XSParticleDecl.PARTICLE_WILDCARD) + return null; + + Vector children = new Vector(); + + XSModelGroupImpl group = (XSModelGroupImpl)p.fValue; + for (int i = 0; i < group.fParticleCount; i++) + gatherChildren(group.fCompositor, group.fParticles[i], children); + + return children; + } + + + private static void gatherChildren(int parentType, XSParticleDecl p, Vector children) { + + int min = p.fMinOccurs; + int max = p.fMaxOccurs; + int type = p.fType; + if (type == XSParticleDecl.PARTICLE_MODELGROUP) + type = ((XSModelGroupImpl)p.fValue).fCompositor; + + if (type == XSParticleDecl.PARTICLE_ELEMENT || + type== XSParticleDecl.PARTICLE_WILDCARD) { + children.addElement(p); + return; + } + + if (! (min==1 && max==1)) { + children.addElement(p); + } + else if (parentType == type) { + XSModelGroupImpl group = (XSModelGroupImpl)p.fValue; + for (int i = 0; i < group.fParticleCount; i++) + gatherChildren(type, group.fParticles[i], children); + } + else if (!p.isEmpty()) { + children.addElement(p); + } + + } + + private static void checkNameAndTypeOK(XSElementDecl dElement, int dMin, int dMax, + XSElementDecl bElement, int bMin, int bMax) + throws XMLSchemaException { + + + // + // Check that the names are the same + // + if (dElement.fName != bElement.fName || + dElement.fTargetNamespace != bElement.fTargetNamespace) { + throw new XMLSchemaException( + "rcase-NameAndTypeOK.1",new Object[]{dElement.fName, + dElement.fTargetNamespace, bElement.fName, bElement.fTargetNamespace}); + } + + // + // Check nillable + // + if (!bElement.getNillable() && dElement.getNillable()) { + throw new XMLSchemaException("rcase-NameAndTypeOK.2", + new Object[]{dElement.fName}); + } + + // + // Check occurrence range + // + if (!checkOccurrenceRange(dMin, dMax, bMin, bMax)) { + throw new XMLSchemaException("rcase-NameAndTypeOK.3", + new Object[]{ + dElement.fName, + Integer.toString(dMin), + dMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(dMax), + Integer.toString(bMin), + bMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(bMax)}); + } + + // + // Check for consistent fixed values + // + if (bElement.getConstraintType() == XSConstants.VC_FIXED) { + // derived one has to have a fixed value + if (dElement.getConstraintType() != XSConstants.VC_FIXED) { + throw new XMLSchemaException("rcase-NameAndTypeOK.4.a", + new Object[]{dElement.fName, bElement.fDefault.stringValue()}); + } + + // get simple type + boolean isSimple = false; + if (dElement.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE || + ((XSComplexTypeDecl)dElement.fType).fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { + isSimple = true; + } + + // if there is no simple type, then compare based on string + if (!isSimple && !bElement.fDefault.normalizedValue.equals(dElement.fDefault.normalizedValue) || + isSimple && !bElement.fDefault.actualValue.equals(dElement.fDefault.actualValue)) { + throw new XMLSchemaException("rcase-NameAndTypeOK.4.b", + new Object[]{dElement.fName, + dElement.fDefault.stringValue(), + bElement.fDefault.stringValue()}); + } + } + + // + // Check identity constraints + // + checkIDConstraintRestriction(dElement, bElement); + + // + // Check for disallowed substitutions + // + int blockSet1 = dElement.fBlock; + int blockSet2 = bElement.fBlock; + if (((blockSet1 & blockSet2)!=blockSet2) || + (blockSet1==XSConstants.DERIVATION_NONE && blockSet2!=XSConstants.DERIVATION_NONE)) + throw new XMLSchemaException("rcase-NameAndTypeOK.6", + new Object[]{dElement.fName}); + + + // + // Check that the derived element's type is derived from the base's. + // + if (!checkTypeDerivationOk(dElement.fType, bElement.fType, + (short)(XSConstants.DERIVATION_EXTENSION|XSConstants.DERIVATION_LIST|XSConstants.DERIVATION_UNION))) { + throw new XMLSchemaException("rcase-NameAndTypeOK.7", + new Object[]{dElement.fName, dElement.fType.getName(), bElement.fType.getName()}); + } + + } + + + private static void checkIDConstraintRestriction(XSElementDecl derivedElemDecl, + XSElementDecl baseElemDecl) + throws XMLSchemaException { + // TODO + } // checkIDConstraintRestriction + + + private static boolean checkOccurrenceRange(int min1, int max1, int min2, int max2) { + + if ((min1 >= min2) && + ((max2==SchemaSymbols.OCCURRENCE_UNBOUNDED) || + (max1!=SchemaSymbols.OCCURRENCE_UNBOUNDED && max1<=max2))) + return true; + else + return false; + } + + private static void checkNSCompat(XSElementDecl elem, int min1, int max1, + XSWildcardDecl wildcard, int min2, int max2, + boolean checkWCOccurrence) + throws XMLSchemaException { + + // check Occurrence ranges + if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) { + throw new XMLSchemaException("rcase-NSCompat.2", + new Object[]{ + elem.fName, + Integer.toString(min1), + max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), + Integer.toString(min2), + max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); + } + + // check wildcard allows namespace of element + if (!wildcard.allowNamespace(elem.fTargetNamespace)) { + throw new XMLSchemaException("rcase-NSCompat.1", + new Object[]{elem.fName,elem.fTargetNamespace}); + } + + } + + private static void checkNSSubset(XSWildcardDecl dWildcard, int min1, int max1, + XSWildcardDecl bWildcard, int min2, int max2) + throws XMLSchemaException { + + // check Occurrence ranges + if (!checkOccurrenceRange(min1,max1,min2,max2)) { + throw new XMLSchemaException("rcase-NSSubset.2", new Object[]{ + Integer.toString(min1), + max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), + Integer.toString(min2), + max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); + } + + // check wildcard subset + if (!dWildcard.isSubsetOf(bWildcard)) { + throw new XMLSchemaException("rcase-NSSubset.1", null); + } + + if (dWildcard.weakerProcessContents(bWildcard)) { + throw new XMLSchemaException("rcase-NSSubset.3", + new Object[]{dWildcard.getProcessContentsAsString(), + bWildcard.getProcessContentsAsString()}); + } + + } + + + private static void checkNSRecurseCheckCardinality(Vector children, int min1, int max1, + SubstitutionGroupHandler dSGHandler, + XSParticleDecl wildcard, int min2, int max2, + boolean checkWCOccurrence) + throws XMLSchemaException { + + + // check Occurrence ranges + if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) { + throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.2", new Object[]{ + Integer.toString(min1), + max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), + Integer.toString(min2), + max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); + } + + // Check that each member of the group is a valid restriction of the wildcard + int count = children.size(); + try { + for (int i = 0; i < count; i++) { + XSParticleDecl particle1 = (XSParticleDecl)children.elementAt(i); + particleValidRestriction(particle1, dSGHandler, wildcard, null, false); + + } + } + // REVISIT: should we really just ignore original cause of this error? + // how can we report it? + catch (XMLSchemaException e) { + throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.1", null); + } + + } + + private static void checkRecurse(Vector dChildren, int min1, int max1, + SubstitutionGroupHandler dSGHandler, + Vector bChildren, int min2, int max2, + SubstitutionGroupHandler bSGHandler) + throws XMLSchemaException { + + // check Occurrence ranges + if (!checkOccurrenceRange(min1,max1,min2,max2)) { + throw new XMLSchemaException("rcase-Recurse.1", new Object[]{ + Integer.toString(min1), + max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), + Integer.toString(min2), + max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); + } + + int count1= dChildren.size(); + int count2= bChildren.size(); + + int current = 0; + label: for (int i = 0; i + // + // + // + // + // + // + // + // + // + + // check Occurrence ranges + if (!checkOccurrenceRange(min1,max1,min2,max2)) { + throw new XMLSchemaException("rcase-MapAndSum.2", + new Object[]{Integer.toString(min1), + max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), + Integer.toString(min2), + max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); + } + + int count1 = dChildren.size(); + int count2 = bChildren.size(); + + label: for (int i = 0; i= 0; i--) { + if (subGroup[i].fName == element2.fName && + subGroup[i].fTargetNamespace == element2.fTargetNamespace) { + return true; + } + } + + // or if there is an element decl in element2's substitution group, + // who has the same name/namespace with element1 + subGroup = sgHandler.getSubstitutionGroup(element2); + for (int i = subGroup.length-1; i >= 0; i--) { + if (subGroup[i].fName == element1.fName && + subGroup[i].fTargetNamespace == element1.fTargetNamespace) { + return true; + } + } + + return false; + } + + // to check whether an element overlaps with a wildcard, + // as defined in constraint UPA + public static boolean overlapUPA(XSElementDecl element, + XSWildcardDecl wildcard, + SubstitutionGroupHandler sgHandler) { + // if the wildcard allows the element + if (wildcard.allowNamespace(element.fTargetNamespace)) + return true; + + // or if the wildcard allows any element in the substitution group + XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element); + for (int i = subGroup.length-1; i >= 0; i--) { + if (wildcard.allowNamespace(subGroup[i].fTargetNamespace)) + return true; + } + + return false; + } + + public static boolean overlapUPA(XSWildcardDecl wildcard1, + XSWildcardDecl wildcard2) { + // if the intersection of the two wildcard is not empty list + XSWildcardDecl intersect = wildcard1.performIntersectionWith(wildcard2, wildcard1.fProcessContents); + if (intersect == null || + intersect.fType != XSWildcardDecl.NSCONSTRAINT_LIST || + intersect.fNamespaceList.length != 0) { + return true; + } + + return false; + } + + // call one of the above methods according to the type of decls + public static boolean overlapUPA(Object decl1, Object decl2, + SubstitutionGroupHandler sgHandler) { + if (decl1 instanceof XSElementDecl) { + if (decl2 instanceof XSElementDecl) { + return overlapUPA((XSElementDecl)decl1, + (XSElementDecl)decl2, + sgHandler); + } + else { + return overlapUPA((XSElementDecl)decl1, + (XSWildcardDecl)decl2, + sgHandler); + } + } + else { + if (decl2 instanceof XSElementDecl) { + return overlapUPA((XSElementDecl)decl2, + (XSWildcardDecl)decl1, + sgHandler); + } + else { + return overlapUPA((XSWildcardDecl)decl1, + (XSWildcardDecl)decl2); + } + } + } + +} // class XSContraints diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSDDescription.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSDDescription.java new file mode 100644 index 0000000..2253bf4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSDDescription.java @@ -0,0 +1,260 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.util.XMLResourceIdentifierImpl; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLSchemaDescription; + +/** + * All information specific to XML Schema grammars. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @author Neeraj Bajaj, SUN Microsystems. + * + * @version $Id$ + */ +public class XSDDescription extends XMLResourceIdentifierImpl + implements XMLSchemaDescription { + // used to indicate what triggered the call + /** + * Indicate that this description was just initialized. + */ + public final static short CONTEXT_INITIALIZE = -1; + /** + * Indicate that the current schema document is d by another + * schema document. + */ + public final static short CONTEXT_INCLUDE = 0; + /** + * Indicate that the current schema document is d by another + * schema document. + */ + public final static short CONTEXT_REDEFINE = 1; + /** + * Indicate that the current schema document is ed by another + * schema document. + */ + public final static short CONTEXT_IMPORT = 2; + /** + * Indicate that the current schema document is being preparsed. + */ + public final static short CONTEXT_PREPARSE = 3; + /** + * Indicate that the parse of the current schema document is triggered + * by xsi:schemaLocation/noNamespaceSchemaLocation attribute(s) in the + * instance document. This value is only used if we don't defer the loading + * of schema documents. + */ + public final static short CONTEXT_INSTANCE = 4; + /** + * Indicate that the parse of the current schema document is triggered by + * the occurrence of an element whose namespace is the target namespace + * of this schema document. This value is only used if we do defer the + * loading of schema documents until a component from that namespace is + * referenced from the instance. + */ + public final static short CONTEXT_ELEMENT = 5; + /** + * Indicate that the parse of the current schema document is triggered by + * the occurrence of an attribute whose namespace is the target namespace + * of this schema document. This value is only used if we do defer the + * loading of schema documents until a component from that namespace is + * referenced from the instance. + */ + public final static short CONTEXT_ATTRIBUTE = 6; + /** + * Indicate that the parse of the current schema document is triggered by + * the occurrence of an "xsi:type" attribute, whose value (a QName) has + * the target namespace of this schema document as its namespace. + * This value is only used if we do defer the loading of schema documents + * until a component from that namespace is referenced from the instance. + */ + public final static short CONTEXT_XSITYPE = 7; + + // REVISIT: write description of these fields + protected short fContextType; + protected String [] fLocationHints ; + protected QName fTriggeringComponent; + protected QName fEnclosedElementName; + protected XMLAttributes fAttributes; + + /** + * the type of the grammar (e.g., DTD or XSD); + * + * @see org.apache.xerces.xni.grammars.Grammar + */ + public String getGrammarType() { + return XMLGrammarDescription.XML_SCHEMA; + } + + /** + * Get the context. The returned value is one of the pre-defined + * CONTEXT_xxx constants. + * + * @return the value indicating the context + */ + public short getContextType() { + return fContextType ; + } + + /** + * If the context is "include" or "redefine", then return the target + * namespace of the enclosing schema document; otherwise, the expected + * target namespace of this document. + * + * @return the expected/enclosing target namespace + */ + public String getTargetNamespace() { + return fNamespace; + } + + /** + * For import and references from the instance document, it's possible to + * have multiple hints for one namespace. So this method returns an array, + * which contains all location hints. + * + * @return an array of all location hints associated to the expected + * target namespace + */ + public String[] getLocationHints() { + return fLocationHints ; + } + + /** + * If a call is triggered by an element/attribute/xsi:type in the instance, + * this call returns the name of such triggering component: the name of + * the element/attribute, or the value of the xsi:type. + * + * @return the name of the triggering component + */ + public QName getTriggeringComponent() { + return fTriggeringComponent ; + } + + /** + * If a call is triggered by an attribute or xsi:type, then this mehtod + * returns the enclosing element of such element. + * + * @return the name of the enclosing element + */ + public QName getEnclosingElementName() { + return fEnclosedElementName ; + } + + /** + * If a call is triggered by an element/attribute/xsi:type in the instance, + * this call returns all attribute of such element (or enclosing element). + * + * @return all attributes of the tiggering/enclosing element + */ + public XMLAttributes getAttributes() { + return fAttributes; + } + + public boolean fromInstance() { + return fContextType == CONTEXT_ATTRIBUTE || + fContextType == CONTEXT_ELEMENT || + fContextType == CONTEXT_INSTANCE || + fContextType == CONTEXT_XSITYPE; + } + + /** + * Compares this grammar with the given grammar. Currently, we compare + * the target namespaces. + * + * @param descObj The description of the grammar to be compared with + * @return True if they are equal, else false + */ + public boolean equals(Object descObj) { + if(!(descObj instanceof XMLSchemaDescription)) return false; + XMLSchemaDescription desc = (XMLSchemaDescription)descObj; + if (fNamespace != null) + return fNamespace.equals(desc.getTargetNamespace()); + else // fNamespace == null + return desc.getTargetNamespace() == null; + } + + /** + * Returns the hash code of this grammar + * + * @return The hash code + */ + public int hashCode() { + return (fNamespace == null) ? 0 : fNamespace.hashCode(); + } + + public void setContextType(short contextType){ + fContextType = contextType ; + } + + public void setTargetNamespace(String targetNamespace){ + fNamespace = targetNamespace ; + } + + public void setLocationHints(String [] locationHints){ + int length = locationHints.length ; + fLocationHints = new String[length]; + System.arraycopy(locationHints, 0, fLocationHints, 0, length); + //fLocationHints = locationHints ; + } + + public void setTriggeringComponent(QName triggeringComponent){ + fTriggeringComponent = triggeringComponent ; + } + + public void setEnclosingElementName(QName enclosedElementName){ + fEnclosedElementName = enclosedElementName ; + } + + public void setAttributes(XMLAttributes attributes){ + fAttributes = attributes ; + } + + /** + * resets all the fields + */ + public void reset(){ + super.clear(); + fContextType = CONTEXT_INITIALIZE; + fLocationHints = null ; + fTriggeringComponent = null ; + fEnclosedElementName = null ; + fAttributes = null ; + } + + public XSDDescription makeClone() { + XSDDescription desc = new XSDDescription(); + desc.fAttributes = this.fAttributes; + desc.fBaseSystemId = this.fBaseSystemId; + desc.fContextType = this.fContextType; + desc.fEnclosedElementName = this.fEnclosedElementName; + desc.fExpandedSystemId = this.fExpandedSystemId; + desc.fLiteralSystemId = this.fLiteralSystemId; + desc.fLocationHints = this.fLocationHints; + desc.fPublicId = this.fPublicId; + desc.fNamespace = this.fNamespace; + desc.fTriggeringComponent = this.fTriggeringComponent; + return desc; + } + +} // XSDDescription diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSDeclarationPool.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSDeclarationPool.java new file mode 100644 index 0000000..d453a86 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSDeclarationPool.java @@ -0,0 +1,315 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl; +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; + +/** + * This class is pool that enables caching of XML Schema declaration objects. + * Before a compiled grammar object is garbage collected, + * the implementation will add all XML Schema component + * declarations to the pool. + * Note: The cashing mechanism is not implemented yet. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public final class XSDeclarationPool { + /** Chunk shift (8). */ + private static final int CHUNK_SHIFT = 8; // 2^8 = 256 + + /** Chunk size (1 << CHUNK_SHIFT). */ + private static final int CHUNK_SIZE = 1 << CHUNK_SHIFT; + + /** Chunk mask (CHUNK_SIZE - 1). */ + private static final int CHUNK_MASK = CHUNK_SIZE - 1; + + /** Initial chunk count (). */ + private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k + + /** Element declaration pool*/ + private XSElementDecl fElementDecl[][] = new XSElementDecl[INITIAL_CHUNK_COUNT][]; + private int fElementDeclIndex = 0; + + /** Particle declaration pool */ + private XSParticleDecl fParticleDecl[][] = new XSParticleDecl[INITIAL_CHUNK_COUNT][]; + private int fParticleDeclIndex = 0; + + /** Particle declaration pool */ + private XSModelGroupImpl fModelGroup[][] = new XSModelGroupImpl[INITIAL_CHUNK_COUNT][]; + private int fModelGroupIndex = 0; + + /** Attribute declaration pool */ + private XSAttributeDecl fAttrDecl[][] = new XSAttributeDecl[INITIAL_CHUNK_COUNT][]; + private int fAttrDeclIndex = 0; + + /** ComplexType declaration pool */ + private XSComplexTypeDecl fCTDecl[][] = new XSComplexTypeDecl[INITIAL_CHUNK_COUNT][]; + private int fCTDeclIndex = 0; + + /** SimpleType declaration pool */ + private XSSimpleTypeDecl fSTDecl[][] = new XSSimpleTypeDecl[INITIAL_CHUNK_COUNT][]; + private int fSTDeclIndex = 0; + + /** AttributeUse declaration pool */ + private XSAttributeUseImpl fAttributeUse[][] = new XSAttributeUseImpl[INITIAL_CHUNK_COUNT][]; + private int fAttributeUseIndex = 0; + + private SchemaDVFactoryImpl dvFactory; + public void setDVFactory(SchemaDVFactoryImpl dvFactory) { + this.dvFactory = dvFactory; + } + + public final XSElementDecl getElementDecl(){ + int chunk = fElementDeclIndex >> CHUNK_SHIFT; + int index = fElementDeclIndex & CHUNK_MASK; + ensureElementDeclCapacity(chunk); + if (fElementDecl[chunk][index] == null) { + fElementDecl[chunk][index] = new XSElementDecl(); + } else { + fElementDecl[chunk][index].reset(); + } + fElementDeclIndex++; + return fElementDecl[chunk][index]; + } + + public final XSAttributeDecl getAttributeDecl(){ + int chunk = fAttrDeclIndex >> CHUNK_SHIFT; + int index = fAttrDeclIndex & CHUNK_MASK; + ensureAttrDeclCapacity(chunk); + if (fAttrDecl[chunk][index] == null) { + fAttrDecl[chunk][index] = new XSAttributeDecl(); + } else { + fAttrDecl[chunk][index].reset(); + } + fAttrDeclIndex++; + return fAttrDecl[chunk][index]; + + } + + public final XSAttributeUseImpl getAttributeUse(){ + int chunk = fAttributeUseIndex >> CHUNK_SHIFT; + int index = fAttributeUseIndex & CHUNK_MASK; + ensureAttributeUseCapacity(chunk); + if (fAttributeUse[chunk][index] == null) { + fAttributeUse[chunk][index] = new XSAttributeUseImpl(); + } else { + fAttributeUse[chunk][index].reset(); + } + fAttributeUseIndex++; + return fAttributeUse[chunk][index]; + + } + + public final XSComplexTypeDecl getComplexTypeDecl(){ + int chunk = fCTDeclIndex >> CHUNK_SHIFT; + int index = fCTDeclIndex & CHUNK_MASK; + ensureCTDeclCapacity(chunk); + if (fCTDecl[chunk][index] == null) { + + fCTDecl[chunk][index] = new XSComplexTypeDecl(); + } else { + fCTDecl[chunk][index].reset(); + } + fCTDeclIndex++; + return fCTDecl[chunk][index]; + } + + public final XSSimpleTypeDecl getSimpleTypeDecl(){ + int chunk = fSTDeclIndex >> CHUNK_SHIFT; + int index = fSTDeclIndex & CHUNK_MASK; + ensureSTDeclCapacity(chunk); + if (fSTDecl[chunk][index] == null) { + fSTDecl[chunk][index] = dvFactory.newXSSimpleTypeDecl(); + } else { + fSTDecl[chunk][index].reset(); + } + fSTDeclIndex++; + return fSTDecl[chunk][index]; + + } + + public final XSParticleDecl getParticleDecl(){ + int chunk = fParticleDeclIndex >> CHUNK_SHIFT; + int index = fParticleDeclIndex & CHUNK_MASK; + ensureParticleDeclCapacity(chunk); + if (fParticleDecl[chunk][index] == null) { + fParticleDecl[chunk][index] = new XSParticleDecl(); + } else { + fParticleDecl[chunk][index].reset(); + } + fParticleDeclIndex++; + return fParticleDecl[chunk][index]; + } + + public final XSModelGroupImpl getModelGroup(){ + int chunk = fModelGroupIndex >> CHUNK_SHIFT; + int index = fModelGroupIndex & CHUNK_MASK; + ensureModelGroupCapacity(chunk); + if (fModelGroup[chunk][index] == null) { + fModelGroup[chunk][index] = new XSModelGroupImpl(); + } else { + fModelGroup[chunk][index].reset(); + } + fModelGroupIndex++; + return fModelGroup[chunk][index]; + } + + // REVISIT: do we need decl pool for group declarations, attribute group, + // notations? + // it seems like each schema would use a small number of those + // components, so it probably is not worth keeping those components + // in the pool. + + private boolean ensureElementDeclCapacity(int chunk) { + if (chunk >= fElementDecl.length) { + fElementDecl = resize(fElementDecl, fElementDecl.length * 2); + } else if (fElementDecl[chunk] != null) { + return false; + } + + fElementDecl[chunk] = new XSElementDecl[CHUNK_SIZE]; + return true; + } + + private static XSElementDecl[][] resize(XSElementDecl array[][], int newsize) { + XSElementDecl newarray[][] = new XSElementDecl[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private boolean ensureParticleDeclCapacity(int chunk) { + if (chunk >= fParticleDecl.length) { + fParticleDecl = resize(fParticleDecl, fParticleDecl.length * 2); + } else if (fParticleDecl[chunk] != null) { + return false; + } + + fParticleDecl[chunk] = new XSParticleDecl[CHUNK_SIZE]; + return true; + } + + private boolean ensureModelGroupCapacity(int chunk) { + if (chunk >= fModelGroup.length) { + fModelGroup = resize(fModelGroup, fModelGroup.length * 2); + } else if (fModelGroup[chunk] != null) { + return false; + } + + fModelGroup[chunk] = new XSModelGroupImpl[CHUNK_SIZE]; + return true; + } + + private static XSParticleDecl[][] resize(XSParticleDecl array[][], int newsize) { + XSParticleDecl newarray[][] = new XSParticleDecl[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private static XSModelGroupImpl[][] resize(XSModelGroupImpl array[][], int newsize) { + XSModelGroupImpl newarray[][] = new XSModelGroupImpl[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private boolean ensureAttrDeclCapacity(int chunk) { + if (chunk >= fAttrDecl.length) { + fAttrDecl = resize(fAttrDecl, fAttrDecl.length * 2); + } else if (fAttrDecl[chunk] != null) { + return false; + } + + fAttrDecl[chunk] = new XSAttributeDecl[CHUNK_SIZE]; + return true; + } + + private static XSAttributeDecl[][] resize(XSAttributeDecl array[][], int newsize) { + XSAttributeDecl newarray[][] = new XSAttributeDecl[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private boolean ensureAttributeUseCapacity(int chunk) { + if (chunk >= fAttributeUse.length) { + fAttributeUse = resize(fAttributeUse, fAttributeUse.length * 2); + } else if (fAttributeUse[chunk] != null) { + return false; + } + + fAttributeUse[chunk] = new XSAttributeUseImpl[CHUNK_SIZE]; + return true; + } + + private static XSAttributeUseImpl[][] resize(XSAttributeUseImpl array[][], int newsize) { + XSAttributeUseImpl newarray[][] = new XSAttributeUseImpl[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private boolean ensureSTDeclCapacity(int chunk) { + if (chunk >= fSTDecl.length) { + fSTDecl = resize(fSTDecl, fSTDecl.length * 2); + } else if (fSTDecl[chunk] != null) { + return false; + } + + fSTDecl[chunk] = new XSSimpleTypeDecl[CHUNK_SIZE]; + return true; + } + + private static XSSimpleTypeDecl[][] resize(XSSimpleTypeDecl array[][], int newsize) { + XSSimpleTypeDecl newarray[][] = new XSSimpleTypeDecl[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + private boolean ensureCTDeclCapacity(int chunk) { + + if (chunk >= fCTDecl.length) { + fCTDecl = resize(fCTDecl, fCTDecl.length * 2); + } else if (fCTDecl[chunk] != null){ + return false; + } + + fCTDecl[chunk] = new XSComplexTypeDecl[CHUNK_SIZE]; + return true; + } + + private static XSComplexTypeDecl[][] resize(XSComplexTypeDecl array[][], int newsize) { + XSComplexTypeDecl newarray[][] = new XSComplexTypeDecl[newsize][]; + System.arraycopy(array, 0, newarray, 0, array.length); + return newarray; + } + + + + public void reset(){ + fElementDeclIndex = 0; + fParticleDeclIndex = 0; + fModelGroupIndex = 0; + fSTDeclIndex = 0; + fCTDeclIndex = 0; + fAttrDeclIndex = 0; + fAttributeUseIndex = 0; + } + + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSElementDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSElementDecl.java new file mode 100644 index 0000000..7b637a0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSElementDecl.java @@ -0,0 +1,390 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.xs.identity.IdentityConstraint; +import org.apache.xerces.impl.xs.util.XSNamedMapImpl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSComplexTypeDefinition; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSElementDeclaration; +import org.apache.xerces.xs.XSNamedMap; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; +import org.apache.xerces.xs.XSValue; + +/** + * The XML representation for an element declaration + * schema component is an <element> element information item + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Sandy Gao, IBM + * @version $Id$ + */ +public class XSElementDecl implements XSElementDeclaration { + + // scopes + public final static short SCOPE_ABSENT = 0; + public final static short SCOPE_GLOBAL = 1; + public final static short SCOPE_LOCAL = 2; + + // name of the element + public String fName = null; + // target namespace of the element + public String fTargetNamespace = null; + // type of the element + public XSTypeDefinition fType = null; + public QName fUnresolvedTypeName = null; + // misc flag of the element: nillable/abstract/fixed + short fMiscFlags = 0; + public short fScope = XSConstants.SCOPE_ABSENT; + // enclosing complex type, when the scope is local + XSComplexTypeDecl fEnclosingCT = null; + // block set (disallowed substitutions) of the element + public short fBlock = XSConstants.DERIVATION_NONE; + // final set (substitution group exclusions) of the element + public short fFinal = XSConstants.DERIVATION_NONE; + // optional annotation + public XSObjectList fAnnotations = null; + // value constraint value + public ValidatedInfo fDefault = null; + // the substitution group affiliation of the element + public XSElementDecl fSubGroup = null; + // identity constraints + static final int INITIAL_SIZE = 2; + int fIDCPos = 0; + IdentityConstraint[] fIDConstraints = new IdentityConstraint[INITIAL_SIZE]; + // The namespace schema information item corresponding to the target namespace + // of the element declaration, if it is globally declared; or null otherwise. + private XSNamespaceItem fNamespaceItem = null; + + private static final short CONSTRAINT_MASK = 3; + private static final short NILLABLE = 4; + private static final short ABSTRACT = 8; + + // methods to get/set misc flag + public void setConstraintType(short constraintType) { + // first clear the bits + fMiscFlags ^= (fMiscFlags & CONSTRAINT_MASK); + // then set the proper one + fMiscFlags |= (constraintType & CONSTRAINT_MASK); + } + public void setIsNillable() { + fMiscFlags |= NILLABLE; + } + public void setIsAbstract() { + fMiscFlags |= ABSTRACT; + } + public void setIsGlobal() { + fScope = SCOPE_GLOBAL; + } + public void setIsLocal(XSComplexTypeDecl enclosingCT) { + fScope = SCOPE_LOCAL; + fEnclosingCT = enclosingCT; + } + + public void addIDConstraint(IdentityConstraint idc) { + if (fIDCPos == fIDConstraints.length) { + fIDConstraints = resize(fIDConstraints, fIDCPos*2); + } + fIDConstraints[fIDCPos++] = idc; + } + + public IdentityConstraint[] getIDConstraints() { + if (fIDCPos == 0) { + return null; + } + if (fIDCPos < fIDConstraints.length) { + fIDConstraints = resize(fIDConstraints, fIDCPos); + } + return fIDConstraints; + } + + static final IdentityConstraint[] resize(IdentityConstraint[] oldArray, int newSize) { + IdentityConstraint[] newArray = new IdentityConstraint[newSize]; + System.arraycopy(oldArray, 0, newArray, 0, Math.min(oldArray.length, newSize)); + return newArray; + } + + /** + * get the string description of this element + */ + private String fDescription = null; + public String toString() { + if (fDescription == null) { + if (fTargetNamespace != null) { + StringBuffer buffer = new StringBuffer( + fTargetNamespace.length() + + ((fName != null) ? fName.length() : 4) + 3); + buffer.append('"'); + buffer.append(fTargetNamespace); + buffer.append('"'); + buffer.append(':'); + buffer.append(fName); + fDescription = buffer.toString(); + } + else { + fDescription = fName; + } + } + return fDescription; + } + + /** + * get the hash code + */ + public int hashCode() { + int code = fName.hashCode(); + if (fTargetNamespace != null) + code = (code<<16)+fTargetNamespace.hashCode(); + return code; + } + + /** + * whether two decls are the same + */ + public boolean equals(Object o) { + return o == this; + } + + /** + * Reset current element declaration + */ + public void reset(){ + fScope = XSConstants.SCOPE_ABSENT; + fName = null; + fTargetNamespace = null; + fType = null; + fUnresolvedTypeName = null; + fMiscFlags = 0; + fBlock = XSConstants.DERIVATION_NONE; + fFinal = XSConstants.DERIVATION_NONE; + fDefault = null; + fAnnotations = null; + fSubGroup = null; + // reset identity constraints + for (int i=0;iname of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return fName; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return fTargetNamespace; + } + + /** + * Either a simple type definition or a complex type definition. + */ + public XSTypeDefinition getTypeDefinition() { + return fType; + } + + /** + * Optional. Either global or a complex type definition ( + * ctDefinition). This property is absent in the case of + * declarations within named model groups: their scope will be + * determined when they are used in the construction of complex type + * definitions. + */ + public short getScope() { + return fScope; + } + + /** + * Locally scoped declarations are available for use only within the + * complex type definition identified by the scope + * property. + */ + public XSComplexTypeDefinition getEnclosingCTDefinition() { + return fEnclosingCT; + } + + /** + * A value constraint: one of default, fixed. + */ + public short getConstraintType() { + return (short)(fMiscFlags & CONSTRAINT_MASK); + } + + /** + * A value constraint: The actual value (with respect to the {type + * definition}) + */ + public String getConstraintValue() { + // REVISIT: SCAPI: what's the proper representation + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.stringValue(); + } + + /** + * If {nillable} is true, then an element may also be valid if it carries + * the namespace qualified attribute with [local name] nil from + * namespace http://www.w3.org/2001/XMLSchema-instance and value true + * (see xsi:nil (2.6.2)) even if it has no text or element content + * despite a {content type} which would otherwise require content. + */ + public boolean getNillable() { + return ((fMiscFlags & NILLABLE) != 0); + } + + /** + * {identity-constraint definitions} A set of constraint definitions. + */ + public XSNamedMap getIdentityConstraints() { + return new XSNamedMapImpl(fIDConstraints, fIDCPos); + } + + /** + * {substitution group affiliation} Optional. A top-level element + * definition. + */ + public XSElementDeclaration getSubstitutionGroupAffiliation() { + return fSubGroup; + } + + /** + * Convenience method. Check if exclusion is a substitution + * group exclusion for this element declaration. + * @param exclusion Extension, restriction or none. Represents final + * set for the element. + * @return True if exclusion is a part of the substitution + * group exclusion subset. + */ + public boolean isSubstitutionGroupExclusion(short exclusion) { + return (fFinal & exclusion) != 0; + } + + /** + * Specifies if this declaration can be nominated as + * the {substitution group affiliation} of other + * element declarations having the same {type definition} + * or types derived therefrom. + * + * @return A bit flag representing {extension, restriction} or NONE. + */ + public short getSubstitutionGroupExclusions() { + return fFinal; + } + + /** + * Convenience method. Check if disallowed is a disallowed + * substitution for this element declaration. + * @param disallowed Substitution, extension, restriction or none. + * Represents a block set for the element. + * @return True if disallowed is a part of the substitution + * group exclusion subset. + */ + public boolean isDisallowedSubstitution(short disallowed) { + return (fBlock & disallowed) != 0; + } + + /** + * The supplied values for {disallowed substitutions} + * + * @return A bit flag representing {substitution, extension, restriction} or NONE. + */ + public short getDisallowedSubstitutions() { + return fBlock; + } + + /** + * {abstract} A boolean. + */ + public boolean getAbstract() { + return ((fMiscFlags & ABSTRACT) != 0); + } + + /** + * Optional. Annotation. + */ + public XSAnnotation getAnnotation() { + return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return fNamespaceItem; + } + + void setNamespaceItem(XSNamespaceItem namespaceItem) { + fNamespaceItem = namespaceItem; + } + + public Object getActualVC() { + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.actualValue; + } + + public short getActualVCType() { + return getConstraintType() == XSConstants.VC_NONE ? + XSConstants.UNAVAILABLE_DT : + fDefault.actualValueType; + } + + public ShortList getItemValueTypes() { + return getConstraintType() == XSConstants.VC_NONE ? + null : + fDefault.itemValueTypes; + } + + public XSValue getValueConstraintValue() { + return fDefault; + } + +} // class XSElementDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSElementDeclHelper.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSElementDeclHelper.java new file mode 100644 index 0000000..b32f6d7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSElementDeclHelper.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.xni.QName; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public interface XSElementDeclHelper { + + public XSElementDecl getGlobalElementDecl(QName element); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSGrammarBucket.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSGrammarBucket.java new file mode 100644 index 0000000..08eaab3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSGrammarBucket.java @@ -0,0 +1,236 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +/** + * A class used to hold the internal schema grammar set for the current instance + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @version $Id$ + */ +public class XSGrammarBucket { + + // Data + + /** + * Hashtable that maps between Namespace and a Grammar + */ + Hashtable fGrammarRegistry = new Hashtable(); + SchemaGrammar fNoNSGrammar = null; + + /** + * Get the schema grammar for the specified namespace + * + * @param namespace + * @return SchemaGrammar associated with the namespace + */ + public SchemaGrammar getGrammar(String namespace) { + if (namespace == null) + return fNoNSGrammar; + return (SchemaGrammar)fGrammarRegistry.get(namespace); + } + + /** + * Put a schema grammar into the registry + * This method is for internal use only: it assumes that a grammar with + * the same target namespace is not already in the bucket. + * + * @param grammar the grammar to put in the registry + */ + public void putGrammar(SchemaGrammar grammar) { + if (grammar.getTargetNamespace() == null) + fNoNSGrammar = grammar; + else + fGrammarRegistry.put(grammar.getTargetNamespace(), grammar); + } + + /** + * put a schema grammar and any grammars imported by it (directly or + * inderectly) into the registry. when a grammar with the same target + * namespace is already in the bucket, and different from the one being + * added, it's an error, and no grammar will be added into the bucket. + * + * @param grammar the grammar to put in the registry + * @param deep whether to add imported grammars + * @return whether the process succeeded + */ + public boolean putGrammar(SchemaGrammar grammar, boolean deep) { + // whether there is one with the same tns + SchemaGrammar sg = getGrammar(grammar.fTargetNamespace); + if (sg != null) { + // if the one we have is different from the one passed, it's an error + return sg == grammar; + } + // not deep import, then just add this one grammar + if (!deep) { + putGrammar(grammar); + return true; + } + + // get all imported grammars, and make a copy of the Vector, so that + // we can recursively process the grammars, and add distinct ones + // to the same vector + Vector currGrammars = (Vector)grammar.getImportedGrammars(); + if (currGrammars == null) { + putGrammar(grammar); + return true; + } + + Vector grammars = ((Vector)currGrammars.clone()); + SchemaGrammar sg1, sg2; + Vector gs; + // for all (recursively) imported grammars + for (int i = 0; i < grammars.size(); i++) { + // get the grammar + sg1 = (SchemaGrammar)grammars.elementAt(i); + // check whether the bucket has one with the same tns + sg2 = getGrammar(sg1.fTargetNamespace); + if (sg2 == null) { + // we need to add grammars imported by sg1 too + gs = sg1.getImportedGrammars(); + // for all grammars imported by sg2, but not in the vector + // we add them to the vector + if(gs == null) continue; + for (int j = gs.size() - 1; j >= 0; j--) { + sg2 = (SchemaGrammar)gs.elementAt(j); + if (!grammars.contains(sg2)) + grammars.addElement(sg2); + } + } + // we found one with the same target namespace + // if the two grammars are not the same object, then it's an error + else if (sg2 != sg1) { + return false; + } + } + + // now we have all imported grammars stored in the vector. add them + putGrammar(grammar); + for (int i = grammars.size() - 1; i >= 0; i--) + putGrammar((SchemaGrammar)grammars.elementAt(i)); + + return true; + } + + /** + * put a schema grammar and any grammars imported by it (directly or + * inderectly) into the registry. when a grammar with the same target + * namespace is already in the bucket, and different from the one being + * added, no grammar will be added into the bucket. + * + * @param grammar the grammar to put in the registry + * @param deep whether to add imported grammars + * @param ignoreConflict whether to ignore grammars that already exist in the grammar + * bucket or not - including 'grammar' parameter. + * @return whether the process succeeded + */ + public boolean putGrammar(SchemaGrammar grammar, boolean deep, boolean ignoreConflict) { + if (!ignoreConflict) { + return putGrammar(grammar, deep); + } + + // if grammar already exist in the bucket, we ignore the request + SchemaGrammar sg = getGrammar(grammar.fTargetNamespace); + if (sg == null) { + putGrammar(grammar); + } + + // not adding the imported grammars + if (!deep) { + return true; + } + + // get all imported grammars, and make a copy of the Vector, so that + // we can recursively process the grammars, and add distinct ones + // to the same vector + Vector currGrammars = (Vector)grammar.getImportedGrammars(); + if (currGrammars == null) { + return true; + } + + Vector grammars = ((Vector)currGrammars.clone()); + SchemaGrammar sg1, sg2; + Vector gs; + // for all (recursively) imported grammars + for (int i = 0; i < grammars.size(); i++) { + // get the grammar + sg1 = (SchemaGrammar)grammars.elementAt(i); + // check whether the bucket has one with the same tns + sg2 = getGrammar(sg1.fTargetNamespace); + if (sg2 == null) { + // we need to add grammars imported by sg1 too + gs = sg1.getImportedGrammars(); + // for all grammars imported by sg2, but not in the vector + // we add them to the vector + if(gs == null) continue; + for (int j = gs.size() - 1; j >= 0; j--) { + sg2 = (SchemaGrammar)gs.elementAt(j); + if (!grammars.contains(sg2)) + grammars.addElement(sg2); + } + } + // we found one with the same target namespace, ignore it + else { + grammars.remove(sg1); + } + } + + // now we have all imported grammars stored in the vector. add them + for (int i = grammars.size() - 1; i >= 0; i--) { + putGrammar((SchemaGrammar)grammars.elementAt(i)); + } + + return true; + } + + /** + * get all grammars in the registry + * + * @return an array of SchemaGrammars. + */ + public SchemaGrammar[] getGrammars() { + // get the number of grammars + int count = fGrammarRegistry.size() + (fNoNSGrammar==null ? 0 : 1); + SchemaGrammar[] grammars = new SchemaGrammar[count]; + // get grammars with target namespace + Enumeration schemas = fGrammarRegistry.elements(); + int i = 0; + while (schemas.hasMoreElements()) + grammars[i++] = (SchemaGrammar)schemas.nextElement(); + // add the grammar without target namespace, if any + if (fNoNSGrammar != null) + grammars[count-1] = fNoNSGrammar; + return grammars; + } + + /** + * Clear the registry. + * REVISIT: update to use another XSGrammarBucket + */ + public void reset() { + fNoNSGrammar = null; + fGrammarRegistry.clear(); + } + +} // class XSGrammarBucket diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSGroupDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSGroupDecl.java new file mode 100644 index 0000000..3dac4b6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSGroupDecl.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSModelGroup; +import org.apache.xerces.xs.XSModelGroupDefinition; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; + +/** + * The XML representation for a group declaration + * schema component is a global <group> element information item + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @version $Id$ + */ +public class XSGroupDecl implements XSModelGroupDefinition { + + // name of the group + public String fName = null; + // target namespace of the group + public String fTargetNamespace = null; + // model group of the group + public XSModelGroupImpl fModelGroup = null; + // optional annotations + public XSObjectList fAnnotations = null; + // The namespace schema information item corresponding to the target namespace + // of the model group definition, if it is globally declared; or null otherwise. + private XSNamespaceItem fNamespaceItem = null; + + /** + * Get the type of the object, i.e ELEMENT_DECLARATION. + */ + public short getType() { + return XSConstants.MODEL_GROUP_DEFINITION; + } + + /** + * The name of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return fName; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return fTargetNamespace; + } + + /** + * {model group} A model group. + */ + public XSModelGroup getModelGroup() { + return fModelGroup; + } + + /** + * Optional. Annotation. + */ + public XSAnnotation getAnnotation() { + return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return fNamespaceItem; + } + + void setNamespaceItem(XSNamespaceItem namespaceItem) { + fNamespaceItem = namespaceItem; + } + +} // class XSGroupDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSImplementationImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSImplementationImpl.java new file mode 100644 index 0000000..2f36fda --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSImplementationImpl.java @@ -0,0 +1,127 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.dom.PSVIDOMImplementationImpl; +import org.apache.xerces.impl.xs.util.LSInputListImpl; +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.xs.LSInputList; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSException; +import org.apache.xerces.xs.XSImplementation; +import org.apache.xerces.xs.XSLoader; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.ls.LSInput; + +/** + * Implements XSImplementation interface that allows one to retrieve an instance of XSLoader. + * This interface should be implemented on the same object that implements + * DOMImplementation. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public class XSImplementationImpl extends PSVIDOMImplementationImpl + implements XSImplementation { + + // + // Data + // + + // static + + /** Dom implementation singleton. */ + static final XSImplementationImpl singleton = new XSImplementationImpl(); + + // + // Public methods + // + + /** NON-DOM: Obtain and return the single shared object */ + public static DOMImplementation getDOMImplementation() { + return singleton; + } + + // + // DOMImplementation methods + // + + /** + * Test if the DOM implementation supports a specific "feature" -- + * currently meaning language and level thereof. + * + * @param feature The package name of the feature to test. + * In Level 1, supported values are "HTML" and "XML" (case-insensitive). + * At this writing, org.apache.xerces.dom supports only XML. + * + * @param version The version number of the feature being tested. + * This is interpreted as "Version of the DOM API supported for the + * specified Feature", and in Level 1 should be "1.0" + * + * @return true iff this implementation is compatable with the specified + * feature and version. + */ + public boolean hasFeature(String feature, String version) { + + return (feature.equalsIgnoreCase("XS-Loader") && (version == null || version.equals("1.0")) || + super.hasFeature(feature, version)); + } // hasFeature(String,String):boolean + + /* (non-Javadoc) + * @see org.apache.xerces.xs.XSImplementation#createXSLoader(org.apache.xerces.xs.StringList) + */ + public XSLoader createXSLoader(StringList versions) throws XSException { + XSLoader loader = new XSLoaderImpl(); + if (versions == null){ + return loader; + } + for (int i=0; iAn implementation of XSLoader which wraps XMLSchemaLoader.

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class XSLoaderImpl implements XSLoader, DOMConfiguration { + + /** + * Grammar pool. Need this to prevent us from + * getting two grammars from the same namespace. + */ + private final XSGrammarPool fGrammarPool = new XSGrammarMerger(); + + /** Schema loader. **/ + private final XMLSchemaLoader fSchemaLoader = new XMLSchemaLoader(); + + /** + * No-args constructor. + */ + public XSLoaderImpl() { + fSchemaLoader.setProperty(XMLSchemaLoader.XMLGRAMMAR_POOL, fGrammarPool); + } + + /** + * The configuration of a document. It maintains a table of recognized + * parameters. Using the configuration, it is possible to change the + * behavior of the load methods. The configuration may support the + * setting of and the retrieval of the following non-boolean parameters + * defined on the DOMConfiguration interface: + * error-handler (DOMErrorHandler) and + * resource-resolver (LSResourceResolver). + *
The following list of boolean parameters is defined: + *
+ *
+ * "validate"
+ *
+ *
+ *
true
+ *
[required] (default) Validate an XML + * Schema during loading. If validation errors are found, the error + * handler is notified.
+ *
false
+ *
[optional] Do not + * report errors during the loading of an XML Schema document.
+ *
+ *
+ */ + public DOMConfiguration getConfig() { + return this; + } + + /** + * Parses the content of XML Schema documents specified as the list of URI + * references. If the URI contains a fragment identifier, the behavior + * is not defined by this specification. + * @param uriList The list of URI locations. + * @return An XSModel representing the schema documents. + */ + public XSModel loadURIList(StringList uriList) { + int length = uriList.getLength(); + try { + fGrammarPool.clear(); + for (int i = 0; i < length; ++i) { + fSchemaLoader.loadGrammar(new XMLInputSource(null, uriList.item(i), null)); + } + return fGrammarPool.toXSModel(); + } + catch (Exception e) { + fSchemaLoader.reportDOMFatalError(e); + return null; + } + } + + /** + * Parses the content of XML Schema documents specified as a list of + * LSInputs. + * @param is The list of LSInputs from which the XML + * Schema documents are to be read. + * @return An XSModel representing the schema documents. + */ + public XSModel loadInputList(LSInputList is) { + final int length = is.getLength(); + try { + fGrammarPool.clear(); + for (int i = 0; i < length; ++i) { + fSchemaLoader.loadGrammar(fSchemaLoader.dom2xmlInputSource(is.item(i))); + } + return fGrammarPool.toXSModel(); + } + catch (Exception e) { + fSchemaLoader.reportDOMFatalError(e); + return null; + } + } + + /** + * Parse an XML Schema document from a location identified by a URI + * reference. If the URI contains a fragment identifier, the behavior is + * not defined by this specification. + * @param uri The location of the XML Schema document to be read. + * @return An XSModel representing this schema. + */ + public XSModel loadURI(String uri) { + try { + fGrammarPool.clear(); + return ((XSGrammar) fSchemaLoader.loadGrammar(new XMLInputSource(null, uri, null))).toXSModel(); + } + catch (Exception e){ + fSchemaLoader.reportDOMFatalError(e); + return null; + } + } + + /** + * Parse an XML Schema document from a resource identified by a + * LSInput . + * @param is The LSInput from which the source + * document is to be read. + * @return An XSModel representing this schema. + */ + public XSModel load(LSInput is) { + try { + fGrammarPool.clear(); + return ((XSGrammar) fSchemaLoader.loadGrammar(fSchemaLoader.dom2xmlInputSource(is))).toXSModel(); + } + catch (Exception e) { + fSchemaLoader.reportDOMFatalError(e); + return null; + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.dom3.DOMConfiguration#setParameter(java.lang.String, java.lang.Object) + */ + public void setParameter(String name, Object value) throws DOMException { + fSchemaLoader.setParameter(name, value); + } + + /* (non-Javadoc) + * @see org.apache.xerces.dom3.DOMConfiguration#getParameter(java.lang.String) + */ + public Object getParameter(String name) throws DOMException { + return fSchemaLoader.getParameter(name); + } + + /* (non-Javadoc) + * @see org.apache.xerces.dom3.DOMConfiguration#canSetParameter(java.lang.String, java.lang.Object) + */ + public boolean canSetParameter(String name, Object value) { + return fSchemaLoader.canSetParameter(name, value); + } + + /* (non-Javadoc) + * @see org.apache.xerces.dom3.DOMConfiguration#getParameterNames() + */ + public DOMStringList getParameterNames() { + return fSchemaLoader.getParameterNames(); + } + + /** + * Grammar pool which merges grammars from the same namespace into one. This eliminates + * duplicate named components. It doesn't ensure that the grammar is consistent, however + * this no worse than than the behaviour of XMLSchemaLoader alone when used as an XSLoader. + */ + private static final class XSGrammarMerger extends XSGrammarPool { + + public XSGrammarMerger () {} + + public void putGrammar(Grammar grammar) { + SchemaGrammar cachedGrammar = + toSchemaGrammar(super.getGrammar(grammar.getGrammarDescription())); + if (cachedGrammar != null) { + SchemaGrammar newGrammar = toSchemaGrammar(grammar); + if (newGrammar != null) { + mergeSchemaGrammars(cachedGrammar, newGrammar); + } + } + else { + super.putGrammar(grammar); + } + } + + private SchemaGrammar toSchemaGrammar (Grammar grammar) { + return (grammar instanceof SchemaGrammar) ? (SchemaGrammar) grammar : null; + } + + private void mergeSchemaGrammars(SchemaGrammar cachedGrammar, SchemaGrammar newGrammar) { + + /** Add new top-level element declarations. **/ + XSNamedMap map = newGrammar.getComponents(XSConstants.ELEMENT_DECLARATION); + int length = map.getLength(); + for (int i = 0; i < length; ++i) { + XSElementDecl decl = (XSElementDecl) map.item(i); + if (cachedGrammar.getGlobalElementDecl(decl.getName()) == null) { + cachedGrammar.addGlobalElementDecl(decl); + } + } + + /** Add new top-level attribute declarations. **/ + map = newGrammar.getComponents(XSConstants.ATTRIBUTE_DECLARATION); + length = map.getLength(); + for (int i = 0; i < length; ++i) { + XSAttributeDecl decl = (XSAttributeDecl) map.item(i); + if (cachedGrammar.getGlobalAttributeDecl(decl.getName()) == null) { + cachedGrammar.addGlobalAttributeDecl(decl); + } + } + + /** Add new top-level type definitions. **/ + map = newGrammar.getComponents(XSConstants.TYPE_DEFINITION); + length = map.getLength(); + for (int i = 0; i < length; ++i) { + XSTypeDefinition decl = (XSTypeDefinition) map.item(i); + if (cachedGrammar.getGlobalTypeDecl(decl.getName()) == null) { + cachedGrammar.addGlobalTypeDecl(decl); + } + } + + /** Add new top-level attribute group definitions. **/ + map = newGrammar.getComponents(XSConstants.ATTRIBUTE_GROUP); + length = map.getLength(); + for (int i = 0; i < length; ++i) { + XSAttributeGroupDecl decl = (XSAttributeGroupDecl) map.item(i); + if (cachedGrammar.getGlobalAttributeGroupDecl(decl.getName()) == null) { + cachedGrammar.addGlobalAttributeGroupDecl(decl); + } + } + + /** Add new top-level model group definitions. **/ + map = newGrammar.getComponents(XSConstants.MODEL_GROUP); + length = map.getLength(); + for (int i = 0; i < length; ++i) { + XSGroupDecl decl = (XSGroupDecl) map.item(i); + if (cachedGrammar.getGlobalGroupDecl(decl.getName()) == null) { + cachedGrammar.addGlobalGroupDecl(decl); + } + } + + /** Add new top-level notation declarations. **/ + map = newGrammar.getComponents(XSConstants.NOTATION_DECLARATION); + length = map.getLength(); + for (int i = 0; i < length; ++i) { + XSNotationDecl decl = (XSNotationDecl) map.item(i); + if (cachedGrammar.getGlobalNotationDecl(decl.getName()) == null) { + cachedGrammar.addGlobalNotationDecl(decl); + } + } + + /** + * Add all annotations. Since these components are not named it's + * possible we'll add duplicate components. There isn't much we can + * do. It's no worse than XMLSchemaLoader when used as an XSLoader. + */ + XSObjectList annotations = newGrammar.getAnnotations(); + length = annotations.getLength(); + for (int i = 0; i < length; ++i) { + cachedGrammar.addAnnotation((XSAnnotationImpl) annotations.item(i)); + } + + } + + public boolean containsGrammar(XMLGrammarDescription desc) { + return false; + } + + public Grammar getGrammar(XMLGrammarDescription desc) { + return null; + } + + public Grammar retrieveGrammar(XMLGrammarDescription desc) { + return null; + } + + public Grammar [] retrieveInitialGrammarSet (String grammarType) { + return new Grammar[0]; + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSMessageFormatter.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSMessageFormatter.java new file mode 100644 index 0000000..5436204 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSMessageFormatter.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.xerces.util.MessageFormatter; + +/** + * SchemaMessageProvider implements an XMLMessageProvider that + * provides localizable error messages for the W3C XML Schema Language + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public class XSMessageFormatter implements MessageFormatter { + /** + * The domain of messages concerning the XML Schema: Structures specification. + */ + public static final String SCHEMA_DOMAIN = "http://www.w3.org/TR/xml-schema-1"; + + + // private objects to cache the locale and resource bundle + private Locale fLocale = null; + private ResourceBundle fResourceBundle = null; + + /** + * Formats a message with the specified arguments using the given + * locale information. + * + * @param locale The locale of the message. + * @param key The message key. + * @param arguments The message replacement text arguments. The order + * of the arguments must match that of the placeholders + * in the actual message. + * + * @return Returns the formatted message. + * + * @throws MissingResourceException Thrown if the message with the + * specified key cannot be found. + */ + public String formatMessage(Locale locale, String key, Object[] arguments) + throws MissingResourceException { + + if (locale == null) { + locale = Locale.getDefault(); + } + if (locale != fLocale) { + fResourceBundle = ResourceBundle.getBundle("org.apache.xerces.impl.msg.XMLSchemaMessages", locale); + // memorize the most-recent locale + fLocale = locale; + } + + String msg = fResourceBundle.getString(key); + if (arguments != null) { + try { + msg = java.text.MessageFormat.format(msg, arguments); + } catch (Exception e) { + msg = fResourceBundle.getString("FormatFailed"); + msg += " " + fResourceBundle.getString(key); + } + } + + if (msg == null) { + msg = fResourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(msg, "org.apache.xerces.impl.msg.SchemaMessages", key); + } + + return msg; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSModelGroupImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSModelGroupImpl.java new file mode 100644 index 0000000..3127b9b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSModelGroupImpl.java @@ -0,0 +1,243 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSModelGroup; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; + +/** + * Store schema model group declaration. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class XSModelGroupImpl implements XSModelGroup { + + // types of model groups + // REVISIT: can't use same constants as those for particles, because + // there are place where the constants are used together. For example, + // to check whether the content is an element or a sequence. + public static final short MODELGROUP_CHOICE = 101; + public static final short MODELGROUP_SEQUENCE = 102; + public static final short MODELGROUP_ALL = 103; + + // compositor of the model group + public short fCompositor; + + // particles + public XSParticleDecl[] fParticles = null; + public int fParticleCount = 0; + + // this particle's optional annotations + public XSObjectList fAnnotations = null; + + // whether this model group contains nothing + public boolean isEmpty() { + for (int i = 0; i < fParticleCount; i++) { + if (!fParticles[i].isEmpty()) + return false; + } + return true; + } + + /** + * 3.8.6 Effective Total Range (all and sequence) and + * Effective Total Range (choice) + * The following methods are used to return min/max range for a particle. + * They are not exactly the same as it's described in the spec, but all the + * values from the spec are retrievable by these methods. + */ + public int minEffectiveTotalRange() { + if (fCompositor == MODELGROUP_CHOICE) + return minEffectiveTotalRangeChoice(); + else + return minEffectiveTotalRangeAllSeq(); + } + + // return the sum of all min values of the particles + private int minEffectiveTotalRangeAllSeq() { + int total = 0; + for (int i = 0; i < fParticleCount; i++) + total += fParticles[i].minEffectiveTotalRange(); + return total; + } + + // return the min of all min values of the particles + private int minEffectiveTotalRangeChoice() { + int min = 0, one; + if (fParticleCount > 0) + min = fParticles[0].minEffectiveTotalRange(); + + for (int i = 1; i < fParticleCount; i++) { + one = fParticles[i].minEffectiveTotalRange(); + if (one < min) + min = one; + } + + return min; + } + + public int maxEffectiveTotalRange() { + if (fCompositor == MODELGROUP_CHOICE) + return maxEffectiveTotalRangeChoice(); + else + return maxEffectiveTotalRangeAllSeq(); + } + + // if one of the max value of the particles is unbounded, return unbounded; + // otherwise return the sum of all max values + private int maxEffectiveTotalRangeAllSeq() { + int total = 0, one; + for (int i = 0; i < fParticleCount; i++) { + one = fParticles[i].maxEffectiveTotalRange(); + if (one == SchemaSymbols.OCCURRENCE_UNBOUNDED) + return SchemaSymbols.OCCURRENCE_UNBOUNDED; + total += one; + } + return total; + } + + // if one of the max value of the particles is unbounded, return unbounded; + // otherwise return the max of all max values + private int maxEffectiveTotalRangeChoice() { + int max = 0, one; + if (fParticleCount > 0) { + max = fParticles[0].maxEffectiveTotalRange(); + if (max == SchemaSymbols.OCCURRENCE_UNBOUNDED) + return SchemaSymbols.OCCURRENCE_UNBOUNDED; + } + + for (int i = 1; i < fParticleCount; i++) { + one = fParticles[i].maxEffectiveTotalRange(); + if (one == SchemaSymbols.OCCURRENCE_UNBOUNDED) + return SchemaSymbols.OCCURRENCE_UNBOUNDED; + if (one > max) + max = one; + } + return max; + } + + /** + * get the string description of this particle + */ + private String fDescription = null; + public String toString() { + // REVISIT: Commented code may help to eliminate redundant parentheses (test first before committing) + if (fDescription == null) { + StringBuffer buffer = new StringBuffer(); + if (fCompositor == MODELGROUP_ALL) + buffer.append("all("); + else //if (fMinOccurs != 1 || fMaxOccurs != 1) + buffer.append('('); + if (fParticleCount > 0) + buffer.append(fParticles[0].toString()); + for (int i = 1; i < fParticleCount; i++) { + if (fCompositor == MODELGROUP_CHOICE) + buffer.append('|'); + else + buffer.append(','); + buffer.append(fParticles[i].toString()); + } + //if (fCompositor == MODELGROUP_ALL || fMinOccurs != 1 || fMaxOccurs != 1) + buffer.append(')'); + fDescription = buffer.toString(); + } + return fDescription; + } + + public void reset(){ + fCompositor = MODELGROUP_SEQUENCE; + fParticles = null; + fParticleCount = 0; + fDescription = null; + fAnnotations = null; + } + + /** + * Get the type of the object, i.e ELEMENT_DECLARATION. + */ + public short getType() { + return XSConstants.MODEL_GROUP; + } + + /** + * The name of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return null; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return null; + } + + /** + * {compositor} One of all, choice or sequence. The valid constants values + * are: ALL, CHOICE, SEQUENCE. + */ + public short getCompositor() { + if (fCompositor == MODELGROUP_CHOICE) + return XSModelGroup.COMPOSITOR_CHOICE; + else if (fCompositor == MODELGROUP_SEQUENCE) + return XSModelGroup.COMPOSITOR_SEQUENCE; + else + return XSModelGroup.COMPOSITOR_ALL; + } + + /** + * {particles} A list of particles + */ + public XSObjectList getParticles() { + return new XSObjectListImpl(fParticles, fParticleCount); + } + + /** + * Optional. Annotation. + */ + public XSAnnotation getAnnotation() { + return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return null; + } + +} // class XSModelGroupImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSModelImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSModelImpl.java new file mode 100644 index 0000000..c524e54 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSModelImpl.java @@ -0,0 +1,847 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import java.lang.reflect.Array; +import java.util.AbstractList; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.Vector; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.impl.xs.util.XSNamedMap4Types; +import org.apache.xerces.impl.xs.util.XSNamedMapImpl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSAttributeDeclaration; +import org.apache.xerces.xs.XSAttributeGroupDefinition; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSElementDeclaration; +import org.apache.xerces.xs.XSIDCDefinition; +import org.apache.xerces.xs.XSModel; +import org.apache.xerces.xs.XSModelGroupDefinition; +import org.apache.xerces.xs.XSNamedMap; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSNamespaceItemList; +import org.apache.xerces.xs.XSNotationDeclaration; +import org.apache.xerces.xs.XSObject; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * Implements XSModel: a read-only interface that represents an XML Schema, + * which could be components from different namespaces. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public final class XSModelImpl extends AbstractList implements XSModel, XSNamespaceItemList { + + // the max index / the max value of XSObject type + private static final short MAX_COMP_IDX = XSTypeDefinition.SIMPLE_TYPE; + private static final boolean[] GLOBAL_COMP = {false, // null + true, // attribute + true, // element + true, // type + false, // attribute use + true, // attribute group + true, // group + false, // model group + false, // particle + false, // wildcard + true, // idc + true, // notation + false, // annotation + false, // facet + false, // multi value facet + true, // complex type + true // simple type + }; + + // number of grammars/namespaces stored here + private final int fGrammarCount; + // all target namespaces + private final String[] fNamespaces; + // all schema grammar objects (for each namespace) + private final SchemaGrammar[] fGrammarList; + // a map from namespace to schema grammar + private final SymbolHash fGrammarMap; + // a map from element declaration to its substitution group + private final SymbolHash fSubGroupMap; + + // store a certain kind of components from all namespaces + private final XSNamedMap[] fGlobalComponents; + // store a certain kind of components from one namespace + private final XSNamedMap[][] fNSComponents; + + // a string list of all the target namespaces. + private final StringList fNamespacesList; + // store all annotations + private XSObjectList fAnnotations = null; + + // whether there is any IDC in this XSModel + private final boolean fHasIDC; + + /** + * Construct an XSModelImpl, by storing some grammars and grammars imported + * by them to this object. + * + * @param grammars the array of schema grammars + */ + public XSModelImpl(SchemaGrammar[] grammars) { + this(grammars, Constants.SCHEMA_VERSION_1_0); + } + + public XSModelImpl(SchemaGrammar[] grammars, short s4sVersion) { + // copy namespaces/grammars from the array to our arrays + int len = grammars.length; + final int initialSize = Math.max(len+1, 5); + String[] namespaces = new String[initialSize]; + SchemaGrammar[] grammarList = new SchemaGrammar[initialSize]; + boolean hasS4S = false; + for (int i = 0; i < len; i++) { + final SchemaGrammar sg = grammars[i]; + final String tns = sg.getTargetNamespace(); + namespaces[i] = tns; + grammarList[i] = sg; + if (tns == SchemaSymbols.URI_SCHEMAFORSCHEMA) { + hasS4S = true; + } + } + // If a schema for the schema namespace isn't included, include it here. + if (!hasS4S) { + namespaces[len] = SchemaSymbols.URI_SCHEMAFORSCHEMA; + grammarList[len++] = SchemaGrammar.getS4SGrammar(s4sVersion); + } + + SchemaGrammar sg1, sg2; + Vector gs; + int i, j, k; + // and recursively get all imported grammars, add them to our arrays + for (i = 0; i < len; i++) { + // get the grammar + sg1 = grammarList[i]; + gs = sg1.getImportedGrammars(); + // for each imported grammar + for (j = gs == null ? -1 : gs.size() - 1; j >= 0; j--) { + sg2 = (SchemaGrammar)gs.elementAt(j); + // check whether this grammar is already in the list + for (k = 0; k < len; k++) { + if (sg2 == grammarList[k]) { + break; + } + } + // if it's not, add it to the list + if (k == len) { + // ensure the capacity of the arrays + if (len == grammarList.length) { + String[] newSA = new String[len*2]; + System.arraycopy(namespaces, 0, newSA, 0, len); + namespaces = newSA; + SchemaGrammar[] newGA = new SchemaGrammar[len*2]; + System.arraycopy(grammarList, 0, newGA, 0, len); + grammarList = newGA; + } + namespaces[len] = sg2.getTargetNamespace(); + grammarList[len] = sg2; + len++; + } + } + } + + fNamespaces = namespaces; + fGrammarList = grammarList; + + boolean hasIDC = false; + // establish the mapping from namespace to grammars + fGrammarMap = new SymbolHash(len*2); + for (i = 0; i < len; i++) { + fGrammarMap.put(null2EmptyString(fNamespaces[i]), fGrammarList[i]); + // update the idc field + if (fGrammarList[i].hasIDConstraints()) { + hasIDC = true; + } + } + + fHasIDC = hasIDC; + fGrammarCount = len; + fGlobalComponents = new XSNamedMap[MAX_COMP_IDX+1]; + fNSComponents = new XSNamedMap[len][MAX_COMP_IDX+1]; + fNamespacesList = new StringListImpl(fNamespaces, fGrammarCount); + + // build substitution groups + fSubGroupMap = buildSubGroups(); + } + + private SymbolHash buildSubGroups_Org() { + SubstitutionGroupHandler sgHandler = new SubstitutionGroupHandler(null); + for (int i = 0 ; i < fGrammarCount; i++) { + sgHandler.addSubstitutionGroup(fGrammarList[i].getSubstitutionGroups()); + } + + final XSNamedMap elements = getComponents(XSConstants.ELEMENT_DECLARATION); + final int len = elements.getLength(); + final SymbolHash subGroupMap = new SymbolHash(len*2); + XSElementDecl head; + XSElementDeclaration[] subGroup; + for (int i = 0; i < len; i++) { + head = (XSElementDecl)elements.item(i); + subGroup = sgHandler.getSubstitutionGroup(head); + subGroupMap.put(head, subGroup.length > 0 ? + new XSObjectListImpl(subGroup, subGroup.length) : XSObjectListImpl.EMPTY_LIST); + } + return subGroupMap; + } + + private SymbolHash buildSubGroups() { + SubstitutionGroupHandler sgHandler = new SubstitutionGroupHandler(null); + for (int i = 0 ; i < fGrammarCount; i++) { + sgHandler.addSubstitutionGroup(fGrammarList[i].getSubstitutionGroups()); + } + + final XSObjectListImpl elements = getGlobalElements(); + final int len = elements.getLength(); + final SymbolHash subGroupMap = new SymbolHash(len*2); + XSElementDecl head; + XSElementDeclaration[] subGroup; + for (int i = 0; i < len; i++) { + head = (XSElementDecl)elements.item(i); + subGroup = sgHandler.getSubstitutionGroup(head); + subGroupMap.put(head, subGroup.length > 0 ? + new XSObjectListImpl(subGroup, subGroup.length) : XSObjectListImpl.EMPTY_LIST); + } + return subGroupMap; + } + + private XSObjectListImpl getGlobalElements() { + final SymbolHash[] tables = new SymbolHash[fGrammarCount]; + int length = 0; + + for (int i = 0; i < fGrammarCount; i++) { + tables[i] = fGrammarList[i].fAllGlobalElemDecls; + length += tables[i].getLength(); + } + + if (length == 0) { + return XSObjectListImpl.EMPTY_LIST; + } + + final XSObject[] components = new XSObject[length]; + + int start = 0; + for (int i = 0; i < fGrammarCount; i++) { + tables[i].getValues(components, start); + start += tables[i].getLength(); + } + + return new XSObjectListImpl(components, length); + } + + /** + * Convenience method. Returns a list of all namespaces that belong to + * this schema. + * @return A list of all namespaces that belong to this schema or + * null if all components don't have a targetNamespace. + */ + public StringList getNamespaces() { + return fNamespacesList; + } + + /** + * A set of namespace schema information information items (of type + * XSNamespaceItem), one for each namespace name which + * appears as the target namespace of any schema component in the schema + * used for that assessment, and one for absent if any schema component + * in the schema had no target namespace. For more information see + * schema information. + */ + public XSNamespaceItemList getNamespaceItems() { + return this; + } + + /** + * Returns a list of top-level components, i.e. element declarations, + * attribute declarations, etc. + * @param objectType The type of the declaration, i.e. + * ELEMENT_DECLARATION. Note that + * XSTypeDefinition.SIMPLE_TYPE and + * XSTypeDefinition.COMPLEX_TYPE can also be used as the + * objectType to retrieve only complex types or simple + * types, instead of all types. + * @return A list of top-level definitions of the specified type in + * objectType or an empty XSNamedMap if no + * such definitions exist. + */ + public synchronized XSNamedMap getComponents(short objectType) { + if (objectType <= 0 || objectType > MAX_COMP_IDX || + !GLOBAL_COMP[objectType]) { + return XSNamedMapImpl.EMPTY_MAP; + } + + SymbolHash[] tables = new SymbolHash[fGrammarCount]; + // get all hashtables from all namespaces for this type of components + if (fGlobalComponents[objectType] == null) { + for (int i = 0; i < fGrammarCount; i++) { + switch (objectType) { + case XSConstants.TYPE_DEFINITION: + case XSTypeDefinition.COMPLEX_TYPE: + case XSTypeDefinition.SIMPLE_TYPE: + tables[i] = fGrammarList[i].fGlobalTypeDecls; + break; + case XSConstants.ATTRIBUTE_DECLARATION: + tables[i] = fGrammarList[i].fGlobalAttrDecls; + break; + case XSConstants.ELEMENT_DECLARATION: + tables[i] = fGrammarList[i].fGlobalElemDecls; + break; + case XSConstants.ATTRIBUTE_GROUP: + tables[i] = fGrammarList[i].fGlobalAttrGrpDecls; + break; + case XSConstants.MODEL_GROUP_DEFINITION: + tables[i] = fGrammarList[i].fGlobalGroupDecls; + break; + case XSConstants.NOTATION_DECLARATION: + tables[i] = fGrammarList[i].fGlobalNotationDecls; + break; + case XSConstants.IDENTITY_CONSTRAINT: + tables[i] = fGrammarList[i].fGlobalIDConstraintDecls; + break; + } + } + // for complex/simple types, create a special implementation, + // which take specific types out of the hash table + if (objectType == XSTypeDefinition.COMPLEX_TYPE || + objectType == XSTypeDefinition.SIMPLE_TYPE) { + fGlobalComponents[objectType] = new XSNamedMap4Types(fNamespaces, tables, fGrammarCount, objectType); + } + else { + fGlobalComponents[objectType] = new XSNamedMapImpl(fNamespaces, tables, fGrammarCount); + } + } + + return fGlobalComponents[objectType]; + } + + /** + * Convenience method. Returns a list of top-level component declarations + * that are defined within the specified namespace, i.e. element + * declarations, attribute declarations, etc. + * @param objectType The type of the declaration, i.e. + * ELEMENT_DECLARATION. + * @param namespace The namespace to which the declaration belongs or + * null (for components with no target namespace). + * @return A list of top-level definitions of the specified type in + * objectType and defined in the specified + * namespace or an empty XSNamedMap. + */ + public synchronized XSNamedMap getComponentsByNamespace(short objectType, + String namespace) { + if (objectType <= 0 || objectType > MAX_COMP_IDX || + !GLOBAL_COMP[objectType]) { + return XSNamedMapImpl.EMPTY_MAP; + } + + // try to find the grammar + int i = 0; + if (namespace != null) { + for (; i < fGrammarCount; ++i) { + if (namespace.equals(fNamespaces[i])) { + break; + } + } + } + else { + for (; i < fGrammarCount; ++i) { + if (fNamespaces[i] == null) { + break; + } + } + } + if (i == fGrammarCount) { + return XSNamedMapImpl.EMPTY_MAP; + } + + // get the hashtable for this type of components + if (fNSComponents[i][objectType] == null) { + SymbolHash table = null; + switch (objectType) { + case XSConstants.TYPE_DEFINITION: + case XSTypeDefinition.COMPLEX_TYPE: + case XSTypeDefinition.SIMPLE_TYPE: + table = fGrammarList[i].fGlobalTypeDecls; + break; + case XSConstants.ATTRIBUTE_DECLARATION: + table = fGrammarList[i].fGlobalAttrDecls; + break; + case XSConstants.ELEMENT_DECLARATION: + table = fGrammarList[i].fGlobalElemDecls; + break; + case XSConstants.ATTRIBUTE_GROUP: + table = fGrammarList[i].fGlobalAttrGrpDecls; + break; + case XSConstants.MODEL_GROUP_DEFINITION: + table = fGrammarList[i].fGlobalGroupDecls; + break; + case XSConstants.NOTATION_DECLARATION: + table = fGrammarList[i].fGlobalNotationDecls; + break; + case XSConstants.IDENTITY_CONSTRAINT: + table = fGrammarList[i].fGlobalIDConstraintDecls; + break; + } + + // for complex/simple types, create a special implementation, + // which take specific types out of the hash table + if (objectType == XSTypeDefinition.COMPLEX_TYPE || + objectType == XSTypeDefinition.SIMPLE_TYPE) { + fNSComponents[i][objectType] = new XSNamedMap4Types(namespace, table, objectType); + } + else { + fNSComponents[i][objectType] = new XSNamedMapImpl(namespace, table); + } + } + + return fNSComponents[i][objectType]; + } + + /** + * Convenience method. Returns a top-level simple or complex type + * definition. + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise null. + * @return An XSTypeDefinition or null if such definition + * does not exist. + */ + public XSTypeDefinition getTypeDefinition(String name, + String namespace) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return (XSTypeDefinition)sg.fGlobalTypeDecls.get(name); + } + + /** + * Convenience method. Returns a top-level simple or complex type + * definition. + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise null. + * @param loc The schema location where the component was defined + * @return An XSTypeDefinition or null if such definition + * does not exist. + */ + public XSTypeDefinition getTypeDefinition(String name, + String namespace, + String loc) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return sg.getGlobalTypeDecl(name, loc); + } + + /** + * Convenience method. Returns a top-level attribute declaration. + * @param name The name of the declaration. + * @param namespace The namespace of the definition, otherwise null. + * @return A top-level attribute declaration or null if such declaration + * does not exist. + */ + public XSAttributeDeclaration getAttributeDeclaration(String name, + String namespace) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return (XSAttributeDeclaration)sg.fGlobalAttrDecls.get(name); + } + + /** + * Convenience method. Returns a top-level attribute declaration. + * @param name The name of the declaration. + * @param namespace The namespace of the definition, otherwise null. + * @param loc The schema location where the component was defined + * @return A top-level attribute declaration or null if such declaration + * does not exist. + */ + public XSAttributeDeclaration getAttributeDeclaration(String name, + String namespace, + String loc) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return sg.getGlobalAttributeDecl(name, loc); + } + + /** + * Convenience method. Returns a top-level element declaration. + * @param name The name of the declaration. + * @param namespace The namespace of the definition, otherwise null. + * @return A top-level element declaration or null if such declaration + * does not exist. + */ + public XSElementDeclaration getElementDeclaration(String name, + String namespace) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return (XSElementDeclaration)sg.fGlobalElemDecls.get(name); + } + + /** + * Convenience method. Returns a top-level element declaration. + * @param name The name of the declaration. + * @param namespace The namespace of the definition, otherwise null. + * @param loc The schema location where the component was defined + * @return A top-level element declaration or null if such declaration + * does not exist. + */ + public XSElementDeclaration getElementDeclaration(String name, + String namespace, + String loc) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return sg.getGlobalElementDecl(name, loc); + } + + /** + * Convenience method. Returns a top-level attribute group definition. + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise null. + * @return A top-level attribute group definition or null if such + * definition does not exist. + */ + public XSAttributeGroupDefinition getAttributeGroup(String name, + String namespace) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return (XSAttributeGroupDefinition)sg.fGlobalAttrGrpDecls.get(name); + } + + /** + * Convenience method. Returns a top-level attribute group definition. + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise null. + * @param loc The schema location where the component was defined + * @return A top-level attribute group definition or null if such + * definition does not exist. + */ + public XSAttributeGroupDefinition getAttributeGroup(String name, + String namespace, + String loc) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return sg.getGlobalAttributeGroupDecl(name, loc); + } + + /** + * Convenience method. Returns a top-level model group definition. + * + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise null. + * @return A top-level model group definition definition or null if such + * definition does not exist. + */ + public XSModelGroupDefinition getModelGroupDefinition(String name, + String namespace) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return (XSModelGroupDefinition)sg.fGlobalGroupDecls.get(name); + } + + /** + * Convenience method. Returns a top-level model group definition. + * + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise null. + * @param loc The schema location where the component was defined + * @return A top-level model group definition definition or null if such + * definition does not exist. + */ + public XSModelGroupDefinition getModelGroupDefinition(String name, + String namespace, + String loc) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return sg.getGlobalGroupDecl(name, loc); + } + + /** + * Convenience method. Returns a top-level model group definition. + * + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise null. + * @return A top-level model group definition definition or null if such + * definition does not exist. + */ + public XSIDCDefinition getIDCDefinition(String name, String namespace) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return (XSIDCDefinition)sg.fGlobalIDConstraintDecls.get(name); + } + + /** + * Convenience method. Returns a top-level model group definition. + * + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise null. + * @param loc The schema location where the component was defined + * @return A top-level model group definition definition or null if such + * definition does not exist. + */ + public XSIDCDefinition getIDCDefinition(String name, String namespace, + String loc) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return sg.getIDConstraintDecl(name, loc); + } + + + /** + * @see org.apache.xerces.xs.XSModel#getNotationDeclaration(String, String) + */ + public XSNotationDeclaration getNotationDeclaration(String name, + String namespace) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return (XSNotationDeclaration)sg.fGlobalNotationDecls.get(name); + } + + public XSNotationDeclaration getNotationDeclaration(String name, + String namespace, + String loc) { + SchemaGrammar sg = (SchemaGrammar)fGrammarMap.get(null2EmptyString(namespace)); + if (sg == null) { + return null; + } + return sg.getGlobalNotationDecl(name, loc); + } + + /** + * [annotations]: a set of annotations if it exists, otherwise an empty + * XSObjectList. + */ + public synchronized XSObjectList getAnnotations() { + if (fAnnotations != null) { + return fAnnotations; + } + + // do this in two passes to avoid inaccurate array size + int totalAnnotations = 0; + for (int i = 0; i < fGrammarCount; i++) { + totalAnnotations += fGrammarList[i].fNumAnnotations; + } + if (totalAnnotations == 0) { + fAnnotations = XSObjectListImpl.EMPTY_LIST; + return fAnnotations; + } + XSAnnotationImpl [] annotations = new XSAnnotationImpl [totalAnnotations]; + int currPos = 0; + for (int i = 0; i < fGrammarCount; i++) { + SchemaGrammar currGrammar = fGrammarList[i]; + if (currGrammar.fNumAnnotations > 0) { + System.arraycopy(currGrammar.fAnnotations, 0, annotations, currPos, currGrammar.fNumAnnotations); + currPos += currGrammar.fNumAnnotations; + } + } + fAnnotations = new XSObjectListImpl(annotations, annotations.length); + return fAnnotations; + } + + private static final String null2EmptyString(String str) { + return str == null ? XMLSymbols.EMPTY_STRING : str; + } + + /** + * REVISIT: to expose identity constraints from XSModel. + * For now, we only expose whether there are any IDCs. + * We also need to add these methods to the public + * XSModel interface. + */ + public boolean hasIDConstraints() { + return fHasIDC; + } + + /** + * Convenience method. Returns a list containing the members of the + * substitution group for the given XSElementDeclaration + * or an empty XSObjectList if the substitution group + * contains no members. + * @param head The substitution group head. + * @return A list containing the members of the substitution group + * for the given XSElementDeclaration or an empty + * XSObjectList if the substitution group contains + * no members. + */ + public XSObjectList getSubstitutionGroup(XSElementDeclaration head) { + return (XSObjectList)fSubGroupMap.get(head); + } + + // + // XSNamespaceItemList methods + // + + /** + * The number of XSNamespaceItems in the list. The range of + * valid child object indices is 0 to length-1 inclusive. + */ + public int getLength() { + return fGrammarCount; + } + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The XSNamespaceItem at the indexth + * position in the XSNamespaceItemList, or + * null if the index specified is not valid. + */ + public XSNamespaceItem item(int index) { + if (index < 0 || index >= fGrammarCount) { + return null; + } + return fGrammarList[index]; + } + + // + // java.util.List methods + // + + public Object get(int index) { + if (index >= 0 && index < fGrammarCount) { + return fGrammarList[index]; + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + + public Iterator iterator() { + return listIterator0(0); + } + + public ListIterator listIterator() { + return listIterator0(0); + } + + public ListIterator listIterator(int index) { + if (index >= 0 && index < fGrammarCount) { + return listIterator0(index); + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + private ListIterator listIterator0(int index) { + return new XSNamespaceItemListIterator(index); + } + + public Object[] toArray() { + Object[] a = new Object[fGrammarCount]; + toArray0(a); + return a; + } + + public Object[] toArray(Object[] a) { + if (a.length < fGrammarCount) { + Class arrayClass = a.getClass(); + Class componentType = arrayClass.getComponentType(); + a = (Object[]) Array.newInstance(componentType, fGrammarCount); + } + toArray0(a); + if (a.length > fGrammarCount) { + a[fGrammarCount] = null; + } + return a; + } + + private void toArray0(Object[] a) { + if (fGrammarCount > 0) { + System.arraycopy(fGrammarList, 0, a, 0, fGrammarCount); + } + } + + private final class XSNamespaceItemListIterator implements ListIterator { + private int index; + public XSNamespaceItemListIterator(int index) { + this.index = index; + } + public boolean hasNext() { + return (index < fGrammarCount); + } + public Object next() { + if (index < fGrammarCount) { + return fGrammarList[index++]; + } + throw new NoSuchElementException(); + } + public boolean hasPrevious() { + return (index > 0); + } + public Object previous() { + if (index > 0) { + return fGrammarList[--index]; + } + throw new NoSuchElementException(); + } + public int nextIndex() { + return index; + } + public int previousIndex() { + return index - 1; + } + public void remove() { + throw new UnsupportedOperationException(); + } + public void set(Object o) { + throw new UnsupportedOperationException(); + } + public void add(Object o) { + throw new UnsupportedOperationException(); + } + } + +} // class XSModelImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSNotationDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSNotationDecl.java new file mode 100644 index 0000000..c42fae5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSNotationDecl.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSNotationDeclaration; +import org.apache.xerces.xs.XSObjectList; + +/** + * The XML representation for a NOTATION declaration + * schema component is a global <notation> element information item + * + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * @version $Id$ + */ +public class XSNotationDecl implements XSNotationDeclaration { + + // name of the group + public String fName = null; + // target namespace of the group + public String fTargetNamespace = null; + // public id of the notation + public String fPublicId = null; + // system id of the notation + public String fSystemId = null; + + // optional annotation + public XSObjectList fAnnotations = null; + + // The namespace schema information item corresponding to the target namespace + // of the notation declaration, if it is globally declared; or null otherwise. + private XSNamespaceItem fNamespaceItem = null; + + /** + * Get the type of the object, i.e ELEMENT_DECLARATION. + */ + public short getType() { + return XSConstants.NOTATION_DECLARATION; + } + + /** + * The name of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return fName; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return fTargetNamespace; + } + + /** + * Optional if {public identifier} is present. A URI reference. + */ + public String getSystemId() { + return fSystemId; + } + + /** + * Optional if {system identifier} is present. A public identifier, + * as defined in [XML 1.0 (Second Edition)]. + */ + public String getPublicId() { + return fPublicId; + } + + /** + * Optional. Annotation. + */ + public XSAnnotation getAnnotation() { + return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return fNamespaceItem; + } + + void setNamespaceItem(XSNamespaceItem namespaceItem) { + fNamespaceItem = namespaceItem; + } + +} // class XSNotationDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSParticleDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSParticleDecl.java new file mode 100644 index 0000000..69558ce --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSParticleDecl.java @@ -0,0 +1,245 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSParticle; +import org.apache.xerces.xs.XSTerm; + +/** + * Store schema particle declaration. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class XSParticleDecl implements XSParticle { + + // types of particles + public static final short PARTICLE_EMPTY = 0; + public static final short PARTICLE_ELEMENT = 1; + public static final short PARTICLE_WILDCARD = 2; + public static final short PARTICLE_MODELGROUP = 3; + public static final short PARTICLE_ZERO_OR_MORE = 4; + public static final short PARTICLE_ZERO_OR_ONE = 5; + public static final short PARTICLE_ONE_OR_MORE = 6; + + // type of the particle + public short fType = PARTICLE_EMPTY; + + // term of the particle + // for PARTICLE_ELEMENT : the element decl + // for PARTICLE_WILDCARD: the wildcard decl + // for PARTICLE_MODELGROUP: the model group + public XSTerm fValue = null; + + // minimum occurrence of this particle + public int fMinOccurs = 1; + // maximum occurrence of this particle + public int fMaxOccurs = 1; + // optional annotation + public XSObjectList fAnnotations = null; + + // clone this decl + public XSParticleDecl makeClone() { + XSParticleDecl particle = new XSParticleDecl(); + particle.fType = fType; + particle.fMinOccurs = fMinOccurs; + particle.fMaxOccurs = fMaxOccurs; + particle.fDescription = fDescription; + particle.fValue = fValue; + particle.fAnnotations = fAnnotations; + return particle; + } + + /** + * 3.9.6 Schema Component Constraint: Particle Emptiable + * whether this particle is emptible + */ + public boolean emptiable() { + return minEffectiveTotalRange() == 0; + } + + // whether this particle contains nothing + public boolean isEmpty() { + if (fType == PARTICLE_EMPTY) + return true; + if (fType == PARTICLE_ELEMENT || fType == PARTICLE_WILDCARD) + return false; + + return ((XSModelGroupImpl)fValue).isEmpty(); + } + + /** + * 3.8.6 Effective Total Range (all and sequence) and + * Effective Total Range (choice) + * The following methods are used to return min/max range for a particle. + * They are not exactly the same as it's described in the spec, but all the + * values from the spec are retrievable by these methods. + */ + public int minEffectiveTotalRange() { + if (fType == XSParticleDecl.PARTICLE_EMPTY) { + return 0; + } + if (fType == PARTICLE_MODELGROUP) { + return ((XSModelGroupImpl)fValue).minEffectiveTotalRange() * fMinOccurs; + } + return fMinOccurs; + } + + public int maxEffectiveTotalRange() { + if (fType == XSParticleDecl.PARTICLE_EMPTY) { + return 0; + } + if (fType == PARTICLE_MODELGROUP) { + int max = ((XSModelGroupImpl)fValue).maxEffectiveTotalRange(); + if (max == SchemaSymbols.OCCURRENCE_UNBOUNDED) + return SchemaSymbols.OCCURRENCE_UNBOUNDED; + if (max != 0 && fMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED) + return SchemaSymbols.OCCURRENCE_UNBOUNDED; + return max * fMaxOccurs; + } + return fMaxOccurs; + } + + /** + * get the string description of this particle + */ + private String fDescription = null; + public String toString() { + if (fDescription == null) { + StringBuffer buffer = new StringBuffer(); + appendParticle(buffer); + if (!(fMinOccurs == 0 && fMaxOccurs == 0 || + fMinOccurs == 1 && fMaxOccurs == 1)) { + buffer.append('{').append(fMinOccurs); + if (fMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED) + buffer.append("-UNBOUNDED"); + else if (fMinOccurs != fMaxOccurs) + buffer.append('-').append(fMaxOccurs); + buffer.append('}'); + } + fDescription = buffer.toString(); + } + return fDescription; + } + + /** + * append the string description of this particle to the string buffer + * this is for error message. + */ + void appendParticle(StringBuffer buffer) { + switch (fType) { + case PARTICLE_EMPTY: + buffer.append("EMPTY"); + break; + case PARTICLE_ELEMENT: + buffer.append(fValue.toString()); + break; + case PARTICLE_WILDCARD: + buffer.append('('); + buffer.append(fValue.toString()); + buffer.append(')'); + break; + case PARTICLE_MODELGROUP: + buffer.append(fValue.toString()); + break; + } + } + + public void reset(){ + fType = PARTICLE_EMPTY; + fValue = null; + fMinOccurs = 1; + fMaxOccurs = 1; + fDescription = null; + fAnnotations = null; + } + + /** + * Get the type of the object, i.e ELEMENT_DECLARATION. + */ + public short getType() { + return XSConstants.PARTICLE; + } + + /** + * The name of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return null; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return null; + } + + /** + * {min occurs} determines the minimum number of terms that can occur. + */ + public int getMinOccurs() { + return fMinOccurs; + } + + /** + * {max occurs} whether the maxOccurs value is unbounded. + */ + public boolean getMaxOccursUnbounded() { + return fMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED; + } + + /** + * {max occurs} determines the maximum number of terms that can occur. + */ + public int getMaxOccurs() { + return fMaxOccurs; + } + + /** + * {term} One of a model group, a wildcard, or an element declaration. + */ + public XSTerm getTerm() { + return fValue; + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return null; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + +} // class XSParticleDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSWildcardDecl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSWildcardDecl.java new file mode 100644 index 0000000..9cda6dc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/XSWildcardDecl.java @@ -0,0 +1,596 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs; + +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSAnnotation; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSWildcard; + +/** + * The XML representation for a wildcard declaration + * schema component is an <any> or <anyAttribute> element information item + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id$ + */ +public class XSWildcardDecl implements XSWildcard { + + public static final String ABSENT = null; + + // the type of wildcard: any, other, or list + public short fType = NSCONSTRAINT_ANY; + // the type of process contents: strict, lax, or skip + public short fProcessContents = PC_STRICT; + // the namespace list: + // for NSCONSTRAINT_LIST, it means one of the namespaces in the list + // for NSCONSTRAINT_NOT, it means not any of the namespaces in the list + public String[] fNamespaceList; + + // optional annotation + public XSObjectList fAnnotations = null; + + // I'm trying to implement the following constraint exactly as what the + // spec describes. Sometimes it seems redundant, and sometimes there seems + // to be much easier solutions. But it makes it easy to understand, + // easy to maintain, and easy to find a bug (either in the code, or in the + // spec). -SG + // + // NOTE: Schema spec only requires that ##other not(tNS,absent). + // The way we store ##other is not(NS1,NS2,...,NSN), which covers + // what's required by Schema, and allows future enhanced features. + // + // In the following in-line comments: + // - Bullet removed from w3c specification. + // + Bullet added as proposed by Sandy Gao, IBM. + // / Since we store ##other as not(NS1,NS2,...,NSN), we need to put some + // comments on where we didn't follow the spec exactly. + // * When we really support not(NS1,NS2,...,NSN), we need to revisit these items. + + /** + * Validation Rule: Wildcard allows Namespace Name + */ + public boolean allowNamespace(String namespace) { + // For a value which is either a namespace name or absent to be valid with respect to a wildcard constraint (the value of a {namespace constraint}) one of the following must be true: + + // 1 The constraint must be any. + if (fType == NSCONSTRAINT_ANY) + return true; + + // 2 All of the following must be true: + // 2.1 The constraint is a pair of not and a namespace name or absent ([Definition:] call this the namespace test). + // 2.2 The value must not be identical to the namespace test. + // 2.3 The value must not be absent. + // / we store ##other as not(list), so our actual rule is + // / 2 The constraint is a pair of not and a set, and the value is not in such set. + if (fType == NSCONSTRAINT_NOT) { + boolean found = false; + int listNum = fNamespaceList.length; + for (int i = 0; i < listNum && !found; i++) { + if (namespace == fNamespaceList[i]) + found = true; + } + + if (!found) + return true; + } + + // 3 The constraint is a set, and the value is identical to one of the members of the set. + if (fType == NSCONSTRAINT_LIST) { + int listNum = fNamespaceList.length; + for (int i = 0; i < listNum; i++) { + if (namespace == fNamespaceList[i]) + return true; + } + } + + // none of the above conditions applied, so return false. + return false; + } + + /** + * Schema Component Constraint: Wildcard Subset + */ + public boolean isSubsetOf(XSWildcardDecl superWildcard) { + // if the super is null (not expressible), return false + if (superWildcard == null) + return false; + + // For a namespace constraint (call it sub) to be an intensional subset of another + // namespace constraint (call it super) one of the following must be true: + + // 1 super must be any. + if (superWildcard.fType == NSCONSTRAINT_ANY) { + return true; + } + + // 2 All of the following must be true: + // 2.1 sub must be a pair of not and a namespace name or absent. + // 2.2 super must be a pair of not and the same value. + // * we can't just compare whether the namespace are the same value + // since we store other as not(list) + if (fType == NSCONSTRAINT_NOT) { + if (superWildcard.fType == NSCONSTRAINT_NOT && + fNamespaceList[0] == superWildcard.fNamespaceList[0]) { + return true; + } + } + + // 3 All of the following must be true: + // 3.1 sub must be a set whose members are either namespace names or absent. + // 3.2 One of the following must be true: + // 3.2.1 super must be the same set or a superset thereof. + // -3.2.2 super must be a pair of not and a namespace name or absent and + // that value must not be in sub's set. + // +3.2.2 super must be a pair of not and a namespace name or absent and + // either that value or absent must not be in sub's set. + // * since we store ##other as not(list), we acturally need to make sure + // that none of the namespaces in super.list is in sub.list. + if (fType == NSCONSTRAINT_LIST) { + if (superWildcard.fType == NSCONSTRAINT_LIST && + subset2sets(fNamespaceList, superWildcard.fNamespaceList)) { + return true; + } + + if (superWildcard.fType == NSCONSTRAINT_NOT && + !elementInSet(superWildcard.fNamespaceList[0], fNamespaceList) && + !elementInSet(ABSENT, fNamespaceList)) { + return true; + } + } + + // none of the above conditions applied, so return false. + return false; + + } // isSubsetOf + + /** + * Check whether this wildcard has a weaker process contents than the super. + */ + public boolean weakerProcessContents(XSWildcardDecl superWildcard) { + return fProcessContents == XSWildcardDecl.PC_LAX && + superWildcard.fProcessContents == XSWildcardDecl.PC_STRICT || + fProcessContents == XSWildcardDecl.PC_SKIP && + superWildcard.fProcessContents != XSWildcardDecl.PC_SKIP; + } + + /** + * Schema Component Constraint: Attribute Wildcard Union + */ + public XSWildcardDecl performUnionWith(XSWildcardDecl wildcard, + short processContents) { + // if the other wildcard is not expressible, the result is still not expressible + if (wildcard == null) + return null; + + // For a wildcard's {namespace constraint} value to be the intensional union of two + // other such values (call them O1 and O2): the appropriate case among the following + // must be true: + + XSWildcardDecl unionWildcard = new XSWildcardDecl(); + unionWildcard.fProcessContents = processContents; + + // 1 If O1 and O2 are the same value, then that value must be the value. + if (areSame(wildcard)) { + unionWildcard.fType = fType; + unionWildcard.fNamespaceList = fNamespaceList; + } + + // 2 If either O1 or O2 is any, then any must be the value. + else if ( (fType == NSCONSTRAINT_ANY) || (wildcard.fType == NSCONSTRAINT_ANY) ) { + unionWildcard.fType = NSCONSTRAINT_ANY; + } + + // 3 If both O1 and O2 are sets of (namespace names or absent), then the union of + // those sets must be the value. + else if ( (fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_LIST) ) { + unionWildcard.fType = NSCONSTRAINT_LIST; + unionWildcard.fNamespaceList = union2sets(fNamespaceList, wildcard.fNamespaceList); + } + + // -4 If the two are negations of different namespace names, then the intersection + // is not expressible. + // +4 If the two are negations of different namespace names or absent, then + // a pair of not and absent must be the value. + // * now we store ##other as not(list), the result should be + // not(intersection of two lists). + else if (fType == NSCONSTRAINT_NOT && wildcard.fType == NSCONSTRAINT_NOT) { + unionWildcard.fType = NSCONSTRAINT_NOT; + unionWildcard.fNamespaceList = new String[2]; + unionWildcard.fNamespaceList[0] = ABSENT; + unionWildcard.fNamespaceList[1] = ABSENT; + } + + // 5 If either O1 or O2 is a pair of not and a namespace name and the other is a set of + // (namespace names or absent), then The appropriate case among the following must be true: + // -5.1 If the set includes the negated namespace name, then any must be the value. + // -5.2 If the set does not include the negated namespace name, then whichever of O1 or O2 + // is a pair of not and a namespace name must be the value. + // +5.1 If the negated value is a namespace name, then The appropriate case + // among the following must be true: + // +5.1.1 If the set includes both the namespace name and absent, then any + // must be the value. + // +5.1.2 If the set includes the namespace name but does not include + // absent, then a pair of not and absent must be the value. + // +5.1.3 If the set does not include the namespace name but includes + // absent, then the union is not expressible. + // +5.1.4 If the set does not include either the namespace name or absent, + // then whichever of O1 or O2 is a pair of not and a namespace name must be + // the value. + // +5.2 If the negated value is absent, then The appropriate case among the + // following must be true: + // +5.2.1 If the set includes absent, then any must be the value. + // +5.2.2 If the set does not include absent, then whichever of O1 or O2 is + // a pair of not and a namespace name must be the value. + // * when we have not(list), the operation is just not(otherlist-list) + else if ( ((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST)) || + ((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT)) ) { + String[] other = null; + String[] list = null; + + if (fType == NSCONSTRAINT_NOT) { + other = fNamespaceList; + list = wildcard.fNamespaceList; + } + else { + other = wildcard.fNamespaceList; + list = fNamespaceList; + } + + boolean foundAbsent = elementInSet(ABSENT, list); + + if (other[0] != ABSENT) { + boolean foundNS = elementInSet(other[0], list); + if (foundNS && foundAbsent) { + unionWildcard.fType = NSCONSTRAINT_ANY; + } else if (foundNS && !foundAbsent) { + unionWildcard.fType = NSCONSTRAINT_NOT; + unionWildcard.fNamespaceList = new String[2]; + unionWildcard.fNamespaceList[0] = ABSENT; + unionWildcard.fNamespaceList[1] = ABSENT; + } else if (!foundNS && foundAbsent) { + return null; + } else { // !foundNS && !foundAbsent + unionWildcard.fType = NSCONSTRAINT_NOT; + unionWildcard.fNamespaceList = other; + } + } else { // other[0] == ABSENT + if (foundAbsent) { + unionWildcard.fType = NSCONSTRAINT_ANY; + } else { // !foundAbsent + unionWildcard.fType = NSCONSTRAINT_NOT; + unionWildcard.fNamespaceList = other; + } + } + } + + return unionWildcard; + + } // performUnionWith + + /** + * Schema Component Constraint: Attribute Wildcard Intersection + */ + public XSWildcardDecl performIntersectionWith(XSWildcardDecl wildcard, + short processContents) { + // if the other wildcard is not expressible, the result is still not expressible + if (wildcard == null) + return null; + + // For a wildcard's {namespace constraint} value to be the intensional intersection of + // two other such values (call them O1 and O2): the appropriate case among the following + // must be true: + + XSWildcardDecl intersectWildcard = new XSWildcardDecl(); + intersectWildcard.fProcessContents = processContents; + + // 1 If O1 and O2 are the same value, then that value must be the value. + if (areSame(wildcard)) { + intersectWildcard.fType = fType; + intersectWildcard.fNamespaceList = fNamespaceList; + } + + // 2 If either O1 or O2 is any, then the other must be the value. + else if ( (fType == NSCONSTRAINT_ANY) || (wildcard.fType == NSCONSTRAINT_ANY) ) { + // both cannot be ANY, if we have reached here. + XSWildcardDecl other = this; + + if (fType == NSCONSTRAINT_ANY) + other = wildcard; + + intersectWildcard.fType = other.fType; + intersectWildcard.fNamespaceList = other.fNamespaceList; + } + + // -3 If either O1 or O2 is a pair of not and a namespace name and the other is a set of + // (namespace names or absent), then that set, minus the negated namespace name if + // it was in the set, must be the value. + // +3 If either O1 or O2 is a pair of not and a namespace name and the other + // is a set of (namespace names or absent), then that set, minus the negated + // namespace name if it was in the set, then minus absent if it was in the + // set, must be the value. + // * when we have not(list), the operation is just list-otherlist + else if ( ((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST)) || + ((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT)) ) { + String[] list = null; + String[] other = null; + + if (fType == NSCONSTRAINT_NOT) { + other = fNamespaceList; + list = wildcard.fNamespaceList; + } + else { + other = wildcard.fNamespaceList; + list = fNamespaceList; + } + + int listSize = list.length; + String[] intersect = new String[listSize]; + int newSize = 0; + for (int i = 0; i < listSize; i++) { + if (list[i] != other[0] && list[i] != ABSENT) + intersect[newSize++] = list[i]; + } + + intersectWildcard.fType = NSCONSTRAINT_LIST; + intersectWildcard.fNamespaceList = new String[newSize]; + System.arraycopy(intersect, 0, intersectWildcard.fNamespaceList, 0, newSize); + } + + // 4 If both O1 and O2 are sets of (namespace names or absent), then the intersection of those + // sets must be the value. + else if ( (fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_LIST) ) { + intersectWildcard.fType = NSCONSTRAINT_LIST; + intersectWildcard.fNamespaceList = intersect2sets(fNamespaceList, wildcard.fNamespaceList); + } + + // -5 If the two are negations of different namespace names, then the intersection is not expressible. + // +5 If the two are negations of namespace names or absent, then The + // appropriate case among the following must be true: + // +5.1 If the two are negations of different namespace names, then the + // intersection is not expressible. + // +5.2 If one of the two is a pair of not and absent, the other must be + // the value. + // * when we have not(list), the operation is just not(onelist+otherlist) + else if (fType == NSCONSTRAINT_NOT && wildcard.fType == NSCONSTRAINT_NOT) { + if (fNamespaceList[0] != ABSENT && wildcard.fNamespaceList[0] != ABSENT) + return null; + + XSWildcardDecl other = this; + if (fNamespaceList[0] == ABSENT) + other = wildcard; + + intersectWildcard.fType = other.fType; + intersectWildcard.fNamespaceList = other.fNamespaceList; + } + + return intersectWildcard; + + } // performIntersectionWith + + private boolean areSame(XSWildcardDecl wildcard) { + if (fType == wildcard.fType) { + // ##any, true + if (fType == NSCONSTRAINT_ANY) + return true; + + // ##other, only check the negated value + // * when we support not(list), we need to check in the same way + // as for NSCONSTRAINT_LIST. + if (fType == NSCONSTRAINT_NOT) + return fNamespaceList[0] == wildcard.fNamespaceList[0]; + + // ## list, must have the same length, + // and each item in one list must appear in the other one + // (we are assuming that there are no duplicate items in a list) + if (fNamespaceList.length == wildcard.fNamespaceList.length) { + for (int i=0; iname of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return null; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return null; + } + + /** + * Namespace constraint: A constraint type: any, not, list. + */ + public short getConstraintType() { + return fType; + } + + /** + * Namespace constraint. For constraintType + * LIST_NSCONSTRAINT, the list contains allowed namespaces. For + * constraintType NOT_NSCONSTRAINT, the list contains + * disallowed namespaces. + */ + public StringList getNsConstraintList() { + return new StringListImpl(fNamespaceList, fNamespaceList == null ? 0 : fNamespaceList.length); + } + + /** + * {process contents} One of skip, lax or strict. Valid constants values + * are: PC_SKIP, PC_LAX, PC_STRICT. + */ + public short getProcessContents() { + return fProcessContents; + } + + /** + * String valid of {process contents}. One of "skip", "lax" or "strict". + */ + public String getProcessContentsAsString() { + switch (fProcessContents) { + case XSWildcardDecl.PC_SKIP: return "skip"; + case XSWildcardDecl.PC_LAX: return "lax"; + case XSWildcardDecl.PC_STRICT: return "strict"; + default: return "invalid value"; + } + } + + /** + * Optional. Annotation. + */ + public XSAnnotation getAnnotation() { + return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; + } + + /** + * Optional. Annotations. + */ + public XSObjectList getAnnotations() { + return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + return null; + } + +} // class XSWildcardDecl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/Field.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/Field.java new file mode 100644 index 0000000..2de86df --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/Field.java @@ -0,0 +1,305 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.identity; + +import org.apache.xerces.impl.xpath.XPathException; +import org.apache.xerces.impl.xs.util.ShortListImpl; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.XSComplexTypeDefinition; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * Schema identity constraint field. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @version $Id$ + */ +public class Field { + + // + // Data + // + + /** Field XPath. */ + protected final Field.XPath fXPath; + + + /** Identity constraint. */ + protected final IdentityConstraint fIdentityConstraint; + + // + // Constructors + // + + /** Constructs a field. */ + public Field(Field.XPath xpath, + IdentityConstraint identityConstraint) { + fXPath = xpath; + fIdentityConstraint = identityConstraint; + } // (Field.XPath,IdentityConstraint) + + // + // Public methods + // + + /** Returns the field XPath. */ + public org.apache.xerces.impl.xpath.XPath getXPath() { + return fXPath; + } // getXPath():org.apache.xerces.impl.v1.schema.identity.XPath + + /** Returns the identity constraint. */ + public IdentityConstraint getIdentityConstraint() { + return fIdentityConstraint; + } // getIdentityConstraint():IdentityConstraint + + // factory method + + /** Creates a field matcher. */ + public XPathMatcher createMatcher(ValueStore store) { + return new Field.Matcher(fXPath, store); + } // createMatcher(ValueStore):XPathMatcher + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + return fXPath.toString(); + } // toString():String + + // + // Classes + // + + /** + * Field XPath. + * + * @author Andy Clark, IBM + */ + public static class XPath + extends org.apache.xerces.impl.xpath.XPath { + + // + // Constructors + // + + /** Constructs a field XPath expression. */ + public XPath(String xpath, + SymbolTable symbolTable, + NamespaceContext context) throws XPathException { + super(fixupXPath(xpath), symbolTable, context); + + // verify that only one attribute is selected per branch + for (int i=0;i(String,SymbolTable,NamespacesContext) + + /** Fixup XPath expression. Avoid creating a new String if possible. */ + private static String fixupXPath(String xpath) { + + final int end = xpath.length(); + int offset = 0; + boolean whitespace = true; + char c; + + // NOTE: We have to prefix the field XPath with "./" in + // order to handle selectors such as "@attr" that + // select the attribute because the fields could be + // relative to the selector element. -Ac + // Unless xpath starts with a descendant node -Achille Fokoue + // ... or a / or a . - NG + for (; offset < end; ++offset) { + c = xpath.charAt(offset); + if (whitespace) { + if (!XMLChar.isSpace(c)) { + if (c == '.' || c == '/') { + whitespace = false; + } + else if (c != '|') { + return fixupXPath2(xpath, offset, end); + } + } + } + else if (c == '|') { + whitespace = true; + } + } + return xpath; + + } // fixupXPath(String):String + + private static String fixupXPath2(String xpath, int offset, final int end) { + + StringBuffer buffer = new StringBuffer(end + 2); + for (int i = 0; i < offset; ++i) { + buffer.append(xpath.charAt(i)); + } + buffer.append("./"); + + boolean whitespace = false; + char c; + + for (; offset < end; ++offset) { + c = xpath.charAt(offset); + if (whitespace) { + if (!XMLChar.isSpace(c)) { + if (c == '.' || c == '/') { + whitespace = false; + } + else if (c != '|') { + buffer.append("./"); + whitespace = false; + } + } + } + else if (c == '|') { + whitespace = true; + } + buffer.append(c); + } + return buffer.toString(); + + } // fixupXPath2(String, int, int):String + + } // class XPath + + /** + * Field matcher. + * + * @author Andy Clark, IBM + */ + protected class Matcher + extends XPathMatcher { + + // + // Data + // + + /** Value store for data values. */ + protected final ValueStore fStore; + + /** A flag indicating whether the field is allowed to match a value. */ + protected boolean fMayMatch = true; + + // + // Constructors + // + + /** Constructs a field matcher. */ + public Matcher(Field.XPath xpath, ValueStore store) { + super(xpath); + fStore = store; + } // (Field.XPath,ValueStore) + + // + // XPathHandler methods + // + + /** + * This method is called when the XPath handler matches the + * XPath expression. + */ + protected void matched(Object actualValue, short valueType, ShortList itemValueType, boolean isNil) { + super.matched(actualValue, valueType, itemValueType, isNil); + if(isNil && (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY)) { + String code = "KeyMatchesNillable"; + fStore.reportError(code, + new Object[]{fIdentityConstraint.getElementName(), fIdentityConstraint.getIdentityConstraintName()}); + } + fStore.addValue(Field.this, fMayMatch, actualValue, convertToPrimitiveKind(valueType), convertToPrimitiveKind(itemValueType)); + // once we've stored the value for this field, we set the mayMatch + // member to false so that in the same scope, we don't match any more + // values (and throw an error instead). + fMayMatch = false; + } // matched(String) + + private short convertToPrimitiveKind(short valueType) { + /** Primitive datatypes. */ + if (valueType <= XSConstants.NOTATION_DT) { + return valueType; + } + /** Types derived from string. */ + if (valueType <= XSConstants.ENTITY_DT) { + return XSConstants.STRING_DT; + } + /** Types derived from decimal. */ + if (valueType <= XSConstants.POSITIVEINTEGER_DT) { + return XSConstants.DECIMAL_DT; + } + /** Other types. */ + return valueType; + } + + private ShortList convertToPrimitiveKind(ShortList itemValueType) { + if (itemValueType != null) { + int i; + final int length = itemValueType.getLength(); + for (i = 0; i < length; ++i) { + short type = itemValueType.item(i); + if (type != convertToPrimitiveKind(type)) { + break; + } + } + if (i != length) { + final short [] arr = new short[length]; + for (int j = 0; j < i; ++j) { + arr[j] = itemValueType.item(j); + } + for(; i < length; ++i) { + arr[i] = convertToPrimitiveKind(itemValueType.item(i)); + } + return new ShortListImpl(arr, arr.length); + } + } + return itemValueType; + } + + protected void handleContent(XSTypeDefinition type, boolean nillable, Object actualValue, short valueType, ShortList itemValueType) { + if (type == null || + type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE && + ((XSComplexTypeDefinition) type).getContentType() + != XSComplexTypeDefinition.CONTENTTYPE_SIMPLE) { + + // the content must be simpleType content + fStore.reportError( "cvc-id.3", new Object[] { + fIdentityConstraint.getName(), + fIdentityConstraint.getElementName()}); + + } + fMatchedString = actualValue; + matched(fMatchedString, valueType, itemValueType, nillable); + } // handleContent(XSElementDecl, String) + + } // class Matcher + +} // class Field diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/FieldActivator.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/FieldActivator.java new file mode 100644 index 0000000..1ed307a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/FieldActivator.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.identity; + + +/** + * Interface for a field activator. The field activator is responsible + * for activating fields within a specific scope; the caller merely + * requests the fields to be activated. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface FieldActivator { + + // + // FieldActivator methods + // + + /** + * Start the value scope for the specified identity constraint. This + * method is called when the selector matches in order to initialize + * the value store. + * + * @param identityConstraint The identity constraint. + * @param initialDepth the depth at which the selector began matching + */ + public void startValueScopeFor(IdentityConstraint identityConstraint, + int initialDepth); + + /** + * Request to activate the specified field. This method returns the + * matcher for the field. + * + * @param field The field to activate. + * @param initialDepth the 0-indexed depth in the instance document at which the Selector began to match. + */ + public XPathMatcher activateField(Field field, int initialDepth); + + /** + * Ends the value scope for the specified identity constraint. + * + * @param identityConstraint The identity constraint. + * @param initialDepth the 0-indexed depth where the Selector began to match. + */ + public void endValueScopeFor(IdentityConstraint identityConstraint, int initialDepth); + +} // interface FieldActivator diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/IdentityConstraint.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/IdentityConstraint.java new file mode 100644 index 0000000..252a7d1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/IdentityConstraint.java @@ -0,0 +1,248 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.identity; + +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.util.StringListImpl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSIDCDefinition; +import org.apache.xerces.xs.XSNamespaceItem; +import org.apache.xerces.xs.XSObjectList; + +/** + * Base class of Schema identity constraint. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @version $Id$ + */ +public abstract class IdentityConstraint implements XSIDCDefinition { + + // + // Data + // + + /** type */ + protected short type; + + /** target namespace */ + protected final String fNamespace; + + /** Identity constraint name. */ + protected final String fIdentityConstraintName; + + /** name of owning element */ + protected final String fElementName; + + /** Selector. */ + protected Selector fSelector; + + /** Field count. */ + protected int fFieldCount; + + /** Fields. */ + protected Field[] fFields; + + // optional annotations + protected XSAnnotationImpl [] fAnnotations = null; + + // number of annotations in this identity constraint + protected int fNumAnnotations; + + // + // Constructors + // + + /** Default constructor. */ + protected IdentityConstraint(String namespace, String identityConstraintName, String elemName) { + fNamespace = namespace; + fIdentityConstraintName = identityConstraintName; + fElementName = elemName; + } // (String,String) + + // + // Public methods + // + + /** Returns the identity constraint name. */ + public String getIdentityConstraintName() { + return fIdentityConstraintName; + } // getIdentityConstraintName():String + + /** Sets the selector. */ + public void setSelector(Selector selector) { + fSelector = selector; + } // setSelector(Selector) + + /** Returns the selector. */ + public Selector getSelector() { + return fSelector; + } // getSelector():Selector + + /** Adds a field. */ + public void addField(Field field) { + if (fFields == null) + fFields = new Field[4]; + else if (fFieldCount == fFields.length) + fFields = resize(fFields, fFieldCount*2); + fFields[fFieldCount++] = field; + } // addField(Field) + + /** Returns the field count. */ + public int getFieldCount() { + return fFieldCount; + } // getFieldCount():int + + /** Returns the field at the specified index. */ + public Field getFieldAt(int index) { + return fFields[index]; + } // getFieldAt(int):Field + + // get the name of the owning element + public String getElementName () { + return fElementName; + } // getElementName(): String + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + String s = super.toString(); + int index1 = s.lastIndexOf('$'); + if (index1 != -1) { + return s.substring(index1 + 1); + } + int index2 = s.lastIndexOf('.'); + if (index2 != -1) { + return s.substring(index2 + 1); + } + return s; + } // toString():String + + // equals: returns true if and only if the String + // representations of all members of both objects (except for + // the elenemtName field) are equal. + public boolean equals(IdentityConstraint id) { + boolean areEqual = fIdentityConstraintName.equals(id.fIdentityConstraintName); + if(!areEqual) return false; + areEqual = fSelector.toString().equals(id.fSelector.toString()); + if(!areEqual) return false; + areEqual = (fFieldCount == id.fFieldCount); + if(!areEqual) return false; + for(int i=0; iname of this XSObject depending on the + * XSObject type. + */ + public String getName() { + return fIdentityConstraintName; + } + + /** + * The namespace URI of this node, or null if it is + * unspecified. defines how a namespace URI is attached to schema + * components. + */ + public String getNamespace() { + return fNamespace; + } + + /** + * {identity-constraint category} One of key, keyref or unique. + */ + public short getCategory() { + return type; + } + + /** + * {selector} A restricted XPath ([XPath]) expression + */ + public String getSelectorStr() { + return (fSelector != null) ? fSelector.toString() : null; + } + + /** + * {fields} A non-empty list of restricted XPath ([XPath]) expressions. + */ + public StringList getFieldStrs() { + String[] strs = new String[fFieldCount]; + for (int i = 0; i < fFieldCount; i++) + strs[i] = fFields[i].toString(); + return new StringListImpl(strs, fFieldCount); + } + + /** + * {referenced key} Required if {identity-constraint category} is keyref, + * forbidden otherwise. An identity-constraint definition with + * {identity-constraint category} equal to key or unique. + */ + public XSIDCDefinition getRefKey() { + return null; + } + + /** + * Optional. Annotation. + */ + public XSObjectList getAnnotations() { + return new XSObjectListImpl(fAnnotations, fNumAnnotations); + } + + /** + * @see org.apache.xerces.xs.XSObject#getNamespaceItem() + */ + public XSNamespaceItem getNamespaceItem() { + // REVISIT: implement + return null; + } + + public void addAnnotation(XSAnnotationImpl annotation) { + if(annotation == null) + return; + if(fAnnotations == null) { + fAnnotations = new XSAnnotationImpl[2]; + } else if(fNumAnnotations == fAnnotations.length) { + XSAnnotationImpl[] newArray = new XSAnnotationImpl[fNumAnnotations << 1]; + System.arraycopy(fAnnotations, 0, newArray, 0, fNumAnnotations); + fAnnotations = newArray; + } + fAnnotations[fNumAnnotations++] = annotation; + } + +} // class IdentityConstraint diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/KeyRef.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/KeyRef.java new file mode 100644 index 0000000..2e8e655 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/KeyRef.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.identity; + +import org.apache.xerces.xs.XSIDCDefinition; + +/** + * Schema key reference identity constraint. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @version $Id$ + */ +public class KeyRef + extends IdentityConstraint { + + // + // Data + // + + /** The key (or unique) being referred to. */ + protected final UniqueOrKey fKey; + + // + // Constructors + // + + /** Constructs a keyref with the specified name. */ + public KeyRef(String namespace, String identityConstraintName, + String elemName, UniqueOrKey key) { + super(namespace, identityConstraintName, elemName); + fKey = key; + type = IC_KEYREF; + } // (String,String,String) + + // + // Public methods + // + + /** Returns the key being referred to. */ + public UniqueOrKey getKey() { + return fKey; + } // getKey(): int + + /** + * {referenced key} Required if {identity-constraint category} is keyref, + * forbidden otherwise. An identity-constraint definition with + * {identity-constraint category} equal to key or unique. + */ + public XSIDCDefinition getRefKey() { + return fKey; + } + +} // class KeyRef diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/Selector.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/Selector.java new file mode 100644 index 0000000..391f101 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/Selector.java @@ -0,0 +1,254 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.identity; + +import org.apache.xerces.impl.xpath.XPathException; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * Schema identity constraint selector. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @version $Id$ + */ +public class Selector { + + // + // Data + // + + /** XPath. */ + protected final Selector.XPath fXPath; + + /** Identity constraint. */ + protected final IdentityConstraint fIdentityConstraint; + + // the Identity constraint we're the matcher for. Only + // used for selectors! + protected IdentityConstraint fIDConstraint; + + // + // Constructors + // + + /** Constructs a selector. */ + public Selector(Selector.XPath xpath, + IdentityConstraint identityConstraint) { + fXPath = xpath; + fIdentityConstraint = identityConstraint; + } // (Selector.XPath,IdentityConstraint) + + // + // Public methods + // + + /** Returns the selector XPath. */ + public org.apache.xerces.impl.xpath.XPath getXPath() { + return fXPath; + } // getXPath():org.apache.xerces.v1.schema.identity.XPath + + /** Returns the identity constraint. */ + public IdentityConstraint getIDConstraint() { + return fIdentityConstraint; + } // getIDConstraint():IdentityConstraint + + // factory method + + /** Creates a selector matcher. + * @param activator The activator for this selector's fields. + * @param initialDepth The depth in the document at which this matcher began its life; + * used in correctly handling recursive elements. + */ + public XPathMatcher createMatcher(FieldActivator activator, int initialDepth) { + return new Selector.Matcher(fXPath, activator, initialDepth); + } // createMatcher(FieldActivator):XPathMatcher + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + return fXPath.toString(); + } // toString():String + + // + // Classes + // + + /** + * Schema identity constraint selector XPath expression. + * + * @author Andy Clark, IBM + * @version $Id$ + */ + public static class XPath + extends org.apache.xerces.impl.xpath.XPath { + + // + // Constructors + // + + /** Constructs a selector XPath expression. */ + public XPath(String xpath, SymbolTable symbolTable, + NamespaceContext context) throws XPathException { + super(normalize(xpath), symbolTable, context); + // verify that an attribute is not selected + for (int i=0;i(String,SymbolTable,NamespacesScope) + + private static String normalize(String xpath) { + // NOTE: We have to prefix the selector XPath with "./" in + // order to handle selectors such as "." that select + // the element container because the fields could be + // relative to that element. -Ac + // Unless xpath starts with a descendant node -Achille Fokoue + // ... or a '.' or a '/' - NG + // And we also need to prefix exprs to the right of | with ./ - NG + StringBuffer modifiedXPath = new StringBuffer(xpath.length()+5); + int unionIndex = -1; + do { + if(!(XMLChar.trim(xpath).startsWith("/") || XMLChar.trim(xpath).startsWith("."))) { + modifiedXPath.append("./"); + } + unionIndex = xpath.indexOf('|'); + if(unionIndex == -1) { + modifiedXPath.append(xpath); + break; + } + modifiedXPath.append(xpath.substring(0,unionIndex+1)); + xpath = xpath.substring(unionIndex+1, xpath.length()); + } while(true); + return modifiedXPath.toString(); + } + + } // class Selector.XPath + + /** + * Selector matcher. + * + * @author Andy Clark, IBM + */ + public class Matcher + extends XPathMatcher { + + // + // Data + // + + /** Field activator. */ + protected final FieldActivator fFieldActivator; + + /** Initial depth in the document at which this matcher was created. */ + protected final int fInitialDepth; + + /** Element depth. */ + protected int fElementDepth; + + /** Depth at match. */ + protected int fMatchedDepth; + + // + // Constructors + // + + /** Constructs a selector matcher. */ + public Matcher(Selector.XPath xpath, FieldActivator activator, + int initialDepth) { + super(xpath); + fFieldActivator = activator; + fInitialDepth = initialDepth; + } // (Selector.XPath,FieldActivator) + + // + // XMLDocumentFragmentHandler methods + // + + public void startDocumentFragment(){ + super.startDocumentFragment(); + fElementDepth = 0; + fMatchedDepth = -1; + } // startDocumentFragment() + + /** + * The start of an element. If the document specifies the start element + * by using an empty tag, then the startElement method will immediately + * be followed by the endElement method, with no intervening methods. + * + * @param element The name of the element. + * @param attributes The element attributes. + * + */ + public void startElement(QName element, XMLAttributes attributes) { + super.startElement(element, attributes); + fElementDepth++; + // activate the fields, if selector is matched + //int matched = isMatched(); + + if (isMatched()) { +/* (fMatchedDepth == -1 && ((matched & MATCHED) == MATCHED)) || + ((matched & MATCHED_DESCENDANT) == MATCHED_DESCENDANT)) { */ + fMatchedDepth = fElementDepth; + fFieldActivator.startValueScopeFor(fIdentityConstraint, fInitialDepth); + int count = fIdentityConstraint.getFieldCount(); + for (int i = 0; i < count; i++) { + Field field = fIdentityConstraint.getFieldAt(i); + XPathMatcher matcher = fFieldActivator.activateField(field, fInitialDepth); + matcher.startElement(element, attributes); + } + } + + } // startElement(QName,XMLAttrList,int) + + public void endElement(QName element, XSTypeDefinition type, boolean nillable, Object actualValue, short valueType, ShortList itemValueType) { + super.endElement(element, type, nillable, actualValue, valueType, itemValueType); + if (fElementDepth-- == fMatchedDepth) { + fMatchedDepth = -1; + fFieldActivator.endValueScopeFor(fIdentityConstraint, fInitialDepth); + } + } + + /** Returns the identity constraint. */ + public IdentityConstraint getIdentityConstraint() { + return fIdentityConstraint; + } // getIdentityConstraint():IdentityConstraint + + /** get the initial depth at which this selector matched. */ + public int getInitialDepth() { + return fInitialDepth; + } // getInitialDepth(): int + + + } // class Matcher + +} // class Selector diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/UniqueOrKey.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/UniqueOrKey.java new file mode 100644 index 0000000..51c4555 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/UniqueOrKey.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.identity; + +/** + * Schema unique or key identity constraint. + * These two kinds of identity constraint have been combined to save + * the creation of a separate Vector object for any element that + * has both. A short int is used to distinguish which this object is. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * @version $Id$ + */ +public class UniqueOrKey + extends IdentityConstraint { + + // + // Constructors + // + + /** Constructs a unique or a key identity constraint. */ + public UniqueOrKey(String namespace, String identityConstraintName, + String elemName, short type) { + super(namespace, identityConstraintName, elemName); + this.type = type; + } // (String,String) + + // + // Public methods + // + +} // class Unique diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/ValueStore.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/ValueStore.java new file mode 100644 index 0000000..4fc50f5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/ValueStore.java @@ -0,0 +1,71 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.identity; + +import org.apache.xerces.xs.ShortList; + + +/** + * Interface for storing values associated to an identity constraint. + * Each value stored corresponds to a field declared for the identity + * constraint. One instance of an object implementing this interface + * is created for each identity constraint per element declaration in + * the instance document to store the information for this identity + * constraint. + *

+ * Note: The component performing identity constraint + * collection and validation is responsible for providing an + * implementation of this interface. The component is also responsible + * for performing the necessary checks required by each type of identity + * constraint. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface ValueStore { + + // + // ValueStore methods + // + + /** + * Adds the specified value to the value store. + * + * @param field The field associated to the value. This reference + * is used to ensure that each field only adds a value + * once within a selection scope. + * @param mayMatch a flag indiciating whether the field may be matched. + * @param actualValue The value to add. + * @param valueType Type of the value to add. + * @param itemValueType If the value is a list, a list of types for each of the values in the list. + */ + public void addValue(Field field, boolean mayMatch, Object actualValue, short valueType, ShortList itemValueType); + + /** + * Since the valueStore will have access to an error reporter, this + * allows it to be called appropriately. + * @param key the key of the localized error message + * @param args the list of arguments for substitution. + */ + public void reportError(String key, Object[] args); + + +} // interface ValueStore diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/XPathMatcher.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/XPathMatcher.java new file mode 100644 index 0000000..021ae0f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/identity/XPathMatcher.java @@ -0,0 +1,532 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.identity; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.xpath.XPath; +import org.apache.xerces.util.IntStack; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.XSTypeDefinition; +import org.xml.sax.SAXException; + +/** + * XPath matcher. + * + * @xerces.internal + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XPathMatcher { + + // + // Constants + // + + // debugging + + /** Compile to true to debug everything. */ + protected static final boolean DEBUG_ALL = false; + + /** Compile to true to debug method callbacks. */ + protected static final boolean DEBUG_METHODS = false || DEBUG_ALL; + + /** Compile to true to debug important method callbacks. */ + protected static final boolean DEBUG_METHODS2 = false || DEBUG_METHODS || DEBUG_ALL; + + /** Compile to true to debug the really important methods. */ + protected static final boolean DEBUG_METHODS3 = false || DEBUG_METHODS || DEBUG_ALL; + + /** Compile to true to debug match. */ + protected static final boolean DEBUG_MATCH = false || DEBUG_ALL; + + /** Compile to true to debug step index stack. */ + protected static final boolean DEBUG_STACK = false || DEBUG_ALL; + + /** Don't touch this value unless you add more debug constants. */ + protected static final boolean DEBUG_ANY = DEBUG_METHODS || + DEBUG_METHODS2 || + DEBUG_METHODS3 || + DEBUG_MATCH || + DEBUG_STACK; + + // constants describing whether a match was made, + // and if so how. + // matched any way + protected static final int MATCHED = 1; + // matched on the attribute axis + protected static final int MATCHED_ATTRIBUTE = 3; + // matched on the descendant-or-self axixs + protected static final int MATCHED_DESCENDANT = 5; + // matched some previous (ancestor) node on the descendant-or-self-axis, but not this node + protected static final int MATCHED_DESCENDANT_PREVIOUS = 13; + + // + // Data + // + + /** XPath location path. */ + private final XPath.LocationPath[] fLocationPaths; + + /** True if XPath has been matched. */ + private final int[] fMatched; + + /** The matching string. */ + protected Object fMatchedString; + + /** Integer stack of step indexes. */ + private final IntStack[] fStepIndexes; + + /** Current step. */ + private final int[] fCurrentStep; + + /** + * No match depth. The value of this field will be zero while + * matching is successful for the given xpath expression. + */ + private final int [] fNoMatchDepth; + + final QName fQName = new QName(); + + + // + // Constructors + // + + /** + * Constructs an XPath matcher that implements a document fragment + * handler. + * + * @param xpath The xpath. + */ + public XPathMatcher(XPath xpath) { + fLocationPaths = xpath.getLocationPaths(); + fStepIndexes = new IntStack[fLocationPaths.length]; + for(int i=0; i(XPath) + + // + // Public methods + // + + /** + * Returns value of first member of fMatched that + * is nonzero. + */ + public boolean isMatched() { + // xpath has been matched if any one of the members of the union have matched. + for (int i=0; i < fLocationPaths.length; i++) + if (((fMatched[i] & MATCHED) == MATCHED) + && ((fMatched[i] & MATCHED_DESCENDANT_PREVIOUS) != MATCHED_DESCENDANT_PREVIOUS) + && ((fNoMatchDepth[i] == 0) + || ((fMatched[i] & MATCHED_DESCENDANT) == MATCHED_DESCENDANT))) + return true; + + return false; + } // isMatched():int + + // + // Protected methods + // + + // a place-holder method; to be overridden by subclasses + // that care about matching element content. + protected void handleContent(XSTypeDefinition type, boolean nillable, Object value, short valueType, ShortList itemValueType) { + } + + /** + * This method is called when the XPath handler matches the + * XPath expression. Subclasses can override this method to + * provide default handling upon a match. + */ + protected void matched(Object actualValue, short valueType, ShortList itemValueType, boolean isNil) { + if (DEBUG_METHODS3) { + System.out.println(toString()+"#matched(\""+actualValue+"\")"); + } + } // matched(String content, XSSimpleType val) + + // + // ~XMLDocumentFragmentHandler methods + // + + /** + * The start of the document fragment. + */ + public void startDocumentFragment(){ + if (DEBUG_METHODS) { + System.out.println(toString()+"#startDocumentFragment("+ + ")"); + } + + // reset state + fMatchedString = null; + for(int i = 0; i < fLocationPaths.length; i++) { + fStepIndexes[i].clear(); + fCurrentStep[i] = 0; + fNoMatchDepth[i] = 0; + fMatched[i] = 0; + } + + + } // startDocumentFragment() + + /** + * The start of an element. If the document specifies the start element + * by using an empty tag, then the startElement method will immediately + * be followed by the endElement method, with no intervening methods. + * + * @param element The name of the element. + * @param attributes The element attributes. + * + * @throws SAXException Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes) { + if (DEBUG_METHODS2) { + System.out.println(toString()+"#startElement("+ + "element={"+element+"},"+ + "attributes=..."+attributes+ + ")"); + } + + for (int i = 0; i < fLocationPaths.length; i++) { + // push context + int startStep = fCurrentStep[i]; + fStepIndexes[i].push(startStep); + + // try next xpath, if not matching + if ((fMatched[i] & MATCHED_DESCENDANT) == MATCHED || fNoMatchDepth[i] > 0) { + fNoMatchDepth[i]++; + continue; + } + if((fMatched[i] & MATCHED_DESCENDANT) == MATCHED_DESCENDANT) { + fMatched[i] = MATCHED_DESCENDANT_PREVIOUS; + } + + if (DEBUG_STACK) { + System.out.println(toString()+": "+fStepIndexes[i]); + } + + // consume self::node() steps + XPath.Step[] steps = fLocationPaths[i].steps; + while (fCurrentStep[i] < steps.length && + steps[fCurrentStep[i]].axis.type == XPath.Axis.SELF) { + if (DEBUG_MATCH) { + XPath.Step step = steps[fCurrentStep[i]]; + System.out.println(toString()+" [SELF] MATCHED!"); + } + fCurrentStep[i]++; + } + if (fCurrentStep[i] == steps.length) { + if (DEBUG_MATCH) { + System.out.println(toString()+" XPath MATCHED!"); + } + fMatched[i] = MATCHED; + continue; + } + + // now if the current step is a descendant step, we let the next + // step do its thing; if it fails, we reset ourselves + // to look at this step for next time we're called. + // so first consume all descendants: + int descendantStep = fCurrentStep[i]; + while(fCurrentStep[i] < steps.length && steps[fCurrentStep[i]].axis.type == XPath.Axis.DESCENDANT) { + if (DEBUG_MATCH) { + XPath.Step step = steps[fCurrentStep[i]]; + System.out.println(toString()+" [DESCENDANT] MATCHED!"); + } + fCurrentStep[i]++; + } + boolean sawDescendant = fCurrentStep[i] > descendantStep; + if (fCurrentStep[i] == steps.length) { + if (DEBUG_MATCH) { + System.out.println(toString()+" XPath DIDN'T MATCH!"); + } + fNoMatchDepth[i]++; + if (DEBUG_MATCH) { + System.out.println(toString()+" [CHILD] after NO MATCH"); + } + continue; + } + + // match child::... step, if haven't consumed any self::node() + if ((fCurrentStep[i] == startStep || fCurrentStep[i] > descendantStep) && + steps[fCurrentStep[i]].axis.type == XPath.Axis.CHILD) { + XPath.Step step = steps[fCurrentStep[i]]; + XPath.NodeTest nodeTest = step.nodeTest; + if (DEBUG_MATCH) { + System.out.println(toString()+" [CHILD] before"); + } + if (!matches(nodeTest, element)) { + if (fCurrentStep[i] > descendantStep) { + fCurrentStep[i] = descendantStep; + continue; + } + fNoMatchDepth[i]++; + if (DEBUG_MATCH) { + System.out.println(toString()+" [CHILD] after NO MATCH"); + } + continue; + } + fCurrentStep[i]++; + if (DEBUG_MATCH) { + System.out.println(toString()+" [CHILD] after MATCHED!"); + } + } + if (fCurrentStep[i] == steps.length) { + if (sawDescendant) { + fCurrentStep[i] = descendantStep; + fMatched[i] = MATCHED_DESCENDANT; + } + else { + fMatched[i] = MATCHED; + } + continue; + } + + // match attribute::... step + if (fCurrentStep[i] < steps.length && + steps[fCurrentStep[i]].axis.type == XPath.Axis.ATTRIBUTE) { + if (DEBUG_MATCH) { + System.out.println(toString()+" [ATTRIBUTE] before"); + } + int attrCount = attributes.getLength(); + if (attrCount > 0) { + XPath.NodeTest nodeTest = steps[fCurrentStep[i]].nodeTest; + + for (int aIndex = 0; aIndex < attrCount; aIndex++) { + attributes.getName(aIndex, fQName); + if (matches(nodeTest, fQName)) { + fCurrentStep[i]++; + if (fCurrentStep[i] == steps.length) { + fMatched[i] = MATCHED_ATTRIBUTE; + int j = 0; + for(; j < i && ((fMatched[j] & MATCHED) != MATCHED); j++); + if (j == i) { + AttributePSVI attrPSVI = (AttributePSVI)attributes.getAugmentations(aIndex).getItem(Constants.ATTRIBUTE_PSVI); + fMatchedString = attrPSVI.getActualNormalizedValue(); + matched(fMatchedString, attrPSVI.getActualNormalizedValueType(), attrPSVI.getItemValueTypes(), false); + } + } + break; + } + } + } + if ((fMatched[i] & MATCHED) != MATCHED) { + if(fCurrentStep[i] > descendantStep) { + fCurrentStep[i] = descendantStep; + continue; + } + fNoMatchDepth[i]++; + if (DEBUG_MATCH) { + System.out.println(toString()+" [ATTRIBUTE] after"); + } + continue; + } + if (DEBUG_MATCH) { + System.out.println(toString()+" [ATTRIBUTE] after MATCHED!"); + } + } + } + + } + // startElement(QName,XMLAttrList,int) + + /** + * @param element + * name of the element. + * @param type + * content type of this element. IOW, the XML schema type + * of the value. Note that this may not be the type declared + * in the element declaration, but it is "the actual type". For example, + * if the XML is <foo xsi:type="xs:string">aaa</foo>, this + * parameter will be "xs:string". + * @param nillable - nillable + * true if the element declaration is nillable. + * @param value - actual value + * the typed value of the content of this element. + */ + public void endElement(QName element, XSTypeDefinition type, boolean nillable, Object value, short valueType, ShortList itemValueType) { + if (DEBUG_METHODS2) { + System.out.println(toString()+"#endElement("+ + "element={"+element+"},"+ + ")"); + } + for (int i = 0; i < fLocationPaths.length; i++) { + // go back a step + fCurrentStep[i] = fStepIndexes[i].pop(); + + // don't do anything, if not matching + if (fNoMatchDepth[i] > 0) { + fNoMatchDepth[i]--; + } + + // signal match, if appropriate + else { + int j = 0; + for(; j < i && ((fMatched[j] & MATCHED) != MATCHED); j++); + if ((j < i) || (fMatched[j] == 0)) { + continue; + } + if ((fMatched[j] & MATCHED_ATTRIBUTE) == MATCHED_ATTRIBUTE) { + fMatched[i] = 0; + continue; + } + // only certain kinds of matchers actually + // match element content. This permits + // them a way to override this to do nothing + // and hopefully save a few operations. + handleContent(type, nillable, value, valueType, itemValueType); + fMatched[i] = 0; + } + + if (DEBUG_STACK) { + System.out.println(toString()+": "+fStepIndexes[i]); + } + } + + } // endElement(QName) + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + /*** + return fLocationPath.toString(); + /***/ + StringBuffer str = new StringBuffer(); + String s = super.toString(); + int index2 = s.lastIndexOf('.'); + if (index2 != -1) { + s = s.substring(index2 + 1); + } + str.append(s); + for(int i =0;i \""+xpath.toString()+'"'); + final String uri = argv[++i]; + System.out.println("#### argv["+i+"]: "+uri); + parser.parse(uri); + } + } + + } // main(String[]) + /***/ + +} // class XPathMatcher diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/CMBuilder.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/CMBuilder.java new file mode 100644 index 0000000..5afce7c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/CMBuilder.java @@ -0,0 +1,451 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +import org.apache.xerces.impl.dtd.models.CMNode; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSComplexTypeDecl; +import org.apache.xerces.impl.xs.XSDeclarationPool; +import org.apache.xerces.impl.xs.XSElementDecl; +import org.apache.xerces.impl.xs.XSModelGroupImpl; +import org.apache.xerces.impl.xs.XSParticleDecl; + +/** + * This class constructs content models for a given grammar. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class CMBuilder { + + // REVISIT: should update the decl pool to cache XSCM objects too + private XSDeclarationPool fDeclPool = null; + + // It never changes, so a static member is good enough + private static final XSEmptyCM fEmptyCM = new XSEmptyCM(); + + // needed for DFA construction + private int fLeafCount; + // needed for UPA + private int fParticleCount; + //Factory to create Bin, Uni, Leaf nodes + private final CMNodeFactory fNodeFactory; + + public CMBuilder(CMNodeFactory nodeFactory) { + fDeclPool = null; + fNodeFactory = nodeFactory ; + } + + public void setDeclPool(XSDeclarationPool declPool) { + fDeclPool = declPool; + } + + /** + * Get content model for the a given type + * + * @param typeDecl get content model for which complex type + * @return a content model validator + */ + public XSCMValidator getContentModel(XSComplexTypeDecl typeDecl, boolean forUPA) { + + // for complex type with empty or simple content, + // there is no content model validator + short contentType = typeDecl.getContentType(); + if (contentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE || + contentType == XSComplexTypeDecl.CONTENTTYPE_EMPTY) { + return null; + } + + XSParticleDecl particle = (XSParticleDecl)typeDecl.getParticle(); + + // if the content is element only or mixed, but no particle + // is defined, return the empty content model + if (particle == null) + return fEmptyCM; + + // if the content model contains "all" model group, + // we create an "all" content model, otherwise a DFA content model + XSCMValidator cmValidator = null; + if (particle.fType == XSParticleDecl.PARTICLE_MODELGROUP && + ((XSModelGroupImpl)particle.fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL) { + cmValidator = createAllCM(particle); + } + else { + cmValidator = createDFACM(particle, forUPA); + } + + //now we are throught building content model and have passed sucessfully of the nodecount check + //if set by the application + fNodeFactory.resetNodeCount() ; + + // if the validator returned is null, it means there is nothing in + // the content model, so we return the empty content model. + if (cmValidator == null) + cmValidator = fEmptyCM; + + return cmValidator; + } + + XSCMValidator createAllCM(XSParticleDecl particle) { + if (particle.fMaxOccurs == 0) + return null; + + // get the model group, and add all children of it to the content model + XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue; + // create an all content model. the parameter indicates whether + // the itself is optional + XSAllCM allContent = new XSAllCM(particle.fMinOccurs == 0, group.fParticleCount); + for (int i = 0; i < group.fParticleCount; i++) { + // add the element decl to the all content model + allContent.addElement((XSElementDecl)group.fParticles[i].fValue, + group.fParticles[i].fMinOccurs == 0); + } + return allContent; + } + + XSCMValidator createDFACM(XSParticleDecl particle, boolean forUPA) { + fLeafCount = 0; + fParticleCount = 0; + // convert particle tree to CM tree + CMNode node = useRepeatingLeafNodes(particle) ? buildCompactSyntaxTree(particle) : buildSyntaxTree(particle, forUPA); + if (node == null) + return null; + // build DFA content model from the CM tree + return new XSDFACM(node, fLeafCount); + } + + // 1. convert particle tree to CM tree: + // 2. expand all occurrence values: a{n, unbounded} -> a, a, ..., a+ + // a{n, m} -> a, a, ..., a?, a?, ... + // 3. convert model groups (a, b, c, ...) or (a | b | c | ...) to + // binary tree: (((a,b),c),...) or (((a|b)|c)|...) + // 4. make sure each leaf node (XSCMLeaf) has a distinct position + private CMNode buildSyntaxTree(XSParticleDecl particle, boolean forUPA) { + + int maxOccurs = particle.fMaxOccurs; + int minOccurs = particle.fMinOccurs; + + boolean compactedForUPA = false; + if (forUPA) { + // When doing UPA, we reduce the size of the minOccurs/maxOccurs values to make + // processing the DFA faster. For UPA the exact values don't matter. + if (minOccurs > 1) { + if (maxOccurs > minOccurs || particle.getMaxOccursUnbounded()) { + minOccurs = 1; + compactedForUPA = true; + } + else { // maxOccurs == minOccurs + minOccurs = 2; + compactedForUPA = true; + } + } + if (maxOccurs > 1) { + maxOccurs = 2; + compactedForUPA = true; + } + } + + short type = particle.fType; + CMNode nodeRet = null; + + if ((type == XSParticleDecl.PARTICLE_WILDCARD) || + (type == XSParticleDecl.PARTICLE_ELEMENT)) { + // (task 1) element and wildcard particles should be converted to + // leaf nodes + // REVISIT: Make a clone of the leaf particle, so that if there + // are two references to the same group, we have two different + // leaf particles for the same element or wildcard decl. + // This is useful for checking UPA. + nodeRet = fNodeFactory.getCMLeafNode(particle.fType, particle.fValue, fParticleCount++, fLeafCount++); + // (task 2) expand occurrence values + nodeRet = expandContentModel(nodeRet, minOccurs, maxOccurs); + if (nodeRet != null) { + nodeRet.setIsCompactUPAModel(compactedForUPA); + } + } + else if (type == XSParticleDecl.PARTICLE_MODELGROUP) { + // (task 1,3) convert model groups to binary trees + XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue; + CMNode temp = null; + // when the model group is a choice of more than one particles, but + // only one of the particle is not empty, (for example + // + // + // + // + // ) we can't not return that one particle ("e"). instead, we should + // treat such particle as optional ("e?"). + // the following int variable keeps track of the number of non-empty children + int count = 0; + for (int i = 0; i < group.fParticleCount; i++) { + // first convert each child to a CM tree + temp = buildSyntaxTree(group.fParticles[i], forUPA); + // then combine them using binary operation + if (temp != null) { + compactedForUPA |= temp.isCompactedForUPA(); + ++count; + if (nodeRet == null) { + nodeRet = temp; + } + else { + nodeRet = fNodeFactory.getCMBinOpNode(group.fCompositor, nodeRet, temp); + } + } + } + // (task 2) expand occurrence values + if (nodeRet != null) { + // when the group is "choice" and the group has one or more empty children, + // we need to create a zero-or-one (optional) node for the non-empty particles. + if (group.fCompositor == XSModelGroupImpl.MODELGROUP_CHOICE && count < group.fParticleCount) { + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_ONE, nodeRet); + } + nodeRet = expandContentModel(nodeRet, minOccurs, maxOccurs); + nodeRet.setIsCompactUPAModel(compactedForUPA); + } + } + + return nodeRet; + } + + // 2. expand all occurrence values: a{n, unbounded} -> a, a, ..., a+ + // a{n, m} -> a, a, ..., a?, a?, ... + // 4. make sure each leaf node (XSCMLeaf) has a distinct position + private CMNode expandContentModel(CMNode node, + int minOccurs, int maxOccurs) { + + CMNode nodeRet = null; + + if (minOccurs==1 && maxOccurs==1) { + nodeRet = node; + } + else if (minOccurs==0 && maxOccurs==1) { + //zero or one + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_ONE, node); + } + else if (minOccurs == 0 && maxOccurs==SchemaSymbols.OCCURRENCE_UNBOUNDED) { + //zero or more + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_MORE, node); + } + else if (minOccurs == 1 && maxOccurs==SchemaSymbols.OCCURRENCE_UNBOUNDED) { + //one or more + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ONE_OR_MORE, node); + } + else if (maxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED) { + // => a,a,..,a+ + // create a+ node first, then put minOccurs-1 a's in front of it + // for the first time "node" is used, we don't need to make a copy + // and for other references to node, we make copies + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ONE_OR_MORE, node); + // (task 4) we need to call copyNode here, so that we append + // an entire new copy of the node (a subtree). this is to ensure + // all leaf nodes have distinct position + // we know that minOccurs > 1 + nodeRet = fNodeFactory.getCMBinOpNode(XSModelGroupImpl.MODELGROUP_SEQUENCE, + multiNodes(node, minOccurs-1, true), nodeRet); + } + else { + // {n,m} => a,a,a,...(a),(a),... + // first n a's, then m-n a?'s. + // copyNode is called, for the same reason as above + if (minOccurs > 0) { + nodeRet = multiNodes(node, minOccurs, false); + } + if (maxOccurs > minOccurs) { + node = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_ONE, node); + if (nodeRet == null) { + nodeRet = multiNodes(node, maxOccurs-minOccurs, false); + } + else { + nodeRet = fNodeFactory.getCMBinOpNode(XSModelGroupImpl.MODELGROUP_SEQUENCE, + nodeRet, multiNodes(node, maxOccurs-minOccurs, true)); + } + } + } + + return nodeRet; + } + + private CMNode multiNodes(CMNode node, int num, boolean copyFirst) { + if (num == 0) { + return null; + } + if (num == 1) { + return copyFirst ? copyNode(node) : node; + } + int num1 = num/2; + return fNodeFactory.getCMBinOpNode(XSModelGroupImpl.MODELGROUP_SEQUENCE, + multiNodes(node, num1, copyFirst), + multiNodes(node, num-num1, true)); + } + + // 4. make sure each leaf node (XSCMLeaf) has a distinct position + private CMNode copyNode(CMNode node) { + int type = node.type(); + // for choice or sequence, copy the two subtrees, and combine them + if (type == XSModelGroupImpl.MODELGROUP_CHOICE || + type == XSModelGroupImpl.MODELGROUP_SEQUENCE) { + XSCMBinOp bin = (XSCMBinOp)node; + node = fNodeFactory.getCMBinOpNode(type, copyNode(bin.getLeft()), + copyNode(bin.getRight())); + } + // for ?+*, copy the subtree, and put it in a new ?+* node + else if (type == XSParticleDecl.PARTICLE_ZERO_OR_MORE || + type == XSParticleDecl.PARTICLE_ONE_OR_MORE || + type == XSParticleDecl.PARTICLE_ZERO_OR_ONE) { + XSCMUniOp uni = (XSCMUniOp)node; + node = fNodeFactory.getCMUniOpNode(type, copyNode(uni.getChild())); + } + // for element/wildcard (leaf), make a new leaf node, + // with a distinct position + else if (type == XSParticleDecl.PARTICLE_ELEMENT || + type == XSParticleDecl.PARTICLE_WILDCARD) { + XSCMLeaf leaf = (XSCMLeaf)node; + node = fNodeFactory.getCMLeafNode(leaf.type(), leaf.getLeaf(), leaf.getParticleId(), fLeafCount++); + } + + return node; + } + + // A special version of buildSyntaxTree() which builds a compact syntax tree + // containing compound leaf nodes which carry occurence information. This method + // for building the syntax tree is chosen over buildSyntaxTree() when + // useRepeatingLeafNodes() returns true. + private CMNode buildCompactSyntaxTree(XSParticleDecl particle) { + int maxOccurs = particle.fMaxOccurs; + int minOccurs = particle.fMinOccurs; + short type = particle.fType; + CMNode nodeRet = null; + + if ((type == XSParticleDecl.PARTICLE_WILDCARD) || + (type == XSParticleDecl.PARTICLE_ELEMENT)) { + return buildCompactSyntaxTree2(particle, minOccurs, maxOccurs); + } + else if (type == XSParticleDecl.PARTICLE_MODELGROUP) { + XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue; + if (group.fParticleCount == 1 && (minOccurs != 1 || maxOccurs != 1)) { + return buildCompactSyntaxTree2(group.fParticles[0], minOccurs, maxOccurs); + } + else { + CMNode temp = null; + + // when the model group is a choice of more than one particles, but + // only one of the particle is not empty, (for example + // + // + // + // + // ) we can't not return that one particle ("e"). instead, we should + // treat such particle as optional ("e?"). + // the following int variable keeps track of the number of non-empty children + int count = 0; + for (int i = 0; i < group.fParticleCount; i++) { + // first convert each child to a CM tree + temp = buildCompactSyntaxTree(group.fParticles[i]); + // then combine them using binary operation + if (temp != null) { + ++count; + if (nodeRet == null) { + nodeRet = temp; + } + else { + nodeRet = fNodeFactory.getCMBinOpNode(group.fCompositor, nodeRet, temp); + } + } + } + if (nodeRet != null) { + // when the group is "choice" and the group has one or more empty children, + // we need to create a zero-or-one (optional) node for the non-empty particles. + if (group.fCompositor == XSModelGroupImpl.MODELGROUP_CHOICE && count < group.fParticleCount) { + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_ONE, nodeRet); + } + } + } + } + return nodeRet; + } + + private CMNode buildCompactSyntaxTree2(XSParticleDecl particle, int minOccurs, int maxOccurs) { + // Convert element and wildcard particles to leaf nodes. Wrap repeating particles in a CMUniOpNode. + CMNode nodeRet = null; + if (minOccurs == 1 && maxOccurs == 1) { + nodeRet = fNodeFactory.getCMLeafNode(particle.fType, particle.fValue, fParticleCount++, fLeafCount++); + } + else if (minOccurs == 0 && maxOccurs == 1) { + // zero or one + nodeRet = fNodeFactory.getCMLeafNode(particle.fType, particle.fValue, fParticleCount++, fLeafCount++); + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_ONE, nodeRet); + } + else if (minOccurs == 0 && maxOccurs==SchemaSymbols.OCCURRENCE_UNBOUNDED) { + // zero or more + nodeRet = fNodeFactory.getCMLeafNode(particle.fType, particle.fValue, fParticleCount++, fLeafCount++); + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_MORE, nodeRet); + } + else if (minOccurs == 1 && maxOccurs==SchemaSymbols.OCCURRENCE_UNBOUNDED) { + // one or more + nodeRet = fNodeFactory.getCMLeafNode(particle.fType, particle.fValue, fParticleCount++, fLeafCount++); + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ONE_OR_MORE, nodeRet); + } + else { + // {n,m}: Instead of expanding this out, create a compound leaf node which carries the + // occurence information and wrap it in the appropriate CMUniOpNode. + nodeRet = fNodeFactory.getCMRepeatingLeafNode(particle.fType, particle.fValue, minOccurs, maxOccurs, fParticleCount++, fLeafCount++); + if (minOccurs == 0) { + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_MORE, nodeRet); + } + else { + nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ONE_OR_MORE, nodeRet); + } + } + return nodeRet; + } + + // This method checks if this particle can be transformed into a compact syntax + // tree containing compound leaf nodes which carry occurence information. Currently + // it returns true if each model group has minOccurs/maxOccurs == 1 or + // contains only one element/wildcard particle with minOccurs/maxOccurs == 1. + private boolean useRepeatingLeafNodes(XSParticleDecl particle) { + int maxOccurs = particle.fMaxOccurs; + int minOccurs = particle.fMinOccurs; + short type = particle.fType; + + if (type == XSParticleDecl.PARTICLE_MODELGROUP) { + XSModelGroupImpl group = (XSModelGroupImpl) particle.fValue; + if (minOccurs != 1 || maxOccurs != 1) { + if (group.fParticleCount == 1) { + XSParticleDecl particle2 = (XSParticleDecl) group.fParticles[0]; + short type2 = particle2.fType; + return ((type2 == XSParticleDecl.PARTICLE_ELEMENT || + type2 == XSParticleDecl.PARTICLE_WILDCARD) && + particle2.fMinOccurs == 1 && + particle2.fMaxOccurs == 1); + } + return (group.fParticleCount == 0); + } + for (int i = 0; i < group.fParticleCount; ++i) { + if (!useRepeatingLeafNodes(group.fParticles[i])) { + return false; + } + } + } + return true; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/CMNodeFactory.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/CMNodeFactory.java new file mode 100644 index 0000000..3899c19 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/CMNodeFactory.java @@ -0,0 +1,169 @@ +/* + * 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. + */ + + +package org.apache.xerces.impl.xs.models; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dtd.models.CMNode; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; + +/** + * + * @xerces.internal + * + * @author Neeraj Bajaj + * + * @version $Id$ + */ +public class CMNodeFactory { + + + /** Property identifier: error reporter. */ + private static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** property identifier: security manager. */ + private static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + private static final boolean DEBUG = false ; + + // + private static final int MULTIPLICITY = 1 ; + + //count of number of nodes created + private int nodeCount = 0; + + //No. of nodes allowed. + private int maxNodeLimit ; + + + /** + * Error reporter. This property identifier is: + * http://apache.org/xml/properties/internal/error-reporter + */ + private XMLErrorReporter fErrorReporter; + + // stores defaults for different security holes (maxOccurLimit in current context) if it has + // been set on the configuration. + private SecurityManager fSecurityManager = null; + + /** default constructor */ + public CMNodeFactory() { + } + + public void reset(XMLComponentManager componentManager) { + fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); + try { + fSecurityManager = (SecurityManager)componentManager.getProperty(SECURITY_MANAGER); + reset(); + } + catch (XMLConfigurationException e) { + fSecurityManager = null; + } + + }//reset() + + public void reset() { + // we are setting the limit of number of nodes to 3 times the maxOccurs value. + if (fSecurityManager != null) { + maxNodeLimit = fSecurityManager.getMaxOccurNodeLimit() * MULTIPLICITY; + } + } + + public CMNode getCMLeafNode(int type, Object leaf, int id, int position) { + nodeCountCheck(); + return new XSCMLeaf(type, leaf, id, position) ; + } + + public CMNode getCMRepeatingLeafNode(int type, Object leaf, + int minOccurs, int maxOccurs, int id, int position) { + nodeCountCheck(); + return new XSCMRepeatingLeaf(type, leaf, minOccurs, maxOccurs, id, position); + } + + public CMNode getCMUniOpNode(int type, CMNode childNode) { + nodeCountCheck(); + return new XSCMUniOp(type, childNode) ; + } + + public CMNode getCMBinOpNode(int type, CMNode leftNode, CMNode rightNode) { + nodeCountCheck() ; + return new XSCMBinOp(type, leftNode, rightNode) ; + } + + public void nodeCountCheck(){ + if( fSecurityManager != null && nodeCount++ > maxNodeLimit){ + if(DEBUG){ + System.out.println("nodeCount = " + nodeCount ) ; + System.out.println("nodeLimit = " + maxNodeLimit ) ; + } + fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, "maxOccurLimit", new Object[]{ new Integer(maxNodeLimit) }, XMLErrorReporter.SEVERITY_FATAL_ERROR); + // similarly to entity manager behaviour, take into accont + // behaviour if continue-after-fatal-error is set. + nodeCount = 0; + } + + }//nodeCountCheck() + + //reset the node count + public void resetNodeCount(){ + nodeCount = 0 ; + } + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

+ * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // Xerces properties + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SECURITY_MANAGER_PROPERTY.length() && + propertyId.endsWith(Constants.SECURITY_MANAGER_PROPERTY)) { + fSecurityManager = (SecurityManager)value; + maxNodeLimit = (fSecurityManager != null) ? fSecurityManager.getMaxOccurNodeLimit() * MULTIPLICITY : 0 ; + return; + } + if (suffixLength == Constants.ERROR_REPORTER_PROPERTY.length() && + propertyId.endsWith(Constants.ERROR_REPORTER_PROPERTY)) { + fErrorReporter = (XMLErrorReporter)value; + return; + } + } + + } // setProperty(String,Object) + +}//CMNodeFactory() diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSAllCM.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSAllCM.java new file mode 100644 index 0000000..91431df --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSAllCM.java @@ -0,0 +1,228 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +import java.util.Vector; + +import org.apache.xerces.impl.xs.SubstitutionGroupHandler; +import org.apache.xerces.impl.xs.XMLSchemaException; +import org.apache.xerces.impl.xs.XSConstraints; +import org.apache.xerces.impl.xs.XSElementDecl; +import org.apache.xerces.xni.QName; + +/** + * XSAllCM implements XSCMValidator and handles <all>. + * + * @xerces.internal + * + * @author Pavani Mukthipudi, Sun Microsystems Inc. + * @version $Id$ + */ +public class XSAllCM implements XSCMValidator { + + // + // Constants + // + + // start the content model: did not see any children + private static final short STATE_START = 0; + private static final short STATE_VALID = 1; + private static final short STATE_CHILD = 1; + + + // + // Data + // + + private final XSElementDecl fAllElements[]; + private final boolean fIsOptionalElement[]; + private final boolean fHasOptionalContent; + private int fNumElements = 0; + + // + // Constructors + // + + public XSAllCM (boolean hasOptionalContent, int size) { + fHasOptionalContent = hasOptionalContent; + fAllElements = new XSElementDecl[size]; + fIsOptionalElement = new boolean[size]; + } + + public void addElement (XSElementDecl element, boolean isOptional) { + fAllElements[fNumElements] = element; + fIsOptionalElement[fNumElements] = isOptional; + fNumElements++; + } + + + // + // XSCMValidator methods + // + + /** + * This methods to be called on entering a first element whose type + * has this content model. It will return the initial state of the + * content model + * + * @return Start state of the content model + */ + public int[] startContentModel() { + + int[] state = new int[fNumElements + 1]; + + for (int i = 0; i <= fNumElements; i++) { + state[i] = STATE_START; + } + return state; + } + + // convinient method: when error occurs, to find a matching decl + // from the candidate elements. + Object findMatchingDecl(QName elementName, SubstitutionGroupHandler subGroupHandler) { + Object matchingDecl = null; + for (int i = 0; i < fNumElements; i++) { + matchingDecl = subGroupHandler.getMatchingElemDecl(elementName, fAllElements[i]); + if (matchingDecl != null) + break; + } + return matchingDecl; + } + + /** + * The method corresponds to one transition in the content model. + * + * @param elementName + * @param currentState Current state + * @return an element decl object + */ + public Object oneTransition (QName elementName, int[] currentState, SubstitutionGroupHandler subGroupHandler) { + + // error state + if (currentState[0] < 0) { + currentState[0] = XSCMValidator.SUBSEQUENT_ERROR; + return findMatchingDecl(elementName, subGroupHandler); + } + + // seen child + currentState[0] = STATE_CHILD; + + Object matchingDecl = null; + + for (int i = 0; i < fNumElements; i++) { + // we only try to look for a matching decl if we have not seen + // this element yet. + if (currentState[i+1] != STATE_START) + continue; + matchingDecl = subGroupHandler.getMatchingElemDecl(elementName, fAllElements[i]); + if (matchingDecl != null) { + // found the decl, mark this element as "seen". + currentState[i+1] = STATE_VALID; + return matchingDecl; + } + } + + // couldn't find the decl, change to error state. + currentState[0] = XSCMValidator.FIRST_ERROR; + return findMatchingDecl(elementName, subGroupHandler); + } + + + /** + * The method indicates the end of list of children + * + * @param currentState Current state of the content model + * @return true if the last state was a valid final state + */ + public boolean endContentModel (int[] currentState) { + + int state = currentState[0]; + + if (state == XSCMValidator.FIRST_ERROR || state == XSCMValidator.SUBSEQUENT_ERROR) { + return false; + } + + // If has minOccurs of zero and there are + // no children to validate, it is trivially valid + if (fHasOptionalContent && state == STATE_START) { + return true; + } + + for (int i = 0; i < fNumElements; i++) { + // if one element is required, but not present, then error + if (!fIsOptionalElement[i] && currentState[i+1] == STATE_START) + return false; + } + + return true; + } + + /** + * check whether this content violates UPA constraint. + * + * @param subGroupHandler the substitution group handler + * @return true if this content model contains other or list wildcard + */ + public boolean checkUniqueParticleAttribution(SubstitutionGroupHandler subGroupHandler) throws XMLSchemaException { + // check whether there is conflict between any two leaves + for (int i = 0; i < fNumElements; i++) { + for (int j = i+1; j < fNumElements; j++) { + if (XSConstraints.overlapUPA(fAllElements[i], fAllElements[j], subGroupHandler)) { + // REVISIT: do we want to report all errors? or just one? + throw new XMLSchemaException("cos-nonambig", new Object[]{fAllElements[i].toString(), + fAllElements[j].toString()}); + } + } + } + + return false; + } + + /** + * Check which elements are valid to appear at this point. This method also + * works if the state is in error, in which case it returns what should + * have been seen. + * + * @param state the current state + * @return a Vector whose entries are instances of + * either XSWildcardDecl or XSElementDecl. + */ + public Vector whatCanGoHere(int[] state) { + Vector ret = new Vector(); + for (int i = 0; i < fNumElements; i++) { + // we only try to look for a matching decl if we have not seen + // this element yet. + if (state[i+1] == STATE_START) + ret.addElement(fAllElements[i]); + } + return ret; + } + + public int [] occurenceInfo(int[] state) { + return null; + } + + public String getTermName(int termId) { + return null; + } + + public boolean isCompactedForUPA() { + return false; + } +} // class XSAllCM + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMBinOp.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMBinOp.java new file mode 100644 index 0000000..329fc36 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMBinOp.java @@ -0,0 +1,140 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +import org.apache.xerces.impl.dtd.models.CMNode; +import org.apache.xerces.impl.dtd.models.CMStateSet; +import org.apache.xerces.impl.xs.XSModelGroupImpl; + +/** + * + * Content model Bin-Op node. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +public class XSCMBinOp extends CMNode { + // ------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------- + public XSCMBinOp(int type, CMNode leftNode, CMNode rightNode) + { + super(type); + + // Insure that its one of the types we require + if ((type() != XSModelGroupImpl.MODELGROUP_CHOICE) + && (type() != XSModelGroupImpl.MODELGROUP_SEQUENCE)) { + throw new RuntimeException("ImplementationMessages.VAL_BST"); + } + + // Store the nodes and init any data that needs it + fLeftChild = leftNode; + fRightChild = rightNode; + } + + + // ------------------------------------------------------------------- + // Package, final methods + // ------------------------------------------------------------------- + final CMNode getLeft() { + return fLeftChild; + } + + final CMNode getRight() { + return fRightChild; + } + + + // ------------------------------------------------------------------- + // Package, inherited methods + // ------------------------------------------------------------------- + public boolean isNullable() { + // + // If its an alternation, then if either child is nullable then + // this node is nullable. If its a concatenation, then both of + // them have to be nullable. + // + if (type() == XSModelGroupImpl.MODELGROUP_CHOICE) + return (fLeftChild.isNullable() || fRightChild.isNullable()); + else if (type() == XSModelGroupImpl.MODELGROUP_SEQUENCE) + return (fLeftChild.isNullable() && fRightChild.isNullable()); + else + throw new RuntimeException("ImplementationMessages.VAL_BST"); + } + + + // ------------------------------------------------------------------- + // Protected, inherited methods + // ------------------------------------------------------------------- + protected void calcFirstPos(CMStateSet toSet) { + if (type() == XSModelGroupImpl.MODELGROUP_CHOICE) { + // Its the the union of the first positions of our children. + toSet.setTo(fLeftChild.firstPos()); + toSet.union(fRightChild.firstPos()); + } + else if (type() == XSModelGroupImpl.MODELGROUP_SEQUENCE) { + // + // If our left child is nullable, then its the union of our + // children's first positions. Else is our left child's first + // positions. + // + toSet.setTo(fLeftChild.firstPos()); + if (fLeftChild.isNullable()) + toSet.union(fRightChild.firstPos()); + } + else { + throw new RuntimeException("ImplementationMessages.VAL_BST"); + } + } + + protected void calcLastPos(CMStateSet toSet) { + if (type() == XSModelGroupImpl.MODELGROUP_CHOICE) { + // Its the the union of the first positions of our children. + toSet.setTo(fLeftChild.lastPos()); + toSet.union(fRightChild.lastPos()); + } + else if (type() == XSModelGroupImpl.MODELGROUP_SEQUENCE) { + // + // If our right child is nullable, then its the union of our + // children's last positions. Else is our right child's last + // positions. + // + toSet.setTo(fRightChild.lastPos()); + if (fRightChild.isNullable()) + toSet.union(fLeftChild.lastPos()); + } + else { + throw new RuntimeException("ImplementationMessages.VAL_BST"); + } + } + + + // ------------------------------------------------------------------- + // Private data members + // + // fLeftChild + // fRightChild + // These are the references to the two nodes that are on either + // side of this binary operation. + // ------------------------------------------------------------------- + private CMNode fLeftChild; + private CMNode fRightChild; +} // XSCMBinOp + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMLeaf.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMLeaf.java new file mode 100644 index 0000000..591e187 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMLeaf.java @@ -0,0 +1,132 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +import org.apache.xerces.impl.dtd.models.CMNode; +import org.apache.xerces.impl.dtd.models.CMStateSet; + +/** + * Content model leaf node. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +public class XSCMLeaf + extends CMNode { + + // + // Data + // + + /** This is the leaf: element decl or wildcard decl. */ + private final Object fLeaf; + + /** + * Identify the particle: for UPA checking + */ + private int fParticleId = -1; + + /** + * Part of the algorithm to convert a regex directly to a DFA + * numbers each leaf sequentially. If its -1, that means its an + * epsilon node. Zero and greater are non-epsilon positions. + */ + private int fPosition = -1; + + // + // Constructors + // + + /** Constructs a content model leaf. */ + public XSCMLeaf(int type, Object leaf, int id, int position) { + super(type); + + // Store the element index and position + fLeaf = leaf; + fParticleId = id; + fPosition = position; + } + + // + // Package methods + // + + final Object getLeaf() { + return fLeaf; + } + + final int getParticleId() { + return fParticleId; + } + + final int getPosition() { + return fPosition; + } + + final void setPosition(int newPosition) { + fPosition = newPosition; + } + + // + // CMNode methods + // + + // package + + public boolean isNullable() { + // Leaf nodes are never nullable unless its an epsilon node + return (fPosition == -1); + } + + public String toString() { + StringBuffer strRet = new StringBuffer(fLeaf.toString()); + if (fPosition >= 0) { + strRet.append(" (Pos:") + .append(Integer.toString(fPosition)) + .append(')'); + } + return strRet.toString(); + } + + // protected + + protected void calcFirstPos(CMStateSet toSet) { + // If we are an epsilon node, then the first pos is an empty set + if (fPosition == -1) + toSet.zeroBits(); + + // Otherwise, its just the one bit of our position + else + toSet.setBit(fPosition); + } + + protected void calcLastPos(CMStateSet toSet) { + // If we are an epsilon node, then the last pos is an empty set + if (fPosition == -1) + toSet.zeroBits(); + + // Otherwise, its just the one bit of our position + else + toSet.setBit(fPosition); + } + +} // class XSCMLeaf + + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMRepeatingLeaf.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMRepeatingLeaf.java new file mode 100644 index 0000000..2ccd6c1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMRepeatingLeaf.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +/** + * A compound content model leaf node which carries occurence information. + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +public final class XSCMRepeatingLeaf extends XSCMLeaf { + + private final int fMinOccurs; + private final int fMaxOccurs; + + public XSCMRepeatingLeaf(int type, Object leaf, + int minOccurs, int maxOccurs, int id, int position) { + super(type, leaf, id, position); + fMinOccurs = minOccurs; + fMaxOccurs = maxOccurs; + } + + final int getMinOccurs() { + return fMinOccurs; + } + + final int getMaxOccurs() { + return fMaxOccurs; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMUniOp.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMUniOp.java new file mode 100644 index 0000000..b7f71e1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMUniOp.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +import org.apache.xerces.impl.dtd.models.CMNode; +import org.apache.xerces.impl.dtd.models.CMStateSet; +import org.apache.xerces.impl.xs.XSParticleDecl; + +/** + * + * Content model Uni-Op node. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +public class XSCMUniOp extends CMNode { + // ------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------- + public XSCMUniOp(int type, CMNode childNode) { + super(type); + + // Insure that its one of the types we require + if ((type() != XSParticleDecl.PARTICLE_ZERO_OR_ONE) + && (type() != XSParticleDecl.PARTICLE_ZERO_OR_MORE) + && (type() != XSParticleDecl.PARTICLE_ONE_OR_MORE)) { + throw new RuntimeException("ImplementationMessages.VAL_UST"); + } + + // Store the node and init any data that needs it + fChild = childNode; + } + + + // ------------------------------------------------------------------- + // Package, final methods + // ------------------------------------------------------------------- + final CMNode getChild() { + return fChild; + } + + + // ------------------------------------------------------------------- + // Package, inherited methods + // ------------------------------------------------------------------- + public boolean isNullable() { + // + // For debugging purposes, make sure we got rid of all non '*' + // repetitions. Otherwise, '*' style nodes are always nullable. + // + if (type() == XSParticleDecl.PARTICLE_ONE_OR_MORE) + return fChild.isNullable(); + else + return true; + } + + + // ------------------------------------------------------------------- + // Protected, inherited methods + // ------------------------------------------------------------------- + protected void calcFirstPos(CMStateSet toSet) { + // Its just based on our child node's first pos + toSet.setTo(fChild.firstPos()); + } + + protected void calcLastPos(CMStateSet toSet) { + // Its just based on our child node's last pos + toSet.setTo(fChild.lastPos()); + } + + + // ------------------------------------------------------------------- + // Private data members + // + // fChild + // This is the reference to the one child that we have for this + // unary operation. + // ------------------------------------------------------------------- + private CMNode fChild; +} // XSCMUniOp + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMValidator.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMValidator.java new file mode 100644 index 0000000..9597aca --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSCMValidator.java @@ -0,0 +1,127 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +import java.util.Vector; + +import org.apache.xerces.impl.xs.SubstitutionGroupHandler; +import org.apache.xerces.impl.xs.XMLSchemaException; +import org.apache.xerces.xni.QName; + +/** + * Note: State of the content model is stored in the validator + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @author Elena Litani, IBM + * @version $Id$ + */ +public interface XSCMValidator { + + + public static final short FIRST_ERROR = -1; + + // on subsequent errors the validator should not report + // an error + // + public static final short SUBSEQUENT_ERROR = -2; + + /** + * This methods to be called on entering a first element whose type + * has this content model. It will return the initial state of the content model + * + * @return Start state of the content model + */ + public int[] startContentModel(); + + + /** + * The method corresponds to one transaction in the content model. + * + * @param elementName + * @param state Current state + * @return element decl or wildcard decl that + * corresponds to the element from the Schema grammar + */ + public Object oneTransition (QName elementName, int[] state, SubstitutionGroupHandler subGroupHandler); + + + /** + * The method indicates the end of list of children + * + * @param state Current state of the content model + * @return true if the last state was a valid final state + */ + public boolean endContentModel (int[] state); + + /** + * check whether this content violates UPA constraint. + * + * @param subGroupHandler the substitution group handler + * @return true if this content model contains other or list wildcard + */ + public boolean checkUniqueParticleAttribution(SubstitutionGroupHandler subGroupHandler) throws XMLSchemaException; + + /** + * Check which elements are valid to appear at this point. This method also + * works if the state is in error, in which case it returns what should + * have been seen. + * + * @param state the current state + * @return a Vector whose entries are instances of + * either XSWildcardDecl or XSElementDecl. + */ + public Vector whatCanGoHere(int[] state); + + /** + *

Returns an array containing information about the current repeating term + * or null if no occurrence counting was being performed at the + * current state.

+ * + *

If an array is returned it will have a length == 4 and will contain: + *

    + *
  • a[0] :: min occurs
  • + *
  • a[1] :: max occurs
  • + *
  • a[2] :: current value of the counter
  • + *
  • a[3] :: identifier for the repeating term
  • + *
+ *

+ * + * @param state the current state + * @return an array containing information about the current repeating term + */ + public int [] occurenceInfo(int[] state); + + /** + * Returns the name of the term (element or wildcard) for the given identifier. + * + * @param termId identifier for the element declaration or wildcard + * @return the name of the element declaration or wildcard + */ + public String getTermName(int termId); + + /** + * Checks if this content model has had its min/maxOccurs values reduced for + * purposes of speeding up UPA. If so, this content model should not be used + * for any purpose other than checking unique particle attribution + * + * @return a boolean that says whether this content has been compacted for UPA + */ + public boolean isCompactedForUPA(); +} // XSCMValidator diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSDFACM.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSDFACM.java new file mode 100644 index 0000000..b2973b3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSDFACM.java @@ -0,0 +1,1173 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +import java.util.HashMap; +import java.util.Vector; + +import org.apache.xerces.impl.dtd.models.CMNode; +import org.apache.xerces.impl.dtd.models.CMStateSet; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.SubstitutionGroupHandler; +import org.apache.xerces.impl.xs.XMLSchemaException; +import org.apache.xerces.impl.xs.XSConstraints; +import org.apache.xerces.impl.xs.XSElementDecl; +import org.apache.xerces.impl.xs.XSModelGroupImpl; +import org.apache.xerces.impl.xs.XSParticleDecl; +import org.apache.xerces.impl.xs.XSWildcardDecl; +import org.apache.xerces.xni.QName; + +/** + * DFAContentModel is the implementation of XSCMValidator that does + * all of the non-trivial element content validation. This class does + * the conversion from the regular expression to the DFA that + * it then uses in its validation algorithm. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +public class XSDFACM + implements XSCMValidator { + + // + // Constants + // + private static final boolean DEBUG = false; + + // special strings + + // debugging + + /** Set to true to debug content model validation. */ + private static final boolean DEBUG_VALIDATE_CONTENT = false; + + // + // Data + // + + /** + * This is the map of unique input symbol elements to indices into + * each state's per-input symbol transition table entry. This is part + * of the built DFA information that must be kept around to do the + * actual validation. Note tat since either XSElementDecl or XSParticleDecl object + * can live here, we've got to use an Object. + */ + private Object fElemMap[] = null; + + /** + * This is a map of whether the element map contains information + * related to ANY models. + */ + private int fElemMapType[] = null; + + /** + * id of the unique input symbol + */ + private int fElemMapId[] = null; + + /** The element map size. */ + private int fElemMapSize = 0; + + /** + * This is an array of booleans, one per state (there are + * fTransTableSize states in the DFA) that indicates whether that + * state is a final state. + */ + private boolean fFinalStateFlags[] = null; + + /** + * The list of follow positions for each NFA position (i.e. for each + * non-epsilon leaf node.) This is only used during the building of + * the DFA, and is let go afterwards. + */ + private CMStateSet fFollowList[] = null; + + /** + * This is the head node of our intermediate representation. It is + * only non-null during the building of the DFA (just so that it + * does not have to be passed all around.) Once the DFA is built, + * this is no longer required so its nulled out. + */ + private CMNode fHeadNode = null; + + /** + * The count of leaf nodes. This is an important number that set some + * limits on the sizes of data structures in the DFA process. + */ + private int fLeafCount = 0; + + /** + * An array of non-epsilon leaf nodes, which is used during the DFA + * build operation, then dropped. + */ + private XSCMLeaf fLeafList[] = null; + + /** Array mapping ANY types to the leaf list. */ + private int fLeafListType[] = null; + + /** + * This is the transition table that is the main by product of all + * of the effort here. It is an array of arrays of ints. The first + * dimension is the number of states we end up with in the DFA. The + * second dimensions is the number of unique elements in the content + * model (fElemMapSize). Each entry in the second dimension indicates + * the new state given that input for the first dimension's start + * state. + *

+ * The fElemMap array handles mapping from element indexes to + * positions in the second dimension of the transition table. + */ + private int fTransTable[][] = null; + + /** + * Array containing occurence information for looping states + * which use counters to check minOccurs/maxOccurs. + */ + private Occurence [] fCountingStates = null; + static final class Occurence { + final int minOccurs; + final int maxOccurs; + final int elemIndex; + public Occurence (XSCMRepeatingLeaf leaf, int elemIndex) { + minOccurs = leaf.getMinOccurs(); + maxOccurs = leaf.getMaxOccurs(); + this.elemIndex = elemIndex; + } + public String toString() { + return "minOccurs=" + minOccurs + + ";maxOccurs=" + + ((maxOccurs != SchemaSymbols.OCCURRENCE_UNBOUNDED) + ? Integer.toString(maxOccurs) : "unbounded"); + } + } + + /** + * The number of valid entries in the transition table, and in the other + * related tables such as fFinalStateFlags. + */ + private int fTransTableSize = 0; + + private boolean fIsCompactedForUPA; + + // temp variables + + // + // Constructors + // + + /** + * Constructs a DFA content model. + * + * @param syntaxTree The syntax tree of the content model. + * @param leafCount The number of leaves. + * + * @exception RuntimeException Thrown if DFA can't be built. + */ + + public XSDFACM(CMNode syntaxTree, int leafCount) { + + // Store away our index and pools in members + fLeafCount = leafCount; + fIsCompactedForUPA = syntaxTree.isCompactedForUPA(); + + // + // Create some string pool indexes that represent the names of some + // magical nodes in the syntax tree. + // (already done in static initialization... + // + + // + // Ok, so lets grind through the building of the DFA. This method + // handles the high level logic of the algorithm, but it uses a + // number of helper classes to do its thing. + // + // In order to avoid having hundreds of references to the error and + // string handlers around, this guy and all of his helper classes + // just throw a simple exception and we then pass it along. + // + + if(DEBUG_VALIDATE_CONTENT) { + XSDFACM.time -= System.currentTimeMillis(); + } + + buildDFA(syntaxTree); + + if(DEBUG_VALIDATE_CONTENT) { + XSDFACM.time += System.currentTimeMillis(); + System.out.println("DFA build: " + XSDFACM.time + "ms"); + } + } + + private static long time = 0; + + // + // XSCMValidator methods + // + + /** + * check whether the given state is one of the final states + * + * @param state the state to check + * + * @return whether it's a final state + */ + public boolean isFinalState (int state) { + return (state < 0)? false : + fFinalStateFlags[state]; + } + + /** + * one transition only + * + * @param curElem The current element's QName + * @param state stack to store the previous state + * @param subGroupHandler the substitution group handler + * + * @return null if transition is invalid; otherwise the Object corresponding to the + * XSElementDecl or XSWildcardDecl identified. Also, the + * state array will be modified to include the new state; this so that the validator can + * store it away. + * + * @exception RuntimeException thrown on error + */ + public Object oneTransition(QName curElem, int[] state, SubstitutionGroupHandler subGroupHandler) { + int curState = state[0]; + + if(curState == XSCMValidator.FIRST_ERROR || curState == XSCMValidator.SUBSEQUENT_ERROR) { + // there was an error last time; so just go find correct Object in fElemmMap. + // ... after resetting state[0]. + if(curState == XSCMValidator.FIRST_ERROR) + state[0] = XSCMValidator.SUBSEQUENT_ERROR; + + return findMatchingDecl(curElem, subGroupHandler); + } + + int nextState = 0; + int elemIndex = 0; + Object matchingDecl = null; + + for (; elemIndex < fElemMapSize; elemIndex++) { + nextState = fTransTable[curState][elemIndex]; + if (nextState == -1) + continue; + int type = fElemMapType[elemIndex] ; + if (type == XSParticleDecl.PARTICLE_ELEMENT) { + matchingDecl = subGroupHandler.getMatchingElemDecl(curElem, (XSElementDecl)fElemMap[elemIndex]); + if (matchingDecl != null) { + break; + } + } + else if (type == XSParticleDecl.PARTICLE_WILDCARD) { + if (((XSWildcardDecl)fElemMap[elemIndex]).allowNamespace(curElem.uri)) { + matchingDecl = fElemMap[elemIndex]; + break; + } + } + } + + // if we still can't find a match, set the state to first_error + // and return null + if (elemIndex == fElemMapSize) { + state[1] = state[0]; + state[0] = XSCMValidator.FIRST_ERROR; + return findMatchingDecl(curElem, subGroupHandler); + } + + if (fCountingStates != null) { + Occurence o = fCountingStates[curState]; + if (o != null) { + if (curState == nextState) { + if (++state[2] > o.maxOccurs && + o.maxOccurs != SchemaSymbols.OCCURRENCE_UNBOUNDED) { + // It's likely that we looped too many times on the current state + // however it's possible that we actually matched another particle + // which allows the same name. + // + // Consider: + // + // + // + // + // + // + // and + // + // + // + // + // + // + // In the DFA there will be two transitions from the current state which + // allow "foo". Note that this is not a UPA violation. The ambiguity of which + // transition to take is resolved by the current value of the counter. Since + // we've already seen enough instances of the first "foo" perhaps there is + // another element declaration or wildcard deeper in the element map which + // matches. + return findMatchingDecl(curElem, state, subGroupHandler, elemIndex); + } + } + else if (state[2] < o.minOccurs) { + // not enough loops on the current state. + state[1] = state[0]; + state[0] = XSCMValidator.FIRST_ERROR; + return findMatchingDecl(curElem, subGroupHandler); + } + else { + // Exiting a counting state. If we're entering a new + // counting state, reset the counter. + o = fCountingStates[nextState]; + if (o != null) { + state[2] = (elemIndex == o.elemIndex) ? 1 : 0; + } + } + } + else { + o = fCountingStates[nextState]; + if (o != null) { + // Entering a new counting state. Reset the counter. + // If we've already seen one instance of the looping + // particle set the counter to 1, otherwise set it + // to 0. + state[2] = (elemIndex == o.elemIndex) ? 1 : 0; + } + } + } + + state[0] = nextState; + return matchingDecl; + } // oneTransition(QName, int[], SubstitutionGroupHandler): Object + + Object findMatchingDecl(QName curElem, SubstitutionGroupHandler subGroupHandler) { + Object matchingDecl = null; + + for (int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++) { + int type = fElemMapType[elemIndex] ; + if (type == XSParticleDecl.PARTICLE_ELEMENT) { + matchingDecl = subGroupHandler.getMatchingElemDecl(curElem, (XSElementDecl)fElemMap[elemIndex]); + if (matchingDecl != null) { + return matchingDecl; + } + } + else if (type == XSParticleDecl.PARTICLE_WILDCARD) { + if(((XSWildcardDecl)fElemMap[elemIndex]).allowNamespace(curElem.uri)) + return fElemMap[elemIndex]; + } + } + + return null; + } // findMatchingDecl(QName, SubstitutionGroupHandler): Object + + Object findMatchingDecl(QName curElem, int[] state, SubstitutionGroupHandler subGroupHandler, int elemIndex) { + + int curState = state[0]; + int nextState = 0; + Object matchingDecl = null; + + while (++elemIndex < fElemMapSize) { + nextState = fTransTable[curState][elemIndex]; + if (nextState == -1) + continue; + int type = fElemMapType[elemIndex] ; + if (type == XSParticleDecl.PARTICLE_ELEMENT) { + matchingDecl = subGroupHandler.getMatchingElemDecl(curElem, (XSElementDecl)fElemMap[elemIndex]); + if (matchingDecl != null) { + break; + } + } + else if (type == XSParticleDecl.PARTICLE_WILDCARD) { + if (((XSWildcardDecl)fElemMap[elemIndex]).allowNamespace(curElem.uri)) { + matchingDecl = fElemMap[elemIndex]; + break; + } + } + } + + // if we still can't find a match, set the state to FIRST_ERROR and return null + if (elemIndex == fElemMapSize) { + state[1] = state[0]; + state[0] = XSCMValidator.FIRST_ERROR; + return findMatchingDecl(curElem, subGroupHandler); + } + + // if we found a match, set the next state and reset the + // counter if the next state is a counting state. + state[0] = nextState; + final Occurence o = fCountingStates[nextState]; + if (o != null) { + state[2] = (elemIndex == o.elemIndex) ? 1 : 0; + } + return matchingDecl; + } // findMatchingDecl(QName, int[], SubstitutionGroupHandler, int): Object + + // This method returns the start states of the content model. + public int[] startContentModel() { + // [0] : the current state + // [1] : if [0] is an error state then the + // last valid state before the error + // [2] : occurence counter for counting states + return new int [3]; + } // startContentModel():int[] + + // this method returns whether the last state was a valid final state + public boolean endContentModel(int[] state) { + final int curState = state[0]; + if (fFinalStateFlags[curState]) { + if (fCountingStates != null) { + Occurence o = fCountingStates[curState]; + if (o != null && state[2] < o.minOccurs) { + // not enough loops on the current state to be considered final. + return false; + } + } + return true; + } + return false; + } // endContentModel(int[]): boolean + + // Killed off whatCanGoHere; we may need it for DOM canInsert(...) etc., + // but we can put it back later. + + // + // Private methods + // + + /** + * Builds the internal DFA transition table from the given syntax tree. + * + * @param syntaxTree The syntax tree. + * + * @exception RuntimeException Thrown if DFA cannot be built. + */ + private void buildDFA(CMNode syntaxTree) { + // + // The first step we need to take is to rewrite the content model + // using our CMNode objects, and in the process get rid of any + // repetition short cuts, converting them into '*' style repetitions + // or getting rid of repetitions altogether. + // + // The conversions done are: + // + // x+ -> (x|x*) + // x? -> (x|epsilon) + // + // This is a relatively complex scenario. What is happening is that + // we create a top level binary node of which the special EOC value + // is set as the right side node. The the left side is set to the + // rewritten syntax tree. The source is the original content model + // info from the decl pool. The rewrite is done by buildSyntaxTree() + // which recurses the decl pool's content of the element and builds + // a new tree in the process. + // + // Note that, during this operation, we set each non-epsilon leaf + // node's DFA state position and count the number of such leafs, which + // is left in the fLeafCount member. + // + // The nodeTmp object is passed in just as a temp node to use during + // the recursion. Otherwise, we'd have to create a new node on every + // level of recursion, which would be piggy in Java (as is everything + // for that matter.) + // + + /* MODIFIED (Jan, 2001) + * + * Use following rules. + * nullable(x+) := nullable(x), first(x+) := first(x), last(x+) := last(x) + * nullable(x?) := true, first(x?) := first(x), last(x?) := last(x) + * + * The same computation of follow as x* is applied to x+ + * + * The modification drastically reduces computation time of + * "(a, (b, a+, (c, (b, a+)+, a+, (d, (c, (b, a+)+, a+)+, (b, a+)+, a+)+)+)+)+" + */ + + // + // And handle specially the EOC node, which also must be numbered + // and counted as a non-epsilon leaf node. It could not be handled + // in the above tree build because it was created before all that + // started. We save the EOC position since its used during the DFA + // building loop. + // + int EOCPos = fLeafCount; + XSCMLeaf nodeEOC = new XSCMLeaf(XSParticleDecl.PARTICLE_ELEMENT, null, -1, fLeafCount++); + fHeadNode = new XSCMBinOp( + XSModelGroupImpl.MODELGROUP_SEQUENCE, + syntaxTree, + nodeEOC + ); + + // + // Ok, so now we have to iterate the new tree and do a little more + // work now that we know the leaf count. One thing we need to do is + // to calculate the first and last position sets of each node. This + // is cached away in each of the nodes. + // + // Along the way we also set the leaf count in each node as the + // maximum state count. They must know this in order to create their + // first/last pos sets. + // + // We also need to build an array of references to the non-epsilon + // leaf nodes. Since we iterate it in the same way as before, this + // will put them in the array according to their position values. + // + fLeafList = new XSCMLeaf[fLeafCount]; + fLeafListType = new int[fLeafCount]; + postTreeBuildInit(fHeadNode); + + // + // And, moving onward... We now need to build the follow position + // sets for all the nodes. So we allocate an array of state sets, + // one for each leaf node (i.e. each DFA position.) + // + fFollowList = new CMStateSet[fLeafCount]; + for (int index = 0; index < fLeafCount; index++) + fFollowList[index] = new CMStateSet(fLeafCount); + calcFollowList(fHeadNode); + // + // And finally the big push... Now we build the DFA using all the + // states and the tree we've built up. First we set up the various + // data structures we are going to use while we do this. + // + // First of all we need an array of unique element names in our + // content model. For each transition table entry, we need a set of + // contiguous indices to represent the transitions for a particular + // input element. So we need to a zero based range of indexes that + // map to element types. This element map provides that mapping. + // + fElemMap = new Object[fLeafCount]; + fElemMapType = new int[fLeafCount]; + fElemMapId = new int[fLeafCount]; + fElemMapSize = 0; + Occurence [] elemOccurenceMap = null; + for (int outIndex = 0; outIndex < fLeafCount; outIndex++) { + // optimization from Henry Zongaro: + //fElemMap[outIndex] = new Object (); + fElemMap[outIndex] = null; + + int inIndex = 0; + final int id = fLeafList[outIndex].getParticleId(); + for (; inIndex < fElemMapSize; inIndex++) { + if (id == fElemMapId[inIndex]) + break; + } + + // If it was not in the list, then add it, if not the EOC node + if (inIndex == fElemMapSize) { + XSCMLeaf leaf = fLeafList[outIndex]; + fElemMap[fElemMapSize] = leaf.getLeaf(); + if (leaf instanceof XSCMRepeatingLeaf) { + if (elemOccurenceMap == null) { + elemOccurenceMap = new Occurence[fLeafCount]; + } + elemOccurenceMap[fElemMapSize] = new Occurence((XSCMRepeatingLeaf) leaf, fElemMapSize); + } + fElemMapType[fElemMapSize] = fLeafListType[outIndex]; + fElemMapId[fElemMapSize] = id; + fElemMapSize++; + } + } + + // the last entry in the element map must be the EOC element. + // remove it from the map. + if (DEBUG) { + if (fElemMapId[fElemMapSize-1] != -1) + System.err.println("interal error in DFA: last element is not EOC."); + } + fElemMapSize--; + + /*** + * Optimization(Jan, 2001); We sort fLeafList according to + * elemIndex which is *uniquely* associated to each leaf. + * We are *assuming* that each element appears in at least one leaf. + **/ + + int[] fLeafSorter = new int[fLeafCount + fElemMapSize]; + int fSortCount = 0; + + for (int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++) { + final int id = fElemMapId[elemIndex]; + for (int leafIndex = 0; leafIndex < fLeafCount; leafIndex++) { + if (id == fLeafList[leafIndex].getParticleId()) + fLeafSorter[fSortCount++] = leafIndex; + } + fLeafSorter[fSortCount++] = -1; + } + + /* Optimization(Jan, 2001) */ + + // + // Next lets create some arrays, some that hold transient + // information during the DFA build and some that are permament. + // These are kind of sticky since we cannot know how big they will + // get, but we don't want to use any Java collections because of + // performance. + // + // Basically they will probably be about fLeafCount*2 on average, + // but can be as large as 2^(fLeafCount*2), worst case. So we start + // with fLeafCount*4 as a middle ground. This will be very unlikely + // to ever have to expand, though it if does, the overhead will be + // somewhat ugly. + // + int curArraySize = fLeafCount * 4; + CMStateSet[] statesToDo = new CMStateSet[curArraySize]; + fFinalStateFlags = new boolean[curArraySize]; + fTransTable = new int[curArraySize][]; + + // + // Ok we start with the initial set as the first pos set of the + // head node (which is the seq node that holds the content model + // and the EOC node.) + // + CMStateSet setT = fHeadNode.firstPos(); + + // + // Init our two state flags. Basically the unmarked state counter + // is always chasing the current state counter. When it catches up, + // that means we made a pass through that did not add any new states + // to the lists, at which time we are done. We could have used a + // expanding array of flags which we used to mark off states as we + // complete them, but this is easier though less readable maybe. + // + int unmarkedState = 0; + int curState = 0; + + // + // Init the first transition table entry, and put the initial state + // into the states to do list, then bump the current state. + // + fTransTable[curState] = makeDefStateList(); + statesToDo[curState] = setT; + curState++; + + /* Optimization(Jan, 2001); This is faster for + * a large content model such as, "(t001+|t002+|.... |t500+)". + */ + + HashMap stateTable = new HashMap(); + + /* Optimization(Jan, 2001) */ + + // + // Ok, almost done with the algorithm... We now enter the + // loop where we go until the states done counter catches up with + // the states to do counter. + // + while (unmarkedState < curState) { + // + // Get the first unmarked state out of the list of states to do. + // And get the associated transition table entry. + // + setT = statesToDo[unmarkedState]; + int[] transEntry = fTransTable[unmarkedState]; + + // Mark this one final if it contains the EOC state + fFinalStateFlags[unmarkedState] = setT.getBit(EOCPos); + + // Bump up the unmarked state count, marking this state done + unmarkedState++; + + // Loop through each possible input symbol in the element map + CMStateSet newSet = null; + /* Optimization(Jan, 2001) */ + int sorterIndex = 0; + /* Optimization(Jan, 2001) */ + for (int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++) { + // + // Build up a set of states which is the union of all of + // the follow sets of DFA positions that are in the current + // state. If we gave away the new set last time through then + // create a new one. Otherwise, zero out the existing one. + // + if (newSet == null) + newSet = new CMStateSet(fLeafCount); + else + newSet.zeroBits(); + + /* Optimization(Jan, 2001) */ + int leafIndex = fLeafSorter[sorterIndex++]; + + while (leafIndex != -1) { + // If this leaf index (DFA position) is in the current set... + if (setT.getBit(leafIndex)) { + // + // If this leaf is the current input symbol, then we + // want to add its follow list to the set of states to + // transition to from the current state. + // + newSet.union(fFollowList[leafIndex]); + } + + leafIndex = fLeafSorter[sorterIndex++]; + } + /* Optimization(Jan, 2001) */ + + // + // If this new set is not empty, then see if its in the list + // of states to do. If not, then add it. + // + if (!newSet.isEmpty()) { + // + // Search the 'states to do' list to see if this new + // state set is already in there. + // + + /* Optimization(Jan, 2001) */ + Integer stateObj = (Integer)stateTable.get(newSet); + int stateIndex = (stateObj == null ? curState : stateObj.intValue()); + /* Optimization(Jan, 2001) */ + + // If we did not find it, then add it + if (stateIndex == curState) { + // + // Put this new state into the states to do and init + // a new entry at the same index in the transition + // table. + // + statesToDo[curState] = newSet; + fTransTable[curState] = makeDefStateList(); + + /* Optimization(Jan, 2001) */ + stateTable.put(newSet, new Integer(curState)); + /* Optimization(Jan, 2001) */ + + // We now have a new state to do so bump the count + curState++; + + // + // Null out the new set to indicate we adopted it. + // This will cause the creation of a new set on the + // next time around the loop. + // + newSet = null; + } + + // + // Now set this state in the transition table's entry + // for this element (using its index), with the DFA + // state we will move to from the current state when we + // see this input element. + // + transEntry[elemIndex] = stateIndex; + + // Expand the arrays if we're full + if (curState == curArraySize) { + // + // Yikes, we overflowed the initial array size, so + // we've got to expand all of these arrays. So adjust + // up the size by 50% and allocate new arrays. + // + final int newSize = (int)(curArraySize * 1.5); + CMStateSet[] newToDo = new CMStateSet[newSize]; + boolean[] newFinalFlags = new boolean[newSize]; + int[][] newTransTable = new int[newSize][]; + + // Copy over all of the existing content + System.arraycopy(statesToDo, 0, newToDo, 0, curArraySize); + System.arraycopy(fFinalStateFlags, 0, newFinalFlags, 0, curArraySize); + System.arraycopy(fTransTable, 0, newTransTable, 0, curArraySize); + + // Store the new array size + curArraySize = newSize; + statesToDo = newToDo; + fFinalStateFlags = newFinalFlags; + fTransTable = newTransTable; + } + } + } + } + + // + // Fill in the occurence information for each looping state + // if we're using counters. + // + if (elemOccurenceMap != null) { + fCountingStates = new Occurence[curState]; + for (int i = 0; i < curState; ++i) { + int [] transitions = fTransTable[i]; + for (int j = 0; j < transitions.length; ++j) { + if (i == transitions[j]) { + fCountingStates[i] = elemOccurenceMap[j]; + break; + } + } + } + } + + // + // And now we can say bye bye to the temp representation since we've + // built the DFA. + // + if (DEBUG_VALIDATE_CONTENT) + dumpTree(fHeadNode, 0); + fHeadNode = null; + fLeafList = null; + fFollowList = null; + fLeafListType = null; + fElemMapId = null; + } + + /** + * Calculates the follow list of the current node. + * + * @param nodeCur The curent node. + * + * @exception RuntimeException Thrown if follow list cannot be calculated. + */ + private void calcFollowList(CMNode nodeCur) { + // Recurse as required + if (nodeCur.type() == XSModelGroupImpl.MODELGROUP_CHOICE) { + // Recurse only + calcFollowList(((XSCMBinOp)nodeCur).getLeft()); + calcFollowList(((XSCMBinOp)nodeCur).getRight()); + } + else if (nodeCur.type() == XSModelGroupImpl.MODELGROUP_SEQUENCE) { + // Recurse first + calcFollowList(((XSCMBinOp)nodeCur).getLeft()); + calcFollowList(((XSCMBinOp)nodeCur).getRight()); + + // + // Now handle our level. We use our left child's last pos + // set and our right child's first pos set, so go ahead and + // get them ahead of time. + // + final CMStateSet last = ((XSCMBinOp)nodeCur).getLeft().lastPos(); + final CMStateSet first = ((XSCMBinOp)nodeCur).getRight().firstPos(); + + // + // Now, for every position which is in our left child's last set + // add all of the states in our right child's first set to the + // follow set for that position. + // + for (int index = 0; index < fLeafCount; index++) { + if (last.getBit(index)) + fFollowList[index].union(first); + } + } + else if (nodeCur.type() == XSParticleDecl.PARTICLE_ZERO_OR_MORE + || nodeCur.type() == XSParticleDecl.PARTICLE_ONE_OR_MORE) { + // Recurse first + calcFollowList(((XSCMUniOp)nodeCur).getChild()); + + // + // Now handle our level. We use our own first and last position + // sets, so get them up front. + // + final CMStateSet first = nodeCur.firstPos(); + final CMStateSet last = nodeCur.lastPos(); + + // + // For every position which is in our last position set, add all + // of our first position states to the follow set for that + // position. + // + for (int index = 0; index < fLeafCount; index++) { + if (last.getBit(index)) + fFollowList[index].union(first); + } + } + + else if (nodeCur.type() == XSParticleDecl.PARTICLE_ZERO_OR_ONE) { + // Recurse only + calcFollowList(((XSCMUniOp)nodeCur).getChild()); + } + + } + + /** + * Dumps the tree of the current node to standard output. + * + * @param nodeCur The current node. + * @param level The maximum levels to output. + * + * @exception RuntimeException Thrown on error. + */ + private void dumpTree(CMNode nodeCur, int level) { + for (int index = 0; index < level; index++) + System.out.print(" "); + + int type = nodeCur.type(); + + switch(type ) { + + case XSModelGroupImpl.MODELGROUP_CHOICE: + case XSModelGroupImpl.MODELGROUP_SEQUENCE: { + if (type == XSModelGroupImpl.MODELGROUP_CHOICE) + System.out.print("Choice Node "); + else + System.out.print("Seq Node "); + + if (nodeCur.isNullable()) + System.out.print("Nullable "); + + System.out.print("firstPos="); + System.out.print(nodeCur.firstPos().toString()); + System.out.print(" lastPos="); + System.out.println(nodeCur.lastPos().toString()); + + dumpTree(((XSCMBinOp)nodeCur).getLeft(), level+1); + dumpTree(((XSCMBinOp)nodeCur).getRight(), level+1); + break; + } + case XSParticleDecl.PARTICLE_ZERO_OR_MORE: + case XSParticleDecl.PARTICLE_ONE_OR_MORE: + case XSParticleDecl.PARTICLE_ZERO_OR_ONE: { + System.out.print("Rep Node "); + + if (nodeCur.isNullable()) + System.out.print("Nullable "); + + System.out.print("firstPos="); + System.out.print(nodeCur.firstPos().toString()); + System.out.print(" lastPos="); + System.out.println(nodeCur.lastPos().toString()); + + dumpTree(((XSCMUniOp)nodeCur).getChild(), level+1); + break; + } + case XSParticleDecl.PARTICLE_ELEMENT: { + System.out.print + ( + "Leaf: (pos=" + + ((XSCMLeaf)nodeCur).getPosition() + + "), " + + "(elemIndex=" + + ((XSCMLeaf)nodeCur).getLeaf() + + ") " + ); + + if (nodeCur.isNullable()) + System.out.print(" Nullable "); + + System.out.print("firstPos="); + System.out.print(nodeCur.firstPos().toString()); + System.out.print(" lastPos="); + System.out.println(nodeCur.lastPos().toString()); + break; + } + case XSParticleDecl.PARTICLE_WILDCARD: + System.out.print("Any Node: "); + + System.out.print("firstPos="); + System.out.print(nodeCur.firstPos().toString()); + System.out.print(" lastPos="); + System.out.println(nodeCur.lastPos().toString()); + break; + default: { + throw new RuntimeException("ImplementationMessages.VAL_NIICM"); + } + } + + } + + + /** + * -1 is used to represent bad transitions in the transition table + * entry for each state. So each entry is initialized to an all -1 + * array. This method creates a new entry and initializes it. + */ + private int[] makeDefStateList() + { + int[] retArray = new int[fElemMapSize]; + for (int index = 0; index < fElemMapSize; index++) + retArray[index] = -1; + return retArray; + } + + /** Post tree build initialization. */ + private void postTreeBuildInit(CMNode nodeCur) throws RuntimeException { + // Set the maximum states on this node + nodeCur.setMaxStates(fLeafCount); + + XSCMLeaf leaf = null; + int pos = 0; + // Recurse as required + if (nodeCur.type() == XSParticleDecl.PARTICLE_WILDCARD) { + leaf = (XSCMLeaf)nodeCur; + pos = leaf.getPosition(); + fLeafList[pos] = leaf; + fLeafListType[pos] = XSParticleDecl.PARTICLE_WILDCARD; + } + else if ((nodeCur.type() == XSModelGroupImpl.MODELGROUP_CHOICE) || + (nodeCur.type() == XSModelGroupImpl.MODELGROUP_SEQUENCE)) { + postTreeBuildInit(((XSCMBinOp)nodeCur).getLeft()); + postTreeBuildInit(((XSCMBinOp)nodeCur).getRight()); + } + else if (nodeCur.type() == XSParticleDecl.PARTICLE_ZERO_OR_MORE || + nodeCur.type() == XSParticleDecl.PARTICLE_ONE_OR_MORE || + nodeCur.type() == XSParticleDecl.PARTICLE_ZERO_OR_ONE) { + postTreeBuildInit(((XSCMUniOp)nodeCur).getChild()); + } + else if (nodeCur.type() == XSParticleDecl.PARTICLE_ELEMENT) { + // Put this node in the leaf list at the current index if its + // a non-epsilon leaf. + leaf = (XSCMLeaf)nodeCur; + pos = leaf.getPosition(); + fLeafList[pos] = leaf; + fLeafListType[pos] = XSParticleDecl.PARTICLE_ELEMENT; + } + else { + throw new RuntimeException("ImplementationMessages.VAL_NIICM"); + } + } + + /** + * check whether this content violates UPA constraint. + * + * @param subGroupHandler the substitution group handler + * @return true if this content model contains other or list wildcard + */ + public boolean checkUniqueParticleAttribution(SubstitutionGroupHandler subGroupHandler) throws XMLSchemaException { + // Unique Particle Attribution + // store the conflict results between any two elements in fElemMap + // 0: not compared; -1: no conflict; 1: conflict + // initialize the conflict table (all 0 initially) + byte conflictTable[][] = new byte[fElemMapSize][fElemMapSize]; + + // for each state, check whether it has overlap transitions + for (int i = 0; i < fTransTable.length && fTransTable[i] != null; i++) { + for (int j = 0; j < fElemMapSize; j++) { + for (int k = j+1; k < fElemMapSize; k++) { + if (fTransTable[i][j] != -1 && + fTransTable[i][k] != -1) { + if (conflictTable[j][k] == 0) { + if (XSConstraints.overlapUPA + (fElemMap[j], fElemMap[k], + subGroupHandler)) { + if (fCountingStates != null) { + Occurence o = fCountingStates[i]; + // If "i" is a counting state and exactly one of the transitions + // loops back to "i" then the two particles do not overlap if + // minOccurs == maxOccurs. + if (o != null && + fTransTable[i][j] == i ^ fTransTable[i][k] == i && + o.minOccurs == o.maxOccurs) { + conflictTable[j][k] = (byte) -1; + continue; + } + } + conflictTable[j][k] = (byte) 1; + } + else { + conflictTable[j][k] = (byte) -1; + } + } + } + } + } + } + + // report all errors + for (int i = 0; i < fElemMapSize; i++) { + for (int j = 0; j < fElemMapSize; j++) { + if (conflictTable[i][j] == 1) { + //errors.newError("cos-nonambig", new Object[]{fElemMap[i].toString(), + // fElemMap[j].toString()}); + // REVISIT: do we want to report all errors? or just one? + throw new XMLSchemaException("cos-nonambig", new Object[]{fElemMap[i].toString(), + fElemMap[j].toString()}); + } + } + } + + // if there is a other or list wildcard, we need to check this CM + // again, if this grammar is cached. + for (int i = 0; i < fElemMapSize; i++) { + if (fElemMapType[i] == XSParticleDecl.PARTICLE_WILDCARD) { + XSWildcardDecl wildcard = (XSWildcardDecl)fElemMap[i]; + if (wildcard.fType == XSWildcardDecl.NSCONSTRAINT_LIST || + wildcard.fType == XSWildcardDecl.NSCONSTRAINT_NOT) { + return true; + } + } + } + + return false; + } + + /** + * Check which elements are valid to appear at this point. This method also + * works if the state is in error, in which case it returns what should + * have been seen. + * + * @param state the current state + * @return a Vector whose entries are instances of + * either XSWildcardDecl or XSElementDecl. + */ + public Vector whatCanGoHere(int[] state) { + int curState = state[0]; + if (curState < 0) + curState = state[1]; + Occurence o = (fCountingStates != null) ? + fCountingStates[curState] : null; + int count = state[2]; + + Vector ret = new Vector(); + for (int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++) { + int nextState = fTransTable[curState][elemIndex]; + if (nextState != -1) { + if (o != null) { + if (curState == nextState) { + // Do not include transitions which loop back to the + // current state if we've looped the maximum number + // of times or greater. + if (count >= o.maxOccurs && + o.maxOccurs != SchemaSymbols.OCCURRENCE_UNBOUNDED) { + continue; + } + } + // Do not include transitions which advance past the + // current state if we have not looped enough times. + else if (count < o.minOccurs) { + continue; + } + } + ret.addElement(fElemMap[elemIndex]); + } + } + return ret; + } + + public int [] occurenceInfo(int[] state) { + if (fCountingStates != null) { + int curState = state[0]; + if (curState < 0) { + curState = state[1]; + } + Occurence o = fCountingStates[curState]; + if (o != null) { + int [] occurenceInfo = new int[4]; + occurenceInfo[0] = o.minOccurs; + occurenceInfo[1] = o.maxOccurs; + occurenceInfo[2] = state[2]; + occurenceInfo[3] = o.elemIndex; + return occurenceInfo; + } + } + return null; + } + + public String getTermName(int termId) { + Object term = fElemMap[termId]; + return (term != null) ? term.toString() : null; + } + + public boolean isCompactedForUPA() { + return fIsCompactedForUPA; + } +} // class DFAContentModel diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSEmptyCM.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSEmptyCM.java new file mode 100644 index 0000000..c0d0299 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/models/XSEmptyCM.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.models; + +import java.util.Vector; + +import org.apache.xerces.impl.xs.SubstitutionGroupHandler; +import org.apache.xerces.impl.xs.XMLSchemaException; +import org.apache.xerces.xni.QName; + +/** + * XSEmptyCM is a derivative of the abstract content model base class that + * handles a content model with no children (elements). + * + * This model validated on the way in. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Lisa Martin, IBM + * @version $Id$ + */ +public class XSEmptyCM implements XSCMValidator { + + // + // Constants + // + + // start the content model: did not see any children + private static final short STATE_START = 0; + + private static final Vector EMPTY = new Vector(0); + + // + // Data + // + + // + // XSCMValidator methods + // + + /** + * This methods to be called on entering a first element whose type + * has this content model. It will return the initial state of the content model + * + * @return Start state of the content model + */ + public int[] startContentModel(){ + return (new int[] {STATE_START}); + } + + + /** + * The method corresponds to one transaction in the content model. + * + * @param elementName the qualified name of the element + * @param currentState Current state + * @param subGroupHandler the substitution group handler + * @return element index corresponding to the element from the Schema grammar + */ + public Object oneTransition (QName elementName, int[] currentState, SubstitutionGroupHandler subGroupHandler){ + + // error state + if (currentState[0] < 0) { + currentState[0] = XSCMValidator.SUBSEQUENT_ERROR; + return null; + } + + currentState[0] = XSCMValidator.FIRST_ERROR; + return null; + } + + + /** + * The method indicates the end of list of children + * + * @param currentState Current state of the content model + * @return true if the last state was a valid final state + */ + public boolean endContentModel (int[] currentState){ + boolean isFinal = false; + int state = currentState[0]; + + // restore content model state: + + // error + if (state < 0) { + return false; + } + + + return true; + } + + /** + * check whether this content violates UPA constraint. + * + * @param subGroupHandler the substitution group handler + * @return true if this content model contains other or list wildcard + */ + public boolean checkUniqueParticleAttribution(SubstitutionGroupHandler subGroupHandler) throws XMLSchemaException { + return false; + } + + /** + * Check which elements are valid to appear at this point. This method also + * works if the state is in error, in which case it returns what should + * have been seen. + * + * @param state the current state + * @return a Vector whose entries are instances of + * either XSWildcardDecl or XSElementDecl. + */ + public Vector whatCanGoHere(int[] state) { + return EMPTY; + } + + public int [] occurenceInfo(int[] state) { + return null; + } + + public String getTermName(int termId) { + return null; + } + + public boolean isCompactedForUPA() { + return false; + } +} // class XSEmptyCM diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/AttrImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/AttrImpl.java new file mode 100644 index 0000000..3e34715 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/AttrImpl.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; + + +/** + * This class represents a single attribute. + * + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id$ + */ +public class AttrImpl extends NodeImpl + implements Attr { + + Element element; + String value; + + /** Default Constructor */ + public AttrImpl() { + nodeType = Node.ATTRIBUTE_NODE; + } + + /** + * Constructs an attribute. + * + * @param element Element which owns this attribute + * @param prefix The QName prefix. + * @param localpart The QName localpart. + * @param rawname The QName rawname. + * @param uri The uri binding for the associated prefix. + * @param value The value of the attribute. + */ + public AttrImpl(Element element, String prefix, String localpart, String rawname, String uri, String value) { + super(prefix, localpart, rawname, uri, Node.ATTRIBUTE_NODE); + this.element = element; + this.value = value; + } + + public String getName() { + return rawname; + } + + public boolean getSpecified() { + return true; + } + + public String getValue() { + return value; + } + + public String getNodeValue() { + return getValue(); + } + + public Element getOwnerElement() { + return element; + } + + public Document getOwnerDocument() { + return element.getOwnerDocument(); + } + + public void setValue(String value) throws DOMException { + this.value = value; + } + + /** + * @since DOM Level 3 + */ + public boolean isId(){ + return false; + } + + /** + * Method getSchemaTypeInfo. + * @return TypeInfo + */ + public TypeInfo getSchemaTypeInfo(){ + return null; + } + + /** NON-DOM method for debugging convenience */ + public String toString() { + return getName() + "=" + "\"" + getValue() + "\""; + } +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultDocument.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultDocument.java new file mode 100644 index 0000000..d11214e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultDocument.java @@ -0,0 +1,297 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + + +/** + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id$ + */ +public class DefaultDocument extends NodeImpl + implements Document { + + private String fDocumentURI = null; + + // default constructor + public DefaultDocument() { + this.nodeType = Node.DOCUMENT_NODE; + } + + // + // org.w3c.dom.Node methods + // + + public String getNodeName() { + return "#document"; + } + + // + // org.w3c.dom.Document methods + // + + public DocumentType getDoctype() { + return null; + } + + + public DOMImplementation getImplementation() { + return null; + } + + + public Element getDocumentElement() { + return null; + } + + + public NodeList getElementsByTagName(String tagname) { + return null; + } + + + public NodeList getElementsByTagNameNS(String namespaceURI, String localName) { + return null; + } + + + public Element getElementById(String elementId) { + return null; + } + + + public Node importNode(Node importedNode, boolean deep) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Element createElement(String tagName) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public DocumentFragment createDocumentFragment() { + return null; + } + + + public Text createTextNode(String data) { + return null; + } + + public Comment createComment(String data) { + return null; + } + + + public CDATASection createCDATASection(String data) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public ProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Attr createAttribute(String name) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public EntityReference createEntityReference(String name) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Element createElementNS(String namespaceURI, String qualifiedName) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Attr createAttributeNS(String namespaceURI, String qualifiedName) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + // DOM Level 3 methods. + + public String getInputEncoding(){ + return null; + } + + /** + public void setInputEncoding(String actualEncoding){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + */ + + public String getXmlEncoding(){ + return null; + } + + + /** + * An attribute specifying, as part of the XML declaration, the encoding + * of this document. This is null when unspecified. + * @since DOM Level 3 + public void setXmlEncoding(String encoding){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + */ + + /** + * An attribute specifying, as part of the XML declaration, whether this + * document is standalone. + *
This attribute represents the property [standalone] defined in . + * @since DOM Level 3 + */ + public boolean getXmlStandalone(){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + /** + * An attribute specifying, as part of the XML declaration, whether this + * document is standalone. + *
This attribute represents the property [standalone] defined in . + * @since DOM Level 3 + */ + public void setXmlStandalone(boolean standalone){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * An attribute specifying, as part of the XML declaration, the version + * number of this document. This is null when unspecified. + *
This attribute represents the property [version] defined in . + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised if the version is set to a value that is + * not supported by this Document. + * @since DOM Level 3 + */ + public String getXmlVersion(){ + return null; + } + /** + * An attribute specifying, as part of the XML declaration, the version + * number of this document. This is null when unspecified. + *
This attribute represents the property [version] defined in . + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised if the version is set to a value that is + * not supported by this Document. + * @since DOM Level 3 + */ + public void setXmlVersion(String version) throws DOMException{ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * An attribute specifying whether errors 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. In case of error, the + * behavior is undefined. This attribute is true by + * defaults. + * @since DOM Level 3 + */ + public boolean getStrictErrorChecking(){ + return false; + } + /** + * An attribute specifying whether errors 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. In case of error, the + * behavior is undefined. This attribute is true by + * defaults. + * @since DOM Level 3 + */ + public void setStrictErrorChecking(boolean strictErrorChecking){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * The location of the document or null if undefined. + *
Beware that when the Document supports the feature + * "HTML" , the href attribute of the HTML BASE element takes precedence + * over this attribute. + * @since DOM Level 3 + */ + public String getDocumentURI() { + return fDocumentURI; + } + + /** + * The location of the document or null if undefined. + *
Beware that when the Document supports the feature + * "HTML" , the href attribute of the HTML BASE element takes precedence + * over this attribute. + * @since DOM Level 3 + */ + public void setDocumentURI(String documentURI) { + fDocumentURI = documentURI; + } + + /** DOM Level 3*/ + public Node adoptNode(Node source) throws DOMException{ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** DOM Level 3*/ + public void normalizeDocument(){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * The configuration used when Document.normalizeDocument is + * invoked. + * @since DOM Level 3 + */ + public DOMConfiguration getDomConfig(){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** DOM Level 3*/ + public Node renameNode(Node n,String namespaceURI, String name) throws DOMException{ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + + + + + + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultElement.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultElement.java new file mode 100644 index 0000000..3fd1f74 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultElement.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.w3c.dom.TypeInfo; + + +/** + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id$ + */ +public class DefaultElement extends NodeImpl + implements Element { + + // default constructor + public DefaultElement() { + } + + + public DefaultElement(String prefix, String localpart, String rawname, String uri, short nodeType) { + super(prefix, localpart, rawname, uri, nodeType); + } + + + // + // org.w3c.dom.Element methods + // + + // getter methods + public String getTagName() { + return null; + } + + + public String getAttribute(String name) { + return null; + } + + + public Attr getAttributeNode(String name) { + return null; + } + + + public NodeList getElementsByTagName(String name) { + return null; + } + + + public String getAttributeNS(String namespaceURI, String localName) { + return null; + } + + + public Attr getAttributeNodeNS(String namespaceURI, String localName) { + return null; + } + + + public NodeList getElementsByTagNameNS(String namespaceURI, String localName) { + return null; + } + + + public boolean hasAttribute(String name) { + return false; + } + + + public boolean hasAttributeNS(String namespaceURI, String localName) { + return false; + } + + public TypeInfo getSchemaTypeInfo(){ + return null; + } + + + // setter methods + public void setAttribute(String name, String value) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public void removeAttribute(String name) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Attr removeAttributeNode(Attr oldAttr) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Attr setAttributeNode(Attr newAttr) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public void removeAttributeNS(String namespaceURI, String localName) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Attr setAttributeNodeNS(Attr newAttr) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public void setIdAttributeNode(Attr at, boolean makeId) throws DOMException{ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + public void setIdAttribute(String name, boolean makeId) throws DOMException{ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public void setIdAttributeNS(String namespaceURI, String localName, + boolean makeId) throws DOMException{ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + +} + \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultNode.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultNode.java new file mode 100644 index 0000000..fa0203e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultNode.java @@ -0,0 +1,216 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.UserDataHandler; + + +/** + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id$ + */ +public class DefaultNode implements Node { + + // default constructor + public DefaultNode() { + } + + // + // org.w3c.dom.Node methods + // + + // getter methods + public String getNodeName() { + return null; + } + + + public String getNodeValue() throws DOMException { + return null; + } + + + public short getNodeType() { + return -1; + } + + + public Node getParentNode() { + return null; + } + + + public NodeList getChildNodes() { + return null; + } + + + public Node getFirstChild() { + return null; + } + + + public Node getLastChild() { + return null; + } + + + public Node getPreviousSibling() { + return null; + } + + + public Node getNextSibling() { + return null; + } + + + public NamedNodeMap getAttributes() { + return null; + } + + + public Document getOwnerDocument() { + return null; + } + + + public boolean hasChildNodes() { + return false; + } + + + public Node cloneNode(boolean deep) { + return null; + } + + + public void normalize() { + } + + + public boolean isSupported(String feature, String version) { + return false; + } + + + public String getNamespaceURI() { + return null; + } + + + public String getPrefix() { + return null; + } + + + public String getLocalName() { + return null; + } + /** DOM Level 3*/ + public String getBaseURI(){ + return null; + } + + + + public boolean hasAttributes() { + return false; + } + + // setter methods + public void setNodeValue(String nodeValue) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Node insertBefore(Node newChild, Node refChild) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Node replaceChild(Node newChild, Node oldChild) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Node removeChild(Node oldChild) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public Node appendChild(Node newChild) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + + public void setPrefix(String prefix) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public short compareDocumentPosition(Node other){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public String getTextContent() throws DOMException{ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + public void setTextContent(String textContent)throws DOMException{ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + public boolean isSameNode(Node other){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + + } + public String lookupPrefix(String namespaceURI){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + public boolean isDefaultNamespace(String namespaceURI){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public String lookupNamespaceURI(String prefix){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public boolean isEqualNode(Node arg){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + + } + + public Object getFeature(String feature, String version){ + return null; + } + public Object setUserData(String key, Object data, UserDataHandler handler){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + public Object getUserData(String key){ + return null; + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultText.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultText.java new file mode 100644 index 0000000..8d9bc5a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultText.java @@ -0,0 +1,236 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Text; + +/** + * The Text interface inherits from CharacterData + * and represents the textual content (termed character data in XML) of an + * Element or Attr. If there is no markup inside + * an element's content, the text is contained in a single object + * implementing the Text interface that is the only child of + * the element. If there is markup, it is parsed into the information items + * (elements, comments, etc.) and Text nodes that form the list + * of children of the element. + *

When a document is first made available via the DOM, there is only one + * Text node for each block of text. Users may create adjacent + * Text nodes that represent the contents of a given element + * without any intervening markup, but should be aware that there is no way + * to represent the separations between these nodes in XML or HTML, so they + * will not (in general) persist between DOM editing sessions. The + * normalize() method on Node merges any such + * adjacent Text objects into a single node for each block of + * text. + *

See also the Document Object Model (DOM) Level 2 Core Specification. + * + * This is an empty implementation. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class DefaultText extends NodeImpl implements Text { + + // CharacterData methods + + /** + * The character data of the node that implements this interface. The DOM + * implementation may not put arbitrary limits on the amount of data + * that may be stored in a CharacterData node. However, + * implementation limits may mean that the entirety of a node's data may + * not fit into a single DOMString. In such cases, the user + * may call substringData to retrieve the data in + * appropriately sized pieces. + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. + * @exception DOMException + * DOMSTRING_SIZE_ERR: Raised when it would return more characters than + * fit in a DOMString variable on the implementation + * platform. + */ + public String getData() + throws DOMException { + return null; + } + + /** + * The character data of the node that implements this interface. The DOM + * implementation may not put arbitrary limits on the amount of data + * that may be stored in a CharacterData node. However, + * implementation limits may mean that the entirety of a node's data may + * not fit into a single DOMString. In such cases, the user + * may call substringData to retrieve the data in + * appropriately sized pieces. + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. + * @exception DOMException + * DOMSTRING_SIZE_ERR: Raised when it would return more characters than + * fit in a DOMString variable on the implementation + * platform. + */ + public void setData(String data) + throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * The number of 16-bit units that are available through data + * and the substringData method below. This may have the + * value zero, i.e., CharacterData nodes may be empty. + */ + public int getLength() { + return 0; + } + + /** + * Extracts a range of data from the node. + * @param offset Start offset of substring to extract. + * @param count The number of 16-bit units to extract. + * @return The specified substring. If the sum of offset and + * count exceeds the length, then all 16-bit + * units to the end of the data are returned. + * @exception 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. + *
DOMSTRING_SIZE_ERR: Raised if the specified range of text does + * not fit into a DOMString. + */ + public String substringData(int offset, + int count) + throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Append the string to the end of the character data of the node. Upon + * success, data provides access to the concatenation of + * data and the DOMString specified. + * @param arg The DOMString to append. + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + */ + public void appendData(String arg) + throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Insert a string at the specified 16-bit unit offset. + * @param offset The character offset at which to insert. + * @param arg The DOMString to insert. + * @exception DOMException + * INDEX_SIZE_ERR: Raised if the specified offset is + * negative or greater than the number of 16-bit units in + * data. + *
NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + */ + public void insertData(int offset, + String arg) + throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Remove a range of 16-bit units from the node. Upon success, + * data and length reflect the change. + * @param offset The offset from which to start removing. + * @param count The number of 16-bit units to delete. If the sum of + * offset and count exceeds + * length then all 16-bit units from offset + * to the end of the data are deleted. + * @exception 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. + *
NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + */ + public void deleteData(int offset, + int count) + throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Replace the characters starting at the specified 16-bit unit offset + * with the specified string. + * @param offset The offset from which to start replacing. + * @param count The number of 16-bit units to replace. If the sum of + * offset and count exceeds + * length, then all 16-bit units to the end of the data + * are replaced; (i.e., the effect is the same as a remove + * method call with the same range, followed by an append + * method invocation). + * @param arg The DOMString with which the range must be + * replaced. + * @exception 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. + *
NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + */ + public void replaceData(int offset, + int count, + String arg) + throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + // Text node methods + /** + * Breaks this node into two nodes at the specified offset, + * keeping both in the tree as siblings. After being split, this node + * will contain all the content up to the offset point. A + * new node of the same type, which contains all the content at and + * after the offset point, is returned. If the original + * node had a parent node, the new node is inserted as the next sibling + * of the original node. When the offset is equal to the + * length of this node, the new node has no data. + * @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 DOMException + * INDEX_SIZE_ERR: Raised if the specified offset is negative or greater + * than the number of 16-bit units in data. + *
NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + */ + public Text splitText(int offset) + throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** DOM Level 3 CR */ + public boolean isElementContentWhitespace(){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public String getWholeText(){ + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public Text replaceWholeText(String content) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultXMLDocumentHandler.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultXMLDocumentHandler.java new file mode 100644 index 0000000..949b023 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/DefaultXMLDocumentHandler.java @@ -0,0 +1,868 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDTDContentModelSource; +import org.apache.xerces.xni.parser.XMLDTDSource; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class DefaultXMLDocumentHandler implements XMLDocumentHandler, + XMLDTDHandler, + XMLDTDContentModelHandler { + + /** Default Constructor */ + public DefaultXMLDocumentHandler() { + } + + // + // XMLDocumentHandler methods + // + + /** + * The start of the document. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing + * of this document. However, it is strongly + * recommended that a locator be supplied that can + * at least report the system identifier of the + * document. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext context, Augmentations augs) + throws XNIException { + } + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) + throws XNIException { + } + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement + * The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * otherwise. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) + throws XNIException { + } + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException { + } + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException { + } + + /** + * The start of a namespace prefix mapping. This method will only be + * called when namespace processing is enabled. + * + * @param prefix The namespace prefix. + * @param uri The URI bound to the prefix. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startPrefixMapping(String prefix, String uri, Augmentations augs) + throws XNIException { + } + + /** + * The start of an element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + } + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + } + + /** + * This method notifies the start of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException { + } + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

+ * Note: This method will never be called for the + * document entity; it is only called for external general entities + * referenced in document content. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { + } + + /** + * This method notifies the end of a general entity. + *

+ * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augs) throws XNIException { + } + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException { + } + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + } + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException { + } + + /** + * The end of a namespace prefix mapping. This method will only be + * called when namespace processing is enabled. + * + * @param prefix The namespace prefix. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endPrefixMapping(String prefix, Augmentations augs) throws XNIException { + } + + /** + * The start of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException { + } + + /** + * The end of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException { + } + + /** + * The end of the document. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endDocument(Augmentations augs) throws XNIException { + } + + + // + // XMLDTDHandler methods + // + + /** + * The start of the DTD. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing of + * the document DTD. However, it is strongly + * recommended that a locator be supplied that can + * at least report the base system identifier of the + * DTD. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDTD(XMLLocator locator, Augmentations augmentations) + throws XNIException { + } + + /** + * This method notifies of the start of a parameter entity. The parameter + * entity name start with a '%' character. + * + * @param name The name of the parameter entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal parameter entities). + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startParameterEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augmentations) throws XNIException { + } + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

+ * Note: This method is only called for external + * parameter entities referenced in the DTD. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ +/* + public void textDecl(String version, String encoding, + Augmentations augmentations) throws XNIException { + } +*/ + + /** + * This method notifies the end of a parameter entity. Parameter entity + * names begin with a '%' character. + * + * @param name The name of the parameter entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endParameterEntity(String name, Augmentations augmentations) + throws XNIException { + } + + /** + * The start of the DTD external subset. + * + * @param identifier The resource identifier. + * @param augmentations + * Additional information that may include infoset + * augmentations. + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startExternalSubset(XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException { + } + + /** + * The end of the DTD external subset. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endExternalSubset(Augmentations augmentations) + throws XNIException { + } + + /** + * A comment. + * + * @param text The text in the comment. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by application to signal an error. + */ +/* + public void comment(XMLString text, Augmentations augmentations) + throws XNIException { + } +*/ + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ +/* + public void processingInstruction(String target, XMLString data, + Augmentations augmentations) + throws XNIException { + } +*/ + + + /** + * An element declaration. + * + * @param name The name of the element. + * @param contentModel The element content model. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void elementDecl(String name, String contentModel, + Augmentations augmentations) + throws XNIException { + } + + /** + * The start of an attribute list. + * + * @param elementName The name of the element that this attribute + * list is associated with. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startAttlist(String elementName, + Augmentations augmentations) throws XNIException { + } + + /** + * An attribute declaration. + * + * @param elementName The name of the element that this attribute + * is associated with. + * @param attributeName The name of the attribute. + * @param type The attribute type. This value will be one of + * the following: "CDATA", "ENTITY", "ENTITIES", + * "ENUMERATION", "ID", "IDREF", "IDREFS", + * "NMTOKEN", "NMTOKENS", or "NOTATION". + * @param enumeration If the type has the value "ENUMERATION" or + * "NOTATION", this array holds the allowed attribute + * values; otherwise, this array is null. + * @param defaultType The attribute default type. This value will be + * one of the following: "#FIXED", "#IMPLIED", + * "#REQUIRED", or null. + * @param defaultValue The attribute default value, or null if no + * default value is specified. + * @param nonNormalizedDefaultValue The attribute default value with no normalization + * performed, or null if no default value is specified. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, + String defaultType, XMLString defaultValue, + XMLString nonNormalizedDefaultValue, Augmentations augmentations) + throws XNIException { + } + + /** + * The end of an attribute list. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endAttlist(Augmentations augmentations) throws XNIException { + } + + /** + * An internal entity declaration. + * + * @param name The name of the entity. Parameter entity names start with + * '%', whereas the name of a general entity is just the + * entity name. + * @param text The value of the entity. + * @param nonNormalizedText The non-normalized value of the entity. This + * value contains the same sequence of characters that was in + * the internal entity declaration, without any entity + * references expanded. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void internalEntityDecl(String name, XMLString text, + XMLString nonNormalizedText, + Augmentations augmentations) + throws XNIException { + } + + /** + * An external entity declaration. + * + * @param name The name of the entity. Parameter entity names start + * with '%', whereas the name of a general entity is just + * the entity name. + * @param identifier An object containing all location information + * pertinent to this external entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void externalEntityDecl(String name, + XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException { + } + + /** + * An unparsed entity declaration. + * + * @param name The name of the entity. + * @param identifier An object containing all location information + * pertinent to this unparsed entity declaration. + * @param notation The name of the notation. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void unparsedEntityDecl(String name, + XMLResourceIdentifier identifier, + String notation, Augmentations augmentations) + throws XNIException { + } + + /** + * A notation declaration + * + * @param name The name of the notation. + * @param identifier An object containing all location information + * pertinent to this notation. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void notationDecl(String name, XMLResourceIdentifier identifier, + Augmentations augmentations) throws XNIException { + } + + /** + * The start of a conditional section. + * + * @param type The type of the conditional section. This value will + * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #CONDITIONAL_INCLUDE + * @see #CONDITIONAL_IGNORE + */ + public void startConditional(short type, Augmentations augmentations) + throws XNIException { + } + + /** + * Characters within an IGNORE conditional section. + * + * @param text The ignored text. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignoredCharacters(XMLString text, Augmentations augmentations) + throws XNIException { + } + + /** + * The end of a conditional section. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endConditional(Augmentations augmentations) throws XNIException { + } + + /** + * The end of the DTD. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDTD(Augmentations augmentations) throws XNIException { + } + + + // + // XMLDTDContentModelHandler methods + // + + /** + * The start of a content model. Depending on the type of the content + * model, specific methods may be called between the call to the + * startContentModel method and the call to the endContentModel method. + * + * @param elementName The name of the element. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startContentModel(String elementName, Augmentations augmentations) + throws XNIException { + } + + /** + * A content model of ANY. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #empty + * @see #startGroup + */ + public void any(Augmentations augmentations) throws XNIException { + } + + /** + * A content model of EMPTY. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @see #any + * @see #startGroup + */ + public void empty(Augmentations augmentations) throws XNIException { + } + + /** + * A start of either a mixed or children content model. A mixed + * content model will immediately be followed by a call to the + * pcdata() method. A children content model will + * contain additional groups and/or elements. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #any + * @see #empty + */ + public void startGroup(Augmentations augmentations) throws XNIException { + } + + /** + * The appearance of "#PCDATA" within a group signifying a + * mixed content model. This method will be the first called + * following the content model's startGroup(). + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #startGroup + */ + public void pcdata(Augmentations augmentations) throws XNIException { + } + + /** + * A referenced element in a mixed or children content model. + * + * @param elementName The name of the referenced element. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void element(String elementName, Augmentations augmentations) + throws XNIException { + } + + /** + * The separator between choices or sequences of a mixed or children + * content model. + * + * @param separator The type of children separator. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #SEPARATOR_CHOICE + * @see #SEPARATOR_SEQUENCE + */ + public void separator(short separator, Augmentations augmentations) + throws XNIException { + } + + /** + * The occurrence count for a child in a children content model or + * for the mixed content model group. + * + * @param occurrence The occurrence count for the last element + * or group. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #OCCURS_ZERO_OR_ONE + * @see #OCCURS_ZERO_OR_MORE + * @see #OCCURS_ONE_OR_MORE + */ + public void occurrence(short occurrence, Augmentations augmentations) + throws XNIException { + } + + /** + * The end of a group for mixed or children content models. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endGroup(Augmentations augmentations) throws XNIException { + } + + /** + * The end of a content model. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endContentModel(Augmentations augmentations) throws XNIException { + } + + private XMLDocumentSource fDocumentSource; + + /** Sets the document source. */ + public void setDocumentSource(XMLDocumentSource source) { + fDocumentSource = source; + } + + /** Returns the document source. */ + public XMLDocumentSource getDocumentSource() { + return fDocumentSource; + } + + private XMLDTDSource fDTDSource; + + // set the source of this handler + public void setDTDSource(XMLDTDSource source) { + fDTDSource = source; + } + + // return the source from which this handler derives its events + public XMLDTDSource getDTDSource() { + return fDTDSource; + } + + private XMLDTDContentModelSource fCMSource; + + // set content model source + public void setDTDContentModelSource(XMLDTDContentModelSource source) { + fCMSource = source; + } + + // get content model source + public XMLDTDContentModelSource getDTDContentModelSource() { + return fCMSource; + } + +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/ElementImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/ElementImpl.java new file mode 100644 index 0000000..97a7236 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/ElementImpl.java @@ -0,0 +1,271 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class ElementImpl extends DefaultElement { + + SchemaDOM schemaDOM; + Attr[] attrs; + int row; + int col; + int parentRow; + + int line; + int column; + int charOffset; + String fAnnotation; + String fSyntheticAnnotation; + + public ElementImpl(int line, int column, int offset) { + row = -1; + col = -1; + parentRow = -1; + nodeType = Node.ELEMENT_NODE; + + this.line = line; + this.column = column; + charOffset = offset; + } + + public ElementImpl(int line, int column) { + this(line, column, -1); + } + + + public ElementImpl(String prefix, String localpart, String rawname, + String uri, int line, int column, int offset) { + super(prefix, localpart, rawname, uri, Node.ELEMENT_NODE); + row = -1; + col = -1; + parentRow = -1; + + this.line = line; + this.column = column; + charOffset = offset; + } + + public ElementImpl(String prefix, String localpart, String rawname, + String uri, int line, int column) { + this(prefix, localpart, rawname, uri, line, column, -1); + } + + + // + // org.w3c.dom.Node methods + // + + public Document getOwnerDocument() { + return schemaDOM; + } + + + public Node getParentNode() { + return schemaDOM.relations[row][0]; + } + + + public boolean hasChildNodes() { + if (parentRow == -1) { + return false; + } + else { + return true; + } + } + + + public Node getFirstChild() { + if (parentRow == -1) { + return null; + } + return schemaDOM.relations[parentRow][1]; + } + + + public Node getLastChild() { + if (parentRow == -1) { + return null; + } + int i=1; + for (; i getLength()) { + return null; + } + return attrs[index]; + } + + public int getLength() { + return attrs.length; + } + + public Node getNamedItemNS(String namespaceURI, String localName) { + for (int i=0; i

+ * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException { + if (fAnnotationDepth > -1) { + schemaDOM.processingInstruction(target, data); + } + } + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException { + // when it's not within xs:appinfo or xs:documentation + if (fInnerAnnotationDepth == -1 ) { + for (int i=text.offset; i 0) { + fSawAnnotation.pop(); + } + fSawAnnotation.push(true); + } + fAnnotationDepth = fDepth; + schemaDOM.startAnnotation(element, attributes, fNamespaceContext); + fCurrentAnnotationElement = schemaDOM.startElement(element, attributes, + fLocator.getLineNumber(), + fLocator.getColumnNumber(), + fLocator.getCharacterOffset()); + return; + } + else if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA && fGenerateSyntheticAnnotation) { + fSawAnnotation.push(false); + fHasNonSchemaAttributes.push(hasNonSchemaAttributes(element, attributes)); + } + } + else if (fDepth == fAnnotationDepth + 1) { + fInnerAnnotationDepth = fDepth; + schemaDOM.startAnnotationElement(element, attributes); + } + else { + schemaDOM.startAnnotationElement(element, attributes); + // avoid falling through; don't call startElement in this case + return; + } + schemaDOM.startElement(element, attributes, + fLocator.getLineNumber(), + fLocator.getColumnNumber(), + fLocator.getCharacterOffset()); + + } + + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + if (fGenerateSyntheticAnnotation && fAnnotationDepth == -1 && + element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA && element.localpart != SchemaSymbols.ELT_ANNOTATION && hasNonSchemaAttributes(element, attributes)) { + + schemaDOM.startElement(element, attributes, + fLocator.getLineNumber(), + fLocator.getColumnNumber(), + fLocator.getCharacterOffset()); + + attributes.removeAllAttributes(); + String schemaPrefix = fNamespaceContext.getPrefix(SchemaSymbols.URI_SCHEMAFORSCHEMA); + final String annRawName = (schemaPrefix.length() == 0) ? SchemaSymbols.ELT_ANNOTATION : (schemaPrefix + ':' + SchemaSymbols.ELT_ANNOTATION); + schemaDOM.startAnnotation(annRawName, attributes, fNamespaceContext); + final String elemRawName = (schemaPrefix.length() == 0) ? SchemaSymbols.ELT_DOCUMENTATION : (schemaPrefix + ':' + SchemaSymbols.ELT_DOCUMENTATION); + schemaDOM.startAnnotationElement(elemRawName, attributes); + schemaDOM.charactersRaw("SYNTHETIC_ANNOTATION"); + schemaDOM.endSyntheticAnnotationElement(elemRawName, false); + schemaDOM.endSyntheticAnnotationElement(annRawName, true); + + schemaDOM.endElement(); + + return; + } + // the order of events that occurs here is: + // schemaDOM.startAnnotation/startAnnotationElement (if applicable) + // schemaDOM.emptyElement (basically the same as startElement then endElement) + // schemaDOM.endAnnotationElement (if applicable) + // the order of events that would occur if this was : + // schemaDOM.startAnnotation/startAnnotationElement (if applicable) + // schemaDOM.startElement + // schemaDOM.endAnnotationElement (if applicable) + // schemaDOM.endElementElement + // Thus, we can see that the order of events isn't the same. However, it doesn't + // seem to matter. -- PJM + if (fAnnotationDepth == -1) { + // this is messed up, but a case to consider: + if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA && + element.localpart == SchemaSymbols.ELT_ANNOTATION) { + schemaDOM.startAnnotation(element, attributes, fNamespaceContext); + } + } + else { + schemaDOM.startAnnotationElement(element, attributes); + } + + ElementImpl newElem = schemaDOM.emptyElement(element, attributes, + fLocator.getLineNumber(), + fLocator.getColumnNumber(), + fLocator.getCharacterOffset()); + + if (fAnnotationDepth == -1) { + // this is messed up, but a case to consider: + if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA && + element.localpart == SchemaSymbols.ELT_ANNOTATION) { + schemaDOM.endAnnotation(element, newElem); + } + } + else { + schemaDOM.endAnnotationElement(element); + } + } + + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException { + + // when we reach the endElement of xs:appinfo or xs:documentation, + // change fInnerAnnotationDepth to -1 + if(fAnnotationDepth > -1) { + if (fInnerAnnotationDepth == fDepth) { + fInnerAnnotationDepth = -1; + schemaDOM.endAnnotationElement(element); + schemaDOM.endElement(); + } else if (fAnnotationDepth == fDepth) { + fAnnotationDepth = -1; + schemaDOM.endAnnotation(element, fCurrentAnnotationElement); + schemaDOM.endElement(); + } else { // inside a child of annotation + schemaDOM.endAnnotationElement(element); + } + } else { // not in an annotation at all + if(element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA && fGenerateSyntheticAnnotation) { + boolean value = fHasNonSchemaAttributes.pop(); + boolean sawann = fSawAnnotation.pop(); + if (value && !sawann) { + String schemaPrefix = fNamespaceContext.getPrefix(SchemaSymbols.URI_SCHEMAFORSCHEMA); + final String annRawName = (schemaPrefix.length() == 0) ? SchemaSymbols.ELT_ANNOTATION : (schemaPrefix + ':' + SchemaSymbols.ELT_ANNOTATION); + schemaDOM.startAnnotation(annRawName, fEmptyAttr, fNamespaceContext); + final String elemRawName = (schemaPrefix.length() == 0) ? SchemaSymbols.ELT_DOCUMENTATION : (schemaPrefix + ':' + SchemaSymbols.ELT_DOCUMENTATION); + schemaDOM.startAnnotationElement(elemRawName, fEmptyAttr); + schemaDOM.charactersRaw("SYNTHETIC_ANNOTATION"); + schemaDOM.endSyntheticAnnotationElement(elemRawName, false); + schemaDOM.endSyntheticAnnotationElement(annRawName, true); + } + } + schemaDOM.endElement(); + } + fDepth--; + + } + + /** + * @param attributes + * @return + */ + private boolean hasNonSchemaAttributes(QName element, XMLAttributes attributes) { + final int length = attributes.getLength(); + for (int i = 0; i < length; ++i) { + String uri = attributes.getURI(i); + if (uri != null && uri != SchemaSymbols.URI_SCHEMAFORSCHEMA && + uri != NamespaceContext.XMLNS_URI && + !(uri == NamespaceContext.XML_URI && + attributes.getQName(i) == SchemaSymbols.ATT_XML_LANG && element.localpart == SchemaSymbols.ELT_SCHEMA)) { + return true; + } + } + return false; + } + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + // unlikely to be called, but you never know... + if (fAnnotationDepth != -1 ) { + schemaDOM.characters(text); + } + } + + /** + * The start of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException { + // only deal with CDATA boundaries within an annotation. + if (fAnnotationDepth != -1) { + schemaDOM.startAnnotationCDATA(); + } + } + + /** + * The end of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException { + // only deal with CDATA boundaries within an annotation. + if (fAnnotationDepth != -1) { + schemaDOM.endAnnotationCDATA(); + } + } + + + // + // other methods + // + + /** + * Returns the DOM document object. + */ + public Document getDocument() { + return schemaDOM; + } + + /** + * Delegates to SchemaParsingConfig.setFeature + * @param featureId + * @param state + */ + public void setFeature(String featureId, boolean state){ + config.setFeature(featureId, state); + } + + /** + * Delegates to SchemaParsingConfig.getFeature + * @param featureId + * @return boolean + */ + public boolean getFeature(String featureId){ + return config.getFeature(featureId); + } + + /** + * Delegates to SchemaParsingConfig.setProperty. + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value){ + config.setProperty(propertyId, value); + } + + /** + * Delegates to SchemaParsingConfig.getProperty. + * @param propertyId + * @return Object + */ + public Object getProperty(String propertyId){ + return config.getProperty(propertyId); + } + + /** + * Delegates to SchemaParsingConfig.setEntityResolver. + * @param er XMLEntityResolver + */ + public void setEntityResolver(XMLEntityResolver er) { + config.setEntityResolver(er); + } + + /** + * Delegates parsing to SchemaParsingConfig + * + * @param inputSource + * @throws IOException + */ + public void parse(XMLInputSource inputSource) throws IOException { + config.parse(inputSource); + } + + /** + * Reset SchemaParsingConfig + */ + public void reset() { + ((SchemaParsingConfig)config).reset(); + } + + /** + * ResetNodePool on SchemaParsingConfig + */ + public void resetNodePool() { + ((SchemaParsingConfig)config).resetNodePool(); + } + + /** + * A simple boolean based stack. + * + * @xerces.internal + */ + private static final class BooleanStack { + + // + // Data + // + + /** Stack depth. */ + private int fDepth; + + /** Stack data. */ + private boolean[] fData; + + // + // Constructor + // + + public BooleanStack () {} + + // + // Public methods + // + + /** Returns the size of the stack. */ + public int size() { + return fDepth; + } + + /** Pushes a value onto the stack. */ + public void push(boolean value) { + ensureCapacity(fDepth + 1); + fData[fDepth++] = value; + } + + /** Pops a value off of the stack. */ + public boolean pop() { + return fData[--fDepth]; + } + + /** Clears the stack. */ + public void clear() { + fDepth = 0; + } + + // + // Private methods + // + + /** Ensures capacity. */ + private void ensureCapacity(int size) { + if (fData == null) { + fData = new boolean[32]; + } + else if (fData.length <= size) { + boolean[] newdata = new boolean[fData.length * 2]; + System.arraycopy(fData, 0, newdata, 0, fData.length); + fData = newdata; + } + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/SchemaParsingConfig.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/SchemaParsingConfig.java new file mode 100644 index 0000000..cac274a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/SchemaParsingConfig.java @@ -0,0 +1,1028 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import java.io.IOException; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XML11DTDScannerImpl; +import org.apache.xerces.impl.XML11NSDocumentScannerImpl; +import org.apache.xerces.impl.XMLDTDScannerImpl; +import org.apache.xerces.impl.XMLEntityHandler; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.XMLNSDocumentScannerImpl; +import org.apache.xerces.impl.XMLVersionDetector; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.parsers.BasicParserConfiguration; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDScanner; +import org.apache.xerces.xni.parser.XMLDocumentScanner; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLPullParserConfiguration; + +/** + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id$ + */ +public class SchemaParsingConfig extends BasicParserConfiguration + implements XMLPullParserConfiguration { + + // + // Constants + // + + protected final static String XML11_DATATYPE_VALIDATOR_FACTORY = + "org.apache.xerces.impl.dv.dtd.XML11DTDDVFactoryImpl"; + + // feature identifiers + + /** Feature identifier: warn on duplicate attribute definition. */ + protected static final String WARN_ON_DUPLICATE_ATTDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; + + /** Feature identifier: warn on duplicate entity definition. */ + // protected static final String WARN_ON_DUPLICATE_ENTITYDEF = Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ENTITYDEF_FEATURE; + + /** Feature identifier: warn on undeclared element definition. */ + protected static final String WARN_ON_UNDECLARED_ELEMDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE; + + /** Feature identifier: allow Java encodings. */ + protected static final String ALLOW_JAVA_ENCODINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; + + /** Feature identifier: continue after fatal error. */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + /** Feature identifier: load external DTD. */ + protected static final String LOAD_EXTERNAL_DTD = + Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE; + + /** Feature identifier: notify built-in refereces. */ + protected static final String NOTIFY_BUILTIN_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE; + + /** Feature identifier: notify character refereces. */ + protected static final String NOTIFY_CHAR_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE; + + /** Feature identifier: expose schema normalized value */ + protected static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + + /** Feature identifier: send element default value via characters() */ + protected static final String SCHEMA_ELEMENT_DEFAULT = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; + + /** Feature identifier: generate synthetic annotations. */ + protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE; + + + // property identifiers + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier document scanner: */ + protected static final String DOCUMENT_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_SCANNER_PROPERTY; + + /** Property identifier: DTD scanner. */ + protected static final String DTD_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY; + + /** Property identifier: grammar pool. */ + protected static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: DTD validator. */ + protected static final String DTD_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; + + /** Property identifier: namespace binder. */ + protected static final String NAMESPACE_BINDER = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_BINDER_PROPERTY; + + /** Property identifier: datatype validator factory. */ + protected static final String DATATYPE_VALIDATOR_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; + + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: XML Schema validator. */ + protected static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: locale. */ + protected static final String LOCALE = + Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + + + // debugging + + /** Set to true and recompile to print exception stack trace. */ + private static final boolean PRINT_EXCEPTION_STACK_TRACE = false; + + // + // Data + // + + // + // XML 1.0 components + // + + /** The XML 1.0 Datatype validator factory. */ + protected final DTDDVFactory fDatatypeValidatorFactory; + + /** The XML 1.0 Document scanner. */ + protected final XMLNSDocumentScannerImpl fNamespaceScanner; + + /** The XML 1.0 DTD scanner. */ + protected final XMLDTDScannerImpl fDTDScanner; + + // + // XML 1.1 components + // + + /** The XML 1.1 Datatype validator factory. */ + protected DTDDVFactory fXML11DatatypeFactory = null; + + /** The XML 1.1 Document scanner. */ + protected XML11NSDocumentScannerImpl fXML11NSDocScanner = null; + + /** The XML 1.1 DTD scanner. **/ + protected XML11DTDScannerImpl fXML11DTDScanner = null; + + // common components (non-configurable) + + /** Current Datatype validator factory. */ + protected DTDDVFactory fCurrentDVFactory; + + /** Current scanner */ + protected XMLDocumentScanner fCurrentScanner; + + /** Current DTD scanner. */ + protected XMLDTDScanner fCurrentDTDScanner; + + /** Grammar pool. */ + protected XMLGrammarPool fGrammarPool; + + /** XML version detector. */ + protected final XMLVersionDetector fVersionDetector; + + // common components (configurable) + + /** Error reporter. */ + protected final XMLErrorReporter fErrorReporter; + + /** Entity manager. */ + protected final XMLEntityManager fEntityManager; + + /** Input Source */ + protected XMLInputSource fInputSource; + + protected final ValidationManager fValidationManager; + // state + + /** Locator */ + protected XMLLocator fLocator; + + /** + * True if a parse is in progress. This state is needed because + * some features/properties cannot be set while parsing (e.g. + * validation and namespaces). + */ + protected boolean fParseInProgress = false; + + /** + * fConfigUpdated is set to true if there has been any change to the configuration settings, + * i.e a feature or a property was changed. + */ + protected boolean fConfigUpdated = false; + + /** Flag indiciating whether XML11 components have been initialized. */ + private boolean f11Initialized = false; + + // + // Constructors + // + + /** Default constructor. */ + public SchemaParsingConfig() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public SchemaParsingConfig(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

+ * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public SchemaParsingConfig(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

+ * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public SchemaParsingConfig(SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, parentSettings); + + // add default recognized features + final String[] recognizedFeatures = { + PARSER_SETTINGS, WARN_ON_DUPLICATE_ATTDEF, WARN_ON_UNDECLARED_ELEMDEF, + ALLOW_JAVA_ENCODINGS, CONTINUE_AFTER_FATAL_ERROR, + LOAD_EXTERNAL_DTD, NOTIFY_BUILTIN_REFS, + NOTIFY_CHAR_REFS, GENERATE_SYNTHETIC_ANNOTATIONS + }; + addRecognizedFeatures(recognizedFeatures); + fFeatures.put(PARSER_SETTINGS, Boolean.TRUE); + // set state for default features + fFeatures.put(WARN_ON_DUPLICATE_ATTDEF, Boolean.FALSE); + //setFeature(WARN_ON_DUPLICATE_ENTITYDEF, false); + fFeatures.put(WARN_ON_UNDECLARED_ELEMDEF, Boolean.FALSE); + fFeatures.put(ALLOW_JAVA_ENCODINGS, Boolean.FALSE); + fFeatures.put(CONTINUE_AFTER_FATAL_ERROR, Boolean.FALSE); + fFeatures.put(LOAD_EXTERNAL_DTD, Boolean.TRUE); + fFeatures.put(NOTIFY_BUILTIN_REFS, Boolean.FALSE); + fFeatures.put(NOTIFY_CHAR_REFS, Boolean.FALSE); + fFeatures.put(GENERATE_SYNTHETIC_ANNOTATIONS, Boolean.FALSE); + + // add default recognized properties + final String[] recognizedProperties = { + ERROR_REPORTER, + ENTITY_MANAGER, + DOCUMENT_SCANNER, + DTD_SCANNER, + DTD_VALIDATOR, + NAMESPACE_BINDER, + XMLGRAMMAR_POOL, + DATATYPE_VALIDATOR_FACTORY, + VALIDATION_MANAGER, + GENERATE_SYNTHETIC_ANNOTATIONS, + LOCALE + }; + addRecognizedProperties(recognizedProperties); + + fGrammarPool = grammarPool; + if (fGrammarPool != null) { + setProperty(XMLGRAMMAR_POOL, fGrammarPool); + } + + fEntityManager = new XMLEntityManager(); + fProperties.put(ENTITY_MANAGER, fEntityManager); + addComponent(fEntityManager); + + fErrorReporter = new XMLErrorReporter(); + fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner()); + fProperties.put(ERROR_REPORTER, fErrorReporter); + addComponent(fErrorReporter); + + fNamespaceScanner = new XMLNSDocumentScannerImpl(); + fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner); + addRecognizedParamsAndSetDefaults(fNamespaceScanner); + + fDTDScanner = new XMLDTDScannerImpl(); + fProperties.put(DTD_SCANNER, fDTDScanner); + addRecognizedParamsAndSetDefaults(fDTDScanner); + + fDatatypeValidatorFactory = DTDDVFactory.getInstance(); + fProperties.put(DATATYPE_VALIDATOR_FACTORY, + fDatatypeValidatorFactory); + + fValidationManager = new ValidationManager(); + fProperties.put(VALIDATION_MANAGER, fValidationManager); + + fVersionDetector = new XMLVersionDetector(); + + // add message formatters + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + + if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { + XSMessageFormatter xmft = new XSMessageFormatter(); + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, xmft); + } + + // set locale + try { + setLocale(Locale.getDefault()); + } + catch (XNIException e) { + // do nothing + // REVISIT: What is the right thing to do? -Ac + } + + } // (SymbolTable,XMLGrammarPool) + + // + // Public methods + // + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * @return true if the feature is supported + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + // make this feature special + if (featureId.equals(PARSER_SETTINGS)) { + return fConfigUpdated; + } + return super.getFeature(featureId); + + } // getFeature(String):boolean + + /** + * Set the state of a feature. + * + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + + fConfigUpdated = true; + + // forward to every XML 1.0 component + fNamespaceScanner.setFeature(featureId, state); + fDTDScanner.setFeature(featureId, state); + + // forward to every XML 1.1 component + if (f11Initialized) { + try { + fXML11DTDScanner.setFeature(featureId, state); + } + // ignore the exception. + catch (Exception e) {} + try { + fXML11NSDocScanner.setFeature(featureId, state); + } + // ignore the exception + catch (Exception e) {} + } + + // save state if noone "objects" + super.setFeature(featureId, state); + + } // setFeature(String,boolean) + + /** + * Returns the value of a property. + * + * @param propertyId The property identifier. + * @return the value of the property + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException { + if (LOCALE.equals(propertyId)) { + return getLocale(); + } + return super.getProperty(propertyId); + } + + /** + * setProperty + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + fConfigUpdated = true; + if (LOCALE.equals(propertyId)) { + setLocale((Locale) value); + } + + // forward to every XML 1.0 component + fNamespaceScanner.setProperty(propertyId, value); + fDTDScanner.setProperty(propertyId, value); + + // forward to every XML 1.1 component + if (f11Initialized) { + try { + fXML11DTDScanner.setProperty(propertyId, value); + } + // ignore the exception. + catch (Exception e) {} + try { + fXML11NSDocScanner.setProperty(propertyId, value); + } + // ignore the exception + catch (Exception e) {} + } + + // store value if noone "objects" + super.setProperty(propertyId, value); + + } // setProperty(String,Object) + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException { + super.setLocale(locale); + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + + // + // XMLPullParserConfiguration methods + // + + // parsing + + /** + * Sets the input source for the document to parse. + * + * @param inputSource The document's input source. + * + * @exception XMLConfigurationException Thrown if there is a + * configuration error when initializing the + * parser. + * @exception IOException Thrown on I/O error. + * + * @see #parse(boolean) + */ + public void setInputSource(XMLInputSource inputSource) + throws XMLConfigurationException, IOException { + + // REVISIT: this method used to reset all the components and + // construct the pipeline. Now reset() is called + // in parse (boolean) just before we parse the document + // Should this method still throw exceptions..? + + fInputSource = inputSource; + + } // setInputSource(XMLInputSource) + + /** + * Parses the document in a pull parsing fashion. + * + * @param complete True if the pull parser should parse the + * remaining document completely. + * + * @return True if there is more document to parse. + * + * @exception XNIException Any XNI exception, possibly wrapping + * another exception. + * @exception IOException An IO exception from the parser, possibly + * from a byte stream or character stream + * supplied by the parser. + * + * @see #setInputSource + */ + public boolean parse(boolean complete) throws XNIException, IOException { + // + // reset and configure pipeline and set InputSource. + if (fInputSource != null) { + try { + fValidationManager.reset(); + fVersionDetector.reset(this); + reset(); + + short version = fVersionDetector.determineDocVersion(fInputSource); + // XML 1.0 + if (version == Constants.XML_VERSION_1_0) { + configurePipeline(); + resetXML10(); + } + // XML 1.1 + else if (version == Constants.XML_VERSION_1_1) { + initXML11Components(); + configureXML11Pipeline(); + resetXML11(); + } + // Unrecoverable error reported during version detection + else { + return false; + } + + // mark configuration as fixed + fConfigUpdated = false; + + // resets and sets the pipeline. + fVersionDetector.startDocumentParsing((XMLEntityHandler) fCurrentScanner, version); + fInputSource = null; + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + } + + try { + return fCurrentScanner.scanDocument(complete); + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + + } // parse(boolean):boolean + + /** + * If the application decides to terminate parsing before the xml document + * is fully parsed, the application should call this method to free any + * resource allocated during parsing. For example, close all opened streams. + */ + public void cleanup() { + fEntityManager.closeReaders(); + } + + // + // XMLParserConfiguration methods + // + + /** + * Parses the specified input source. + * + * @param source The input source. + * + * @exception XNIException Throws exception on XNI error. + * @exception java.io.IOException Throws exception on i/o error. + */ + public void parse(XMLInputSource source) throws XNIException, IOException { + + if (fParseInProgress) { + // REVISIT - need to add new error message + throw new XNIException("FWK005 parse may not be called while parsing."); + } + fParseInProgress = true; + + try { + setInputSource(source); + parse(true); + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + finally { + fParseInProgress = false; + // close all streams opened by xerces + this.cleanup(); + } + + } // parse(InputSource) + + // + // Protected methods + // + + /** + * Reset all components before parsing. + * + * @throws XNIException Thrown if an error occurs during initialization. + */ + public void reset() throws XNIException { + + // initialize the common components + super.reset(); + + } // reset() + + /** Configures the XML 1.0 pipeline. */ + protected void configurePipeline() { + + if (fCurrentDVFactory != fDatatypeValidatorFactory) { + fCurrentDVFactory = fDatatypeValidatorFactory; + // use XML 1.0 datatype library + setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); + } + + // setup document pipeline + if (fCurrentScanner != fNamespaceScanner) { + fCurrentScanner = fNamespaceScanner; + setProperty(DOCUMENT_SCANNER, fCurrentScanner); + } + fNamespaceScanner.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fNamespaceScanner); + } + fLastComponent = fNamespaceScanner; + + // setup dtd pipeline + if (fCurrentDTDScanner != fDTDScanner) { + fCurrentDTDScanner = fDTDScanner; + setProperty(DTD_SCANNER, fCurrentDTDScanner); + } + fDTDScanner.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fDTDScanner); + } + fDTDScanner.setDTDContentModelHandler(fDTDContentModelHandler); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.setDTDContentModelSource(fDTDScanner); + } + + } // configurePipeline() + + /** Configures the XML 1.1 pipeline. */ + protected void configureXML11Pipeline() { + + if (fCurrentDVFactory != fXML11DatatypeFactory) { + fCurrentDVFactory = fXML11DatatypeFactory; + // use XML 1.1 datatype library + setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); + } + + // setup document pipeline + if (fCurrentScanner != fXML11NSDocScanner) { + fCurrentScanner = fXML11NSDocScanner; + setProperty(DOCUMENT_SCANNER, fCurrentScanner); + } + fXML11NSDocScanner.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fXML11NSDocScanner); + } + fLastComponent = fXML11NSDocScanner; + + // setup dtd pipeline + if (fCurrentDTDScanner != fXML11DTDScanner) { + fCurrentDTDScanner = fXML11DTDScanner; + setProperty(DTD_SCANNER, fCurrentDTDScanner); + } + fXML11DTDScanner.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXML11DTDScanner); + } + fXML11DTDScanner.setDTDContentModelHandler(fDTDContentModelHandler); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.setDTDContentModelSource(fXML11DTDScanner); + } + + } // configureXML11Pipeline() + + // features and properties + + /** + * Check a feature. If feature is know and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) + throws XMLConfigurationException { + + // + // Xerces Features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/validation/dynamic + // Allows the parser to validate a document only when it + // contains a grammar. Validation is turned on/off based + // on each document instance, automatically. + // + if (suffixLength == Constants.DYNAMIC_VALIDATION_FEATURE.length() && + featureId.endsWith(Constants.DYNAMIC_VALIDATION_FEATURE)) { + return; + } + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE.length() && + featureId.endsWith(Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_CONTENT_MODELS_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_CONTENT_MODELS_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-dtd-grammar + // + if (suffixLength == Constants.LOAD_DTD_GRAMMAR_FEATURE.length() && + featureId.endsWith(Constants.LOAD_DTD_GRAMMAR_FEATURE)) { + return; + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-external-dtd + // + if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() && + featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_DATATYPES_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_DATATYPES_FEATURE)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + } + + // + // Not recognized + // + + super.checkFeature(featureId); + + } // checkFeature(String) + + /** + * Check a property. If the property is know and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkProperty(String propertyId) + throws XMLConfigurationException { + + // + // Xerces Properties + // + + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() && + propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) { + return; + } + } + + if (propertyId.startsWith(Constants.JAXP_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.JAXP_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SCHEMA_SOURCE.length() && + propertyId.endsWith(Constants.SCHEMA_SOURCE)) { + return; + } + } + + // + // Not recognized + // + + super.checkProperty(propertyId); + + } // checkProperty(String) + + /** + * Adds all of the component's recognized features and properties + * to the list of default recognized features and properties, and + * sets default values on the configuration for features and + * properties which were previously absent from the configuration. + * + * @param component The component whose recognized features + * and properties will be added to the configuration + */ + private void addRecognizedParamsAndSetDefaults(XMLComponent component) { + + // register component's recognized features + String[] recognizedFeatures = component.getRecognizedFeatures(); + addRecognizedFeatures(recognizedFeatures); + + // register component's recognized properties + String[] recognizedProperties = component.getRecognizedProperties(); + addRecognizedProperties(recognizedProperties); + + // set default values + if (recognizedFeatures != null) { + for (int i = 0; i < recognizedFeatures.length; ++i) { + String featureId = recognizedFeatures[i]; + Boolean state = component.getFeatureDefault(featureId); + if (state != null) { + // Do not overwrite values already set on the configuration. + if (!fFeatures.containsKey(featureId)) { + fFeatures.put(featureId, state); + // For newly added components who recognize this feature + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + if (recognizedProperties != null) { + for (int i = 0; i < recognizedProperties.length; ++i) { + String propertyId = recognizedProperties[i]; + Object value = component.getPropertyDefault(propertyId); + if (value != null) { + // Do not overwrite values already set on the configuration. + if (!fProperties.containsKey(propertyId)) { + fProperties.put(propertyId, value); + // For newly added components who recognize this property + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + } + + /** + * Reset all XML 1.0 components before parsing + */ + protected final void resetXML10() throws XNIException { + // Reset XML 1.0 components + fNamespaceScanner.reset(this); + fDTDScanner.reset(this); + } // resetXML10() + + /** + * Reset all XML 1.1 components before parsing + */ + protected final void resetXML11() throws XNIException { + // Reset XML 1.1 components + fXML11NSDocScanner.reset(this); + fXML11DTDScanner.reset(this); + } // resetXML11() + + // + // other methods + // + + /** */ + public void resetNodePool() { + // REVISIT: to implement: introduce a node pool to reuse DTM nodes. + // reset this pool here. + } + + private void initXML11Components() { + if (!f11Initialized) { + // create datatype factory + fXML11DatatypeFactory = DTDDVFactory.getInstance(XML11_DATATYPE_VALIDATOR_FACTORY); + + // setup XML 1.1 DTD pipeline + fXML11DTDScanner = new XML11DTDScannerImpl(); + addRecognizedParamsAndSetDefaults(fXML11DTDScanner); + + // setup XML 1.1. document pipeline - namespace aware + fXML11NSDocScanner = new XML11NSDocumentScannerImpl(); + addRecognizedParamsAndSetDefaults(fXML11NSDocScanner); + + f11Initialized = true; + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/TextImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/TextImpl.java new file mode 100644 index 0000000..f692bae --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/opti/TextImpl.java @@ -0,0 +1,132 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.opti; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ + +public class TextImpl extends DefaultText { + + // Data + String fData = null; + SchemaDOM fSchemaDOM = null; + int fRow; + int fCol; + + public TextImpl(StringBuffer str, SchemaDOM sDOM, int row, int col) { + fData = str.toString(); + fSchemaDOM = sDOM; + fRow = row; + fCol = col; + rawname = prefix = localpart = uri = null; + nodeType = Node.TEXT_NODE; + } + + // + // org.w3c.dom.Node methods + // + + public String getNodeName() { + return "#text"; + } + + public Node getParentNode() { + return fSchemaDOM.relations[fRow][0]; + } + + public Node getPreviousSibling() { + if (fCol == 1) { + return null; + } + return fSchemaDOM.relations[fRow][fCol-1]; + } + + + public Node getNextSibling() { + if (fCol == fSchemaDOM.relations[fRow].length-1) { + return null; + } + return fSchemaDOM.relations[fRow][fCol+1]; + } + + // CharacterData methods + + /** + * The character data of the node that implements this interface. The DOM + * implementation may not put arbitrary limits on the amount of data + * that may be stored in a CharacterData node. However, + * implementation limits may mean that the entirety of a node's data may + * not fit into a single DOMString. In such cases, the user + * may call substringData to retrieve the data in + * appropriately sized pieces. + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. + * @exception DOMException + * DOMSTRING_SIZE_ERR: Raised when it would return more characters than + * fit in a DOMString variable on the implementation + * platform. + */ + public String getData() + throws DOMException { + return fData; + } + + /** + * The number of 16-bit units that are available through data + * and the substringData method below. This may have the + * value zero, i.e., CharacterData nodes may be empty. + */ + public int getLength() { + if(fData == null) return 0; + return fData.length(); + } + + /** + * Extracts a range of data from the node. + * @param offset Start offset of substring to extract. + * @param count The number of 16-bit units to extract. + * @return The specified substring. If the sum of offset and + * count exceeds the length, then all 16-bit + * units to the end of the data are returned. + * @exception 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. + *
DOMSTRING_SIZE_ERR: Raised if the specified range of text does + * not fit into a DOMString. + */ + public String substringData(int offset, + int count) + throws DOMException { + if(fData == null) return null; + if(count < 0 || offset < 0 || offset > fData.length()) + throw new DOMException(DOMException.INDEX_SIZE_ERR, "parameter error"); + if(offset+count >= fData.length()) + return fData.substring(offset); + return fData.substring(offset, offset+count); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/SchemaContentHandler.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/SchemaContentHandler.java new file mode 100644 index 0000000..4ef9b96 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/SchemaContentHandler.java @@ -0,0 +1,388 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.opti.SchemaDOMParser; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SAXLocatorWrapper; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLParseException; +import org.w3c.dom.Document; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.LocatorImpl; + +/** + *

SchemaContentHandler converts SAX events into XNI + * and passes them directly to the SchemaDOMParser.

+ * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * @author Jack Z. Wang, IBM + * + * @version $Id$ + */ +final class SchemaContentHandler implements ContentHandler { + + /** Symbol table **/ + private SymbolTable fSymbolTable; + + /** SchemaDOMParser, events will be delegated to SchemaDOMParser to pass */ + private SchemaDOMParser fSchemaDOMParser; + + /** XML Locator wrapper for SAX. **/ + private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper(); + + /** The namespace context of this document: stores namespaces in scope */ + private NamespaceSupport fNamespaceContext = new NamespaceSupport(); + + /** Indicate if push NamespaceContest is needed */ + private boolean fNeedPushNSContext; + + /** Flag used to track whether namespace declarations are reported as attributes. */ + private boolean fNamespacePrefixes = false; + + /** Flag used to track whether XML names and Namespace URIs have been internalized. */ + private boolean fStringsInternalized = false; + + /** Fields for start element, end element and characters. */ + private final QName fElementQName = new QName(); + private final QName fAttributeQName = new QName(); + private final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); + private final XMLString fTempString = new XMLString(); + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + + /** + *

Constructs an SchemaContentHandler.

+ */ + public SchemaContentHandler() {} + + /* + * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator) + */ + public Document getDocument() { + return fSchemaDOMParser.getDocument(); + } + + /* + * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator) + */ + public void setDocumentLocator(Locator locator) { + fSAXLocatorWrapper.setLocator(locator); + } + + /* + * @see org.xml.sax.ContentHandler#startDocument() + */ + public void startDocument() throws SAXException { + fNeedPushNSContext = true; + fNamespaceContext.reset(); + try { + fSchemaDOMParser.startDocument(fSAXLocatorWrapper, null, fNamespaceContext, null); + } + catch (XMLParseException e) { + convertToSAXParseException(e); + } + catch (XNIException e) { + convertToSAXException(e); + } + } + + /* + * @see org.xml.sax.ContentHandler#endDocument() + */ + public void endDocument() throws SAXException { + fSAXLocatorWrapper.setLocator(null); + try { + fSchemaDOMParser.endDocument(null); + } + catch (XMLParseException e) { + convertToSAXParseException(e); + } + catch (XNIException e) { + convertToSAXException(e); + } + } + + /* + * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String) + */ + public void startPrefixMapping(String prefix, String uri) throws SAXException { + if (fNeedPushNSContext) { + fNeedPushNSContext = false; + fNamespaceContext.pushContext(); + } + if (!fStringsInternalized) { + prefix = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING; + uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; + } + else { + if (prefix == null) { + prefix = XMLSymbols.EMPTY_STRING; + } + if (uri != null && uri.length() == 0) { + uri = null; + } + } + fNamespaceContext.declarePrefix(prefix, uri); + } + + /* + * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String) + */ + public void endPrefixMapping(String prefix) throws SAXException { + // do nothing + } + + /* + * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) + */ + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + if (fNeedPushNSContext) { + fNamespaceContext.pushContext(); + } + fNeedPushNSContext = true; + + // Fill element QName and XMLAttributes + fillQName(fElementQName, uri, localName, qName); + fillXMLAttributes(atts); + + // Add namespace declarations if necessary + if (!fNamespacePrefixes) { + final int prefixCount = fNamespaceContext.getDeclaredPrefixCount(); + if (prefixCount > 0) { + addNamespaceDeclarations(prefixCount); + } + } + + try { + fSchemaDOMParser.startElement(fElementQName, fAttributes, null); + } + catch (XMLParseException e) { + convertToSAXParseException(e); + } + catch (XNIException e) { + convertToSAXException(e); + } + } + + /* + * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String) + */ + public void endElement(String uri, String localName, String qName) throws SAXException { + fillQName(fElementQName, uri, localName, qName); + try { + fSchemaDOMParser.endElement(fElementQName, null); + } + catch (XMLParseException e) { + convertToSAXParseException(e); + } + catch (XNIException e) { + convertToSAXException(e); + } + finally { + fNamespaceContext.popContext(); + } + } + + /* + * @see org.xml.sax.ContentHandler#characters(char[], int, int) + */ + public void characters(char[] ch, int start, int length) throws SAXException { + try { + fTempString.setValues(ch, start, length); + fSchemaDOMParser.characters(fTempString, null); + } + catch (XMLParseException e) { + convertToSAXParseException(e); + } + catch (XNIException e) { + convertToSAXException(e); + } + } + + /* + * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int) + */ + public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { + try { + fTempString.setValues(ch, start, length); + fSchemaDOMParser.ignorableWhitespace(fTempString, null); + } + catch (XMLParseException e) { + convertToSAXParseException(e); + } + catch (XNIException e) { + convertToSAXException(e); + } + } + + /* + * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String) + */ + public void processingInstruction(String target, String data) throws SAXException { + try { + fTempString.setValues(data.toCharArray(), 0, data.length()); + fSchemaDOMParser.processingInstruction(target, fTempString, null); + } + catch (XMLParseException e) { + convertToSAXParseException(e); + } + catch (XNIException e) { + convertToSAXException(e); + } + } + + /* + * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String) + */ + public void skippedEntity(String arg) throws SAXException { + // do-nothing + } + + /* + * Other methods + */ + + private void fillQName(QName toFill, String uri, String localpart, String rawname) { + if (!fStringsInternalized) { + uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; + localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING; + rawname = (rawname != null) ? fSymbolTable.addSymbol(rawname) : XMLSymbols.EMPTY_STRING; + } + else { + if (uri != null && uri.length() == 0) { + uri = null; + } + if (localpart == null) { + localpart = XMLSymbols.EMPTY_STRING; + } + if (rawname == null) { + rawname = XMLSymbols.EMPTY_STRING; + } + } + String prefix = XMLSymbols.EMPTY_STRING; + int prefixIdx = rawname.indexOf(':'); + if (prefixIdx != -1) { + prefix = fSymbolTable.addSymbol(rawname.substring(0, prefixIdx)); + // local part may be an empty string if this is a namespace declaration + if (localpart == XMLSymbols.EMPTY_STRING) { + localpart = fSymbolTable.addSymbol(rawname.substring(prefixIdx + 1)); + } + } + // local part may be an empty string if this is a namespace declaration + else if (localpart == XMLSymbols.EMPTY_STRING) { + localpart = rawname; + } + toFill.setValues(prefix, localpart, rawname, uri); + } + + private void fillXMLAttributes(Attributes atts) { + fAttributes.removeAllAttributes(); + final int attrCount = atts.getLength(); + for (int i = 0; i < attrCount; ++i) { + fillQName(fAttributeQName, atts.getURI(i), atts.getLocalName(i), atts.getQName(i)); + String type = atts.getType(i); + fAttributes.addAttributeNS(fAttributeQName, (type != null) ? type : XMLSymbols.fCDATASymbol, atts.getValue(i)); + fAttributes.setSpecified(i, true); + } + } + + private void addNamespaceDeclarations(final int prefixCount) { + String prefix = null; + String localpart = null; + String rawname = null; + String nsPrefix = null; + String nsURI = null; + for (int i = 0; i < prefixCount; ++i) { + nsPrefix = fNamespaceContext.getDeclaredPrefixAt(i); + nsURI = fNamespaceContext.getURI(nsPrefix); + if (nsPrefix.length() > 0) { + prefix = XMLSymbols.PREFIX_XMLNS; + localpart = nsPrefix; + fStringBuffer.clear(); + fStringBuffer.append(prefix); + fStringBuffer.append(':'); + fStringBuffer.append(localpart); + rawname = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); + } + else { + prefix = XMLSymbols.EMPTY_STRING; + localpart = XMLSymbols.PREFIX_XMLNS; + rawname = XMLSymbols.PREFIX_XMLNS; + } + fAttributeQName.setValues(prefix, localpart, rawname, NamespaceContext.XMLNS_URI); + fAttributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, + (nsURI != null) ? nsURI : XMLSymbols.EMPTY_STRING); + } + } + + public void reset(SchemaDOMParser schemaDOMParser, SymbolTable symbolTable, + boolean namespacePrefixes, boolean stringsInternalized) { + fSchemaDOMParser = schemaDOMParser; + fSymbolTable = symbolTable; + fNamespacePrefixes = namespacePrefixes; + fStringsInternalized = stringsInternalized; + } + + /* + * Static methods + */ + + static void convertToSAXParseException(XMLParseException e) throws SAXException { + Exception ex = e.getException(); + if (ex == null) { + // must be a parser exception; mine it for locator info and throw + // a SAXParseException + LocatorImpl locatorImpl = new LocatorImpl(); + locatorImpl.setPublicId(e.getPublicId()); + locatorImpl.setSystemId(e.getExpandedSystemId()); + locatorImpl.setLineNumber(e.getLineNumber()); + locatorImpl.setColumnNumber(e.getColumnNumber()); + throw new SAXParseException(e.getMessage(), locatorImpl); + } + if (ex instanceof SAXException) { + // why did we create an XMLParseException? + throw (SAXException) ex; + } + throw new SAXException(ex); + } + + static void convertToSAXException(XNIException e) throws SAXException { + Exception ex = e.getException(); + if (ex == null) { + throw new SAXException(e.getMessage()); + } + if (ex instanceof SAXException) { + throw (SAXException) ex; + } + throw new SAXException(ex); + } + +} // SchemaContentHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/StAXSchemaParser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/StAXSchemaParser.java new file mode 100644 index 0000000..ef4f7a3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/StAXSchemaParser.java @@ -0,0 +1,421 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import java.util.ArrayList; +import java.util.Iterator; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +import org.apache.xerces.impl.xs.opti.SchemaDOMParser; +import org.apache.xerces.util.JAXPNamespaceContextWrapper; +import org.apache.xerces.util.StAXLocationWrapper; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.w3c.dom.Document; + +/** + *

StAXSchemaParser reads StAX events, converts them into XNI events + * and passes them directly to the SchemaDOMParser.

+ * + * @xerces.internal + * + * @version $Id$ + */ +final class StAXSchemaParser { + + /** Chunk size (1024). */ + private static final int CHUNK_SIZE = (1 << 10); + + /** Chunk mask (CHUNK_SIZE - 1). */ + private static final int CHUNK_MASK = CHUNK_SIZE - 1; + + /** Array for holding character data. **/ + private final char [] fCharBuffer = new char[CHUNK_SIZE]; + + /** Symbol table **/ + private SymbolTable fSymbolTable = new SymbolTable(); + + /** SchemaDOMParser, events will be delegated to SchemaDOMParser to pass */ + private SchemaDOMParser fSchemaDOMParser; + + /** XML Locator wrapper for SAX. **/ + private final StAXLocationWrapper fLocationWrapper = new StAXLocationWrapper(); + + /** The namespace context of this document: stores namespaces in scope */ + private final JAXPNamespaceContextWrapper fNamespaceContext = new JAXPNamespaceContextWrapper(fSymbolTable); + + /** Fields for start element, end element and characters. */ + private final QName fElementQName = new QName(); + private final QName fAttributeQName = new QName(); + private final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); + private final XMLString fTempString = new XMLString(); + private final ArrayList fDeclaredPrefixes = new ArrayList(); + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + private int fDepth; + + public StAXSchemaParser() { + fNamespaceContext.setDeclaredPrefixes(fDeclaredPrefixes); + } + + public void reset(SchemaDOMParser schemaDOMParser, SymbolTable symbolTable) { + fSchemaDOMParser = schemaDOMParser; + fSymbolTable = symbolTable; + fNamespaceContext.setSymbolTable(fSymbolTable); + fNamespaceContext.reset(); + } + + public Document getDocument() { + return fSchemaDOMParser.getDocument(); + } + + public void parse(XMLEventReader input) throws XMLStreamException, XNIException { + XMLEvent currentEvent = input.peek(); + if (currentEvent != null) { + int eventType = currentEvent.getEventType(); + if (eventType != XMLStreamConstants.START_DOCUMENT && + eventType != XMLStreamConstants.START_ELEMENT) { + throw new XMLStreamException(); + } + fLocationWrapper.setLocation(currentEvent.getLocation()); + fSchemaDOMParser.startDocument(fLocationWrapper, null, fNamespaceContext, null); + loop: while (input.hasNext()) { + currentEvent = input.nextEvent(); + eventType = currentEvent.getEventType(); + switch (eventType) { + case XMLStreamConstants.START_ELEMENT: + ++fDepth; + StartElement start = currentEvent.asStartElement(); + fillQName(fElementQName, start.getName()); + fLocationWrapper.setLocation(start.getLocation()); + fNamespaceContext.setNamespaceContext(start.getNamespaceContext()); + fillXMLAttributes(start); + fillDeclaredPrefixes(start); + addNamespaceDeclarations(); + fNamespaceContext.pushContext(); + fSchemaDOMParser.startElement(fElementQName, fAttributes, null); + break; + case XMLStreamConstants.END_ELEMENT: + EndElement end = currentEvent.asEndElement(); + fillQName(fElementQName, end.getName()); + fillDeclaredPrefixes(end); + fLocationWrapper.setLocation(end.getLocation()); + fSchemaDOMParser.endElement(fElementQName, null); + fNamespaceContext.popContext(); + --fDepth; + if (fDepth <= 0) { + break loop; + } + break; + case XMLStreamConstants.CHARACTERS: + sendCharactersToSchemaParser(currentEvent.asCharacters().getData(), false); + break; + case XMLStreamConstants.SPACE: + sendCharactersToSchemaParser(currentEvent.asCharacters().getData(), true); + break; + case XMLStreamConstants.CDATA: + fSchemaDOMParser.startCDATA(null); + sendCharactersToSchemaParser(currentEvent.asCharacters().getData(), false); + fSchemaDOMParser.endCDATA(null); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + ProcessingInstruction pi = (ProcessingInstruction)currentEvent; + fillProcessingInstruction(pi.getData()); + fSchemaDOMParser.processingInstruction(pi.getTarget(), fTempString, null); + break; + case XMLStreamConstants.DTD: + /* There shouldn't be a DTD in the schema */ + break; + case XMLStreamConstants.ENTITY_REFERENCE: + /* Not needed for schemas */ + break; + case XMLStreamConstants.COMMENT: + /* No point in sending comments */ + break; + case XMLStreamConstants.START_DOCUMENT: + fDepth++; + /* We automatically call startDocument before the loop */ + break; + case XMLStreamConstants.END_DOCUMENT: + /* We automatically call endDocument after the loop */ + break; + } + } + fLocationWrapper.setLocation(null); + fNamespaceContext.setNamespaceContext(null); + fSchemaDOMParser.endDocument(null); + } + } + + public void parse(XMLStreamReader input) throws XMLStreamException, XNIException { + if (input.hasNext()) { + int eventType = input.getEventType(); + if (eventType != XMLStreamConstants.START_DOCUMENT && + eventType != XMLStreamConstants.START_ELEMENT) { + throw new XMLStreamException(); + } + fLocationWrapper.setLocation(input.getLocation()); + fSchemaDOMParser.startDocument(fLocationWrapper, null, fNamespaceContext, null); + boolean first = true; + loop: while (input.hasNext()) { + if (!first) { + eventType = input.next(); + } + else { + first = false; + } + switch (eventType) { + case XMLStreamConstants.START_ELEMENT: + ++fDepth; + fLocationWrapper.setLocation(input.getLocation()); + fNamespaceContext.setNamespaceContext(input.getNamespaceContext()); + fillQName(fElementQName, input.getNamespaceURI(), + input.getLocalName(), input.getPrefix()); + fillXMLAttributes(input); + fillDeclaredPrefixes(input); + addNamespaceDeclarations(); + fNamespaceContext.pushContext(); + fSchemaDOMParser.startElement(fElementQName, fAttributes, null); + break; + case XMLStreamConstants.END_ELEMENT: + fLocationWrapper.setLocation(input.getLocation()); + fNamespaceContext.setNamespaceContext(input.getNamespaceContext()); + fillQName(fElementQName, input.getNamespaceURI(), + input.getLocalName(), input.getPrefix()); + fillDeclaredPrefixes(input); + fSchemaDOMParser.endElement(fElementQName, null); + fNamespaceContext.popContext(); + --fDepth; + if (fDepth <= 0) { + break loop; + } + break; + case XMLStreamConstants.CHARACTERS: + fTempString.setValues(input.getTextCharacters(), + input.getTextStart(), input.getTextLength()); + fSchemaDOMParser.characters(fTempString, null); + break; + case XMLStreamConstants.SPACE: + fTempString.setValues(input.getTextCharacters(), + input.getTextStart(), input.getTextLength()); + fSchemaDOMParser.ignorableWhitespace(fTempString, null); + break; + case XMLStreamConstants.CDATA: + fSchemaDOMParser.startCDATA(null); + fTempString.setValues(input.getTextCharacters(), + input.getTextStart(), input.getTextLength()); + fSchemaDOMParser.characters(fTempString, null); + fSchemaDOMParser.endCDATA(null); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + fillProcessingInstruction(input.getPIData()); + fSchemaDOMParser.processingInstruction(input.getPITarget(), fTempString, null); + break; + case XMLStreamConstants.DTD: + /* There shouldn't be a DTD in the schema */ + break; + case XMLStreamConstants.ENTITY_REFERENCE: + /* Not needed for schemas */ + break; + case XMLStreamConstants.COMMENT: + /* No point in sending comments */ + break; + case XMLStreamConstants.START_DOCUMENT: + ++fDepth; + /* We automatically call startDocument before the loop */ + break; + case XMLStreamConstants.END_DOCUMENT: + /* We automatically call endDocument after the loop */ + break; + } + } + fLocationWrapper.setLocation(null); + fNamespaceContext.setNamespaceContext(null); + fSchemaDOMParser.endDocument(null); + } + } + + /** Send characters to the validator in CHUNK_SIZE character chunks. */ + private void sendCharactersToSchemaParser(String str, boolean whitespace) { + if (str != null) { + final int length = str.length(); + final int remainder = length & CHUNK_MASK; + if (remainder > 0) { + str.getChars(0, remainder, fCharBuffer, 0); + fTempString.setValues(fCharBuffer, 0, remainder); + if (whitespace) { + fSchemaDOMParser.ignorableWhitespace(fTempString, null); + } + else { + fSchemaDOMParser.characters(fTempString, null); + } + } + int i = remainder; + while (i < length) { + str.getChars(i, i += CHUNK_SIZE, fCharBuffer, 0); + fTempString.setValues(fCharBuffer, 0, CHUNK_SIZE); + if (whitespace) { + fSchemaDOMParser.ignorableWhitespace(fTempString, null); + } + else { + fSchemaDOMParser.characters(fTempString, null); + } + } + } + } + + // processing instructions must be sent all in one chunk + private void fillProcessingInstruction(String data) { + final int dataLength = data.length(); + char [] charBuffer = fCharBuffer; + if (charBuffer.length < dataLength) { + // toCharArray() creates a newly allocated array, so it's okay + // to keep a reference to it. + charBuffer = data.toCharArray(); + } + else { + data.getChars(0, dataLength, charBuffer, 0); + } + fTempString.setValues(charBuffer, 0, dataLength); + } + + private void fillXMLAttributes(StartElement event) { + fAttributes.removeAllAttributes(); + final Iterator attrs = event.getAttributes(); + while (attrs.hasNext()) { + Attribute attr = (Attribute) attrs.next(); + fillQName(fAttributeQName, attr.getName()); + String type = attr.getDTDType(); + int idx = fAttributes.getLength(); + fAttributes.addAttributeNS(fAttributeQName, + (type != null) ? type : XMLSymbols.fCDATASymbol, attr.getValue()); + fAttributes.setSpecified(idx, attr.isSpecified()); + } + } + + private void fillXMLAttributes(XMLStreamReader input) { + fAttributes.removeAllAttributes(); + final int len = input.getAttributeCount(); + for (int i = 0; i < len; ++i) { + fillQName(fAttributeQName, input.getAttributeNamespace(i), + input.getAttributeLocalName(i), input.getAttributePrefix(i)); + String type = input.getAttributeType(i); + fAttributes.addAttributeNS(fAttributeQName, + (type != null) ? type : XMLSymbols.fCDATASymbol, input.getAttributeValue(i)); + fAttributes.setSpecified(i, input.isAttributeSpecified(i)); + } + } + + private void addNamespaceDeclarations() { + String prefix = null; + String localpart = null; + String rawname = null; + String nsPrefix = null; + String nsURI = null; + + final Iterator iter = fDeclaredPrefixes.iterator(); + while (iter.hasNext()) { + nsPrefix = (String) iter.next(); + nsURI = fNamespaceContext.getURI(nsPrefix); + if (nsPrefix.length() > 0) { + prefix = XMLSymbols.PREFIX_XMLNS; + localpart = nsPrefix; + fStringBuffer.clear(); + fStringBuffer.append(prefix); + fStringBuffer.append(':'); + fStringBuffer.append(localpart); + rawname = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); + } + else { + prefix = XMLSymbols.EMPTY_STRING; + localpart = XMLSymbols.PREFIX_XMLNS; + rawname = XMLSymbols.PREFIX_XMLNS; + } + fAttributeQName.setValues(prefix, localpart, rawname, NamespaceContext.XMLNS_URI); + fAttributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, + (nsURI != null) ? nsURI : XMLSymbols.EMPTY_STRING); + } + } + + /** Fills in the list of declared prefixes. */ + private void fillDeclaredPrefixes(StartElement event) { + fillDeclaredPrefixes(event.getNamespaces()); + } + + /** Fills in the list of declared prefixes. */ + private void fillDeclaredPrefixes(EndElement event) { + fillDeclaredPrefixes(event.getNamespaces()); + } + + /** Fills in the list of declared prefixes. */ + private void fillDeclaredPrefixes(Iterator namespaces) { + fDeclaredPrefixes.clear(); + while (namespaces.hasNext()) { + Namespace ns = (Namespace) namespaces.next(); + String prefix = ns.getPrefix(); + fDeclaredPrefixes.add(prefix != null ? prefix : ""); + } + } + + /** Fills in the list of declared prefixes. */ + private void fillDeclaredPrefixes(XMLStreamReader reader) { + fDeclaredPrefixes.clear(); + final int len = reader.getNamespaceCount(); + for (int i = 0; i < len; ++i) { + String prefix = reader.getNamespacePrefix(i); + fDeclaredPrefixes.add(prefix != null ? prefix : ""); + } + } + + /** Fills in a QName object. */ + private void fillQName(QName toFill, javax.xml.namespace.QName toCopy) { + fillQName(toFill, toCopy.getNamespaceURI(), toCopy.getLocalPart(), toCopy.getPrefix()); + } + + /** Fills in a QName object. */ + final void fillQName(QName toFill, String uri, String localpart, String prefix) { + uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; + localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING; + prefix = (prefix != null && prefix.length() > 0) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING; + String raw = localpart; + if (prefix != XMLSymbols.EMPTY_STRING) { + fStringBuffer.clear(); + fStringBuffer.append(prefix); + fStringBuffer.append(':'); + fStringBuffer.append(localpart); + raw = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); + } + toFill.setValues(prefix, localpart, raw, uri); + } + +} // StAXSchemaParser diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSAnnotationInfo.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSAnnotationInfo.java new file mode 100644 index 0000000..8e2d8b7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSAnnotationInfo.java @@ -0,0 +1,70 @@ +/* + * 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. + */ +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.opti.ElementImpl; +import org.w3c.dom.Element; + +/** + * Objects of this class contain the textual representation of + * an XML schema annotation as well as information on the location + * of the annotation in the document it originated from. + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class XSAnnotationInfo { + + /** Textual representation of annotation. **/ + String fAnnotation; + + /** Line number of <annotation> element. **/ + int fLine; + + /** Column number of <annotation> element. **/ + int fColumn; + + /** Character offset of <annotation> element. **/ + int fCharOffset; + + /** Next annotation. **/ + XSAnnotationInfo next; + + XSAnnotationInfo(String annotation, int line, int column, int charOffset) { + fAnnotation = annotation; + fLine = line; + fColumn = column; + fCharOffset = charOffset; + } + + XSAnnotationInfo(String annotation, Element annotationDecl) { + fAnnotation = annotation; + if (annotationDecl instanceof ElementImpl) { + final ElementImpl annotationDeclImpl = (ElementImpl) annotationDecl; + fLine = annotationDeclImpl.getLineNumber(); + fColumn = annotationDeclImpl.getColumnNumber(); + fCharOffset = annotationDeclImpl.getCharacterOffset(); + } + else { + fLine = -1; + fColumn = -1; + fCharOffset = -1; + } + } +} // XSAnnotationInfo diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSAttributeChecker.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSAttributeChecker.java new file mode 100644 index 0000000..0cab232 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSAttributeChecker.java @@ -0,0 +1,1785 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaNamespaceSupport; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAttributeDecl; +import org.apache.xerces.impl.xs.XSGrammarBucket; +import org.apache.xerces.impl.xs.XSWildcardDecl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XIntPool; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSConstants; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + +/** + * Class XSAttributeCheck is used to check the validity of attributes + * appearing in the schema document. It + * - reports an error for invalid element (invalid namespace, invalid name) + * - reports an error for invalid attribute (invalid namespace, invalid name) + * - reports an error for invalid attribute value + * - return compiled values for attriute values + * - provide default value for missing optional attributes + * - provide default value for incorrect attribute values + * + * But it's the caller's responsibility to check whether a required attribute + * is present. + * + * Things need revisiting: + * - Whether to return non-schema attributes/values + * - Do we need to update NamespaceScope and ErrorReporter when reset()? + * - Should have the datatype validators return compiled value + * - use symbol table instead of many hashtables + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @version $Id$ + */ + +public class XSAttributeChecker { + + // REVISIT: only local element and attribute are different from others. + // it's possible to have either name or ref. all the others + // are only allowed to have one of name or ref, or neither of them. + // we'd better move such checking to the traverser. + private static final String ELEMENT_N = "element_n"; + private static final String ELEMENT_R = "element_r"; + private static final String ATTRIBUTE_N = "attribute_n"; + private static final String ATTRIBUTE_R = "attribute_r"; + + private static int ATTIDX_COUNT = 0; + public static final int ATTIDX_ABSTRACT = ATTIDX_COUNT++; + public static final int ATTIDX_AFORMDEFAULT = ATTIDX_COUNT++; + public static final int ATTIDX_BASE = ATTIDX_COUNT++; + public static final int ATTIDX_BLOCK = ATTIDX_COUNT++; + public static final int ATTIDX_BLOCKDEFAULT = ATTIDX_COUNT++; + public static final int ATTIDX_DEFAULT = ATTIDX_COUNT++; + public static final int ATTIDX_EFORMDEFAULT = ATTIDX_COUNT++; + public static final int ATTIDX_FINAL = ATTIDX_COUNT++; + public static final int ATTIDX_FINALDEFAULT = ATTIDX_COUNT++; + public static final int ATTIDX_FIXED = ATTIDX_COUNT++; + public static final int ATTIDX_FORM = ATTIDX_COUNT++; + public static final int ATTIDX_ID = ATTIDX_COUNT++; + public static final int ATTIDX_ITEMTYPE = ATTIDX_COUNT++; + public static final int ATTIDX_MAXOCCURS = ATTIDX_COUNT++; + public static final int ATTIDX_MEMBERTYPES = ATTIDX_COUNT++; + public static final int ATTIDX_MINOCCURS = ATTIDX_COUNT++; + public static final int ATTIDX_MIXED = ATTIDX_COUNT++; + public static final int ATTIDX_NAME = ATTIDX_COUNT++; + public static final int ATTIDX_NAMESPACE = ATTIDX_COUNT++; + public static final int ATTIDX_NAMESPACE_LIST = ATTIDX_COUNT++; + public static final int ATTIDX_NILLABLE = ATTIDX_COUNT++; + public static final int ATTIDX_NONSCHEMA = ATTIDX_COUNT++; + public static final int ATTIDX_PROCESSCONTENTS = ATTIDX_COUNT++; + public static final int ATTIDX_PUBLIC = ATTIDX_COUNT++; + public static final int ATTIDX_REF = ATTIDX_COUNT++; + public static final int ATTIDX_REFER = ATTIDX_COUNT++; + public static final int ATTIDX_SCHEMALOCATION = ATTIDX_COUNT++; + public static final int ATTIDX_SOURCE = ATTIDX_COUNT++; + public static final int ATTIDX_SUBSGROUP = ATTIDX_COUNT++; + public static final int ATTIDX_SYSTEM = ATTIDX_COUNT++; + public static final int ATTIDX_TARGETNAMESPACE = ATTIDX_COUNT++; + public static final int ATTIDX_TYPE = ATTIDX_COUNT++; + public static final int ATTIDX_USE = ATTIDX_COUNT++; + public static final int ATTIDX_VALUE = ATTIDX_COUNT++; + public static final int ATTIDX_ENUMNSDECLS = ATTIDX_COUNT++; + public static final int ATTIDX_VERSION = ATTIDX_COUNT++; + public static final int ATTIDX_XML_LANG = ATTIDX_COUNT++; + public static final int ATTIDX_XPATH = ATTIDX_COUNT++; + public static final int ATTIDX_FROMDEFAULT = ATTIDX_COUNT++; + //public static final int ATTIDX_OTHERVALUES = ATTIDX_COUNT++; + public static final int ATTIDX_ISRETURNED = ATTIDX_COUNT++; + + private static final XIntPool fXIntPool = new XIntPool(); + // constants to return + private static final XInt INT_QUALIFIED = fXIntPool.getXInt(SchemaSymbols.FORM_QUALIFIED); + private static final XInt INT_UNQUALIFIED = fXIntPool.getXInt(SchemaSymbols.FORM_UNQUALIFIED); + private static final XInt INT_EMPTY_SET = fXIntPool.getXInt(XSConstants.DERIVATION_NONE); + private static final XInt INT_ANY_STRICT = fXIntPool.getXInt(XSWildcardDecl.PC_STRICT); + private static final XInt INT_ANY_LAX = fXIntPool.getXInt(XSWildcardDecl.PC_LAX); + private static final XInt INT_ANY_SKIP = fXIntPool.getXInt(XSWildcardDecl.PC_SKIP); + private static final XInt INT_ANY_ANY = fXIntPool.getXInt(XSWildcardDecl.NSCONSTRAINT_ANY); + private static final XInt INT_ANY_LIST = fXIntPool.getXInt(XSWildcardDecl.NSCONSTRAINT_LIST); + private static final XInt INT_ANY_NOT = fXIntPool.getXInt(XSWildcardDecl.NSCONSTRAINT_NOT); + private static final XInt INT_USE_OPTIONAL = fXIntPool.getXInt(SchemaSymbols.USE_OPTIONAL); + private static final XInt INT_USE_REQUIRED = fXIntPool.getXInt(SchemaSymbols.USE_REQUIRED); + private static final XInt INT_USE_PROHIBITED = fXIntPool.getXInt(SchemaSymbols.USE_PROHIBITED); + private static final XInt INT_WS_PRESERVE = fXIntPool.getXInt(XSSimpleType.WS_PRESERVE); + private static final XInt INT_WS_REPLACE = fXIntPool.getXInt(XSSimpleType.WS_REPLACE); + private static final XInt INT_WS_COLLAPSE = fXIntPool.getXInt(XSSimpleType.WS_COLLAPSE); + private static final XInt INT_UNBOUNDED = fXIntPool.getXInt(SchemaSymbols.OCCURRENCE_UNBOUNDED); + + // used to store the map from element name to attribute list + // for 14 global elements + private static final Hashtable fEleAttrsMapG = new Hashtable(29); + // for 39 local elememnts + private static final Hashtable fEleAttrsMapL = new Hashtable(79); + + // used to initialize fEleAttrsMap + // step 1: all possible data types + // DT_??? >= 0 : validate using a validator, which is initialized staticly + // DT_??? < 0 : validate directly, which is done in "validate()" + + protected static final int DT_ANYURI = 0; + protected static final int DT_ID = 1; + protected static final int DT_QNAME = 2; + protected static final int DT_STRING = 3; + protected static final int DT_TOKEN = 4; + protected static final int DT_NCNAME = 5; + protected static final int DT_XPATH = 6; + protected static final int DT_XPATH1 = 7; + protected static final int DT_LANGUAGE = 8; + + // used to store extra datatype validators + protected static final int DT_COUNT = DT_LANGUAGE + 1; + private static final XSSimpleType[] fExtraDVs = new XSSimpleType[DT_COUNT]; + static { + // step 5: register all datatype validators for new types + SchemaGrammar grammar = SchemaGrammar.SG_SchemaNS; + // anyURI + fExtraDVs[DT_ANYURI] = (XSSimpleType)grammar.getGlobalTypeDecl(SchemaSymbols.ATTVAL_ANYURI); + // ID + fExtraDVs[DT_ID] = (XSSimpleType)grammar.getGlobalTypeDecl(SchemaSymbols.ATTVAL_ID); + // QName + fExtraDVs[DT_QNAME] = (XSSimpleType)grammar.getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME); + // string + fExtraDVs[DT_STRING] = (XSSimpleType)grammar.getGlobalTypeDecl(SchemaSymbols.ATTVAL_STRING); + // token + fExtraDVs[DT_TOKEN] = (XSSimpleType)grammar.getGlobalTypeDecl(SchemaSymbols.ATTVAL_TOKEN); + // NCName + fExtraDVs[DT_NCNAME] = (XSSimpleType)grammar.getGlobalTypeDecl(SchemaSymbols.ATTVAL_NCNAME); + // xpath = a subset of XPath expression + fExtraDVs[DT_XPATH] = fExtraDVs[DT_STRING]; + // xpath = a subset of XPath expression + fExtraDVs[DT_XPATH] = fExtraDVs[DT_STRING]; + // language + fExtraDVs[DT_LANGUAGE] = (XSSimpleType)grammar.getGlobalTypeDecl(SchemaSymbols.ATTVAL_LANGUAGE); + } + + protected static final int DT_BLOCK = -1; + protected static final int DT_BLOCK1 = -2; + protected static final int DT_FINAL = -3; + protected static final int DT_FINAL1 = -4; + protected static final int DT_FINAL2 = -5; + protected static final int DT_FORM = -6; + protected static final int DT_MAXOCCURS = -7; + protected static final int DT_MAXOCCURS1 = -8; + protected static final int DT_MEMBERTYPES = -9; + protected static final int DT_MINOCCURS1 = -10; + protected static final int DT_NAMESPACE = -11; + protected static final int DT_PROCESSCONTENTS = -12; + protected static final int DT_USE = -13; + protected static final int DT_WHITESPACE = -14; + protected static final int DT_BOOLEAN = -15; + protected static final int DT_NONNEGINT = -16; + protected static final int DT_POSINT = -17; + + static { + // step 2: all possible attributes for all elements + int attCount = 0; + int ATT_ABSTRACT_D = attCount++; + int ATT_ATTRIBUTE_FD_D = attCount++; + int ATT_BASE_R = attCount++; + int ATT_BASE_N = attCount++; + int ATT_BLOCK_N = attCount++; + int ATT_BLOCK1_N = attCount++; + int ATT_BLOCK_D_D = attCount++; + int ATT_DEFAULT_N = attCount++; + int ATT_ELEMENT_FD_D = attCount++; + int ATT_FINAL_N = attCount++; + int ATT_FINAL1_N = attCount++; + int ATT_FINAL_D_D = attCount++; + int ATT_FIXED_N = attCount++; + int ATT_FIXED_D = attCount++; + int ATT_FORM_N = attCount++; + int ATT_ID_N = attCount++; + int ATT_ITEMTYPE_N = attCount++; + int ATT_MAXOCCURS_D = attCount++; + int ATT_MAXOCCURS1_D = attCount++; + int ATT_MEMBER_T_N = attCount++; + int ATT_MINOCCURS_D = attCount++; + int ATT_MINOCCURS1_D = attCount++; + int ATT_MIXED_D = attCount++; + int ATT_MIXED_N = attCount++; + int ATT_NAME_R = attCount++; + int ATT_NAMESPACE_D = attCount++; + int ATT_NAMESPACE_N = attCount++; + int ATT_NILLABLE_D = attCount++; + int ATT_PROCESS_C_D = attCount++; + int ATT_PUBLIC_R = attCount++; + int ATT_REF_R = attCount++; + int ATT_REFER_R = attCount++; + int ATT_SCHEMA_L_R = attCount++; + int ATT_SCHEMA_L_N = attCount++; + int ATT_SOURCE_N = attCount++; + int ATT_SUBSTITUTION_G_N = attCount++; + int ATT_SYSTEM_N = attCount++; + int ATT_TARGET_N_N = attCount++; + int ATT_TYPE_N = attCount++; + int ATT_USE_D = attCount++; + int ATT_VALUE_NNI_N = attCount++; + int ATT_VALUE_PI_N = attCount++; + int ATT_VALUE_STR_N = attCount++; + int ATT_VALUE_WS_N = attCount++; + int ATT_VERSION_N = attCount++; + int ATT_XML_LANG = attCount++; + int ATT_XPATH_R = attCount++; + int ATT_XPATH1_R = attCount++; + + // step 3: store all these attributes in an array + OneAttr[] allAttrs = new OneAttr[attCount]; + allAttrs[ATT_ABSTRACT_D] = new OneAttr(SchemaSymbols.ATT_ABSTRACT, + DT_BOOLEAN, + ATTIDX_ABSTRACT, + Boolean.FALSE); + allAttrs[ATT_ATTRIBUTE_FD_D] = new OneAttr(SchemaSymbols.ATT_ATTRIBUTEFORMDEFAULT, + DT_FORM, + ATTIDX_AFORMDEFAULT, + INT_UNQUALIFIED); + allAttrs[ATT_BASE_R] = new OneAttr(SchemaSymbols.ATT_BASE, + DT_QNAME, + ATTIDX_BASE, + null); + allAttrs[ATT_BASE_N] = new OneAttr(SchemaSymbols.ATT_BASE, + DT_QNAME, + ATTIDX_BASE, + null); + allAttrs[ATT_BLOCK_N] = new OneAttr(SchemaSymbols.ATT_BLOCK, + DT_BLOCK, + ATTIDX_BLOCK, + null); + allAttrs[ATT_BLOCK1_N] = new OneAttr(SchemaSymbols.ATT_BLOCK, + DT_BLOCK1, + ATTIDX_BLOCK, + null); + allAttrs[ATT_BLOCK_D_D] = new OneAttr(SchemaSymbols.ATT_BLOCKDEFAULT, + DT_BLOCK, + ATTIDX_BLOCKDEFAULT, + INT_EMPTY_SET); + allAttrs[ATT_DEFAULT_N] = new OneAttr(SchemaSymbols.ATT_DEFAULT, + DT_STRING, + ATTIDX_DEFAULT, + null); + allAttrs[ATT_ELEMENT_FD_D] = new OneAttr(SchemaSymbols.ATT_ELEMENTFORMDEFAULT, + DT_FORM, + ATTIDX_EFORMDEFAULT, + INT_UNQUALIFIED); + allAttrs[ATT_FINAL_N] = new OneAttr(SchemaSymbols.ATT_FINAL, + DT_FINAL, + ATTIDX_FINAL, + null); + allAttrs[ATT_FINAL1_N] = new OneAttr(SchemaSymbols.ATT_FINAL, + DT_FINAL1, + ATTIDX_FINAL, + null); + allAttrs[ATT_FINAL_D_D] = new OneAttr(SchemaSymbols.ATT_FINALDEFAULT, + DT_FINAL2, + ATTIDX_FINALDEFAULT, + INT_EMPTY_SET); + allAttrs[ATT_FIXED_N] = new OneAttr(SchemaSymbols.ATT_FIXED, + DT_STRING, + ATTIDX_FIXED, + null); + allAttrs[ATT_FIXED_D] = new OneAttr(SchemaSymbols.ATT_FIXED, + DT_BOOLEAN, + ATTIDX_FIXED, + Boolean.FALSE); + allAttrs[ATT_FORM_N] = new OneAttr(SchemaSymbols.ATT_FORM, + DT_FORM, + ATTIDX_FORM, + null); + allAttrs[ATT_ID_N] = new OneAttr(SchemaSymbols.ATT_ID, + DT_ID, + ATTIDX_ID, + null); + allAttrs[ATT_ITEMTYPE_N] = new OneAttr(SchemaSymbols.ATT_ITEMTYPE, + DT_QNAME, + ATTIDX_ITEMTYPE, + null); + allAttrs[ATT_MAXOCCURS_D] = new OneAttr(SchemaSymbols.ATT_MAXOCCURS, + DT_MAXOCCURS, + ATTIDX_MAXOCCURS, + fXIntPool.getXInt(1)); + allAttrs[ATT_MAXOCCURS1_D] = new OneAttr(SchemaSymbols.ATT_MAXOCCURS, + DT_MAXOCCURS1, + ATTIDX_MAXOCCURS, + fXIntPool.getXInt(1)); + allAttrs[ATT_MEMBER_T_N] = new OneAttr(SchemaSymbols.ATT_MEMBERTYPES, + DT_MEMBERTYPES, + ATTIDX_MEMBERTYPES, + null); + allAttrs[ATT_MINOCCURS_D] = new OneAttr(SchemaSymbols.ATT_MINOCCURS, + DT_NONNEGINT, + ATTIDX_MINOCCURS, + fXIntPool.getXInt(1)); + allAttrs[ATT_MINOCCURS1_D] = new OneAttr(SchemaSymbols.ATT_MINOCCURS, + DT_MINOCCURS1, + ATTIDX_MINOCCURS, + fXIntPool.getXInt(1)); + allAttrs[ATT_MIXED_D] = new OneAttr(SchemaSymbols.ATT_MIXED, + DT_BOOLEAN, + ATTIDX_MIXED, + Boolean.FALSE); + allAttrs[ATT_MIXED_N] = new OneAttr(SchemaSymbols.ATT_MIXED, + DT_BOOLEAN, + ATTIDX_MIXED, + null); + allAttrs[ATT_NAME_R] = new OneAttr(SchemaSymbols.ATT_NAME, + DT_NCNAME, + ATTIDX_NAME, + null); + allAttrs[ATT_NAMESPACE_D] = new OneAttr(SchemaSymbols.ATT_NAMESPACE, + DT_NAMESPACE, + ATTIDX_NAMESPACE, + INT_ANY_ANY); + allAttrs[ATT_NAMESPACE_N] = new OneAttr(SchemaSymbols.ATT_NAMESPACE, + DT_ANYURI, + ATTIDX_NAMESPACE, + null); + allAttrs[ATT_NILLABLE_D] = new OneAttr(SchemaSymbols.ATT_NILLABLE, + DT_BOOLEAN, + ATTIDX_NILLABLE, + Boolean.FALSE); + allAttrs[ATT_PROCESS_C_D] = new OneAttr(SchemaSymbols.ATT_PROCESSCONTENTS, + DT_PROCESSCONTENTS, + ATTIDX_PROCESSCONTENTS, + INT_ANY_STRICT); + allAttrs[ATT_PUBLIC_R] = new OneAttr(SchemaSymbols.ATT_PUBLIC, + DT_TOKEN, + ATTIDX_PUBLIC, + null); + allAttrs[ATT_REF_R] = new OneAttr(SchemaSymbols.ATT_REF, + DT_QNAME, + ATTIDX_REF, + null); + allAttrs[ATT_REFER_R] = new OneAttr(SchemaSymbols.ATT_REFER, + DT_QNAME, + ATTIDX_REFER, + null); + allAttrs[ATT_SCHEMA_L_R] = new OneAttr(SchemaSymbols.ATT_SCHEMALOCATION, + DT_ANYURI, + ATTIDX_SCHEMALOCATION, + null); + allAttrs[ATT_SCHEMA_L_N] = new OneAttr(SchemaSymbols.ATT_SCHEMALOCATION, + DT_ANYURI, + ATTIDX_SCHEMALOCATION, + null); + allAttrs[ATT_SOURCE_N] = new OneAttr(SchemaSymbols.ATT_SOURCE, + DT_ANYURI, + ATTIDX_SOURCE, + null); + allAttrs[ATT_SUBSTITUTION_G_N] = new OneAttr(SchemaSymbols.ATT_SUBSTITUTIONGROUP, + DT_QNAME, + ATTIDX_SUBSGROUP, + null); + allAttrs[ATT_SYSTEM_N] = new OneAttr(SchemaSymbols.ATT_SYSTEM, + DT_ANYURI, + ATTIDX_SYSTEM, + null); + allAttrs[ATT_TARGET_N_N] = new OneAttr(SchemaSymbols.ATT_TARGETNAMESPACE, + DT_ANYURI, + ATTIDX_TARGETNAMESPACE, + null); + allAttrs[ATT_TYPE_N] = new OneAttr(SchemaSymbols.ATT_TYPE, + DT_QNAME, + ATTIDX_TYPE, + null); + allAttrs[ATT_USE_D] = new OneAttr(SchemaSymbols.ATT_USE, + DT_USE, + ATTIDX_USE, + INT_USE_OPTIONAL); + allAttrs[ATT_VALUE_NNI_N] = new OneAttr(SchemaSymbols.ATT_VALUE, + DT_NONNEGINT, + ATTIDX_VALUE, + null); + allAttrs[ATT_VALUE_PI_N] = new OneAttr(SchemaSymbols.ATT_VALUE, + DT_POSINT, + ATTIDX_VALUE, + null); + allAttrs[ATT_VALUE_STR_N] = new OneAttr(SchemaSymbols.ATT_VALUE, + DT_STRING, + ATTIDX_VALUE, + null); + allAttrs[ATT_VALUE_WS_N] = new OneAttr(SchemaSymbols.ATT_VALUE, + DT_WHITESPACE, + ATTIDX_VALUE, + null); + allAttrs[ATT_VERSION_N] = new OneAttr(SchemaSymbols.ATT_VERSION, + DT_TOKEN, + ATTIDX_VERSION, + null); + allAttrs[ATT_XML_LANG] = new OneAttr(SchemaSymbols.ATT_XML_LANG, + DT_LANGUAGE, + ATTIDX_XML_LANG, + null); + allAttrs[ATT_XPATH_R] = new OneAttr(SchemaSymbols.ATT_XPATH, + DT_XPATH, + ATTIDX_XPATH, + null); + allAttrs[ATT_XPATH1_R] = new OneAttr(SchemaSymbols.ATT_XPATH, + DT_XPATH1, + ATTIDX_XPATH, + null); + + // step 4: for each element, make a list of possible attributes + Container attrList; + + // for element "attribute" - global + attrList = Container.getContainer(5); + // default = string + attrList.put(SchemaSymbols.ATT_DEFAULT, allAttrs[ATT_DEFAULT_N]); + // fixed = string + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + // type = QName + attrList.put(SchemaSymbols.ATT_TYPE, allAttrs[ATT_TYPE_N]); + fEleAttrsMapG.put(SchemaSymbols.ELT_ATTRIBUTE, attrList); + + // for element "attribute" - local name + attrList = Container.getContainer(7); + // default = string + attrList.put(SchemaSymbols.ATT_DEFAULT, allAttrs[ATT_DEFAULT_N]); + // fixed = string + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_N]); + // form = (qualified | unqualified) + attrList.put(SchemaSymbols.ATT_FORM, allAttrs[ATT_FORM_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + // type = QName + attrList.put(SchemaSymbols.ATT_TYPE, allAttrs[ATT_TYPE_N]); + // use = (optional | prohibited | required) : optional + attrList.put(SchemaSymbols.ATT_USE, allAttrs[ATT_USE_D]); + fEleAttrsMapL.put(ATTRIBUTE_N, attrList); + + // for element "attribute" - local ref + attrList = Container.getContainer(5); + // default = string + attrList.put(SchemaSymbols.ATT_DEFAULT, allAttrs[ATT_DEFAULT_N]); + // fixed = string + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // ref = QName + attrList.put(SchemaSymbols.ATT_REF, allAttrs[ATT_REF_R]); + // use = (optional | prohibited | required) : optional + attrList.put(SchemaSymbols.ATT_USE, allAttrs[ATT_USE_D]); + fEleAttrsMapL.put(ATTRIBUTE_R, attrList); + + // for element "element" - global + attrList = Container.getContainer(10); + // abstract = boolean : false + attrList.put(SchemaSymbols.ATT_ABSTRACT, allAttrs[ATT_ABSTRACT_D]); + // block = (#all | List of (extension | restriction | substitution)) + attrList.put(SchemaSymbols.ATT_BLOCK, allAttrs[ATT_BLOCK_N]); + // default = string + attrList.put(SchemaSymbols.ATT_DEFAULT, allAttrs[ATT_DEFAULT_N]); + // final = (#all | List of (extension | restriction)) + attrList.put(SchemaSymbols.ATT_FINAL, allAttrs[ATT_FINAL_N]); + // fixed = string + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + // nillable = boolean : false + attrList.put(SchemaSymbols.ATT_NILLABLE, allAttrs[ATT_NILLABLE_D]); + // substitutionGroup = QName + attrList.put(SchemaSymbols.ATT_SUBSTITUTIONGROUP, allAttrs[ATT_SUBSTITUTION_G_N]); + // type = QName + attrList.put(SchemaSymbols.ATT_TYPE, allAttrs[ATT_TYPE_N]); + fEleAttrsMapG.put(SchemaSymbols.ELT_ELEMENT, attrList); + + // for element "element" - local name + attrList = Container.getContainer(10); + // block = (#all | List of (extension | restriction | substitution)) + attrList.put(SchemaSymbols.ATT_BLOCK, allAttrs[ATT_BLOCK_N]); + // default = string + attrList.put(SchemaSymbols.ATT_DEFAULT, allAttrs[ATT_DEFAULT_N]); + // fixed = string + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_N]); + // form = (qualified | unqualified) + attrList.put(SchemaSymbols.ATT_FORM, allAttrs[ATT_FORM_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // maxOccurs = (nonNegativeInteger | unbounded) : 1 + attrList.put(SchemaSymbols.ATT_MAXOCCURS, allAttrs[ATT_MAXOCCURS_D]); + // minOccurs = nonNegativeInteger : 1 + attrList.put(SchemaSymbols.ATT_MINOCCURS, allAttrs[ATT_MINOCCURS_D]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + // nillable = boolean : false + attrList.put(SchemaSymbols.ATT_NILLABLE, allAttrs[ATT_NILLABLE_D]); + // type = QName + attrList.put(SchemaSymbols.ATT_TYPE, allAttrs[ATT_TYPE_N]); + fEleAttrsMapL.put(ELEMENT_N, attrList); + + // for element "element" - local ref + attrList = Container.getContainer(4); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // maxOccurs = (nonNegativeInteger | unbounded) : 1 + attrList.put(SchemaSymbols.ATT_MAXOCCURS, allAttrs[ATT_MAXOCCURS_D]); + // minOccurs = nonNegativeInteger : 1 + attrList.put(SchemaSymbols.ATT_MINOCCURS, allAttrs[ATT_MINOCCURS_D]); + // ref = QName + attrList.put(SchemaSymbols.ATT_REF, allAttrs[ATT_REF_R]); + fEleAttrsMapL.put(ELEMENT_R, attrList); + + // for element "complexType" - global + attrList = Container.getContainer(6); + // abstract = boolean : false + attrList.put(SchemaSymbols.ATT_ABSTRACT, allAttrs[ATT_ABSTRACT_D]); + // block = (#all | List of (extension | restriction)) + attrList.put(SchemaSymbols.ATT_BLOCK, allAttrs[ATT_BLOCK1_N]); + // final = (#all | List of (extension | restriction)) + attrList.put(SchemaSymbols.ATT_FINAL, allAttrs[ATT_FINAL_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // mixed = boolean : false + attrList.put(SchemaSymbols.ATT_MIXED, allAttrs[ATT_MIXED_D]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + fEleAttrsMapG.put(SchemaSymbols.ELT_COMPLEXTYPE, attrList); + + // for element "notation" - global + attrList = Container.getContainer(4); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + // public = A public identifier, per ISO 8879 + attrList.put(SchemaSymbols.ATT_PUBLIC, allAttrs[ATT_PUBLIC_R]); + // system = anyURI + attrList.put(SchemaSymbols.ATT_SYSTEM, allAttrs[ATT_SYSTEM_N]); + fEleAttrsMapG.put(SchemaSymbols.ELT_NOTATION, attrList); + + + // for element "complexType" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // mixed = boolean : false + attrList.put(SchemaSymbols.ATT_MIXED, allAttrs[ATT_MIXED_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_COMPLEXTYPE, attrList); + + // for element "simpleContent" - local + attrList = Container.getContainer(1); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_SIMPLECONTENT, attrList); + + // for element "restriction" - local + attrList = Container.getContainer(2); + // base = QName + attrList.put(SchemaSymbols.ATT_BASE, allAttrs[ATT_BASE_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_RESTRICTION, attrList); + + // for element "extension" - local + attrList = Container.getContainer(2); + // base = QName + attrList.put(SchemaSymbols.ATT_BASE, allAttrs[ATT_BASE_R]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_EXTENSION, attrList); + + // for element "attributeGroup" - local ref + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // ref = QName + attrList.put(SchemaSymbols.ATT_REF, allAttrs[ATT_REF_R]); + fEleAttrsMapL.put(SchemaSymbols.ELT_ATTRIBUTEGROUP, attrList); + + // for element "anyAttribute" - local + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) : ##any + attrList.put(SchemaSymbols.ATT_NAMESPACE, allAttrs[ATT_NAMESPACE_D]); + // processContents = (lax | skip | strict) : strict + attrList.put(SchemaSymbols.ATT_PROCESSCONTENTS, allAttrs[ATT_PROCESS_C_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_ANYATTRIBUTE, attrList); + + // for element "complexContent" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // mixed = boolean + attrList.put(SchemaSymbols.ATT_MIXED, allAttrs[ATT_MIXED_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_COMPLEXCONTENT, attrList); + + // for element "attributeGroup" - global + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + fEleAttrsMapG.put(SchemaSymbols.ELT_ATTRIBUTEGROUP, attrList); + + // for element "group" - global + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + fEleAttrsMapG.put(SchemaSymbols.ELT_GROUP, attrList); + + // for element "group" - local ref + attrList = Container.getContainer(4); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // maxOccurs = (nonNegativeInteger | unbounded) : 1 + attrList.put(SchemaSymbols.ATT_MAXOCCURS, allAttrs[ATT_MAXOCCURS_D]); + // minOccurs = nonNegativeInteger : 1 + attrList.put(SchemaSymbols.ATT_MINOCCURS, allAttrs[ATT_MINOCCURS_D]); + // ref = QName + attrList.put(SchemaSymbols.ATT_REF, allAttrs[ATT_REF_R]); + fEleAttrsMapL.put(SchemaSymbols.ELT_GROUP, attrList); + + // for element "all" - local + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // maxOccurs = 1 : 1 + attrList.put(SchemaSymbols.ATT_MAXOCCURS, allAttrs[ATT_MAXOCCURS1_D]); + // minOccurs = (0 | 1) : 1 + attrList.put(SchemaSymbols.ATT_MINOCCURS, allAttrs[ATT_MINOCCURS1_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_ALL, attrList); + + // for element "choice" - local + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // maxOccurs = (nonNegativeInteger | unbounded) : 1 + attrList.put(SchemaSymbols.ATT_MAXOCCURS, allAttrs[ATT_MAXOCCURS_D]); + // minOccurs = nonNegativeInteger : 1 + attrList.put(SchemaSymbols.ATT_MINOCCURS, allAttrs[ATT_MINOCCURS_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_CHOICE, attrList); + // for element "sequence" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_SEQUENCE, attrList); + + // for element "any" - local + attrList = Container.getContainer(5); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // maxOccurs = (nonNegativeInteger | unbounded) : 1 + attrList.put(SchemaSymbols.ATT_MAXOCCURS, allAttrs[ATT_MAXOCCURS_D]); + // minOccurs = nonNegativeInteger : 1 + attrList.put(SchemaSymbols.ATT_MINOCCURS, allAttrs[ATT_MINOCCURS_D]); + // namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) : ##any + attrList.put(SchemaSymbols.ATT_NAMESPACE, allAttrs[ATT_NAMESPACE_D]); + // processContents = (lax | skip | strict) : strict + attrList.put(SchemaSymbols.ATT_PROCESSCONTENTS, allAttrs[ATT_PROCESS_C_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_ANY, attrList); + + // for element "unique" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + fEleAttrsMapL.put(SchemaSymbols.ELT_UNIQUE, attrList); + // for element "key" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_KEY, attrList); + + // for element "keyref" - local + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + // refer = QName + attrList.put(SchemaSymbols.ATT_REFER, allAttrs[ATT_REFER_R]); + fEleAttrsMapL.put(SchemaSymbols.ELT_KEYREF, attrList); + + // for element "selector" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // xpath = a subset of XPath expression + attrList.put(SchemaSymbols.ATT_XPATH, allAttrs[ATT_XPATH_R]); + fEleAttrsMapL.put(SchemaSymbols.ELT_SELECTOR, attrList); + + // for element "field" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // xpath = a subset of XPath expression + attrList.put(SchemaSymbols.ATT_XPATH, allAttrs[ATT_XPATH1_R]); + fEleAttrsMapL.put(SchemaSymbols.ELT_FIELD, attrList); + + // for element "annotation" - global + attrList = Container.getContainer(1); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + fEleAttrsMapG.put(SchemaSymbols.ELT_ANNOTATION, attrList); + // for element "annotation" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_ANNOTATION, attrList); + + // for element "appinfo" - local + attrList = Container.getContainer(1); + // source = anyURI + attrList.put(SchemaSymbols.ATT_SOURCE, allAttrs[ATT_SOURCE_N]); + fEleAttrsMapG.put(SchemaSymbols.ELT_APPINFO, attrList); + fEleAttrsMapL.put(SchemaSymbols.ELT_APPINFO, attrList); + + // for element "documentation" - local + attrList = Container.getContainer(2); + // source = anyURI + attrList.put(SchemaSymbols.ATT_SOURCE, allAttrs[ATT_SOURCE_N]); + // xml:lang = language + attrList.put(SchemaSymbols.ATT_XML_LANG, allAttrs[ATT_XML_LANG]); + fEleAttrsMapG.put(SchemaSymbols.ELT_DOCUMENTATION, attrList); + fEleAttrsMapL.put(SchemaSymbols.ELT_DOCUMENTATION, attrList); + + // for element "simpleType" - global + attrList = Container.getContainer(3); + // final = (#all | List of (list | union | restriction)) + attrList.put(SchemaSymbols.ATT_FINAL, allAttrs[ATT_FINAL1_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // name = NCName + attrList.put(SchemaSymbols.ATT_NAME, allAttrs[ATT_NAME_R]); + fEleAttrsMapG.put(SchemaSymbols.ELT_SIMPLETYPE, attrList); + + // for element "simpleType" - local + attrList = Container.getContainer(2); + // final = (#all | List of (list | union | restriction)) + attrList.put(SchemaSymbols.ATT_FINAL, allAttrs[ATT_FINAL1_N]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_SIMPLETYPE, attrList); + + // for element "restriction" - local + // already registered for complexType + + // for element "list" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // itemType = QName + attrList.put(SchemaSymbols.ATT_ITEMTYPE, allAttrs[ATT_ITEMTYPE_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_LIST, attrList); + + // for element "union" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // memberTypes = List of QName + attrList.put(SchemaSymbols.ATT_MEMBERTYPES, allAttrs[ATT_MEMBER_T_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_UNION, attrList); + + // for element "schema" - global + attrList = Container.getContainer(8); + // attributeFormDefault = (qualified | unqualified) : unqualified + attrList.put(SchemaSymbols.ATT_ATTRIBUTEFORMDEFAULT, allAttrs[ATT_ATTRIBUTE_FD_D]); + // blockDefault = (#all | List of (extension | restriction | substitution)) : '' + attrList.put(SchemaSymbols.ATT_BLOCKDEFAULT, allAttrs[ATT_BLOCK_D_D]); + // elementFormDefault = (qualified | unqualified) : unqualified + attrList.put(SchemaSymbols.ATT_ELEMENTFORMDEFAULT, allAttrs[ATT_ELEMENT_FD_D]); + // finalDefault = (#all | List of (extension | restriction | list | union)) : '' + attrList.put(SchemaSymbols.ATT_FINALDEFAULT, allAttrs[ATT_FINAL_D_D]); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // targetNamespace = anyURI + attrList.put(SchemaSymbols.ATT_TARGETNAMESPACE, allAttrs[ATT_TARGET_N_N]); + // version = token + attrList.put(SchemaSymbols.ATT_VERSION, allAttrs[ATT_VERSION_N]); + // xml:lang = language + attrList.put(SchemaSymbols.ATT_XML_LANG, allAttrs[ATT_XML_LANG]); + fEleAttrsMapG.put(SchemaSymbols.ELT_SCHEMA, attrList); + + // for element "include" - global + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // schemaLocation = anyURI + attrList.put(SchemaSymbols.ATT_SCHEMALOCATION, allAttrs[ATT_SCHEMA_L_R]); + fEleAttrsMapG.put(SchemaSymbols.ELT_INCLUDE, attrList); + // for element "redefine" - global + fEleAttrsMapG.put(SchemaSymbols.ELT_REDEFINE, attrList); + + // for element "import" - global + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // namespace = anyURI + attrList.put(SchemaSymbols.ATT_NAMESPACE, allAttrs[ATT_NAMESPACE_N]); + // schemaLocation = anyURI + attrList.put(SchemaSymbols.ATT_SCHEMALOCATION, allAttrs[ATT_SCHEMA_L_N]); + fEleAttrsMapG.put(SchemaSymbols.ELT_IMPORT, attrList); + + // for element "length" - local + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // value = nonNegativeInteger + attrList.put(SchemaSymbols.ATT_VALUE, allAttrs[ATT_VALUE_NNI_N]); + // fixed = boolean : false + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_LENGTH, attrList); + // for element "minLength" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_MINLENGTH, attrList); + // for element "maxLength" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_MAXLENGTH, attrList); + // for element "fractionDigits" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_FRACTIONDIGITS, attrList); + + // for element "totalDigits" - local + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // value = positiveInteger + attrList.put(SchemaSymbols.ATT_VALUE, allAttrs[ATT_VALUE_PI_N]); + // fixed = boolean : false + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_TOTALDIGITS, attrList); + + // for element "pattern" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // value = string + attrList.put(SchemaSymbols.ATT_VALUE, allAttrs[ATT_VALUE_STR_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_PATTERN, attrList); + + // for element "enumeration" - local + attrList = Container.getContainer(2); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // value = anySimpleType + attrList.put(SchemaSymbols.ATT_VALUE, allAttrs[ATT_VALUE_STR_N]); + fEleAttrsMapL.put(SchemaSymbols.ELT_ENUMERATION, attrList); + + // for element "whiteSpace" - local + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // value = preserve | replace | collapse + attrList.put(SchemaSymbols.ATT_VALUE, allAttrs[ATT_VALUE_WS_N]); + // fixed = boolean : false + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_WHITESPACE, attrList); + + // for element "maxInclusive" - local + attrList = Container.getContainer(3); + // id = ID + attrList.put(SchemaSymbols.ATT_ID, allAttrs[ATT_ID_N]); + // value = anySimpleType + attrList.put(SchemaSymbols.ATT_VALUE, allAttrs[ATT_VALUE_STR_N]); + // fixed = boolean : false + attrList.put(SchemaSymbols.ATT_FIXED, allAttrs[ATT_FIXED_D]); + fEleAttrsMapL.put(SchemaSymbols.ELT_MAXINCLUSIVE, attrList); + // for element "maxExclusive" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_MAXEXCLUSIVE, attrList); + // for element "minInclusive" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_MININCLUSIVE, attrList); + // for element "minExclusive" - local + fEleAttrsMapL.put(SchemaSymbols.ELT_MINEXCLUSIVE, attrList); + } + + // used to resolver namespace prefixes + protected XSDHandler fSchemaHandler = null; + + // used to store symbols. + protected SymbolTable fSymbolTable = null; + + // used to store the mapping from processed element to attributes + protected Hashtable fNonSchemaAttrs = new Hashtable(); + + // temprory vector, used to hold the namespace list + protected Vector fNamespaceList = new Vector(); + + // whether this attribute appeared in the current element + protected boolean[] fSeen = new boolean[ATTIDX_COUNT]; + private static boolean[] fSeenTemp = new boolean[ATTIDX_COUNT]; + + // constructor. Sets fErrorReproter and get datatype validators + public XSAttributeChecker(XSDHandler schemaHandler) { + fSchemaHandler = schemaHandler; + } + + public void reset(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + fNonSchemaAttrs.clear(); + } + + /** + * Check whether the specified element conforms to the attributes restriction + * an array of attribute values is returned. the caller must call + * returnAttrArray to return that array. + * + * @param element which element to check + * @param isGlobal whether a child of <schema> or <redefine> + * @param schemaDoc the document where the element lives in + * @return an array containing attribute values + */ + public Object[] checkAttributes(Element element, boolean isGlobal, + XSDocumentInfo schemaDoc) { + return checkAttributes(element, isGlobal, schemaDoc, false); + } + + /** + * Check whether the specified element conforms to the attributes restriction + * an array of attribute values is returned. the caller must call + * returnAttrArray to return that array. This method also takes + * an extra parameter: if the element is "enumeration", whether to make a + * copy of the namespace context, so that the value can be resolved as a + * QName later. + * + * @param element which element to check + * @param isGlobal whether a child of <schema> or <redefine> + * @param schemaDoc the document where the element lives in + * @param enumAsQName whether to tread enumeration value as QName + * @return an array containing attribute values + */ + public Object[] checkAttributes(Element element, boolean isGlobal, + XSDocumentInfo schemaDoc, boolean enumAsQName) { + if (element == null) + return null; + + // get all attributes + Attr[] attrs = DOMUtil.getAttrs(element); + + // update NamespaceSupport + resolveNamespace(element, attrs, schemaDoc.fNamespaceSupport); + + String uri = DOMUtil.getNamespaceURI(element); + String elName = DOMUtil.getLocalName(element); + + if (!SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(uri)) { + reportSchemaError("s4s-elt-schema-ns", new Object[] {elName}, element); + } + + Hashtable eleAttrsMap = fEleAttrsMapG; + String lookupName = elName; + + // REVISIT: only local element and attribute are different from others. + // it's possible to have either name or ref. all the others + // are only allowed to have one of name or ref, or neither of them. + // we'd better move such checking to the traverser. + if (!isGlobal) { + eleAttrsMap = fEleAttrsMapL; + if (elName.equals(SchemaSymbols.ELT_ELEMENT)) { + if (DOMUtil.getAttr(element, SchemaSymbols.ATT_REF) != null) + lookupName = ELEMENT_R; + else + lookupName = ELEMENT_N; + } else if (elName.equals(SchemaSymbols.ELT_ATTRIBUTE)) { + if (DOMUtil.getAttr(element, SchemaSymbols.ATT_REF) != null) + lookupName = ATTRIBUTE_R; + else + lookupName = ATTRIBUTE_N; + } + } + + // get desired attribute list of this element + Container attrList = (Container)eleAttrsMap.get(lookupName); + if (attrList == null) { + // should never gets here. + // when this method is called, the call already knows that + // the element can appear. + reportSchemaError ("s4s-elt-invalid", new Object[] {elName}, element); + return null; + } + + //Hashtable attrValues = new Hashtable(); + Object[] attrValues = getAvailableArray(); + //Hashtable otherValues = new Hashtable(); + long fromDefault = 0; + + // clear the "seen" flag. + System.arraycopy(fSeenTemp, 0, fSeen, 0, ATTIDX_COUNT); + + // traverse all attributes + int length = attrs.length; + Attr sattr = null; + for (int i = 0; i < length; i++) { + sattr = attrs[i]; + // get the attribute name/value + //String attrName = DOMUtil.getLocalName(sattr); + String attrName = sattr.getName(); + String attrURI = DOMUtil.getNamespaceURI(sattr); + String attrVal = DOMUtil.getValue(sattr); + + if (attrName.startsWith("xml")) { + String attrPrefix = DOMUtil.getPrefix(sattr); + // we don't want to add namespace declarations to the non-schema attributes + if ("xmlns".equals(attrPrefix) || "xmlns".equals(attrName)) { + continue; + } + // Both and may have an xml:lang attribute. + // Set the URI for this attribute to null so that we process it + // like any other schema attribute. + else if (SchemaSymbols.ATT_XML_LANG.equals(attrName) && + (SchemaSymbols.ELT_SCHEMA.equals(elName) || + SchemaSymbols.ELT_DOCUMENTATION.equals(elName))) { + attrURI = null; + } + } + + // for attributes with namespace prefix + // + if (attrURI != null && attrURI.length() != 0) { + // attributes with schema namespace are not allowed + // and not allowed on "document" and "appInfo" + if (attrURI.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)) { + reportSchemaError ("s4s-att-not-allowed", new Object[] {elName, attrName}, element); + } + else { + if(attrValues[ATTIDX_NONSCHEMA] == null) { + // these are usually small + attrValues[ATTIDX_NONSCHEMA] = new Vector(4,2); + } + ((Vector)attrValues[ATTIDX_NONSCHEMA]).addElement(attrName); + ((Vector)attrValues[ATTIDX_NONSCHEMA]).addElement(attrVal); + // for attributes from other namespace + // store them in a list, and TRY to validate them after + // schema traversal (because it's "lax") + //otherValues.put(attrName, attrVal); + // REVISIT: actually use this some day... + // String attrRName = attrURI + "," + attrName; + // Vector values = (Vector)fNonSchemaAttrs.get(attrRName); + // if (values == null) { + // values = new Vector(); + // values.addElement(attrName); + // values.addElement(elName); + // values.addElement(attrVal); + // fNonSchemaAttrs.put(attrRName, values); + // } + // else { + // values.addElement(elName); + // values.addElement(attrVal); + // } + } + continue; + } + + // check whether this attribute is allowed + OneAttr oneAttr = attrList.get(attrName); + if (oneAttr == null) { + reportSchemaError ("s4s-att-not-allowed", + new Object[] {elName, attrName}, + element); + continue; + } + + // we've seen this attribute + fSeen[oneAttr.valueIndex] = true; + + // check the value against the datatype + try { + // no checking on string needs to be done here. + // no checking on xpath needs to be done here. + // xpath values are validated in xpath parser + if (oneAttr.dvIndex >= 0) { + if (oneAttr.dvIndex != DT_STRING && + oneAttr.dvIndex != DT_XPATH && + oneAttr.dvIndex != DT_XPATH1) { + XSSimpleType dv = fExtraDVs[oneAttr.dvIndex]; + Object avalue = dv.validate(attrVal, schemaDoc.fValidationContext, null); + // kludge to handle chameleon includes/redefines... + if (oneAttr.dvIndex == DT_QNAME) { + QName qname = (QName)avalue; + if(qname.prefix == XMLSymbols.EMPTY_STRING && qname.uri == null && schemaDoc.fIsChameleonSchema) + qname.uri = schemaDoc.fTargetNamespace; + } + attrValues[oneAttr.valueIndex] = avalue; + } else { + attrValues[oneAttr.valueIndex] = attrVal; + } + } + else { + attrValues[oneAttr.valueIndex] = validate(attrValues, attrName, attrVal, oneAttr.dvIndex, schemaDoc); + } + } catch (InvalidDatatypeValueException ide) { + reportSchemaError ("s4s-att-invalid-value", + new Object[] {elName, attrName, ide.getMessage()}, + element); + if (oneAttr.dfltValue != null) + //attrValues.put(attrName, oneAttr.dfltValue); + attrValues[oneAttr.valueIndex] = oneAttr.dfltValue; + } + + // For "enumeration", and type is possible to be a QName, we need + // to return namespace context for later QName resolution. + if (elName.equals(SchemaSymbols.ELT_ENUMERATION) && enumAsQName) { + attrValues[ATTIDX_ENUMNSDECLS] = new SchemaNamespaceSupport(schemaDoc.fNamespaceSupport); + } + } + + // apply default values + OneAttr[] reqAttrs = attrList.values; + for (int i = 0; i < reqAttrs.length; i++) { + OneAttr oneAttr = reqAttrs[i]; + + // if the attribute didn't apprear, and + // if the attribute is optional with default value, apply it + if (oneAttr.dfltValue != null && !fSeen[oneAttr.valueIndex]) { + //attrValues.put(oneAttr.name, oneAttr.dfltValue); + attrValues[oneAttr.valueIndex] = oneAttr.dfltValue; + fromDefault |= (1< max) { + reportSchemaError ("p-props-correct.2.1", + new Object[] {elName, attrValues[ATTIDX_MINOCCURS], attrValues[ATTIDX_MAXOCCURS]}, + element); + attrValues[ATTIDX_MINOCCURS] = attrValues[ATTIDX_MAXOCCURS]; + } + } + } + + return attrValues; + } + + private Object validate(Object[] attrValues, String attr, String ivalue, int dvIndex, + XSDocumentInfo schemaDoc) throws InvalidDatatypeValueException { + if (ivalue == null) + return null; + + // To validate these types, we don't actually need to normalize the + // strings. We only need to remove the whitespace from both ends. + // In some special cases (list types), StringTokenizer can correctly + // process the un-normalized whitespace. + + String value = XMLChar.trim(ivalue); + Object retValue = null; + Vector memberType; + int choice; + + switch (dvIndex) { + case DT_BOOLEAN: + if (value.equals(SchemaSymbols.ATTVAL_FALSE) || + value.equals(SchemaSymbols.ATTVAL_FALSE_0)) { + retValue = Boolean.FALSE; + } else if (value.equals(SchemaSymbols.ATTVAL_TRUE) || + value.equals(SchemaSymbols.ATTVAL_TRUE_1)) { + retValue = Boolean.TRUE; + } else { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{value, "boolean"}); + } + break; + case DT_NONNEGINT: + try { + if (value.length() > 0 && value.charAt(0) == '+') + value = value.substring(1); + retValue = fXIntPool.getXInt(Integer.parseInt(value)); + } catch (NumberFormatException e) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{value, "nonNegativeInteger"}); + } + if (((XInt)retValue).intValue() < 0) + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{value, "nonNegativeInteger"}); + break; + case DT_POSINT: + try { + if (value.length() > 0 && value.charAt(0) == '+') + value = value.substring(1); + retValue = fXIntPool.getXInt(Integer.parseInt(value)); + } catch (NumberFormatException e) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{value, "positiveInteger"}); + } + if (((XInt)retValue).intValue() <= 0) + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{value, "positiveInteger"}); + break; + case DT_BLOCK: + // block = (#all | List of (extension | restriction | substitution)) + choice = 0; + if (value.equals (SchemaSymbols.ATTVAL_POUNDALL)) { + choice = XSConstants.DERIVATION_SUBSTITUTION|XSConstants.DERIVATION_EXTENSION| + XSConstants.DERIVATION_RESTRICTION|XSConstants.DERIVATION_LIST| + XSConstants.DERIVATION_UNION; + } + else { + StringTokenizer t = new StringTokenizer(value, " \n\t\r"); + while (t.hasMoreTokens()) { + String token = t.nextToken (); + + if (token.equals (SchemaSymbols.ATTVAL_EXTENSION)) { + choice |= XSConstants.DERIVATION_EXTENSION; + } + else if (token.equals (SchemaSymbols.ATTVAL_RESTRICTION)) { + choice |= XSConstants.DERIVATION_RESTRICTION; + } + else if (token.equals (SchemaSymbols.ATTVAL_SUBSTITUTION)) { + choice |= XSConstants.DERIVATION_SUBSTITUTION; + } + else { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.3", new Object[]{value, "(#all | List of (extension | restriction | substitution))"}); + } + } + } + retValue = fXIntPool.getXInt(choice); + break; + case DT_BLOCK1: + case DT_FINAL: + // block = (#all | List of (extension | restriction)) + // final = (#all | List of (extension | restriction)) + choice = 0; + if (value.equals (SchemaSymbols.ATTVAL_POUNDALL)) { + //choice = SchemaSymbols.EXTENSION|SchemaSymbols.RESTRICTION; + // REVISIT: if #all, then make the result the combination of + // everything: substitution/externsion/restriction/list/union. + // would this be a problem? + // the reason doing so is that when final/blockFinal on + // is #all, it's not always the same as the conbination of those + // values allowed by final/blockFinal. + // for example, finalDefault="#all" is not always the same as + // finalDefault="extension restriction". + // if finalDefault="#all", final on any simple type would be + // "extension restriction list union". + choice = XSConstants.DERIVATION_SUBSTITUTION|XSConstants.DERIVATION_EXTENSION| + XSConstants.DERIVATION_RESTRICTION|XSConstants.DERIVATION_LIST| + XSConstants.DERIVATION_UNION; + } + else { + StringTokenizer t = new StringTokenizer(value, " \n\t\r"); + while (t.hasMoreTokens()) { + String token = t.nextToken (); + + if (token.equals (SchemaSymbols.ATTVAL_EXTENSION)) { + choice |= XSConstants.DERIVATION_EXTENSION; + } + else if (token.equals (SchemaSymbols.ATTVAL_RESTRICTION)) { + choice |= XSConstants.DERIVATION_RESTRICTION; + } + else { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.3", new Object[]{value, "(#all | List of (extension | restriction))"}); + } + } + } + retValue = fXIntPool.getXInt(choice); + break; + case DT_FINAL1: + // final = (#all | List of (list | union | restriction)) + choice = 0; + if (value.equals (SchemaSymbols.ATTVAL_POUNDALL)) { + //choice = SchemaSymbols.RESTRICTION|SchemaSymbols.LIST| + // SchemaSymbols.UNION; + // REVISIT: if #all, then make the result the combination of + // everything: substitution/externsion/restriction/list/union. + // would this be a problem? + // same reason as above DT_BLOCK1/DT_FINAL + choice = XSConstants.DERIVATION_SUBSTITUTION|XSConstants.DERIVATION_EXTENSION| + XSConstants.DERIVATION_RESTRICTION|XSConstants.DERIVATION_LIST| + XSConstants.DERIVATION_UNION; + } + else { + StringTokenizer t = new StringTokenizer(value, " \n\t\r"); + while (t.hasMoreTokens()) { + String token = t.nextToken (); + + if (token.equals (SchemaSymbols.ATTVAL_LIST)) { + choice |= XSConstants.DERIVATION_LIST; + } + else if (token.equals (SchemaSymbols.ATTVAL_UNION)) { + choice |= XSConstants.DERIVATION_UNION; + } + else if (token.equals (SchemaSymbols.ATTVAL_RESTRICTION)) { + choice |= XSConstants.DERIVATION_RESTRICTION; + } + else { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.3", new Object[]{value, "(#all | List of (list | union | restriction))"}); + } + } + } + retValue = fXIntPool.getXInt(choice); + break; + case DT_FINAL2: + // finalDefault = (#all | List of (extension | restriction | list | union)) + choice = 0; + if (value.equals (SchemaSymbols.ATTVAL_POUNDALL)) { + //choice = SchemaSymbols.RESTRICTION|SchemaSymbols.LIST| + // SchemaSymbols.UNION; + // REVISIT: if #all, then make the result the combination of + // everything: substitution/externsion/restriction/list/union. + // would this be a problem? + // same reason as above DT_BLOCK1/DT_FINAL + choice = XSConstants.DERIVATION_SUBSTITUTION|XSConstants.DERIVATION_EXTENSION| + XSConstants.DERIVATION_RESTRICTION|XSConstants.DERIVATION_LIST| + XSConstants.DERIVATION_UNION; + } + else { + StringTokenizer t = new StringTokenizer(value, " \n\t\r"); + while (t.hasMoreTokens()) { + String token = t.nextToken (); + + if (token.equals (SchemaSymbols.ATTVAL_EXTENSION)) { + choice |= XSConstants.DERIVATION_EXTENSION; + } + else if (token.equals (SchemaSymbols.ATTVAL_RESTRICTION)) { + choice |= XSConstants.DERIVATION_RESTRICTION; + } + else if (token.equals (SchemaSymbols.ATTVAL_LIST)) { + choice |= XSConstants.DERIVATION_LIST; + } + else if (token.equals (SchemaSymbols.ATTVAL_UNION)) { + choice |= XSConstants.DERIVATION_UNION; + } + else { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.3", new Object[]{value, "(#all | List of (extension | restriction | list | union))"}); + } + } + } + retValue = fXIntPool.getXInt(choice); + break; + case DT_FORM: + // form = (qualified | unqualified) + if (value.equals (SchemaSymbols.ATTVAL_QUALIFIED)) + retValue = INT_QUALIFIED; + else if (value.equals (SchemaSymbols.ATTVAL_UNQUALIFIED)) + retValue = INT_UNQUALIFIED; + else + throw new InvalidDatatypeValueException("cvc-enumeration-valid", + new Object[]{value, "(qualified | unqualified)"}); + break; + case DT_MAXOCCURS: + // maxOccurs = (nonNegativeInteger | unbounded) + if (value.equals(SchemaSymbols.ATTVAL_UNBOUNDED)) { + retValue = INT_UNBOUNDED; + } else { + try { + retValue = validate(attrValues, attr, value, DT_NONNEGINT, schemaDoc); + } catch (NumberFormatException e) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.3", new Object[]{value, "(nonNegativeInteger | unbounded)"}); + } + } + break; + case DT_MAXOCCURS1: + // maxOccurs = 1 + if (value.equals("1")) + retValue = fXIntPool.getXInt(1); + else + throw new InvalidDatatypeValueException("cvc-enumeration-valid", + new Object[]{value, "(1)"}); + break; + case DT_MEMBERTYPES: + // memberTypes = List of QName + memberType = new Vector(); + try { + StringTokenizer t = new StringTokenizer(value, " \n\t\r"); + while (t.hasMoreTokens()) { + String token = t.nextToken (); + QName qname = (QName)fExtraDVs[DT_QNAME].validate(token, schemaDoc.fValidationContext, null); + // kludge to handle chameleon includes/redefines... + if(qname.prefix == XMLSymbols.EMPTY_STRING && qname.uri == null && schemaDoc.fIsChameleonSchema) + qname.uri = schemaDoc.fTargetNamespace; + memberType.addElement(qname); + } + retValue = memberType; + } + catch (InvalidDatatypeValueException ide) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.2", new Object[]{value, "(List of QName)"}); + } + break; + case DT_MINOCCURS1: + // minOccurs = (0 | 1) + if (value.equals("0")) + retValue = fXIntPool.getXInt(0); + else if (value.equals("1")) + retValue = fXIntPool.getXInt(1); + else + throw new InvalidDatatypeValueException("cvc-enumeration-valid", + new Object[]{value, "(0 | 1)"}); + break; + case DT_NAMESPACE: + // namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) + if (value.equals(SchemaSymbols.ATTVAL_TWOPOUNDANY)) { + // ##any + retValue = INT_ANY_ANY; + } else if (value.equals(SchemaSymbols.ATTVAL_TWOPOUNDOTHER)) { + // ##other + retValue = INT_ANY_NOT; + String[] list = new String[2]; + list[0] = schemaDoc.fTargetNamespace; + list[1] = null; + attrValues[ATTIDX_NAMESPACE_LIST] = list; + } else { + // list + retValue = INT_ANY_LIST; + + fNamespaceList.removeAllElements(); + + // tokenize + StringTokenizer tokens = new StringTokenizer(value, " \n\t\r"); + String token; + String tempNamespace; + try { + while (tokens.hasMoreTokens()) { + token = tokens.nextToken(); + if (token.equals(SchemaSymbols.ATTVAL_TWOPOUNDLOCAL)) { + tempNamespace = null; + } else if (token.equals(SchemaSymbols.ATTVAL_TWOPOUNDTARGETNS)) { + tempNamespace = schemaDoc.fTargetNamespace; + } else { + // we have found namespace URI here + // need to add it to the symbol table + fExtraDVs[DT_ANYURI].validate(token, schemaDoc.fValidationContext, null); + tempNamespace = fSymbolTable.addSymbol(token); + } + + //check for duplicate namespaces in the list + if (!fNamespaceList.contains(tempNamespace)) { + fNamespaceList.addElement(tempNamespace); + } + } + } catch (InvalidDatatypeValueException ide) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.3", new Object[]{value, "((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )"}); + } + + // convert the vector to an array + int num = fNamespaceList.size(); + String[] list = new String[num]; + fNamespaceList.copyInto(list); + attrValues[ATTIDX_NAMESPACE_LIST] = list; + } + break; + case DT_PROCESSCONTENTS: + // processContents = (lax | skip | strict) + if (value.equals (SchemaSymbols.ATTVAL_STRICT)) + retValue = INT_ANY_STRICT; + else if (value.equals (SchemaSymbols.ATTVAL_LAX)) + retValue = INT_ANY_LAX; + else if (value.equals (SchemaSymbols.ATTVAL_SKIP)) + retValue = INT_ANY_SKIP; + else + throw new InvalidDatatypeValueException("cvc-enumeration-valid", + new Object[]{value, "(lax | skip | strict)"}); + break; + case DT_USE: + // use = (optional | prohibited | required) + if (value.equals (SchemaSymbols.ATTVAL_OPTIONAL)) + retValue = INT_USE_OPTIONAL; + else if (value.equals (SchemaSymbols.ATTVAL_REQUIRED)) + retValue = INT_USE_REQUIRED; + else if (value.equals (SchemaSymbols.ATTVAL_PROHIBITED)) + retValue = INT_USE_PROHIBITED; + else + throw new InvalidDatatypeValueException("cvc-enumeration-valid", + new Object[]{value, "(optional | prohibited | required)"}); + break; + case DT_WHITESPACE: + // value = preserve | replace | collapse + if (value.equals (SchemaSymbols.ATTVAL_PRESERVE)) + retValue = INT_WS_PRESERVE; + else if (value.equals (SchemaSymbols.ATTVAL_REPLACE)) + retValue = INT_WS_REPLACE; + else if (value.equals (SchemaSymbols.ATTVAL_COLLAPSE)) + retValue = INT_WS_COLLAPSE; + else + throw new InvalidDatatypeValueException("cvc-enumeration-valid", + new Object[]{value, "(preserve | replace | collapse)"}); + break; + } + + return retValue; + } + + void reportSchemaError (String key, Object[] args, Element ele) { + fSchemaHandler.reportSchemaError(key, args, ele); + } + + // validate attriubtes from non-schema namespaces + // REVISIT: why we store the attributes in this way? why not just a list + // of structure {element node, attr name/qname, attr value)? + // REVISIT: pass the proper element node to reportSchemaError + public void checkNonSchemaAttributes(XSGrammarBucket grammarBucket) { + // for all attributes + Iterator entries = fNonSchemaAttrs.entrySet().iterator(); + XSAttributeDecl attrDecl; + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + // get name, uri, localpart + String attrRName = (String) entry.getKey(); + String attrURI = attrRName.substring(0,attrRName.indexOf(',')); + String attrLocal = attrRName.substring(attrRName.indexOf(',')+1); + // find associated grammar + SchemaGrammar sGrammar = grammarBucket.getGrammar(attrURI); + if (sGrammar == null) { + continue; + } + // and get the datatype validator, if there is one + attrDecl = sGrammar.getGlobalAttributeDecl(attrLocal); + if (attrDecl == null) { + continue; + } + XSSimpleType dv = (XSSimpleType)attrDecl.getTypeDefinition(); + if (dv == null) { + continue; + } + + // get all values appeared with this attribute name + Vector values = (Vector) entry.getValue(); + String elName; + String attrName = (String)values.elementAt(0); + // for each of the values + int count = values.size(); + for (int i = 1; i < count; i += 2) { + elName = (String)values.elementAt(i); + try { + // and validate it using the XSSimpleType + // REVISIT: what would be the proper validation context? + // guess we need to save that in the vectors too. + dv.validate((String)values.elementAt(i+1), null, null); + } catch(InvalidDatatypeValueException ide) { + reportSchemaError ("s4s-att-invalid-value", + new Object[] {elName, attrName, ide.getMessage()}, + null); + } + } + } + } + + // normalize the string according to the whiteSpace facet + public static String normalize(String content, short ws) { + int len = content == null ? 0 : content.length(); + if (len == 0 || ws == XSSimpleType.WS_PRESERVE) + return content; + + StringBuffer sb = new StringBuffer(); + if (ws == XSSimpleType.WS_REPLACE) { + char ch; + // when it's replace, just replace #x9, #xa, #xd by #x20 + for (int i = 0; i < len; i++) { + ch = content.charAt(i); + if (ch != 0x9 && ch != 0xa && ch != 0xd) + sb.append(ch); + else + sb.append((char)0x20); + } + } else { + char ch; + int i; + boolean isLeading = true; + // when it's collapse + for (i = 0; i < len; i++) { + ch = content.charAt(i); + // append real characters, so we passed leading ws + if (ch != 0x9 && ch != 0xa && ch != 0xd && ch != 0x20) { + sb.append(ch); + isLeading = false; + } + else { + // for whitespaces, we skip all following ws + for (; i < len-1; i++) { + ch = content.charAt(i+1); + if (ch != 0x9 && ch != 0xa && ch != 0xd && ch != 0x20) + break; + } + // if it's not a leading or tailing ws, then append a space + if (i < len - 1 && !isLeading) + sb.append((char)0x20); + } + } + } + + return sb.toString(); + } + + // the following part implements an attribute-value-array pool. + // when checkAttribute is called, it calls getAvailableArray to get + // an array from the pool; when the caller is done with the array, + // it calls returnAttrArray to return that array to the pool. + + // initial size of the array pool. 10 is big enough + static final int INIT_POOL_SIZE = 10; + // the incremental size of the array pool + static final int INC_POOL_SIZE = 10; + // the array pool + Object[][] fArrayPool = new Object[INIT_POOL_SIZE][ATTIDX_COUNT]; + // used to clear the returned array + // I think System.arrayCopy is more efficient than setting 35 fields to null + private static Object[] fTempArray = new Object[ATTIDX_COUNT]; + // current position of the array pool (# of arrays not returned) + int fPoolPos = 0; + + // get the next available array + protected Object[] getAvailableArray() { + // if no array left in the pool, increase the pool size + if (fArrayPool.length == fPoolPos) { + // increase size + fArrayPool = new Object[fPoolPos+INC_POOL_SIZE][]; + // initialize each *new* array + for (int i = fPoolPos; i < fArrayPool.length; i++) + fArrayPool[i] = new Object[ATTIDX_COUNT]; + } + // get the next available one + Object[] retArray = fArrayPool[fPoolPos]; + // clear it from the pool. this is for GC: if a caller forget to + // return the array, we want that array to be GCed. + fArrayPool[fPoolPos++] = null; + // to make sure that one array is not returned twice, we use + // the last entry to indicate whether an array is already returned + // now set it to false. + System.arraycopy(fTempArray, 0, retArray, 0, ATTIDX_COUNT-1); + retArray[ATTIDX_ISRETURNED] = Boolean.FALSE; + + return retArray; + } + + // return an array back to the pool + public void returnAttrArray(Object[] attrArray, XSDocumentInfo schemaDoc) { + // pop the namespace context + if (schemaDoc != null) + schemaDoc.fNamespaceSupport.popContext(); + + // if 1. the pool is full; 2. the array is null; + // 3. the array is of wrong size; 4. the array is already returned + // then we can't accept this array to be returned + if (fPoolPos == 0 || + attrArray == null || + attrArray.length != ATTIDX_COUNT || + ((Boolean)attrArray[ATTIDX_ISRETURNED]).booleanValue()) { + return; + } + + // mark this array as returned + attrArray[ATTIDX_ISRETURNED] = Boolean.TRUE; + // better clear nonschema vector + if(attrArray[ATTIDX_NONSCHEMA] != null) + ((Vector)attrArray[ATTIDX_NONSCHEMA]).clear(); + // and put it into the pool + fArrayPool[--fPoolPos] = attrArray; + } + + public void resolveNamespace(Element element, Attr[] attrs, + SchemaNamespaceSupport nsSupport) { + // push the namespace context + nsSupport.pushContext(); + + // search for new namespace bindings + int length = attrs.length; + Attr sattr = null; + String rawname, prefix, uri; + for (int i = 0; i < length; i++) { + sattr = attrs[i]; + rawname = DOMUtil.getName(sattr); + prefix = null; + if (rawname.equals(XMLSymbols.PREFIX_XMLNS)) + prefix = XMLSymbols.EMPTY_STRING; + else if (rawname.startsWith("xmlns:")) + prefix = fSymbolTable.addSymbol(DOMUtil.getLocalName(sattr)); + if (prefix != null) { + uri = fSymbolTable.addSymbol(DOMUtil.getValue(sattr)); + nsSupport.declarePrefix(prefix, uri.length()!=0 ? uri : null); + } + } + } +} + +class OneAttr { + // name of the attribute + public String name; + // index of the datatype validator + public int dvIndex; + // whether it's optional, and has default value + public int valueIndex; + // the default value of this attribute + public Object dfltValue; + + public OneAttr(String name, int dvIndex, int valueIndex, Object dfltValue) { + this.name = name; + this.dvIndex = dvIndex; + this.valueIndex = valueIndex; + this.dfltValue = dfltValue; + } +} + +abstract class Container { + static final int THRESHOLD = 5; + static Container getContainer(int size) { + if (size > THRESHOLD) + return new LargeContainer(size); + else + return new SmallContainer(size); + } + abstract void put(String key, OneAttr value); + abstract OneAttr get(String key); + + OneAttr[] values; + int pos = 0; +} + +class SmallContainer extends Container { + String[] keys; + SmallContainer(int size) { + keys = new String[size]; + values = new OneAttr[size]; + } + void put(String key, OneAttr value) { + keys[pos] = key; + values[pos++] = value; + } + OneAttr get(String key) { + for (int i = 0; i < pos; i++) { + if (keys[i].equals(key)) { + return values[i]; + } + } + return null; + } +} + +class LargeContainer extends Container { + Hashtable items; + LargeContainer(int size) { + items = new Hashtable(size*2+1); + values = new OneAttr[size]; + } + void put(String key, OneAttr value) { + items.put(key, value); + values[pos++] = value; + } + OneAttr get(String key) { + OneAttr ret = (OneAttr)items.get(key); + return ret; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractIDConstraintTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractIDConstraintTraverser.java new file mode 100644 index 0000000..a9e7ddc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractIDConstraintTraverser.java @@ -0,0 +1,192 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xpath.XPathException; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.identity.Field; +import org.apache.xerces.impl.xs.identity.IdentityConstraint; +import org.apache.xerces.impl.xs.identity.Selector; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.XMLChar; +import org.w3c.dom.Element; + +/** + * This class contains code that all three IdentityConstraint + * traversers (the XSDUniqueTraverser, XSDKeyTraverser and + * XSDKeyrefTraverser) rely upon. + * + * @xerces.internal + * + * @version $Id$ + */ +class XSDAbstractIDConstraintTraverser extends XSDAbstractTraverser { + + public XSDAbstractIDConstraintTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + boolean traverseIdentityConstraint(IdentityConstraint ic, + Element icElem, XSDocumentInfo schemaDoc, Object [] icElemAttrs) { + + // General Attribute Checking will have been done on icElem by caller + + // check for and get selector + Element sElem = DOMUtil.getFirstChildElement(icElem); + if(sElem == null) { + reportSchemaError("s4s-elt-must-match.2", + new Object[]{"identity constraint", "(annotation?, selector, field+)"}, + icElem); + return false; + } + + // General Attribute Checking on sElem + // first child could be an annotation + if (DOMUtil.getLocalName(sElem).equals(SchemaSymbols.ELT_ANNOTATION)) { + ic.addAnnotation(traverseAnnotationDecl(sElem, icElemAttrs, false, schemaDoc)); + sElem = DOMUtil.getNextSiblingElement(sElem); + // if no more children report an error + if(sElem == null) { + reportSchemaError("s4s-elt-must-match.2", new Object[]{"identity constraint", "(annotation?, selector, field+)"}, icElem); + return false; + } + } + else { + String text = DOMUtil.getSyntheticAnnotation(icElem); + if (text != null) { + ic.addAnnotation(traverseSyntheticAnnotation(icElem, text, icElemAttrs, false, schemaDoc)); + } + } + + // must be + if(!DOMUtil.getLocalName(sElem).equals(SchemaSymbols.ELT_SELECTOR)) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{"identity constraint", "(annotation?, selector, field+)", SchemaSymbols.ELT_SELECTOR}, sElem); + return false; + } + Object [] attrValues = fAttrChecker.checkAttributes(sElem, false, schemaDoc); + + // make sure 's content is fine: + Element selChild = DOMUtil.getFirstChildElement(sElem); + + if (selChild !=null) { + // traverse annotation if any + if (DOMUtil.getLocalName(selChild).equals(SchemaSymbols.ELT_ANNOTATION)) { + ic.addAnnotation(traverseAnnotationDecl(selChild, attrValues, false, schemaDoc)); + selChild = DOMUtil.getNextSiblingElement(selChild); + } + else { + reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_SELECTOR, "(annotation?)", DOMUtil.getLocalName(selChild)}, selChild); + } + if (selChild != null) { + reportSchemaError("s4s-elt-must-match.1", new Object [] {SchemaSymbols.ELT_SELECTOR, "(annotation?)", DOMUtil.getLocalName(selChild)}, selChild); + } + } + else { + String text = DOMUtil.getSyntheticAnnotation(sElem); + if (text != null) { + ic.addAnnotation(traverseSyntheticAnnotation(icElem, text, attrValues, false, schemaDoc)); + } + } + + String sText = ((String)attrValues[XSAttributeChecker.ATTIDX_XPATH]); + if(sText == null) { + reportSchemaError("s4s-att-must-appear", new Object [] {SchemaSymbols.ELT_SELECTOR, SchemaSymbols.ATT_XPATH}, sElem); + return false; + } + sText = XMLChar.trim(sText); + + Selector.XPath sXpath = null; + try { + sXpath = new Selector.XPath(sText, fSymbolTable, + schemaDoc.fNamespaceSupport); + Selector selector = new Selector(sXpath, ic); + ic.setSelector(selector); + } + catch (XPathException e) { + reportSchemaError(e.getKey(), new Object[]{sText}, sElem); + // put back attr values... + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return false; + } + + // put back attr values... + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + // get fields + Element fElem = DOMUtil.getNextSiblingElement(sElem); + if(fElem == null) { + reportSchemaError("s4s-elt-must-match.2", new Object[]{"identity constraint", "(annotation?, selector, field+)"}, sElem); + return false; + } + while (fElem != null) { + if(!DOMUtil.getLocalName(fElem).equals(SchemaSymbols.ELT_FIELD)) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{"identity constraint", "(annotation?, selector, field+)", SchemaSymbols.ELT_FIELD}, fElem); + fElem = DOMUtil.getNextSiblingElement(fElem); + continue; + } + + // General Attribute Checking + attrValues = fAttrChecker.checkAttributes(fElem, false, schemaDoc); + + // and make sure 's content is fine: + Element fieldChild = DOMUtil.getFirstChildElement(fElem); + if (fieldChild != null) { + // traverse annotation + if (DOMUtil.getLocalName(fieldChild).equals(SchemaSymbols.ELT_ANNOTATION)) { + ic.addAnnotation(traverseAnnotationDecl(fieldChild, attrValues, false, schemaDoc)); + fieldChild = DOMUtil.getNextSiblingElement(fieldChild); + } + } + if (fieldChild != null) { + reportSchemaError("s4s-elt-must-match.1", new Object [] {SchemaSymbols.ELT_FIELD, "(annotation?)", DOMUtil.getLocalName(fieldChild)}, fieldChild); + } + else { + String text = DOMUtil.getSyntheticAnnotation(fElem); + if (text != null) { + ic.addAnnotation(traverseSyntheticAnnotation(icElem, text, attrValues, false, schemaDoc)); + } + } + String fText = ((String)attrValues[XSAttributeChecker.ATTIDX_XPATH]); + if (fText == null) { + reportSchemaError("s4s-att-must-appear", new Object [] {SchemaSymbols.ELT_FIELD, SchemaSymbols.ATT_XPATH}, fElem); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return false; + } + fText = XMLChar.trim(fText); + try { + Field.XPath fXpath = new Field.XPath(fText, fSymbolTable, + schemaDoc.fNamespaceSupport); + Field field = new Field(fXpath, ic); + ic.addField(field); + } + catch (XPathException e) { + reportSchemaError(e.getKey(), new Object[]{fText}, fElem); + // put back attr values... + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return false; + } + fElem = DOMUtil.getNextSiblingElement(fElem); + // put back attr values... + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + } + + return ic.getFieldCount() > 0; + } // traverseIdentityConstraint(IdentityConstraint,Element, XSDocumentInfo) +} // XSDAbstractIDConstraintTraverser + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractParticleTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractParticleTraverser.java new file mode 100644 index 0000000..747ae50 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractParticleTraverser.java @@ -0,0 +1,382 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSModelGroupImpl; +import org.apache.xerces.impl.xs.XSParticleDecl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.xs.XSObject; +import org.apache.xerces.xs.XSObjectList; +import org.w3c.dom.Element; + +/** + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Sandy Gao, IBM + * @version $Id$ + */ +abstract class XSDAbstractParticleTraverser extends XSDAbstractTraverser { + + XSDAbstractParticleTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + /** + * + * Traverse the "All" declaration + * + * <all + * id = ID + * maxOccurs = 1 : 1 + * minOccurs = (0 | 1) : 1> + * Content: (annotation? , element*) + * </all> + **/ + XSParticleDecl traverseAll(Element allDecl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + int allContextFlags, + XSObject parent) { + + // General Attribute Checking + + Object[] attrValues = fAttrChecker.checkAttributes(allDecl, false, schemaDoc); + + Element child = DOMUtil.getFirstChildElement(allDecl); + + XSAnnotationImpl annotation = null; + if (child !=null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(allDecl); + if (text != null) { + annotation = traverseSyntheticAnnotation(allDecl, text, attrValues, false, schemaDoc); + } + } + String childName = null; + XSParticleDecl particle; + fPArray.pushContext(); + + for (; child != null; child = DOMUtil.getNextSiblingElement(child)) { + + particle = null; + childName = DOMUtil.getLocalName(child); + + // Only elements are allowed in + if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { + particle = fSchemaHandler.fElementTraverser.traverseLocal(child, schemaDoc, grammar, PROCESSING_ALL_EL, parent); + } + else { + Object[] args = {"all", "(annotation?, element*)", DOMUtil.getLocalName(child)}; + reportSchemaError("s4s-elt-must-match.1", args, child); + } + + if (particle != null) + fPArray.addParticle(particle); + } + + particle = null; + XInt minAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MINOCCURS]; + XInt maxAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS]; + Long defaultVals = (Long)attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT]; + + XSModelGroupImpl group = new XSModelGroupImpl(); + group.fCompositor = XSModelGroupImpl.MODELGROUP_ALL; + group.fParticleCount = fPArray.getParticleCount(); + group.fParticles = fPArray.popContext(); + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl)annotations).addXSObject (annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + group.fAnnotations = annotations; + particle = new XSParticleDecl(); + particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; + particle.fMinOccurs = minAtt.intValue(); + particle.fMaxOccurs = maxAtt.intValue(); + particle.fValue = group; + particle.fAnnotations = annotations; + + particle = checkOccurrences(particle, + SchemaSymbols.ELT_ALL, + (Element)allDecl.getParentNode(), + allContextFlags, + defaultVals.longValue()); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return particle; + } + + /** + * Traverse the Sequence declaration + * + * + * Content: (annotation? , (element | group | choice | sequence | any)*) + * + * + * @param seqDecl + * @param schemaDoc + * @param grammar + * @return + */ + XSParticleDecl traverseSequence(Element seqDecl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + int allContextFlags, + XSObject parent) { + + return traverseSeqChoice(seqDecl, schemaDoc, grammar, allContextFlags, false, parent); + } + + /** + * Traverse the Choice declaration + * + * + * Content: (annotation? , (element | group | choice | sequence | any)*) + * + * + * @param choiceDecl + * @param schemaDoc + * @param grammar + * @return + */ + XSParticleDecl traverseChoice(Element choiceDecl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + int allContextFlags, + XSObject parent) { + + return traverseSeqChoice (choiceDecl, schemaDoc, grammar, allContextFlags, true, parent); + } + + /** + * Common traversal for and + * + * @param decl + * @param schemaDoc + * @param grammar + * @param choice If traversing this parameter is true. + * @return + */ + private XSParticleDecl traverseSeqChoice(Element decl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + int allContextFlags, + boolean choice, + XSObject parent) { + + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(decl, false, schemaDoc); + + Element child = DOMUtil.getFirstChildElement(decl); + XSAnnotationImpl annotation = null; + if (child !=null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(decl); + if (text != null) { + annotation = traverseSyntheticAnnotation(decl, text, attrValues, false, schemaDoc); + } + } + + String childName = null; + XSParticleDecl particle; + fPArray.pushContext(); + + for (;child != null;child = DOMUtil.getNextSiblingElement(child)) { + + particle = null; + + childName = DOMUtil.getLocalName(child); + if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { + particle = fSchemaHandler.fElementTraverser.traverseLocal(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent); + } + else if (childName.equals(SchemaSymbols.ELT_GROUP)) { + particle = fSchemaHandler.fGroupTraverser.traverseLocal(child, schemaDoc, grammar); + + // A content type of all can only appear + // as the content type of a complex type definition. + if (hasAllContent(particle)) { + // don't insert the "all" particle, otherwise we won't be + // able to create DFA from this content model + particle = null; + reportSchemaError("cos-all-limited.1.2", null, child); + } + + } + else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { + particle = traverseChoice(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent); + } + else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { + particle = traverseSequence(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent); + } + else if (childName.equals(SchemaSymbols.ELT_ANY)) { + particle = fSchemaHandler.fWildCardTraverser.traverseAny(child, schemaDoc, grammar); + } + else { + Object [] args; + if (choice) { + args = new Object[]{"choice", "(annotation?, (element | group | choice | sequence | any)*)", DOMUtil.getLocalName(child)}; + } + else { + args = new Object[]{"sequence", "(annotation?, (element | group | choice | sequence | any)*)", DOMUtil.getLocalName(child)}; + } + reportSchemaError("s4s-elt-must-match.1", args, child); + } + + if (particle != null) + fPArray.addParticle(particle); + } + + particle = null; + + XInt minAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MINOCCURS]; + XInt maxAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS]; + Long defaultVals = (Long)attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT]; + + XSModelGroupImpl group = new XSModelGroupImpl(); + group.fCompositor = choice ? XSModelGroupImpl.MODELGROUP_CHOICE : XSModelGroupImpl.MODELGROUP_SEQUENCE; + group.fParticleCount = fPArray.getParticleCount(); + group.fParticles = fPArray.popContext(); + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl)annotations).addXSObject (annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + group.fAnnotations = annotations; + particle = new XSParticleDecl(); + particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; + particle.fMinOccurs = minAtt.intValue(); + particle.fMaxOccurs = maxAtt.intValue(); + particle.fValue = group; + particle.fAnnotations = annotations; + + particle = checkOccurrences(particle, + choice ? SchemaSymbols.ELT_CHOICE : SchemaSymbols.ELT_SEQUENCE, + (Element)decl.getParentNode(), + allContextFlags, + defaultVals.longValue()); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return particle; + } + + // Determines whether a content spec tree represents an "all" content model + protected boolean hasAllContent(XSParticleDecl particle) { + // If the content is not empty, is the top node ALL? + if (particle != null && particle.fType == XSParticleDecl.PARTICLE_MODELGROUP) { + return ((XSModelGroupImpl)particle.fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL; + } + + return false; + } + + // the inner class: used to store particles for model groups + // to avoid creating a new Vector in each model group, or when traversing + // each model group, we use this one big array to store all particles + // for model groups. when the traversal finishes, this class returns an + // XSParticleDecl[] containing all particles for the current model group. + // it's possible that we need to traverse another model group while + // traversing one (one inside another one; referring to a global group, + // etc.), so we have push/pos context methods to save the same of the + // current traversal before starting the traversal of another model group. + static class ParticleArray { + // big array to contain all particles + XSParticleDecl[] fParticles = new XSParticleDecl[10]; + // the ending position of particles in the array for each context + // index 0 is reserved, with value 0. index 1 is used for the fist + // context. so that the number of particles for context 'i' can be + // computed simply by fPos[i] - fPos[i-1]. + int[] fPos = new int[5]; + // number of contexts + int fContextCount = 0; + + // start a new context (start traversing a new model group) + void pushContext() { + fContextCount++; + // resize position array if necessary + if (fContextCount == fPos.length) { + int newSize = fContextCount * 2; + int[] newArray = new int[newSize]; + System.arraycopy(fPos, 0, newArray, 0, fContextCount); + fPos = newArray; + } + // the initial ending position of the current context is the + // ending position of the previsous context. which means there is + // no particle for the current context yet. + fPos[fContextCount] = fPos[fContextCount-1]; + } + + // get the number of particles of this context (model group) + int getParticleCount() { + return fPos[fContextCount] - fPos[fContextCount-1]; + } + + // add a particle to the current context + void addParticle(XSParticleDecl particle) { + // resize the particle array if necessary + if (fPos[fContextCount] == fParticles.length) { + int newSize = fPos[fContextCount] * 2; + XSParticleDecl[] newArray = new XSParticleDecl[newSize]; + System.arraycopy(fParticles, 0, newArray, 0, fPos[fContextCount]); + fParticles = newArray; + } + fParticles[fPos[fContextCount]++] = particle; + } + + // end the current context, and return an array of particles + XSParticleDecl[] popContext() { + int count = fPos[fContextCount] - fPos[fContextCount-1]; + XSParticleDecl[] array = null; + if (count != 0) { + array = new XSParticleDecl[count]; + System.arraycopy(fParticles, fPos[fContextCount-1], array, 0, count); + // clear the particle array, to release memory + for (int i = fPos[fContextCount-1]; i < fPos[fContextCount]; i++) + fParticles[i] = null; + } + fContextCount--; + return array; + } + + } + + // the big particle array to hold all particles in model groups + ParticleArray fPArray = new ParticleArray(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractTraverser.java new file mode 100644 index 0000000..29a4f99 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAbstractTraverser.java @@ -0,0 +1,996 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import java.util.Locale; +import java.util.Vector; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.XSFacets; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.dv.util.Base64; +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.validation.ValidationState; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSAttributeGroupDecl; +import org.apache.xerces.impl.xs.XSAttributeUseImpl; +import org.apache.xerces.impl.xs.XSComplexTypeDecl; +import org.apache.xerces.impl.xs.XSElementDecl; +import org.apache.xerces.impl.xs.XSParticleDecl; +import org.apache.xerces.impl.xs.XSWildcardDecl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSAttributeUse; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.Element; + +/** + * Class XSDAbstractTraverser serves as the base class for all + * other XSD???Traversers. It holds the common data and provides + * a unified way to initialize these data. + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Rahul Srivastava, Sun Microsystems Inc. + * @author Neeraj Bajaj, Sun Microsystems Inc. + * + * @version $Id$ + */ +abstract class XSDAbstractTraverser { + + protected static final String NO_NAME = "(no name)"; + + // Flags for checkOccurrences to indicate any special + // restrictions on minOccurs and maxOccurs relating to "all". + // NOT_ALL_CONTEXT - not processing an + // PROCESSING_ALL_EL - processing an in an + // GROUP_REF_WITH_ALL - processing reference that contained + // CHILD_OF_GROUP - processing a child of a model group definition + // PROCESSING_ALL_GP - processing an group itself + + protected static final int NOT_ALL_CONTEXT = 0; + protected static final int PROCESSING_ALL_EL = 1; + protected static final int GROUP_REF_WITH_ALL = 2; + protected static final int CHILD_OF_GROUP = 4; + protected static final int PROCESSING_ALL_GP = 8; + + //Shared data + protected XSDHandler fSchemaHandler = null; + protected SymbolTable fSymbolTable = null; + protected XSAttributeChecker fAttrChecker = null; + protected boolean fValidateAnnotations = false; + + // used to validate default/fixed attribute values + ValidationState fValidationState = new ValidationState(); + + XSDAbstractTraverser (XSDHandler handler, + XSAttributeChecker attrChecker) { + fSchemaHandler = handler; + fAttrChecker = attrChecker; + } + + void reset(SymbolTable symbolTable, boolean validateAnnotations, Locale locale) { + fSymbolTable = symbolTable; + fValidateAnnotations = validateAnnotations; + fValidationState.setExtraChecking(false); + fValidationState.setSymbolTable(symbolTable); + fValidationState.setLocale(locale); + } + + // traverse the annotation declaration + // REVISIT: how to pass the parentAttrs? as DOM attributes? + // as name/value pairs (string)? in parsed form? + // @return XSAnnotationImpl object + XSAnnotationImpl traverseAnnotationDecl(Element annotationDecl, Object[] parentAttrs, + boolean isGlobal, XSDocumentInfo schemaDoc) { + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(annotationDecl, isGlobal, schemaDoc); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + String contents = DOMUtil.getAnnotation(annotationDecl); + Element child = DOMUtil.getFirstChildElement(annotationDecl); + if (child != null) { + do { + String name = DOMUtil.getLocalName(child); + + // the only valid children of "annotation" are + // "appinfo" and "documentation" + if (!((name.equals(SchemaSymbols.ELT_APPINFO)) || + (name.equals(SchemaSymbols.ELT_DOCUMENTATION)))) { + reportSchemaError("src-annotation", new Object[]{name}, child); + } + else { + // General Attribute Checking + // There is no difference between global or local appinfo/documentation, + // so we assume it's always global. + attrValues = fAttrChecker.checkAttributes(child, true, schemaDoc); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + } + + child = DOMUtil.getNextSiblingElement(child); + } + while (child != null); + } + // if contents was null, must have been some kind of error; + // nothing to contribute to PSVI + if (contents == null) return null; + + // find the grammar; fSchemaHandler must be known! + SchemaGrammar grammar = fSchemaHandler.getGrammar(schemaDoc.fTargetNamespace); + // fish out local attributes passed from parent + Vector annotationLocalAttrs = (Vector)parentAttrs[XSAttributeChecker.ATTIDX_NONSCHEMA]; + // optimize for case where there are no local attributes + if(annotationLocalAttrs != null && !annotationLocalAttrs.isEmpty()) { + StringBuffer localStrBuffer = new StringBuffer(64); + localStrBuffer.append(" "); + // Vector should contain rawname value pairs + int i = 0; + while (i < annotationLocalAttrs.size()) { + String rawname = (String)annotationLocalAttrs.elementAt(i++); + int colonIndex = rawname.indexOf(':'); + String prefix, localpart; + if (colonIndex == -1) { + prefix = ""; + localpart = rawname; + } + else { + prefix = rawname.substring(0,colonIndex); + localpart = rawname.substring(colonIndex+1); + } + String uri = schemaDoc.fNamespaceSupport.getURI(fSymbolTable.addSymbol(prefix)); + if (annotationDecl.getAttributeNS(uri, localpart).length() != 0) { + i++; // skip the next value, too + continue; + } + localStrBuffer.append(rawname) + .append("=\""); + String value = (String)annotationLocalAttrs.elementAt(i++); + // search for pesky "s and xsFacets.maxLength) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_MAXLENGTH, typeName}, contextNode); + } + } + } + else if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(baseValidator.getNamespace()) && + SchemaSymbols.ATTVAL_BASE64BINARY.equals(baseValidator.getName())) { + for (int enumIdx = 0; enumIdx < enumData.size(); enumIdx++) { + String enumVal = ((String)enumData.get(enumIdx)); + byte[] decodedVal = Base64.decode(enumVal); + if (decodedVal != null && (new String(decodedVal)).length() > xsFacets.maxLength) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_MAXLENGTH, typeName}, contextNode); + } + } + } + else { + for (int enumIdx = 0; enumIdx < enumData.size(); enumIdx++) { + String enumVal = ((String)enumData.get(enumIdx)); + if (enumVal.length() > xsFacets.maxLength) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_MAXLENGTH, typeName}, contextNode); + } + } + } + } // checkEnumerationAndMaxLengthInconsistency + + /* + * Check whether values of xs:minLength and xs:enumeration are consistent. Report a warning message if they are not. + */ + private void checkEnumerationAndMinLengthInconsistency(XSSimpleType baseValidator, Vector enumData, Element contextNode, String typeName) { + if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(baseValidator.getNamespace()) && + SchemaSymbols.ATTVAL_HEXBINARY.equals(baseValidator.getName())) { + for (int enumIdx = 0; enumIdx < enumData.size(); enumIdx++) { + String enumVal = ((String)enumData.get(enumIdx)); + if (enumVal.length() / 2 < xsFacets.minLength) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_MINLENGTH, typeName}, contextNode); + } + } + } + else if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(baseValidator.getNamespace()) && + SchemaSymbols.ATTVAL_BASE64BINARY.equals(baseValidator.getName())) { + for (int enumIdx = 0; enumIdx < enumData.size(); enumIdx++) { + String enumVal = ((String)enumData.get(enumIdx)); + byte[] decodedVal = Base64.decode(enumVal); + if (decodedVal != null && (new String(decodedVal)).length() < xsFacets.minLength) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_MINLENGTH, typeName}, contextNode); + } + } + } + else { + for (int enumIdx = 0; enumIdx < enumData.size(); enumIdx++) { + String enumVal = ((String)enumData.get(enumIdx)); + if (enumVal.length() < xsFacets.minLength) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_MINLENGTH, typeName}, contextNode); + } + } + } + } // checkEnumerationAndMinLengthInconsistency + + /* + * Check whether values of xs:length and xs:enumeration are consistent. Report a warning message if they are not. + */ + private void checkEnumerationAndLengthInconsistency(XSSimpleType baseValidator, Vector enumData, Element contextNode, String typeName) { + if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(baseValidator.getNamespace()) && + SchemaSymbols.ATTVAL_HEXBINARY.equals(baseValidator.getName())) { + for (int enumIdx = 0; enumIdx < enumData.size(); enumIdx++) { + String enumVal = ((String)enumData.get(enumIdx)); + if (enumVal.length() / 2 != xsFacets.length) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_LENGTH, typeName}, contextNode); + } + } + } + else if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(baseValidator.getNamespace()) && + SchemaSymbols.ATTVAL_BASE64BINARY.equals(baseValidator.getName())) { + for (int enumIdx = 0; enumIdx < enumData.size(); enumIdx++) { + String enumVal = ((String)enumData.get(enumIdx)); + byte[] decodedVal = Base64.decode(enumVal); + if (decodedVal != null && (new String(decodedVal)).length() != xsFacets.length) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_LENGTH, typeName}, contextNode); + } + } + } + else { + for (int enumIdx = 0; enumIdx < enumData.size(); enumIdx++) { + String enumVal = ((String)enumData.get(enumIdx)); + if (enumVal.length() != xsFacets.length) { + reportSchemaWarning("FacetsContradict", new Object[]{enumVal, SchemaSymbols.ELT_LENGTH, typeName}, contextNode); + } + } + } + } // checkEnumerationAndLengthInconsistency + + + // return whether QName/NOTATION is part of the given type + private boolean containsQName(XSSimpleType type) { + if (type.getVariety() == XSSimpleType.VARIETY_ATOMIC) { + short primitive = type.getPrimitiveKind(); + return (primitive == XSSimpleType.PRIMITIVE_QNAME || + primitive == XSSimpleType.PRIMITIVE_NOTATION); + } + else if (type.getVariety() == XSSimpleType.VARIETY_LIST) { + return containsQName((XSSimpleType)type.getItemType()); + } + else if (type.getVariety() == XSSimpleType.VARIETY_UNION) { + XSObjectList members = type.getMemberTypes(); + for (int i = 0; i < members.getLength(); i++) { + if (containsQName((XSSimpleType)members.item(i))) + return true; + } + } + return false; + } + + // + // Traverse a set of attribute and attribute group elements + // Needed by complexType and attributeGroup traversal + // This method will return the first non-attribute/attrgrp found + // + Element traverseAttrsAndAttrGrps(Element firstAttr, XSAttributeGroupDecl attrGrp, + XSDocumentInfo schemaDoc, SchemaGrammar grammar, + XSComplexTypeDecl enclosingCT) { + + Element child=null; + XSAttributeGroupDecl tempAttrGrp = null; + XSAttributeUseImpl tempAttrUse = null; + XSAttributeUse otherUse = null; + String childName; + + for (child=firstAttr; child!=null; child=DOMUtil.getNextSiblingElement(child)) { + childName = DOMUtil.getLocalName(child); + if (childName.equals(SchemaSymbols.ELT_ATTRIBUTE)) { + tempAttrUse = fSchemaHandler.fAttributeTraverser.traverseLocal(child, + schemaDoc, + grammar, + enclosingCT); + if (tempAttrUse == null) continue; + if (tempAttrUse.fUse == SchemaSymbols.USE_PROHIBITED) { + attrGrp.addAttributeUse(tempAttrUse); + continue; + } + otherUse = attrGrp.getAttributeUseNoProhibited( + tempAttrUse.fAttrDecl.getNamespace(), + tempAttrUse.fAttrDecl.getName()); + if (otherUse==null) { + String idName = attrGrp.addAttributeUse(tempAttrUse); + if (idName != null) { + String code = (enclosingCT == null) ? "ag-props-correct.3" : "ct-props-correct.5"; + String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName(); + reportSchemaError(code, new Object[]{name, tempAttrUse.fAttrDecl.getName(), idName}, child); + } + } + else if (otherUse != tempAttrUse) { + String code = (enclosingCT == null) ? "ag-props-correct.2" : "ct-props-correct.4"; + String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName(); + reportSchemaError(code, new Object[]{name, tempAttrUse.fAttrDecl.getName()}, child); + } + } + else if (childName.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { + //REVISIT: do we need to save some state at this point?? + tempAttrGrp = fSchemaHandler.fAttributeGroupTraverser.traverseLocal( + child, schemaDoc, grammar); + if(tempAttrGrp == null ) continue; + XSObjectList attrUseS = tempAttrGrp.getAttributeUses(); + XSAttributeUseImpl oneAttrUse; + int attrCount = attrUseS.getLength(); + for (int i=0; i, minOccurs attribute + // must be zero or one, and maxOccurs attribute must be one. + // For a complex type definition that contains an or a + // reference a whose model group is an all model group, + // minOccurs and maxOccurs must be one. + if (processingAllEl) { + if (max != 1) { + reportSchemaError("cos-all-limited.2", new Object[]{ + (max == SchemaSymbols.OCCURRENCE_UNBOUNDED) ? SchemaSymbols.ATTVAL_UNBOUNDED : Integer.toString(max), + ((XSElementDecl)particle.fValue).getName()}, parent); + max = 1; + if (min > 1) + min = 1; + } + } + else if (processingAllGP || groupRefWithAll) { + if (max != 1) { + reportSchemaError("cos-all-limited.1.2", null, parent); + if (min > 1) + min = 1; + max = 1; + } + } + + particle.fMinOccurs = min; + particle.fMaxOccurs = max; + + return particle; + } + + private static String processAttValue(String original) { + final int length = original.length(); + // normally, nothing will happen + for (int i = 0; i < length; ++i) { + char currChar = original.charAt(i); + if (currChar == '"' || currChar == '<' || currChar == '&' || + currChar == 0x09 || currChar == 0x0A || currChar == 0x0D) { + return escapeAttValue(original, i); + } + } + return original; + } + + // this is not terribly performant! + private static String escapeAttValue(String original, int from) { + int i; + final int length = original.length(); + StringBuffer newVal = new StringBuffer(length); + newVal.append(original.substring(0, from)); + for (i = from; i < length; ++i) { + char currChar = original.charAt(i); + if (currChar == '"') { + newVal.append("""); + } + else if (currChar == '<') { + newVal.append("<"); + } + else if (currChar == '&') { + newVal.append("&"); + } + // Must escape 0x09, 0x0A and 0x0D if they appear in attribute + // value so that they may be round-tripped. They would otherwise + // be transformed to a 0x20 during attribute value normalization. + else if (currChar == 0x09) { + newVal.append(" "); + } + else if (currChar == 0x0A) { + newVal.append(" "); + } + else if (currChar == 0x0D) { + newVal.append(" "); + } + else { + newVal.append(currChar); + } + } + return newVal.toString(); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAttributeGroupTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAttributeGroupTraverser.java new file mode 100644 index 0000000..65744b8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAttributeGroupTraverser.java @@ -0,0 +1,206 @@ +/* + * 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. + */ +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSAttributeGroupDecl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSObjectList; +import org.w3c.dom.Element; + +/** + * The attribute group definition schema component traverser. + * + * <attributeGroup + * id = ID + * name = NCName + * ref = QName + * {any attributes with non-schema namespace . . .}> + * Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?)) + * </attributeGroup> + * + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +class XSDAttributeGroupTraverser extends XSDAbstractTraverser { + + XSDAttributeGroupTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + + super(handler, gAttrCheck); + } + + + XSAttributeGroupDecl traverseLocal(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking for elmNode declared locally + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, false, schemaDoc); + + // get attribute + QName refAttr = (QName) attrValues[XSAttributeChecker.ATTIDX_REF]; + + XSAttributeGroupDecl attrGrp = null; + + // ref should be here. + if (refAttr == null) { + reportSchemaError("s4s-att-must-appear", new Object[]{"attributeGroup (local)", "ref"}, elmNode); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return null; + } + + // get global decl + attrGrp = (XSAttributeGroupDecl)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.ATTRIBUTEGROUP_TYPE, refAttr, elmNode); + + // no children are allowed here except annotation, which is optional. + Element child = DOMUtil.getFirstChildElement(elmNode); + if (child != null) { + String childName = DOMUtil.getLocalName(child); + if (childName.equals(SchemaSymbols.ELT_ANNOTATION)) { + traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } else { + String text = DOMUtil.getSyntheticAnnotation(child); + if (text != null) { + traverseSyntheticAnnotation(child, text, attrValues, false, schemaDoc); + } + } + + if (child != null) { + Object[] args = new Object [] {refAttr.rawname, "(annotation?)", DOMUtil.getLocalName(child)}; + reportSchemaError("s4s-elt-must-match.1", args, child); + } + } // if + + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return attrGrp; + + } // traverseLocal + + XSAttributeGroupDecl traverseGlobal(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + XSAttributeGroupDecl attrGrp = new XSAttributeGroupDecl(); + + // General Attribute Checking for elmNode declared globally + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, true, schemaDoc); + + String nameAttr = (String) attrValues[XSAttributeChecker.ATTIDX_NAME]; + + // global declaration must have a name + if (nameAttr == null) { + reportSchemaError("s4s-att-must-appear", new Object[]{"attributeGroup (global)", "name"}, elmNode); + nameAttr = NO_NAME; + } + + attrGrp.fName = nameAttr; + attrGrp.fTargetNamespace = schemaDoc.fTargetNamespace; + + // check the content + Element child = DOMUtil.getFirstChildElement(elmNode); + XSAnnotationImpl annotation = null; + + if (child!=null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(elmNode); + if (text != null) { + annotation = traverseSyntheticAnnotation(elmNode, text, attrValues, false, schemaDoc); + } + } + + // Traverse the attribute and attribute group elements and fill in the + // attributeGroup structure + + Element nextNode = traverseAttrsAndAttrGrps(child, attrGrp, schemaDoc, grammar, null); + if (nextNode!=null) { + // An invalid element was found... + Object[] args = new Object [] {nameAttr, "(annotation?, ((attribute | attributeGroup)*, anyAttribute?))", DOMUtil.getLocalName(nextNode)}; + reportSchemaError("s4s-elt-must-match.1", args, nextNode); + } + + if (nameAttr.equals(NO_NAME)) { + // if a global group doesn't have a name, then don't add it. + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return null; + } + + // Remove prohibited attributes from the set + attrGrp.removeProhibitedAttrs(); + + // check for restricted redefine: + XSAttributeGroupDecl redefinedAttrGrp = (XSAttributeGroupDecl)fSchemaHandler.getGrpOrAttrGrpRedefinedByRestriction( + XSDHandler.ATTRIBUTEGROUP_TYPE, + new QName(XMLSymbols.EMPTY_STRING, nameAttr, nameAttr, schemaDoc.fTargetNamespace), + schemaDoc, elmNode); + if(redefinedAttrGrp != null) { + Object[] errArgs = attrGrp.validRestrictionOf(nameAttr, redefinedAttrGrp); + if (errArgs != null) { + reportSchemaError((String)errArgs[errArgs.length-1], errArgs, child); + reportSchemaError("src-redefine.7.2.2", new Object [] {nameAttr, errArgs[errArgs.length-1]}, child); + } + } + + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl)annotations).addXSObject (annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + + attrGrp.fAnnotations = annotations; + + // make an entry in global declarations. + if (grammar.getGlobalAttributeGroupDecl(attrGrp.fName) == null) { + grammar.addGlobalAttributeGroupDecl(attrGrp); + } + + // also add it to extended map + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final XSAttributeGroupDecl attrGrp2 = grammar.getGlobalAttributeGroupDecl(attrGrp.fName, loc); + if (attrGrp2 == null) { + grammar.addGlobalAttributeGroupDecl(attrGrp, loc); + } + + // handle duplicates + if (fSchemaHandler.fTolerateDuplicates) { + if (attrGrp2 != null) { + attrGrp = attrGrp2; + } + fSchemaHandler.addGlobalAttributeGroupDecl(attrGrp); + } + + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return attrGrp; + + } // traverseGlobal + +} // XSDAttributeGroupTraverser diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAttributeTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAttributeTraverser.java new file mode 100644 index 0000000..8fd9ef0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDAttributeTraverser.java @@ -0,0 +1,485 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.dv.InvalidDatatypeValueException; +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSAttributeDecl; +import org.apache.xerces.impl.xs.XSAttributeUseImpl; +import org.apache.xerces.impl.xs.XSComplexTypeDecl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.Element; + +/** + * The attribute declaration schema component traverser. + * + * <attribute + * default = string + * fixed = string + * form = (qualified | unqualified) + * id = ID + * name = NCName + * ref = QName + * type = QName + * use = (optional | prohibited | required) : optional + * {any attributes with non-schema namespace . . .}> + * Content: (annotation?, (simpleType?)) + * </attribute> + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @author Neeraj Bajaj, Sun Microsystems, inc. + * @version $Id$ + */ +class XSDAttributeTraverser extends XSDAbstractTraverser { + + public XSDAttributeTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + protected XSAttributeUseImpl traverseLocal(Element attrDecl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + XSComplexTypeDecl enclosingCT) { + + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(attrDecl, false, schemaDoc); + + String defaultAtt = (String) attrValues[XSAttributeChecker.ATTIDX_DEFAULT]; + String fixedAtt = (String) attrValues[XSAttributeChecker.ATTIDX_FIXED]; + String nameAtt = (String) attrValues[XSAttributeChecker.ATTIDX_NAME]; + QName refAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_REF]; + XInt useAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_USE]; + + // get 'attribute declaration' + XSAttributeDecl attribute = null; + XSAnnotationImpl annotation = null; + if (attrDecl.getAttributeNode(SchemaSymbols.ATT_REF) != null) { + if (refAtt != null) { + attribute = (XSAttributeDecl)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.ATTRIBUTE_TYPE, refAtt, attrDecl); + + Element child = DOMUtil.getFirstChildElement(attrDecl); + if (child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(attrDecl); + if (text != null) { + annotation = traverseSyntheticAnnotation(attrDecl, text, attrValues, false, schemaDoc); + } + } + + if (child != null) { + reportSchemaError("src-attribute.3.2", new Object[]{refAtt.rawname}, child); + } + // for error reporting + nameAtt = refAtt.localpart; + } else { + attribute = null; + } + } else { + attribute = traverseNamedAttr(attrDecl, attrValues, schemaDoc, grammar, false, enclosingCT); + } + + // get 'value constraint' + short consType = XSConstants.VC_NONE; + if (defaultAtt != null) { + consType = XSConstants.VC_DEFAULT; + } else if (fixedAtt != null) { + consType = XSConstants.VC_FIXED; + defaultAtt = fixedAtt; + fixedAtt = null; + } + + XSAttributeUseImpl attrUse = null; + if (attribute != null) { + if (fSchemaHandler.fDeclPool !=null) { + attrUse = fSchemaHandler.fDeclPool.getAttributeUse(); + } else { + attrUse = new XSAttributeUseImpl(); + } + attrUse.fAttrDecl = attribute; + attrUse.fUse = useAtt.shortValue(); + attrUse.fConstraintType = consType; + if (defaultAtt != null) { + attrUse.fDefault = new ValidatedInfo(); + attrUse.fDefault.normalizedValue = defaultAtt; + } + // Get the annotation associated witht the local attr decl + if (attrDecl.getAttributeNode(SchemaSymbols.ATT_REF) == null) { + attrUse.fAnnotations = attribute.getAnnotations(); + } else { + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl) annotations).addXSObject(annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + attrUse.fAnnotations = annotations; + } + } + + //src-attribute + + // 1 default and fixed must not both be present. + if (defaultAtt != null && fixedAtt != null) { + reportSchemaError("src-attribute.1", new Object[]{nameAtt}, attrDecl); + } + + // 2 If default and use are both present, use must have the actual value optional. + if (consType == XSConstants.VC_DEFAULT && + useAtt != null && useAtt.intValue() != SchemaSymbols.USE_OPTIONAL) { + reportSchemaError("src-attribute.2", new Object[]{nameAtt}, attrDecl); + // Recover by honouring the default value + attrUse.fUse = SchemaSymbols.USE_OPTIONAL; + } + + // a-props-correct + + if (defaultAtt != null && attrUse != null) { + // 2 if there is a {value constraint}, the canonical lexical representation of its value must be valid with respect to the {type definition} as defined in String Valid (3.14.4). + fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport); + try { + checkDefaultValid(attrUse); + } + catch (InvalidDatatypeValueException ide) { + reportSchemaError (ide.getKey(), ide.getArgs(), attrDecl); + reportSchemaError ("a-props-correct.2", new Object[]{nameAtt, defaultAtt}, attrDecl); + // Recover by removing the default value + attrUse.fDefault = null; + attrUse.fConstraintType = XSConstants.VC_NONE; + } + + // 3 If the {type definition} is or is derived from ID then there must not be a {value constraint}. + if (((XSSimpleType)attribute.getTypeDefinition()).isIDType() ) { + reportSchemaError ("a-props-correct.3", new Object[]{nameAtt}, attrDecl); + // Recover by removing the default value + attrUse.fDefault = null; + attrUse.fConstraintType = XSConstants.VC_NONE; + } + + // check 3.5.6 constraint + // Attribute Use Correct + // 2 If the {attribute declaration} has a fixed {value constraint}, then if the attribute use itself has a {value constraint}, it must also be fixed and its value must match that of the {attribute declaration}'s {value constraint}. + if (attrUse.fAttrDecl.getConstraintType() == XSConstants.VC_FIXED && + attrUse.fConstraintType != XSConstants.VC_NONE) { + if (attrUse.fConstraintType != XSConstants.VC_FIXED || + !attrUse.fAttrDecl.getValInfo().actualValue.equals(attrUse.fDefault.actualValue)) { + reportSchemaError ("au-props-correct.2", new Object[]{nameAtt, attrUse.fAttrDecl.getValInfo().stringValue()}, attrDecl); + // Recover by using the decl's {value constraint} + attrUse.fDefault = attrUse.fAttrDecl.getValInfo(); + attrUse.fConstraintType = XSConstants.VC_FIXED; + } + } + } + + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return attrUse; + } + + protected XSAttributeDecl traverseGlobal(Element attrDecl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(attrDecl, true, schemaDoc); + XSAttributeDecl attribute = traverseNamedAttr(attrDecl, attrValues, schemaDoc, grammar, true, null); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return attribute; + + } + + /** + * Traverse a globally declared attribute. + * + * @param attrDecl + * @param attrValues + * @param schemaDoc + * @param grammar + * @param isGlobal + * @return the attribute declaration index + */ + XSAttributeDecl traverseNamedAttr(Element attrDecl, + Object[] attrValues, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + boolean isGlobal, + XSComplexTypeDecl enclosingCT) { + + String defaultAtt = (String) attrValues[XSAttributeChecker.ATTIDX_DEFAULT]; + String fixedAtt = (String) attrValues[XSAttributeChecker.ATTIDX_FIXED]; + XInt formAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_FORM]; + String nameAtt = (String) attrValues[XSAttributeChecker.ATTIDX_NAME]; + QName typeAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_TYPE]; + + // Step 1: get declaration information + XSAttributeDecl attribute = null; + if (fSchemaHandler.fDeclPool !=null) { + attribute = fSchemaHandler.fDeclPool.getAttributeDecl(); + } else { + attribute = new XSAttributeDecl(); + } + + // get 'name' + if (nameAtt != null) + nameAtt = fSymbolTable.addSymbol(nameAtt); + + // get 'target namespace' + String tnsAtt = null; + XSComplexTypeDecl enclCT = null; + short scope = XSAttributeDecl.SCOPE_ABSENT; + if (isGlobal) { + tnsAtt = schemaDoc.fTargetNamespace; + scope = XSAttributeDecl.SCOPE_GLOBAL; + } + else { + if (enclosingCT != null) { + enclCT = enclosingCT; + scope = XSAttributeDecl.SCOPE_LOCAL; + } + if (formAtt != null) { + if (formAtt.intValue() == SchemaSymbols.FORM_QUALIFIED) + tnsAtt = schemaDoc.fTargetNamespace; + } else if (schemaDoc.fAreLocalAttributesQualified) { + tnsAtt = schemaDoc.fTargetNamespace; + } + } + // get 'value constraint' + // for local named attribute, value constraint is absent + ValidatedInfo attDefault = null; + short constraintType = XSConstants.VC_NONE; + if (isGlobal) { + if (fixedAtt != null) { + attDefault = new ValidatedInfo(); + attDefault.normalizedValue = fixedAtt; + constraintType = XSConstants.VC_FIXED; + } else if (defaultAtt != null) { + attDefault = new ValidatedInfo(); + attDefault.normalizedValue = defaultAtt; + constraintType = XSConstants.VC_DEFAULT; + } + } + + // get 'annotation' + Element child = DOMUtil.getFirstChildElement(attrDecl); + XSAnnotationImpl annotation = null; + if (child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(attrDecl); + if (text != null) { + annotation = traverseSyntheticAnnotation(attrDecl, text, attrValues, false, schemaDoc); + } + } + + // get 'type definition' + XSSimpleType attrType = null; + boolean haveAnonType = false; + + // Handle Anonymous type if there is one + if (child != null) { + String childName = DOMUtil.getLocalName(child); + + if (childName.equals(SchemaSymbols.ELT_SIMPLETYPE)) { + attrType = fSchemaHandler.fSimpleTypeTraverser.traverseLocal(child, schemaDoc, grammar); + haveAnonType = true; + child = DOMUtil.getNextSiblingElement(child); + } + } + + // Handle type attribute + if (attrType == null && typeAtt != null) { + XSTypeDefinition type = (XSTypeDefinition)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.TYPEDECL_TYPE, typeAtt, attrDecl); + if (type != null && type.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { + attrType = (XSSimpleType)type; + } + else { + reportSchemaError("src-resolve", new Object[]{typeAtt.rawname, "simpleType definition"}, attrDecl); + if (type == null) { + attribute.fUnresolvedTypeName = typeAtt; + } + } + } + + if (attrType == null) { + attrType = SchemaGrammar.fAnySimpleType; + } + + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl)annotations).addXSObject(annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + attribute.setValues(nameAtt, tnsAtt, attrType, constraintType, scope, + attDefault, enclCT, annotations); + + // Step 3: check against schema for schemas + + // required attributes + if (nameAtt == null) { + if (isGlobal) + reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_ATTRIBUTE, SchemaSymbols.ATT_NAME}, attrDecl); + else + reportSchemaError("src-attribute.3.1", null, attrDecl); + nameAtt = NO_NAME; + } + + // element + if (child != null) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{nameAtt, "(annotation?, (simpleType?))", DOMUtil.getLocalName(child)}, child); + } + + // Step 4: check 3.2.3 constraints + + // src-attribute + + // 1 default and fixed must not both be present. + if (defaultAtt != null && fixedAtt != null) { + reportSchemaError("src-attribute.1", new Object[]{nameAtt}, attrDecl); + } + + // 2 If default and use are both present, use must have the actual value optional. + // This is checked in "traverse" method + + // 3 If the item's parent is not , then all of the following must be true: + // 3.1 One of ref or name must be present, but not both. + // This is checked in XSAttributeChecker + + // 3.2 If ref is present, then all of , form and type must be absent. + // Attributes are checked in XSAttributeChecker, elements are checked in "traverse" method + + // 4 type and must not both be present. + if (haveAnonType && (typeAtt != null)) { + reportSchemaError( "src-attribute.4", new Object[]{nameAtt}, attrDecl); + } + + // Step 5: check 3.2.6 constraints + // check for NOTATION type + checkNotationType(nameAtt, attrType, attrDecl); + + // a-props-correct + + // 2 if there is a {value constraint}, the canonical lexical representation of its value must be valid with respect to the {type definition} as defined in String Valid (3.14.4). + if (attDefault != null) { + fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport); + try { + checkDefaultValid(attribute); + } + catch (InvalidDatatypeValueException ide) { + reportSchemaError (ide.getKey(), ide.getArgs(), attrDecl); + reportSchemaError ("a-props-correct.2", new Object[]{nameAtt, attDefault.normalizedValue}, attrDecl); + // Recover by removing the default value + attDefault = null; + constraintType = XSConstants.VC_NONE; + attribute.setValues(nameAtt, tnsAtt, attrType, constraintType, scope, + attDefault, enclCT, annotations); + } + } + + // 3 If the {type definition} is or is derived from ID then there must not be a {value constraint}. + if (attDefault != null) { + if (attrType.isIDType() ) { + reportSchemaError ("a-props-correct.3", new Object[]{nameAtt}, attrDecl); + // Recover by removing the default value + attDefault = null; + constraintType = XSConstants.VC_NONE; + attribute.setValues(nameAtt, tnsAtt, attrType, constraintType, scope, + attDefault, enclCT, annotations); + } + } + + // no-xmlns + + // The {name} of an attribute declaration must not match xmlns. + if (nameAtt != null && nameAtt.equals(XMLSymbols.PREFIX_XMLNS)) { + reportSchemaError("no-xmlns", null, attrDecl); + return null; + } + + // no-xsi + + // The {target namespace} of an attribute declaration, whether local or top-level, must not match http://www.w3.org/2001/XMLSchema-instance (unless it is one of the four built-in declarations given in the next section). + if (tnsAtt != null && tnsAtt.equals(SchemaSymbols.URI_XSI)) { + reportSchemaError("no-xsi", new Object[]{SchemaSymbols.URI_XSI}, attrDecl); + return null; + } + + // Attribute without a name. Return null. + if (nameAtt.equals(NO_NAME)) + return null; + + // Step 2: register attribute decl to the grammar + if (isGlobal) { + if (grammar.getGlobalAttributeDecl(nameAtt) == null) { + grammar.addGlobalAttributeDecl(attribute); + } + + // also add it to extended map + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final XSAttributeDecl attribute2 = grammar.getGlobalAttributeDecl(nameAtt, loc); + if (attribute2 == null) { + grammar.addGlobalAttributeDecl(attribute, loc); + } + + if (fSchemaHandler.fTolerateDuplicates) { + if (attribute2 != null) { + attribute = attribute2; + } + fSchemaHandler.addGlobalAttributeDecl(attribute); + } + } + + return attribute; + } + + // throws an error if the constraint value is invalid for the given type + void checkDefaultValid(XSAttributeDecl attribute) throws InvalidDatatypeValueException { + // validate the original lexical rep, and set the actual value + ((XSSimpleType)attribute.getTypeDefinition()).validate(attribute.getValInfo().normalizedValue, fValidationState, attribute.getValInfo()); + // validate the canonical lexical rep + ((XSSimpleType)attribute.getTypeDefinition()).validate(attribute.getValInfo().stringValue(), fValidationState, attribute.getValInfo()); + } + + // throws an error if the constraint value is invalid for the given type + void checkDefaultValid(XSAttributeUseImpl attrUse) throws InvalidDatatypeValueException { + // validate the original lexical rep, and set the actual value + ((XSSimpleType)attrUse.fAttrDecl.getTypeDefinition()).validate(attrUse.fDefault.normalizedValue, fValidationState, attrUse.fDefault); + // validate the canonical lexical rep + ((XSSimpleType)attrUse.fAttrDecl.getTypeDefinition()).validate(attrUse.fDefault.stringValue(), fValidationState, attrUse.fDefault); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDComplexTypeTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDComplexTypeTraverser.java new file mode 100644 index 0000000..b974d06 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDComplexTypeTraverser.java @@ -0,0 +1,1252 @@ +/* + * 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. + */ +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.dv.InvalidDatatypeFacetException; +import org.apache.xerces.impl.dv.XSFacets; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSAttributeGroupDecl; +import org.apache.xerces.impl.xs.XSAttributeUseImpl; +import org.apache.xerces.impl.xs.XSComplexTypeDecl; +import org.apache.xerces.impl.xs.XSConstraints; +import org.apache.xerces.impl.xs.XSModelGroupImpl; +import org.apache.xerces.impl.xs.XSParticleDecl; +import org.apache.xerces.impl.xs.XSWildcardDecl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSAttributeUse; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.Element; + +/** + * A complex type definition schema component traverser. + * + * + * Content: (annotation?, (simpleContent | complexContent | + * ((group | all | choice | sequence)?, + * ((attribute | attributeGroup)*, anyAttribute?)))) + * + * + * @xerces.internal + * + * @version $Id$ + */ + +class XSDComplexTypeTraverser extends XSDAbstractParticleTraverser { + + // size of stack to hold globals: + private final static int GLOBAL_NUM = 11; + + private static XSParticleDecl fErrorContent = null; + private static XSWildcardDecl fErrorWildcard = null; + private static XSParticleDecl getErrorContent() { + if (fErrorContent == null) { + XSParticleDecl particle = new XSParticleDecl(); + particle.fType = XSParticleDecl.PARTICLE_WILDCARD; + particle.fValue = getErrorWildcard(); + particle.fMinOccurs = 0; + particle.fMaxOccurs = SchemaSymbols.OCCURRENCE_UNBOUNDED; + XSModelGroupImpl group = new XSModelGroupImpl(); + group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE; + group.fParticleCount = 1; + group.fParticles = new XSParticleDecl[1]; + group.fParticles[0] = particle; + XSParticleDecl errorContent = new XSParticleDecl(); + errorContent.fType = XSParticleDecl.PARTICLE_MODELGROUP; + errorContent.fValue = group; + fErrorContent = errorContent; + } + return fErrorContent; + } + private static XSWildcardDecl getErrorWildcard() { + if (fErrorWildcard == null) { + XSWildcardDecl wildcard = new XSWildcardDecl(); + wildcard.fProcessContents = XSWildcardDecl.PC_SKIP; + fErrorWildcard = wildcard; + } + return fErrorWildcard; + } + + // globals for building XSComplexTypeDecls + private String fName = null; + private String fTargetNamespace = null; + private short fDerivedBy = XSConstants.DERIVATION_RESTRICTION; + private short fFinal = XSConstants.DERIVATION_NONE; + private short fBlock = XSConstants.DERIVATION_NONE; + private short fContentType = XSComplexTypeDecl.CONTENTTYPE_EMPTY; + private XSTypeDefinition fBaseType = null; + private XSAttributeGroupDecl fAttrGrp = null; + private XSSimpleType fXSSimpleType = null; + private XSParticleDecl fParticle = null; + private boolean fIsAbstract = false; + private XSComplexTypeDecl fComplexTypeDecl = null; + private XSAnnotationImpl [] fAnnotations = null; + + // our own little stack to retain state when getGlobalDecls is called: + private Object [] fGlobalStore = null; + private int fGlobalStorePos = 0; + + XSDComplexTypeTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + + private static final boolean DEBUG=false; + + private static final class ComplexTypeRecoverableError extends Exception { + + private static final long serialVersionUID = 6802729912091130335L; + + Object[] errorSubstText=null; + Element errorElem = null; + ComplexTypeRecoverableError() { + super(); + } + ComplexTypeRecoverableError(String msgKey, Object[] args, Element e) { + super(msgKey); + errorSubstText=args; + errorElem = e; + } + + } + + /** + * Traverse local complexType declarations + * + * @param Element + * @param XSDocumentInfo + * @param SchemaGrammar + * @return XSComplexTypeDecl + */ + XSComplexTypeDecl traverseLocal(Element complexTypeNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + + Object[] attrValues = fAttrChecker.checkAttributes(complexTypeNode, false, + schemaDoc); + String complexTypeName = genAnonTypeName(complexTypeNode); + contentBackup(); + XSComplexTypeDecl type = traverseComplexTypeDecl (complexTypeNode, + complexTypeName, attrValues, schemaDoc, grammar); + contentRestore(); + // need to add the type to the grammar for later constraint checking + grammar.addComplexTypeDecl(type, fSchemaHandler.element2Locator(complexTypeNode)); + type.setIsAnonymous(); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return type; + } + + /** + * Traverse global complexType declarations + * + * @param Element + * @param XSDocumentInfo + * @param SchemaGrammar + * @return XSComplexTypeDecXSComplexTypeDecl + */ + XSComplexTypeDecl traverseGlobal (Element complexTypeNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + Object[] attrValues = fAttrChecker.checkAttributes(complexTypeNode, true, + schemaDoc); + String complexTypeName = (String) attrValues[XSAttributeChecker.ATTIDX_NAME]; + contentBackup(); + XSComplexTypeDecl type = traverseComplexTypeDecl (complexTypeNode, + complexTypeName, attrValues, schemaDoc, grammar); + contentRestore(); + // need to add the type to the grammar for later constraint checking + grammar.addComplexTypeDecl(type, fSchemaHandler.element2Locator(complexTypeNode)); + + if (complexTypeName == null) { + reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_COMPLEXTYPE, SchemaSymbols.ATT_NAME}, complexTypeNode); + type = null; + } else { + if (grammar.getGlobalTypeDecl(type.getName()) == null) { + grammar.addGlobalComplexTypeDecl(type); + } + + // also add it to extended map + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final XSTypeDefinition type2 = grammar.getGlobalTypeDecl(type.getName(), loc); + if (type2 == null) { + grammar.addGlobalComplexTypeDecl(type, loc); + } + + // handle duplicates + if (fSchemaHandler.fTolerateDuplicates) { + if (type2 != null) { + if (type2 instanceof XSComplexTypeDecl) { + type = (XSComplexTypeDecl) type2; + } + } + fSchemaHandler.addGlobalTypeDecl(type); + } + } + + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return type; + } + + + private XSComplexTypeDecl traverseComplexTypeDecl(Element complexTypeDecl, + String complexTypeName, + Object[] attrValues, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + fComplexTypeDecl = new XSComplexTypeDecl(); + fAttrGrp = new XSAttributeGroupDecl(); + Boolean abstractAtt = (Boolean) attrValues[XSAttributeChecker.ATTIDX_ABSTRACT]; + XInt blockAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_BLOCK]; + Boolean mixedAtt = (Boolean) attrValues[XSAttributeChecker.ATTIDX_MIXED]; + XInt finalAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_FINAL]; + + fName = complexTypeName; + fComplexTypeDecl.setName(fName); + fTargetNamespace = schemaDoc.fTargetNamespace; + + fBlock = blockAtt == null ? schemaDoc.fBlockDefault : blockAtt.shortValue(); + fFinal = finalAtt == null ? schemaDoc.fFinalDefault : finalAtt.shortValue(); + //discard valid Block/Final 'Default' values that are invalid for Block/Final + fBlock &= (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION); + fFinal &= (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION); + + fIsAbstract = (abstractAtt != null && abstractAtt.booleanValue()); + fAnnotations = null; + + Element child = null; + + try { + // --------------------------------------------------------------- + // First, handle any ANNOTATION declaration and get next child + // --------------------------------------------------------------- + child = DOMUtil.getFirstChildElement(complexTypeDecl); + if(child != null) { + if (DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + addAnnotation(traverseAnnotationDecl(child, attrValues, false, schemaDoc)); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(complexTypeDecl); + if (text != null) { + addAnnotation(traverseSyntheticAnnotation(complexTypeDecl, text, attrValues, false, schemaDoc)); + } + } + if (child !=null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,SchemaSymbols.ELT_ANNOTATION}, + child); + } + } + else { + String text = DOMUtil.getSyntheticAnnotation(complexTypeDecl); + if (text != null) { + addAnnotation(traverseSyntheticAnnotation(complexTypeDecl, text, attrValues, false, schemaDoc)); + } + } + // --------------------------------------------------------------- + // Process the content of the complex type definition + // --------------------------------------------------------------- + if (child==null) { + // + // EMPTY complexType with complexContent + // + + // set the base to the anyType + fBaseType = SchemaGrammar.fAnyType; + fDerivedBy = XSConstants.DERIVATION_RESTRICTION; + processComplexContent(child, mixedAtt.booleanValue(), false, + schemaDoc, grammar); + } + else if (DOMUtil.getLocalName(child).equals + (SchemaSymbols.ELT_SIMPLECONTENT)) { + // + // SIMPLE CONTENT + // + traverseSimpleContent(child, schemaDoc, grammar); + Element elemTmp = DOMUtil.getNextSiblingElement(child); + if (elemTmp != null) { + String siblingName = DOMUtil.getLocalName(elemTmp); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,siblingName}, + elemTmp); + } + } + else if (DOMUtil.getLocalName(child).equals + (SchemaSymbols.ELT_COMPLEXCONTENT)) { + traverseComplexContent(child, mixedAtt.booleanValue(), + schemaDoc, grammar); + Element elemTmp = DOMUtil.getNextSiblingElement(child); + if (elemTmp != null) { + String siblingName = DOMUtil.getLocalName(elemTmp); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,siblingName}, + elemTmp); + } + } + else { + // + // We must have .... + // GROUP, ALL, SEQUENCE or CHOICE, followed by optional attributes + // Note that it's possible that only attributes are specified. + // + + // set the base to the anyType + fBaseType = SchemaGrammar.fAnyType; + fDerivedBy = XSConstants.DERIVATION_RESTRICTION; + processComplexContent(child, mixedAtt.booleanValue(), false, + schemaDoc, grammar); + } + + } + catch (ComplexTypeRecoverableError e) { + handleComplexTypeError(e.getMessage(), e.errorSubstText, + e.errorElem); + } + + if (DEBUG) { + System.out.println(fName); + } + fComplexTypeDecl.setValues(fName, fTargetNamespace, fBaseType, + fDerivedBy, fFinal, fBlock, fContentType, fIsAbstract, + fAttrGrp, fXSSimpleType, fParticle, new XSObjectListImpl(fAnnotations, + fAnnotations == null? 0 : fAnnotations.length)); + return fComplexTypeDecl; + } + + + private void traverseSimpleContent(Element simpleContentElement, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) + throws ComplexTypeRecoverableError { + + + Object[] simpleContentAttrValues = fAttrChecker.checkAttributes(simpleContentElement, false, + schemaDoc); + + // ----------------------------------------------------------------------- + // Set content type + // ----------------------------------------------------------------------- + fContentType = XSComplexTypeDecl.CONTENTTYPE_SIMPLE; + fParticle = null; + + Element simpleContent = DOMUtil.getFirstChildElement(simpleContentElement); + if (simpleContent != null && DOMUtil.getLocalName(simpleContent).equals(SchemaSymbols.ELT_ANNOTATION)) { + addAnnotation(traverseAnnotationDecl(simpleContent, simpleContentAttrValues, false, schemaDoc)); + simpleContent = DOMUtil.getNextSiblingElement(simpleContent); + } + else { + String text = DOMUtil.getSyntheticAnnotation(simpleContentElement); + if (text != null) { + addAnnotation(traverseSyntheticAnnotation(simpleContentElement, text, simpleContentAttrValues, false, schemaDoc)); + } + } + + // If there are no children, return + if (simpleContent==null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.2", + new Object[]{fName,SchemaSymbols.ELT_SIMPLECONTENT}, + simpleContentElement); + } + + // ----------------------------------------------------------------------- + // The content should be either "restriction" or "extension" + // ----------------------------------------------------------------------- + String simpleContentName = DOMUtil.getLocalName(simpleContent); + if (simpleContentName.equals(SchemaSymbols.ELT_RESTRICTION)) + fDerivedBy = XSConstants.DERIVATION_RESTRICTION; + else if (simpleContentName.equals(SchemaSymbols.ELT_EXTENSION)) + fDerivedBy = XSConstants.DERIVATION_EXTENSION; + else { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,simpleContentName}, + simpleContent); + } + Element elemTmp = DOMUtil.getNextSiblingElement(simpleContent); + if (elemTmp != null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + String siblingName = DOMUtil.getLocalName(elemTmp); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,siblingName}, + elemTmp); + } + + Object [] derivationTypeAttrValues = fAttrChecker.checkAttributes(simpleContent, false, + schemaDoc); + QName baseTypeName = (QName) derivationTypeAttrValues[XSAttributeChecker.ATTIDX_BASE]; + + + // ----------------------------------------------------------------------- + // Need a base type. + // ----------------------------------------------------------------------- + if (baseTypeName==null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-att-must-appear", + new Object[]{simpleContentName, "base"}, simpleContent); + } + + XSTypeDefinition type = (XSTypeDefinition)fSchemaHandler.getGlobalDecl(schemaDoc, + XSDHandler.TYPEDECL_TYPE, baseTypeName, + simpleContent); + if (type==null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError(); + } + + fBaseType = type; + + XSSimpleType baseValidator = null; + XSComplexTypeDecl baseComplexType = null; + int baseFinalSet = 0; + + // If the base type is complex, it must have simpleContent + if ((type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)) { + + baseComplexType = (XSComplexTypeDecl)type; + baseFinalSet = baseComplexType.getFinal(); + // base is a CT with simple content (both restriction and extension are OK) + if (baseComplexType.getContentType() == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { + baseValidator = (XSSimpleType)baseComplexType.getSimpleType(); + } + // base is a CT with mixed/emptiable content (only restriction is OK) + else if (fDerivedBy == XSConstants.DERIVATION_RESTRICTION && + baseComplexType.getContentType() == XSComplexTypeDecl.CONTENTTYPE_MIXED && + ((XSParticleDecl)baseComplexType.getParticle()).emptiable()) { + } + else { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("src-ct.2.1", + new Object[]{fName, baseComplexType.getName()}, simpleContent); + } + } + else { + baseValidator = (XSSimpleType)type; + // base is a ST (only extension is OK) + if (fDerivedBy == XSConstants.DERIVATION_RESTRICTION) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("src-ct.2.1", + new Object[]{fName, baseValidator.getName()}, simpleContent); + } + baseFinalSet=baseValidator.getFinal(); + } + + // ----------------------------------------------------------------------- + // Check that the base permits the derivation + // ----------------------------------------------------------------------- + if ((baseFinalSet & fDerivedBy)!=0) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + String errorKey = (fDerivedBy==XSConstants.DERIVATION_EXTENSION) ? + "cos-ct-extends.1.1" : "derivation-ok-restriction.1"; + throw new ComplexTypeRecoverableError(errorKey, + new Object[]{fName, fBaseType.getName()}, simpleContent); + } + + // ----------------------------------------------------------------------- + // Skip over any potential annotations + // ----------------------------------------------------------------------- + Element scElement = simpleContent; + simpleContent = DOMUtil.getFirstChildElement(simpleContent); + if (simpleContent != null) { + // traverse annotation if any + + if (DOMUtil.getLocalName(simpleContent).equals(SchemaSymbols.ELT_ANNOTATION)) { + addAnnotation(traverseAnnotationDecl(simpleContent, derivationTypeAttrValues, false, schemaDoc)); + simpleContent = DOMUtil.getNextSiblingElement(simpleContent); + } + else { + String text = DOMUtil.getSyntheticAnnotation(scElement); + if (text != null) { + addAnnotation(traverseSyntheticAnnotation(scElement, text, derivationTypeAttrValues, false, schemaDoc)); + } + } + + if (simpleContent !=null && + DOMUtil.getLocalName(simpleContent).equals(SchemaSymbols.ELT_ANNOTATION)){ + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,SchemaSymbols.ELT_ANNOTATION}, + simpleContent); + } + } + else { + String text = DOMUtil.getSyntheticAnnotation(scElement); + if (text != null) { + addAnnotation(traverseSyntheticAnnotation(scElement, text, derivationTypeAttrValues, false, schemaDoc)); + } + } + + // ----------------------------------------------------------------------- + // Process a RESTRICTION + // ----------------------------------------------------------------------- + if (fDerivedBy == XSConstants.DERIVATION_RESTRICTION) { + + // ----------------------------------------------------------------------- + // There may be a simple type definition in the restriction element + // The data type validator will be based on it, if specified + // ----------------------------------------------------------------------- + if (simpleContent !=null && + DOMUtil.getLocalName(simpleContent).equals(SchemaSymbols.ELT_SIMPLETYPE )) { + + XSSimpleType dv = fSchemaHandler.fSimpleTypeTraverser.traverseLocal( + simpleContent, schemaDoc, grammar); + if (dv == null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError(); + } + //check that this datatype validator is validly derived from the base + //according to derivation-ok-restriction 5.1.2.1 + + if (baseValidator != null && + !XSConstraints.checkSimpleDerivationOk(dv, baseValidator, + baseValidator.getFinal())) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("derivation-ok-restriction.5.2.2.1", + new Object[]{fName, dv.getName(), baseValidator.getName()}, + simpleContent); + } + baseValidator = dv; + simpleContent = DOMUtil.getNextSiblingElement(simpleContent); + } + + // this only happens when restricting a mixed/emptiable CT + // but there is no , which is required + if (baseValidator == null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("src-ct.2.2", + new Object[]{fName}, simpleContent); + } + + // ----------------------------------------------------------------------- + // Traverse any facets + // ----------------------------------------------------------------------- + Element attrNode = null; + XSFacets facetData = null; + short presentFacets = 0 ; + short fixedFacets = 0 ; + + if (simpleContent!=null) { + FacetInfo fi = traverseFacets(simpleContent, fComplexTypeDecl, baseValidator, schemaDoc); + attrNode = fi.nodeAfterFacets; + facetData = fi.facetdata; + presentFacets = fi.fPresentFacets; + fixedFacets = fi.fFixedFacets; + } + + String name = genAnonTypeName(simpleContentElement); + fXSSimpleType = fSchemaHandler.fDVFactory.createTypeRestriction(name,schemaDoc.fTargetNamespace,(short)0,baseValidator,null); + try{ + fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport); + fXSSimpleType.applyFacets(facetData, presentFacets, fixedFacets, fValidationState); + }catch(InvalidDatatypeFacetException ex){ + reportSchemaError(ex.getKey(), ex.getArgs(), simpleContent); + // Recreate the type, ignoring the facets + fXSSimpleType = fSchemaHandler.fDVFactory.createTypeRestriction(name,schemaDoc.fTargetNamespace,(short)0,baseValidator,null); + } + if (fXSSimpleType instanceof XSSimpleTypeDecl) { + ((XSSimpleTypeDecl)fXSSimpleType).setAnonymous(true); + } + + // ----------------------------------------------------------------------- + // Traverse any attributes + // ----------------------------------------------------------------------- + if (attrNode != null) { + if (!isAttrOrAttrGroup(attrNode)) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,DOMUtil.getLocalName(attrNode)}, + attrNode); + } + Element node=traverseAttrsAndAttrGrps(attrNode,fAttrGrp, + schemaDoc,grammar,fComplexTypeDecl); + if (node!=null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,DOMUtil.getLocalName(node)}, + node); + } + } + + try { + mergeAttributes(baseComplexType.getAttrGrp(), fAttrGrp, fName, false, simpleContentElement); + } catch (ComplexTypeRecoverableError e) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw e; + } + // Prohibited uses must be removed after merge for RESTRICTION + fAttrGrp.removeProhibitedAttrs(); + + Object[] errArgs=fAttrGrp.validRestrictionOf(fName, baseComplexType.getAttrGrp()); + if (errArgs != null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError((String)errArgs[errArgs.length-1], + errArgs, attrNode); + } + + } + // ----------------------------------------------------------------------- + // Process a EXTENSION + // ----------------------------------------------------------------------- + else { + fXSSimpleType = baseValidator; + if (simpleContent != null) { + // ----------------------------------------------------------------------- + // Traverse any attributes + // ----------------------------------------------------------------------- + Element attrNode = simpleContent; + if (!isAttrOrAttrGroup(attrNode)) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,DOMUtil.getLocalName(attrNode)}, + attrNode); + } + Element node=traverseAttrsAndAttrGrps(attrNode,fAttrGrp, + schemaDoc,grammar,fComplexTypeDecl); + + if (node!=null) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,DOMUtil.getLocalName(node)}, + node); + } + // Remove prohibited uses. Should be done prior to any merge. + fAttrGrp.removeProhibitedAttrs(); + } + + if (baseComplexType != null) { + try { + mergeAttributes(baseComplexType.getAttrGrp(), fAttrGrp, fName, true, simpleContentElement); + } catch (ComplexTypeRecoverableError e) { + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw e; + } + } + } + // and finally, since we've nothing more to traverse, we can + // return the attributes (and thereby reset the namespace support) + fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + } + + private void traverseComplexContent(Element complexContentElement, + boolean mixedOnType, XSDocumentInfo schemaDoc, + SchemaGrammar grammar) + throws ComplexTypeRecoverableError { + + + Object[] complexContentAttrValues = fAttrChecker.checkAttributes(complexContentElement, false, + schemaDoc); + + + // ----------------------------------------------------------------------- + // Determine if this is mixed content + // ----------------------------------------------------------------------- + boolean mixedContent = mixedOnType; + Boolean mixedAtt = (Boolean) complexContentAttrValues[XSAttributeChecker.ATTIDX_MIXED]; + if (mixedAtt != null) { + mixedContent = mixedAtt.booleanValue(); + } + + + // ----------------------------------------------------------------------- + // Since the type must have complex content, set the simple type validators + // to null + // ----------------------------------------------------------------------- + fXSSimpleType = null; + + Element complexContent = DOMUtil.getFirstChildElement(complexContentElement); + if (complexContent != null && DOMUtil.getLocalName(complexContent).equals(SchemaSymbols.ELT_ANNOTATION)) { + addAnnotation(traverseAnnotationDecl(complexContent, complexContentAttrValues, false, schemaDoc)); + complexContent = DOMUtil.getNextSiblingElement(complexContent); + } + else { + String text = DOMUtil.getSyntheticAnnotation(complexContentElement); + if (text != null) { + addAnnotation(traverseSyntheticAnnotation(complexContentElement, text, complexContentAttrValues, false, schemaDoc)); + } + } + + // If there are no children, return + if (complexContent==null) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.2", + new Object[]{fName,SchemaSymbols.ELT_COMPLEXCONTENT}, + complexContentElement); + } + + // ----------------------------------------------------------------------- + // The content should be either "restriction" or "extension" + // ----------------------------------------------------------------------- + String complexContentName = DOMUtil.getLocalName(complexContent); + if (complexContentName.equals(SchemaSymbols.ELT_RESTRICTION)) + fDerivedBy = XSConstants.DERIVATION_RESTRICTION; + else if (complexContentName.equals(SchemaSymbols.ELT_EXTENSION)) + fDerivedBy = XSConstants.DERIVATION_EXTENSION; + else { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName, complexContentName}, complexContent); + } + Element elemTmp = DOMUtil.getNextSiblingElement(complexContent); + if (elemTmp != null) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + String siblingName = DOMUtil.getLocalName(elemTmp); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName, siblingName}, elemTmp); + } + + Object[] derivationTypeAttrValues = fAttrChecker.checkAttributes(complexContent, false, + schemaDoc); + QName baseTypeName = (QName) derivationTypeAttrValues[XSAttributeChecker.ATTIDX_BASE]; + + + // ----------------------------------------------------------------------- + // Need a base type. Check that it's a complex type + // ----------------------------------------------------------------------- + if (baseTypeName==null) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-att-must-appear", + new Object[]{complexContentName, "base"}, complexContent); + } + + XSTypeDefinition type = (XSTypeDefinition)fSchemaHandler.getGlobalDecl(schemaDoc, + XSDHandler.TYPEDECL_TYPE, + baseTypeName, + complexContent); + + if (type==null) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError(); + } + + if (! (type instanceof XSComplexTypeDecl)) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("src-ct.1", + new Object[]{fName, type.getName()}, complexContent); + } + XSComplexTypeDecl baseType = (XSComplexTypeDecl)type; + fBaseType = baseType; + + // ----------------------------------------------------------------------- + // Check that the base permits the derivation + // ----------------------------------------------------------------------- + if ((baseType.getFinal() & fDerivedBy)!=0) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + String errorKey = (fDerivedBy==XSConstants.DERIVATION_EXTENSION) ? + "cos-ct-extends.1.1" : "derivation-ok-restriction.1"; + throw new ComplexTypeRecoverableError(errorKey, + new Object[]{fName, fBaseType.getName()}, complexContent); + } + + // ----------------------------------------------------------------------- + // Skip over any potential annotations + // ----------------------------------------------------------------------- + complexContent = DOMUtil.getFirstChildElement(complexContent); + + if (complexContent != null) { + // traverse annotation if any + if (DOMUtil.getLocalName(complexContent).equals(SchemaSymbols.ELT_ANNOTATION)) { + addAnnotation(traverseAnnotationDecl(complexContent, derivationTypeAttrValues, false, schemaDoc)); + complexContent = DOMUtil.getNextSiblingElement(complexContent); + } + else { + String text = DOMUtil.getSyntheticAnnotation(complexContent); + if (text != null) { + addAnnotation(traverseSyntheticAnnotation(complexContent, text, derivationTypeAttrValues, false, schemaDoc)); + } + } + if (complexContent !=null && + DOMUtil.getLocalName(complexContent).equals(SchemaSymbols.ELT_ANNOTATION)){ + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1", + new Object[]{fName,SchemaSymbols.ELT_ANNOTATION}, complexContent); + } + } + else { + String text = DOMUtil.getSyntheticAnnotation(complexContent); + if (text != null) { + addAnnotation(traverseSyntheticAnnotation(complexContent, text, derivationTypeAttrValues, false, schemaDoc)); + } + } + // ----------------------------------------------------------------------- + // Process the content. Note: should I try to catch any complexType errors + // here in order to return the attr array? + // ----------------------------------------------------------------------- + try { + processComplexContent(complexContent, mixedContent, true, schemaDoc, + grammar); + } catch (ComplexTypeRecoverableError e) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw e; + } + + // ----------------------------------------------------------------------- + // Compose the final content and attribute uses + // ----------------------------------------------------------------------- + XSParticleDecl baseContent = (XSParticleDecl)baseType.getParticle(); + if (fDerivedBy==XSConstants.DERIVATION_RESTRICTION) { + + // This is an RESTRICTION + + // N.B. derivation-ok-restriction.5.3 is checked under schema + // full checking. That's because we need to wait until locals are + // traversed so that occurrence information is correct. + + + if (fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED && + baseType.getContentType() != XSComplexTypeDecl.CONTENTTYPE_MIXED) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("derivation-ok-restriction.5.4.1.2", + new Object[]{fName, baseType.getName()}, + complexContent); + } + + try { + mergeAttributes(baseType.getAttrGrp(), fAttrGrp, fName, false, complexContent); + } catch (ComplexTypeRecoverableError e) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw e; + } + // Remove prohibited uses. Must be done after merge for RESTRICTION. + fAttrGrp.removeProhibitedAttrs(); + + if (baseType != SchemaGrammar.fAnyType) { + Object[] errArgs = fAttrGrp.validRestrictionOf(fName, baseType.getAttrGrp()); + if (errArgs != null) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError((String)errArgs[errArgs.length-1], + errArgs, complexContent); + } + } + } + else { + + // This is an EXTENSION + + // Create the particle + if (fParticle == null) { + fContentType = baseType.getContentType(); + fXSSimpleType = (XSSimpleType)baseType.getSimpleType(); + fParticle = baseContent; + } + else if (baseType.getContentType() == XSComplexTypeDecl.CONTENTTYPE_EMPTY) { + } + else { + // + // Check if the contentType of the base is consistent with the new type + // cos-ct-extends.1.4.3.2 + if (fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT && + baseType.getContentType() != XSComplexTypeDecl.CONTENTTYPE_ELEMENT) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("cos-ct-extends.1.4.3.2.2.1.a", + new Object[]{fName}, complexContent); + } + else if (fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED && + baseType.getContentType() != XSComplexTypeDecl.CONTENTTYPE_MIXED) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("cos-ct-extends.1.4.3.2.2.1.b", + new Object[]{fName}, complexContent); + } + + // if the content of either type is an "all" model group, error. + if (fParticle.fType == XSParticleDecl.PARTICLE_MODELGROUP && + ((XSModelGroupImpl)fParticle.fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL || + ((XSParticleDecl)baseType.getParticle()).fType == XSParticleDecl.PARTICLE_MODELGROUP && + ((XSModelGroupImpl)(((XSParticleDecl)baseType.getParticle())).fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw new ComplexTypeRecoverableError("cos-all-limited.1.2", + new Object[]{}, complexContent); + } + // the "sequence" model group to contain both particles + XSModelGroupImpl group = new XSModelGroupImpl(); + group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE; + group.fParticleCount = 2; + group.fParticles = new XSParticleDecl[2]; + group.fParticles[0] = (XSParticleDecl)baseType.getParticle(); + group.fParticles[1] = fParticle; + group.fAnnotations = XSObjectListImpl.EMPTY_LIST; + // the particle to contain the above sequence + XSParticleDecl particle = new XSParticleDecl(); + particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; + particle.fValue = group; + particle.fAnnotations = XSObjectListImpl.EMPTY_LIST; + + fParticle = particle; + } + + // Remove prohibited uses. Must be done before merge for EXTENSION. + fAttrGrp.removeProhibitedAttrs(); + try { + mergeAttributes(baseType.getAttrGrp(), fAttrGrp, fName, true, complexContent); + } catch (ComplexTypeRecoverableError e) { + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + throw e; + } + + } + + // and *finally* we can legitimately return the attributes! + fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc); + fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc); + + } // end of traverseComplexContent + + + // This method merges attribute uses from the base, into the derived set. + // LM: may want to merge with attributeGroup processing. + private void mergeAttributes(XSAttributeGroupDecl fromAttrGrp, + XSAttributeGroupDecl toAttrGrp, + String typeName, + boolean extension, + Element elem) + throws ComplexTypeRecoverableError { + + XSObjectList attrUseS = fromAttrGrp.getAttributeUses(); + XSAttributeUseImpl oneAttrUse = null; + int attrCount = attrUseS.getLength(); + for (int i=0; i> 16); + fContentType = (short)i; + i = ((Integer)(fGlobalStore[--fGlobalStorePos])).intValue(); + fDerivedBy = (short)(i >> 16); + fFinal = (short)i; + fTargetNamespace = (String)fGlobalStore[--fGlobalStorePos]; + fName = (String)fGlobalStore[--fGlobalStorePos]; + fIsAbstract = ((Boolean)fGlobalStore[--fGlobalStorePos]).booleanValue(); + fComplexTypeDecl = (XSComplexTypeDecl)fGlobalStore[--fGlobalStorePos]; + } + + private void addAnnotation(XSAnnotationImpl annotation) { + if(annotation == null) + return; + // it isn't very likely that there will be more than one annotation + // in a complexType decl. This saves us fromhaving to push/pop + // one more object from the fGlobalStore, and that's bound + // to be a savings for most applications + if(fAnnotations == null) { + fAnnotations = new XSAnnotationImpl[1]; + } else { + XSAnnotationImpl [] tempArray = new XSAnnotationImpl[fAnnotations.length + 1]; + System.arraycopy(fAnnotations, 0, tempArray, 0, fAnnotations.length); + fAnnotations = tempArray; + } + fAnnotations[fAnnotations.length-1] = annotation; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDElementTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDElementTraverser.java new file mode 100644 index 0000000..372058b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDElementTraverser.java @@ -0,0 +1,541 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import java.util.Locale; + +import org.apache.xerces.impl.dv.ValidatedInfo; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSComplexTypeDecl; +import org.apache.xerces.impl.xs.XSConstraints; +import org.apache.xerces.impl.xs.XSElementDecl; +import org.apache.xerces.impl.xs.XSParticleDecl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObject; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + +/** + * The element declaration schema component traverser. + * + * Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*)) + * + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +class XSDElementTraverser extends XSDAbstractTraverser { + + protected final XSElementDecl fTempElementDecl = new XSElementDecl(); + + // this controls what happens when a local element is encountered. + // We may not encounter all local elements when first parsing. + boolean fDeferTraversingLocalElements; + + XSDElementTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + /** + * Traverse a locally declared element (or an element reference). + * + * To handle the recursive cases efficiently, we delay the traversal + * and return an empty particle node. We'll fill in this particle node + * later after we've done with all the global declarations. + * This method causes a number of data structures in the schema handler to be filled in. + * + * @param elmDecl + * @param schemaDoc + * @param grammar + * @return the particle + */ + XSParticleDecl traverseLocal(Element elmDecl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + int allContextFlags, + XSObject parent) { + + XSParticleDecl particle = null; + if (fSchemaHandler.fDeclPool !=null) { + particle = fSchemaHandler.fDeclPool.getParticleDecl(); + } else { + particle = new XSParticleDecl(); + } + if (fDeferTraversingLocalElements) { + // The only thing we care about now is whether this element has + // minOccurs=0. This affects (if the element appears in a complex + // type) whether a type has emptiable content. + particle.fType = XSParticleDecl.PARTICLE_ELEMENT; + Attr attr = elmDecl.getAttributeNode(SchemaSymbols.ATT_MINOCCURS); + if (attr != null) { + String min = attr.getValue(); + try { + int m = Integer.parseInt(XMLChar.trim(min)); + if (m >= 0) + particle.fMinOccurs = m; + } + catch (NumberFormatException ex) { + } + } + fSchemaHandler.fillInLocalElemInfo(elmDecl, schemaDoc, allContextFlags, parent, particle); + } else { + traverseLocal(particle, elmDecl, schemaDoc, grammar, allContextFlags, parent, null); + // If it's an empty particle, return null. + if (particle.fType == XSParticleDecl.PARTICLE_EMPTY) + particle = null; + } + + return particle; + } + + /** + * Traverse a locally declared element (or an element reference). + * + * This is the real traversal method. It's called after we've done with + * all the global declarations. + * + * @param index + */ + protected void traverseLocal(XSParticleDecl particle, + Element elmDecl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + int allContextFlags, + XSObject parent, + String[] localNSDecls) { + + if (localNSDecls != null) { + schemaDoc.fNamespaceSupport.setEffectiveContext(localNSDecls); + } + + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(elmDecl, false, schemaDoc); + + QName refAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_REF]; + XInt minAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_MINOCCURS]; + XInt maxAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS]; + + XSElementDecl element = null; + XSAnnotationImpl annotation = null; + if (elmDecl.getAttributeNode(SchemaSymbols.ATT_REF) != null) { + if (refAtt != null) { + element = (XSElementDecl)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.ELEMENT_TYPE, refAtt, elmDecl); + + Element child = DOMUtil.getFirstChildElement(elmDecl); + if (child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(elmDecl); + if (text != null) { + annotation = traverseSyntheticAnnotation(elmDecl, text, attrValues, false, schemaDoc); + } + } + // Element Declaration Representation OK + // 2 If the item's parent is not , then all of the following must be true: + // 2.1 One of ref or name must be present, but not both. + // 2.2 If ref is present, then all of , , , , , nillable, default, fixed, form, block and type must be absent, i.e. only minOccurs, maxOccurs, id are allowed in addition to ref, along with . + if (child != null) { + reportSchemaError("src-element.2.2", new Object[]{refAtt.rawname, DOMUtil.getLocalName(child)}, child); + } + } else { + element = null; + } + } else { + element = traverseNamedElement(elmDecl, attrValues, schemaDoc, grammar, false, parent); + } + + particle.fMinOccurs = minAtt.intValue(); + particle.fMaxOccurs = maxAtt.intValue(); + if (element != null) { + particle.fType = XSParticleDecl.PARTICLE_ELEMENT; + particle.fValue = element; + } + else { + particle.fType = XSParticleDecl.PARTICLE_EMPTY; + } + if (refAtt != null) { + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl) annotations).addXSObject(annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + particle.fAnnotations = annotations; + } else { + particle.fAnnotations = ((element != null) ? element.fAnnotations + : XSObjectListImpl.EMPTY_LIST); + } + Long defaultVals = (Long)attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT]; + checkOccurrences(particle, SchemaSymbols.ELT_ELEMENT, + (Element)elmDecl.getParentNode(), allContextFlags, + defaultVals.longValue()); + + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + } + + /** + * Traverse a globally declared element. + * + * @param elmDecl + * @param schemaDoc + * @param grammar + * @return the element declaration + */ + XSElementDecl traverseGlobal(Element elmDecl, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking' + + Object[] attrValues = fAttrChecker.checkAttributes(elmDecl, true, schemaDoc); + XSElementDecl element = traverseNamedElement(elmDecl, attrValues, schemaDoc, grammar, true, null); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return element; + + } + + /** + * Traverse a globally declared element. + * + * @param elmDecl + * @param attrValues + * @param schemaDoc + * @param grammar + * @param isGlobal + * @return the element declaration + */ + XSElementDecl traverseNamedElement(Element elmDecl, + Object[] attrValues, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar, + boolean isGlobal, + XSObject parent) { + + Boolean abstractAtt = (Boolean) attrValues[XSAttributeChecker.ATTIDX_ABSTRACT]; + XInt blockAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_BLOCK]; + String defaultAtt = (String) attrValues[XSAttributeChecker.ATTIDX_DEFAULT]; + XInt finalAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_FINAL]; + String fixedAtt = (String) attrValues[XSAttributeChecker.ATTIDX_FIXED]; + XInt formAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_FORM]; + String nameAtt = (String) attrValues[XSAttributeChecker.ATTIDX_NAME]; + Boolean nillableAtt = (Boolean) attrValues[XSAttributeChecker.ATTIDX_NILLABLE]; + QName subGroupAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_SUBSGROUP]; + QName typeAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_TYPE]; + + // Step 1: get declaration information + + XSElementDecl element = null; + if (fSchemaHandler.fDeclPool !=null) { + element = fSchemaHandler.fDeclPool.getElementDecl(); + } else { + element = new XSElementDecl(); + } + // get 'name' + if (nameAtt != null) + element.fName = fSymbolTable.addSymbol(nameAtt); + + // get 'target namespace' + if (isGlobal) { + element.fTargetNamespace = schemaDoc.fTargetNamespace; + element.setIsGlobal(); + } + else { + if (parent instanceof XSComplexTypeDecl) + element.setIsLocal((XSComplexTypeDecl)parent); + + if (formAtt != null) { + if (formAtt.intValue() == SchemaSymbols.FORM_QUALIFIED) + element.fTargetNamespace = schemaDoc.fTargetNamespace; + else + element.fTargetNamespace = null; + } else if (schemaDoc.fAreLocalElementsQualified) { + element.fTargetNamespace = schemaDoc.fTargetNamespace; + } else { + element.fTargetNamespace = null; + } + } + + // get 'block', 'final', 'nillable', 'abstract' + element.fBlock = blockAtt == null ? schemaDoc.fBlockDefault : blockAtt.shortValue(); + element.fFinal = finalAtt == null ? schemaDoc.fFinalDefault : finalAtt.shortValue(); + // discard valid Block/Final 'Default' values that are invalid for Block/Final + element.fBlock &= (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION | XSConstants.DERIVATION_SUBSTITUTION); + element.fFinal &= (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION); + + if (nillableAtt.booleanValue()) + element.setIsNillable(); + if (abstractAtt != null && abstractAtt.booleanValue()) + element.setIsAbstract(); + + // get 'value constraint' + if (fixedAtt != null) { + element.fDefault = new ValidatedInfo(); + element.fDefault.normalizedValue = fixedAtt; + element.setConstraintType(XSConstants.VC_FIXED); + } else if (defaultAtt != null) { + element.fDefault = new ValidatedInfo(); + element.fDefault.normalizedValue = defaultAtt; + element.setConstraintType(XSConstants.VC_DEFAULT); + } else { + element.setConstraintType(XSConstants.VC_NONE); + } + + // get 'substitutionGroup affiliation' + if (subGroupAtt != null) { + element.fSubGroup = (XSElementDecl)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.ELEMENT_TYPE, subGroupAtt, elmDecl); + } + + // get 'annotation' + Element child = DOMUtil.getFirstChildElement(elmDecl); + XSAnnotationImpl annotation = null; + if(child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(elmDecl); + if (text != null) { + annotation = traverseSyntheticAnnotation(elmDecl, text, attrValues, false, schemaDoc); + } + } + + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl)annotations).addXSObject (annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + element.fAnnotations = annotations; + + // get 'type definition' + XSTypeDefinition elementType = null; + boolean haveAnonType = false; + + // Handle Anonymous type if there is one + if (child != null) { + String childName = DOMUtil.getLocalName(child); + + if (childName.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { + elementType = fSchemaHandler.fComplexTypeTraverser.traverseLocal(child, schemaDoc, grammar); + haveAnonType = true; + child = DOMUtil.getNextSiblingElement(child); + } + else if (childName.equals(SchemaSymbols.ELT_SIMPLETYPE)) { + elementType = fSchemaHandler.fSimpleTypeTraverser.traverseLocal(child, schemaDoc, grammar); + haveAnonType = true; + child = DOMUtil.getNextSiblingElement(child); + } + } + + // Handler type attribute + if (elementType == null && typeAtt != null) { + elementType = (XSTypeDefinition)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.TYPEDECL_TYPE, typeAtt, elmDecl); + if (elementType == null) { + element.fUnresolvedTypeName = typeAtt; + } + } + + // Get it from the substitutionGroup declaration + if (elementType == null && element.fSubGroup != null) { + elementType = element.fSubGroup.fType; + } + + if (elementType == null) { + elementType = SchemaGrammar.fAnyType; + } + + element.fType = elementType; + + // get 'identity constraint' + + // see if there's something here; it had better be key, keyref or unique. + if (child != null) { + String childName = DOMUtil.getLocalName(child); + while (child != null && + (childName.equals(SchemaSymbols.ELT_KEY) || + childName.equals(SchemaSymbols.ELT_KEYREF) || + childName.equals(SchemaSymbols.ELT_UNIQUE))) { + + if (childName.equals(SchemaSymbols.ELT_KEY) || + childName.equals(SchemaSymbols.ELT_UNIQUE)) { + // need to set / to hidden before traversing it, + // because it has global scope + DOMUtil.setHidden(child, fSchemaHandler.fHiddenNodes); + fSchemaHandler.fUniqueOrKeyTraverser.traverse(child, element, schemaDoc, grammar); + if(DOMUtil.getAttrValue(child, SchemaSymbols.ATT_NAME).length() != 0 ) { + fSchemaHandler.checkForDuplicateNames( + (schemaDoc.fTargetNamespace == null) ? ","+DOMUtil.getAttrValue(child, SchemaSymbols.ATT_NAME) + : schemaDoc.fTargetNamespace+","+ DOMUtil.getAttrValue(child, SchemaSymbols.ATT_NAME), + XSDHandler.ATTRIBUTE_TYPE, fSchemaHandler.getIDRegistry(), fSchemaHandler.getIDRegistry_sub(), + child, schemaDoc); + } + } else if (childName.equals(SchemaSymbols.ELT_KEYREF)) { + fSchemaHandler.storeKeyRef(child, schemaDoc, element); + } + child = DOMUtil.getNextSiblingElement(child); + if (child != null) { + childName = DOMUtil.getLocalName(child); + } + } + } + + // Step 3: check against schema for schemas + + // required attributes + if (nameAtt == null) { + if (isGlobal) + reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_ELEMENT, SchemaSymbols.ATT_NAME}, elmDecl); + else + reportSchemaError("src-element.2.1", null, elmDecl); + nameAtt = NO_NAME; + } + + // element + if (child != null) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{nameAtt, "(annotation?, (simpleType | complexType)?, (unique | key | keyref)*))", DOMUtil.getLocalName(child)}, child); + } + + // Step 4: check 3.3.3 constraints + + // src-element + + // 1 default and fixed must not both be present. + if (defaultAtt != null && fixedAtt != null) { + reportSchemaError("src-element.1", new Object[]{nameAtt}, elmDecl); + } + + // 2 If the item's parent is not , then all of the following must be true: + // 2.1 One of ref or name must be present, but not both. + // This is checked in XSAttributeChecker + + // 2.2 If ref is present, then all of , , , , , nillable, default, fixed, form, block and type must be absent, i.e. only minOccurs, maxOccurs, id are allowed in addition to ref, along with . + // Attributes are checked in XSAttributeChecker, elements are checked in "traverse" method + + // 3 type and either or are mutually exclusive. + if (haveAnonType && (typeAtt != null)) { + reportSchemaError("src-element.3", new Object[]{nameAtt}, elmDecl); + } + + // Step 5: check 3.3.6 constraints + // check for NOTATION type + checkNotationType(nameAtt, elementType, elmDecl); + + // e-props-correct + + // 2 If there is a {value constraint}, the canonical lexical representation of its value must be valid with respect to the {type definition} as defined in Element Default Valid (Immediate) (3.3.6). + if (element.fDefault != null) { + fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport); + if (XSConstraints.ElementDefaultValidImmediate(element.fType, element.fDefault.normalizedValue, fValidationState, element.fDefault) == null) { + reportSchemaError ("e-props-correct.2", new Object[]{nameAtt, element.fDefault.normalizedValue}, elmDecl); + element.fDefault = null; + element.setConstraintType(XSConstants.VC_NONE); + } + } + + // 4 If there is an {substitution group affiliation}, the {type definition} of the element declaration must be validly derived from the {type definition} of the {substitution group affiliation}, given the value of the {substitution group exclusions} of the {substitution group affiliation}, as defined in Type Derivation OK (Complex) (3.4.6) (if the {type definition} is complex) or as defined in Type Derivation OK (Simple) (3.14.6) (if the {type definition} is simple). + if (element.fSubGroup != null) { + if (!XSConstraints.checkTypeDerivationOk(element.fType, element.fSubGroup.fType, element.fSubGroup.fFinal)) { + reportSchemaError ("e-props-correct.4", new Object[]{nameAtt, subGroupAtt.prefix+":"+subGroupAtt.localpart}, elmDecl); + element.fSubGroup = null; + } + } + + // 5 If the {type definition} or {type definition}'s {content type} is or is derived from ID then there must not be a {value constraint}. + if (element.fDefault != null) { + if ((elementType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE && + ((XSSimpleType)elementType).isIDType()) || + (elementType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE && + ((XSComplexTypeDecl)elementType).containsTypeID())) { + reportSchemaError ("e-props-correct.5", new Object[]{element.fName}, elmDecl); + element.fDefault = null; + element.setConstraintType(XSConstants.VC_NONE); + } + } + + // Element without a name. Return null. + if (element.fName == null) + return null; + + // Step 5: register the element decl to the grammar + if (isGlobal) { + grammar.addGlobalElementDeclAll(element); + + if (grammar.getGlobalElementDecl(element.fName) == null) { + grammar.addGlobalElementDecl(element); + } + + // we also add the element to the tolerate duplicates list as well + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final XSElementDecl element2 = grammar.getGlobalElementDecl(element.fName, loc); + if (element2 == null) { + grammar.addGlobalElementDecl(element, loc); + } + + // if we are tolerating duplicates, and we found a duplicate declaration + // use the duplicate one instead + if (fSchemaHandler.fTolerateDuplicates) { + if (element2 != null) { + element = element2; + } + fSchemaHandler.addGlobalElementDecl(element); + } + } + + return element; + } + + void reset(SymbolTable symbolTable, boolean validateAnnotations, Locale locale) { + super.reset(symbolTable, validateAnnotations, locale); + fDeferTraversingLocalElements = true; + } // reset() + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDGroupTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDGroupTraverser.java new file mode 100644 index 0000000..af2a48d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDGroupTraverser.java @@ -0,0 +1,267 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSConstraints; +import org.apache.xerces.impl.xs.XSGroupDecl; +import org.apache.xerces.impl.xs.XSModelGroupImpl; +import org.apache.xerces.impl.xs.XSParticleDecl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSObjectList; +import org.w3c.dom.Element; + +/** + * The model group schema component traverser. + * + * + * Content: (annotation?, (all | choice | sequence)) + * + * + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * @author Elena Litani, IBM + * @author Lisa Martin, IBM + * @version $Id$ + */ +class XSDGroupTraverser extends XSDAbstractParticleTraverser { + + XSDGroupTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + + super(handler, gAttrCheck); + } + + XSParticleDecl traverseLocal(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking for elmNode declared locally + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, false, + schemaDoc); + QName refAttr = (QName) attrValues[XSAttributeChecker.ATTIDX_REF]; + XInt minAttr = (XInt) attrValues[XSAttributeChecker.ATTIDX_MINOCCURS]; + XInt maxAttr = (XInt) attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS]; + + XSGroupDecl group = null; + + // ref should be here. + if (refAttr == null) { + reportSchemaError("s4s-att-must-appear", new Object[]{"group (local)", "ref"}, elmNode); + } else { + // get global decl + // index is a particle index. + group = (XSGroupDecl)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.GROUP_TYPE, refAttr, elmNode); + } + + XSAnnotationImpl annotation = null; + // no children other than "annotation?" are allowed + Element child = DOMUtil.getFirstChildElement(elmNode); + if (child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(elmNode); + if (text != null) { + annotation = traverseSyntheticAnnotation(elmNode, text, attrValues, false, schemaDoc); + } + } + + if (child != null) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{"group (local)", "(annotation?)", DOMUtil.getLocalName(elmNode)}, elmNode); + } + + int minOccurs = minAttr.intValue(); + int maxOccurs = maxAttr.intValue(); + + XSParticleDecl particle = null; + + // not empty group, not empty particle + if (group != null && group.fModelGroup != null && + !(minOccurs == 0 && maxOccurs == 0)) { + // create a particle to contain this model group + if (fSchemaHandler.fDeclPool != null) { + particle = fSchemaHandler.fDeclPool.getParticleDecl(); + } else { + particle = new XSParticleDecl(); + } + particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; + particle.fValue = group.fModelGroup; + particle.fMinOccurs = minOccurs; + particle.fMaxOccurs = maxOccurs; + if (group.fModelGroup.fCompositor == XSModelGroupImpl.MODELGROUP_ALL) { + Long defaultVals = (Long)attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT]; + particle = checkOccurrences(particle, SchemaSymbols.ELT_GROUP, + (Element)elmNode.getParentNode(), GROUP_REF_WITH_ALL, + defaultVals.longValue()); + } + if (refAttr != null) { + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl) annotations).addXSObject(annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + particle.fAnnotations = annotations; + } else { + particle.fAnnotations = group.fAnnotations; + } + } + + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return particle; + + } // traverseLocal + + XSGroupDecl traverseGlobal(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking for elmNode declared globally + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, true, + schemaDoc); + String strNameAttr = (String) attrValues[XSAttributeChecker.ATTIDX_NAME]; + + // must have a name + if (strNameAttr == null) { + reportSchemaError("s4s-att-must-appear", new Object[]{"group (global)", "name"}, elmNode); + } + + // Create the group defi up-front, so it can be passed + // to the traversal methods + XSGroupDecl group = new XSGroupDecl(); + XSParticleDecl particle = null; + + // must have at least one child + Element l_elmChild = DOMUtil.getFirstChildElement(elmNode); + XSAnnotationImpl annotation = null; + if (l_elmChild == null) { + reportSchemaError("s4s-elt-must-match.2", + new Object[]{"group (global)", "(annotation?, (all | choice | sequence))"}, + elmNode); + } else { + String childName = l_elmChild.getLocalName(); + if (childName.equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(l_elmChild, attrValues, true, schemaDoc); + l_elmChild = DOMUtil.getNextSiblingElement(l_elmChild); + if (l_elmChild != null) + childName = l_elmChild.getLocalName(); + } + else { + String text = DOMUtil.getSyntheticAnnotation(elmNode); + if (text != null) { + annotation = traverseSyntheticAnnotation(elmNode, text, attrValues, false, schemaDoc); + } + } + + if (l_elmChild == null) { + reportSchemaError("s4s-elt-must-match.2", + new Object[]{"group (global)", "(annotation?, (all | choice | sequence))"}, + elmNode); + } else if (childName.equals(SchemaSymbols.ELT_ALL)) { + particle = traverseAll(l_elmChild, schemaDoc, grammar, CHILD_OF_GROUP, group); + } else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { + particle = traverseChoice(l_elmChild, schemaDoc, grammar, CHILD_OF_GROUP, group); + } else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { + particle = traverseSequence(l_elmChild, schemaDoc, grammar, CHILD_OF_GROUP, group); + } else { + reportSchemaError("s4s-elt-must-match.1", + new Object[]{"group (global)", "(annotation?, (all | choice | sequence))", DOMUtil.getLocalName(l_elmChild)}, + l_elmChild); + } + + if (l_elmChild != null && + DOMUtil.getNextSiblingElement(l_elmChild) != null) { + reportSchemaError("s4s-elt-must-match.1", + new Object[]{"group (global)", "(annotation?, (all | choice | sequence))", + DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(l_elmChild))}, + DOMUtil.getNextSiblingElement(l_elmChild)); + } + } + + // add global group declaration to the grammar + if (strNameAttr != null) { + group.fName = strNameAttr; + group.fTargetNamespace = schemaDoc.fTargetNamespace; + if (particle == null) { + particle = XSConstraints.getEmptySequence(); + } + group.fModelGroup = (XSModelGroupImpl)particle.fValue; + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl) annotations).addXSObject(annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + group.fAnnotations = annotations; + // Add group declaration to grammar + if (grammar.getGlobalGroupDecl(group.fName) == null) { + grammar.addGlobalGroupDecl(group); + } + + // also add it to extended map + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final XSGroupDecl group2 = grammar.getGlobalGroupDecl(group.fName, loc); + if (group2 == null) { + grammar.addGlobalGroupDecl(group, loc); + } + + // handle duplicates + if (fSchemaHandler.fTolerateDuplicates) { + if (group2 != null) { + group = group2; + } + fSchemaHandler.addGlobalGroupDecl(group); + } + } + else { + // name attribute is not there, don't return this group. + group = null; + } + + if (group != null) { + // store groups redefined by restriction in the grammar so + // that we can get at them at full-schema-checking time. + Object redefinedGrp = fSchemaHandler.getGrpOrAttrGrpRedefinedByRestriction(XSDHandler.GROUP_TYPE, + new QName(XMLSymbols.EMPTY_STRING, strNameAttr, strNameAttr, schemaDoc.fTargetNamespace), + schemaDoc, elmNode); + if (redefinedGrp != null) { + // store in grammar + grammar.addRedefinedGroupDecl(group, (XSGroupDecl)redefinedGrp, + fSchemaHandler.element2Locator(elmNode)); + } + } + + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return group; + + } // traverseGlobal +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDHandler.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDHandler.java new file mode 100644 index 0000000..11e907b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDHandler.java @@ -0,0 +1,4323 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Stack; +import java.util.Vector; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dv.SchemaDVFactory; +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaNamespaceSupport; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XMLSchemaException; +import org.apache.xerces.impl.xs.XMLSchemaLoader; +import org.apache.xerces.impl.xs.XSAttributeDecl; +import org.apache.xerces.impl.xs.XSAttributeGroupDecl; +import org.apache.xerces.impl.xs.XSComplexTypeDecl; +import org.apache.xerces.impl.xs.XSDDescription; +import org.apache.xerces.impl.xs.XSDeclarationPool; +import org.apache.xerces.impl.xs.XSElementDecl; +import org.apache.xerces.impl.xs.XSGrammarBucket; +import org.apache.xerces.impl.xs.XSGroupDecl; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.impl.xs.XSModelGroupImpl; +import org.apache.xerces.impl.xs.XSNotationDecl; +import org.apache.xerces.impl.xs.XSParticleDecl; +import org.apache.xerces.impl.xs.identity.IdentityConstraint; +import org.apache.xerces.impl.xs.opti.ElementImpl; +import org.apache.xerces.impl.xs.opti.SchemaDOMParser; +import org.apache.xerces.impl.xs.opti.SchemaParsingConfig; +import org.apache.xerces.impl.xs.util.SimpleLocator; +import org.apache.xerces.impl.xs.util.XSInputSource; +import org.apache.xerces.parsers.SAXParser; +import org.apache.xerces.parsers.XML11Configuration; +import org.apache.xerces.util.DOMInputSource; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.DefaultErrorHandler; +import org.apache.xerces.util.ErrorHandlerWrapper; +import org.apache.xerces.util.SAXInputSource; +import org.apache.xerces.util.StAXInputSource; +import org.apache.xerces.util.StAXLocationWrapper; +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.URI.MalformedURIException; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.grammars.XMLSchemaDescription; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParseException; +import org.apache.xerces.xs.StringList; +import org.apache.xerces.xs.XSAttributeDeclaration; +import org.apache.xerces.xs.XSAttributeGroupDefinition; +import org.apache.xerces.xs.XSAttributeUse; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSElementDeclaration; +import org.apache.xerces.xs.XSModelGroup; +import org.apache.xerces.xs.XSModelGroupDefinition; +import org.apache.xerces.xs.XSNamedMap; +import org.apache.xerces.xs.XSObject; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSParticle; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTerm; +import org.apache.xerces.xs.XSTypeDefinition; +import org.apache.xerces.xs.datatypes.ObjectList; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + + +/** + * The purpose of this class is to co-ordinate the construction of a + * grammar object corresponding to a schema. To do this, it must be + * prepared to parse several schema documents (for instance if the + * schema document originally referred to contains or + * information items). If any of the schemas imports a + * schema, other grammars may be constructed as a side-effect. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @author Pavani Mukthipudi, Sun Microsystems + * + * @version $Id$ + */ +public class XSDHandler { + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** feature identifier: XML Schema validation */ + protected static final String XMLSCHEMA_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** Feature identifier: allow java encodings */ + protected static final String ALLOW_JAVA_ENCODINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; + + /** Feature identifier: continue after fatal error */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + /** Feature identifier: allow java encodings */ + protected static final String STANDARD_URI_CONFORMANT_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE; + + /** Feature: disallow doctype*/ + protected static final String DISALLOW_DOCTYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE; + + /** Feature: generate synthetic annotations */ + protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE; + + /** Feature identifier: validate annotations. */ + protected static final String VALIDATE_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE; + + /** Feature identifier: honour all schemaLocations */ + protected static final String HONOUR_ALL_SCHEMALOCATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; + + /** Feature identifier: namespace growth */ + protected static final String NAMESPACE_GROWTH = + Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; + + /** Feature identifier: tolerate duplicates */ + protected static final String TOLERATE_DUPLICATES = + Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; + + /** Feature identifier: namespace prefixes. */ + private static final String NAMESPACE_PREFIXES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE; + + /** Feature identifier: string interning. */ + protected static final String STRING_INTERNING = + Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: JAXP schema source. */ + protected static final String JAXP_SCHEMA_SOURCE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; + + /** Property identifier: entity resolver. */ + public static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier: error reporter. */ + public static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: grammar pool. */ + public static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: symbol table. */ + public static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: security manager. */ + protected static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + /** Property identifier: locale. */ + protected static final String LOCALE = + Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + + protected static final boolean DEBUG_NODE_POOL = false; + + // Data + + // different sorts of declarations; should make lookup and + // traverser calling more efficient/less bulky. + final static int ATTRIBUTE_TYPE = 1; + final static int ATTRIBUTEGROUP_TYPE = 2; + final static int ELEMENT_TYPE = 3; + final static int GROUP_TYPE = 4; + final static int IDENTITYCONSTRAINT_TYPE = 5; + final static int NOTATION_TYPE = 6; + final static int TYPEDECL_TYPE = 7; + + // this string gets appended to redefined names; it's purpose is to be + // as unlikely as possible to cause collisions. + public final static String REDEF_IDENTIFIER = "_fn3dktizrknc9pi"; + + // + //protected data that can be accessable by any traverser + // stores decl + protected Hashtable fNotationRegistry = new Hashtable(); + + protected XSDeclarationPool fDeclPool = null; + + + // These tables correspond to the symbol spaces defined in the + // spec. + // They are keyed with a QName (that is, String("URI,localpart) and + // their values are nodes corresponding to the given name's decl. + // By asking the node for its ownerDocument and looking in + // XSDocumentInfoRegistry we can easily get the corresponding + // XSDocumentInfo object. + private Hashtable fUnparsedAttributeRegistry = new Hashtable(); + private Hashtable fUnparsedAttributeGroupRegistry = new Hashtable(); + private Hashtable fUnparsedElementRegistry = new Hashtable(); + private Hashtable fUnparsedGroupRegistry = new Hashtable(); + private Hashtable fUnparsedIdentityConstraintRegistry = new Hashtable(); + private Hashtable fUnparsedNotationRegistry = new Hashtable(); + private Hashtable fUnparsedTypeRegistry = new Hashtable(); + // Compensation for the above hashtables to locate XSDocumentInfo, + // Since we may take Schema Element directly, so can not get the + // corresponding XSDocumentInfo object just using above hashtables. + private Hashtable fUnparsedAttributeRegistrySub = new Hashtable(); + private Hashtable fUnparsedAttributeGroupRegistrySub = new Hashtable(); + private Hashtable fUnparsedElementRegistrySub = new Hashtable(); + private Hashtable fUnparsedGroupRegistrySub = new Hashtable(); + private Hashtable fUnparsedIdentityConstraintRegistrySub = new Hashtable(); + private Hashtable fUnparsedNotationRegistrySub = new Hashtable(); + private Hashtable fUnparsedTypeRegistrySub = new Hashtable(); + + // Stores XSDocumentInfo (keyed by component name), to check for duplicate + // components declared within the same xsd document + private Hashtable fUnparsedRegistriesExt[] = new Hashtable[] { + null, + new Hashtable(), // ATTRIBUTE_TYPE + new Hashtable(), // ATTRIBUTEGROUP_TYPE + new Hashtable(), // ELEMENT_TYPE + new Hashtable(), // GROUP_TYPE + new Hashtable(), // IDENTITYCONSTRAINT_TYPE + new Hashtable(), // NOTATION_TYPE + new Hashtable(), // TYPEDECL_TYPE + }; + + // this is keyed with a documentNode (or the schemaRoot nodes + // contained in the XSDocumentInfo objects) and its value is the + // XSDocumentInfo object corresponding to that document. + // Basically, the function of this registry is to be a link + // between the nodes we fetch from calls to the fUnparsed* + // arrays and the XSDocumentInfos they live in. + private Hashtable fXSDocumentInfoRegistry = new Hashtable(); + + // this hashtable is keyed on by XSDocumentInfo objects. Its values + // are Vectors containing the XSDocumentInfo objects d, + // ed or d by the key XSDocumentInfo. + private Hashtable fDependencyMap = new Hashtable(); + + // this hashtable is keyed on by a target namespace. Its values + // are Vectors containing namespaces imported by schema documents + // with the key target namespace. + // if an imprted schema has absent namespace, the value "null" is stored. + private Hashtable fImportMap = new Hashtable(); + // all namespaces that imports other namespaces + // if the importing schema has absent namespace, empty string is stored. + // (because the key of a hashtable can't be null.) + private Vector fAllTNSs = new Vector(); + // stores instance document mappings between namespaces and schema hints + private Hashtable fLocationPairs = null; + private static final Hashtable EMPTY_TABLE = new Hashtable(); + + // Records which nodes are hidden when the input is a DOMInputSource. + Hashtable fHiddenNodes = null; + + // convenience methods + private String null2EmptyString(String ns) { + return ns == null ? XMLSymbols.EMPTY_STRING : ns; + } + private String emptyString2Null(String ns) { + return ns == XMLSymbols.EMPTY_STRING ? null : ns; + } + // use Schema Element to lookup the SystemId. + private String doc2SystemId(Element ele) { + String documentURI = null; + /** + * REVISIT: Casting until DOM Level 3 interfaces are available. -- mrglavas + */ + if(ele.getOwnerDocument() instanceof org.apache.xerces.impl.xs.opti.SchemaDOM){ + documentURI = ((org.apache.xerces.impl.xs.opti.SchemaDOM) ele.getOwnerDocument()).getDocumentURI(); + } + return documentURI != null ? documentURI : (String) fDoc2SystemId.get(ele); + } + + // This vector stores strings which are combinations of the + // publicId and systemId of the inputSource corresponding to a + // schema document. This combination is used so that the user's + // EntityResolver can provide a consistent way of identifying a + // schema document that is included in multiple other schemas. + private Hashtable fTraversed = new Hashtable(); + + // this hashtable contains a mapping from Schema Element to its systemId + // this is useful to resolve a uri relative to the referring document + private Hashtable fDoc2SystemId = new Hashtable(); + + // the primary XSDocumentInfo we were called to parse + private XSDocumentInfo fRoot = null; + + // This hashtable's job is to act as a link between the Schema Element and its + // XSDocumentInfo object. + private Hashtable fDoc2XSDocumentMap = new Hashtable(); + + // map between elements and the XSDocumentInfo + // objects that correspond to the documents being redefined. + private Hashtable fRedefine2XSDMap = new Hashtable(); + + // map between elements and the namespace support + private Hashtable fRedefine2NSSupport = new Hashtable(); + + // these objects store a mapping between the names of redefining + // groups/attributeGroups and the groups/AttributeGroups which + // they redefine by restriction (implicitly). It is up to the + // Group and AttributeGroup traversers to check these restrictions for + // validity. + private Hashtable fRedefinedRestrictedAttributeGroupRegistry = new Hashtable(); + private Hashtable fRedefinedRestrictedGroupRegistry = new Hashtable(); + + // a variable storing whether the last schema document + // processed (by getSchema) was a duplicate. + private boolean fLastSchemaWasDuplicate; + + // validate annotations feature + private boolean fValidateAnnotations = false; + + //handle multiple import feature + private boolean fHonourAllSchemaLocations = false; + + //handle namespace growth feature + boolean fNamespaceGrowth = false; + + // handle tolerate duplicates feature + boolean fTolerateDuplicates = false; + + // the XMLErrorReporter + private XMLErrorReporter fErrorReporter; + private XMLEntityResolver fEntityResolver; + + // the XSAttributeChecker + private XSAttributeChecker fAttributeChecker; + + // the symbol table + private SymbolTable fSymbolTable; + + // the GrammarResolver + private XSGrammarBucket fGrammarBucket; + + // the Grammar description + private XSDDescription fSchemaGrammarDescription; + + // the Grammar Pool + private XMLGrammarPool fGrammarPool; + + //************ Traversers ********** + XSDAttributeGroupTraverser fAttributeGroupTraverser; + XSDAttributeTraverser fAttributeTraverser; + XSDComplexTypeTraverser fComplexTypeTraverser; + XSDElementTraverser fElementTraverser; + XSDGroupTraverser fGroupTraverser; + XSDKeyrefTraverser fKeyrefTraverser; + XSDNotationTraverser fNotationTraverser; + XSDSimpleTypeTraverser fSimpleTypeTraverser; + XSDUniqueOrKeyTraverser fUniqueOrKeyTraverser; + XSDWildcardTraverser fWildCardTraverser; + + SchemaDVFactory fDVFactory; + SchemaDOMParser fSchemaParser; + SchemaContentHandler fXSContentHandler; + StAXSchemaParser fStAXSchemaParser; + XML11Configuration fAnnotationValidator; + XSAnnotationGrammarPool fGrammarBucketAdapter; + + // these data members are needed for the deferred traversal + // of local elements. + + // the initial size of the array to store deferred local elements + private static final int INIT_STACK_SIZE = 30; + // the incremental size of the array to store deferred local elements + private static final int INC_STACK_SIZE = 10; + // current position of the array (# of deferred local elements) + private int fLocalElemStackPos = 0; + + private XSParticleDecl[] fParticle = new XSParticleDecl[INIT_STACK_SIZE]; + private Element[] fLocalElementDecl = new Element[INIT_STACK_SIZE]; + private XSDocumentInfo[] fLocalElementDecl_schema = new XSDocumentInfo[INIT_STACK_SIZE]; //JACK + private int[] fAllContext = new int[INIT_STACK_SIZE]; + private XSObject[] fParent = new XSObject[INIT_STACK_SIZE]; + private String [][] fLocalElemNamespaceContext = new String [INIT_STACK_SIZE][1]; + + // these data members are needed for the deferred traversal + // of keyrefs. + + // the initial size of the array to store deferred keyrefs + private static final int INIT_KEYREF_STACK = 2; + // the incremental size of the array to store deferred keyrefs + private static final int INC_KEYREF_STACK_AMOUNT = 2; + // current position of the array (# of deferred keyrefs) + private int fKeyrefStackPos = 0; + + private Element [] fKeyrefs = new Element[INIT_KEYREF_STACK]; + private XSDocumentInfo [] fKeyrefsMapXSDocumentInfo = new XSDocumentInfo[INIT_KEYREF_STACK]; + private XSElementDecl [] fKeyrefElems = new XSElementDecl [INIT_KEYREF_STACK]; + private String [][] fKeyrefNamespaceContext = new String[INIT_KEYREF_STACK][1]; + + // global decls: map from decl name to decl object + SymbolHash fGlobalAttrDecls = new SymbolHash(12); + SymbolHash fGlobalAttrGrpDecls = new SymbolHash(5); + SymbolHash fGlobalElemDecls = new SymbolHash(25); + SymbolHash fGlobalGroupDecls = new SymbolHash(5); + SymbolHash fGlobalNotationDecls = new SymbolHash(1); + SymbolHash fGlobalIDConstraintDecls = new SymbolHash(3); + SymbolHash fGlobalTypeDecls = new SymbolHash(25); + + // Constructors + public XSDHandler(){ + fHiddenNodes = new Hashtable(); + fSchemaParser = new SchemaDOMParser(new SchemaParsingConfig()); + } + + // it should be possible to use the same XSDHandler to parse + // multiple schema documents; this will allow one to be + // constructed. + public XSDHandler (XSGrammarBucket gBucket) { + this(); + fGrammarBucket = gBucket; + + // Note: don't use SchemaConfiguration internally + // we will get stack overflaw because + // XMLSchemaValidator will be instantiating XSDHandler... + fSchemaGrammarDescription = new XSDDescription(); + } // end constructor + + /** + * This method initiates the parse of a schema. It will likely be + * called from the Validator and it will make the + * resulting grammar available; it returns a reference to this object just + * in case. A reset(XMLComponentManager) must be called before this methods is called. + * @param is + * @param desc + * @param locationPairs + * @return the SchemaGrammar + * @throws IOException + */ + public SchemaGrammar parseSchema(XMLInputSource is, XSDDescription desc, + Hashtable locationPairs) + throws IOException { + fLocationPairs = locationPairs; + fSchemaParser.resetNodePool(); + SchemaGrammar grammar = null; + String schemaNamespace = null; + short referType = desc.getContextType(); + + // if loading using JAXP schemaSource property, or using grammar caching loadGrammar + // the desc.targetNamespace is always null. + // Therefore we should not attempt to find out if + // the schema is already in the bucket, since in the case we have + // no namespace schema in the bucket, findGrammar will always return the + // no namespace schema. + if (referType != XSDDescription.CONTEXT_PREPARSE){ + // first try to find it in the bucket/pool, return if one is found + if (fHonourAllSchemaLocations && referType == XSDDescription.CONTEXT_IMPORT && isExistingGrammar(desc, fNamespaceGrowth)) { + grammar = fGrammarBucket.getGrammar(desc.getTargetNamespace()); + } + else { + grammar = findGrammar(desc, fNamespaceGrowth); + } + if (grammar != null) { + if (!fNamespaceGrowth) { + return grammar; + } + else { + try { + if (grammar.getDocumentLocations().contains(XMLEntityManager.expandSystemId(is.getSystemId(), is.getBaseSystemId(), false))) { + return grammar; + } + } + catch (MalformedURIException e) { + //REVISIT: return the grammar? + } + } + } + + schemaNamespace = desc.getTargetNamespace(); + // handle empty string URI as null + if (schemaNamespace != null) { + schemaNamespace = fSymbolTable.addSymbol(schemaNamespace); + } + } + + // before parsing a schema, need to clear registries associated with + // parsing schemas + prepareForParse(); + + Element schemaRoot = null; + // first phase: construct trees. + if (is instanceof DOMInputSource) { + schemaRoot = getSchemaDocument(schemaNamespace, (DOMInputSource) is, + referType == XSDDescription.CONTEXT_PREPARSE, + referType, null); + } // DOMInputSource + else if (is instanceof SAXInputSource) { + schemaRoot = getSchemaDocument(schemaNamespace, (SAXInputSource) is, + referType == XSDDescription.CONTEXT_PREPARSE, + referType, null); + } // SAXInputSource + else if (is instanceof StAXInputSource) { + schemaRoot = getSchemaDocument(schemaNamespace, (StAXInputSource) is, + referType == XSDDescription.CONTEXT_PREPARSE, + referType, null); + } // StAXInputSource + else if (is instanceof XSInputSource) { + schemaRoot = getSchemaDocument((XSInputSource) is, desc); + } // XSInputSource + else { + schemaRoot = getSchemaDocument(schemaNamespace, is, + referType == XSDDescription.CONTEXT_PREPARSE, + referType, null); + + } //is instanceof XMLInputSource + + if (schemaRoot == null) { + if (is instanceof XSInputSource) { + // Need to return a grammar. If the XSInputSource has a list + // of grammar objects, then get the first one and return it. + // If it has a list of components, then get the grammar that + // contains the first component and return it. + // If we return null, the XMLSchemaLoader will think nothing + // was loaded, and will not try to put the grammar objects + // into the grammar pool. + XSInputSource xsinput = (XSInputSource)is; + SchemaGrammar[] grammars = xsinput.getGrammars(); + if (grammars != null && grammars.length > 0) { + grammar = fGrammarBucket.getGrammar(grammars[0].getTargetNamespace()); + } + else { + XSObject[] components = xsinput.getComponents(); + if (components != null && components.length > 0) { + grammar = fGrammarBucket.getGrammar(components[0].getNamespace()); + } + } + } + // something went wrong right off the hop + return grammar; + } + + if (referType == XSDDescription.CONTEXT_PREPARSE) { + Element schemaElem = schemaRoot; + schemaNamespace = DOMUtil.getAttrValue(schemaElem, SchemaSymbols.ATT_TARGETNAMESPACE); + if(schemaNamespace != null && schemaNamespace.length() > 0) { + // Since now we've discovered a namespace, we need to update xsd key + // and store this schema in traversed schemas bucket + schemaNamespace = fSymbolTable.addSymbol(schemaNamespace); + desc.setTargetNamespace(schemaNamespace); + } + else { + schemaNamespace = null; + } + grammar = findGrammar(desc, fNamespaceGrowth); + String schemaId = XMLEntityManager.expandSystemId(is.getSystemId(), is.getBaseSystemId(), false); + if (grammar != null) { + // When namespace growth is enabled and a null location is provided we cannot tell + // whether we've loaded this schema document before so we must assume that we haven't. + if (!fNamespaceGrowth || (schemaId != null && grammar.getDocumentLocations().contains(schemaId))) { + return grammar; + } + } + + XSDKey key = new XSDKey(schemaId, referType, schemaNamespace); + fTraversed.put(key, schemaRoot); + if (schemaId != null) { + fDoc2SystemId.put(schemaRoot, schemaId); + } + } + + // before constructing trees and traversing a schema, need to reset + // all traversers and clear all registries + prepareForTraverse(); + + fRoot = constructTrees(schemaRoot, is.getSystemId(), desc, grammar != null); + if (fRoot == null) { + return null; + } + + // second phase: fill global registries. + buildGlobalNameRegistries(); + + // third phase: call traversers + ArrayList annotationInfo = fValidateAnnotations ? new ArrayList() : null; + traverseSchemas(annotationInfo); + + // fourth phase: handle local element decls + traverseLocalElements(); + + // fifth phase: handle Keyrefs + resolveKeyRefs(); + + // sixth phase: validate attribute of non-schema namespaces + // REVISIT: skip this for now. we really don't want to do it. + //fAttributeChecker.checkNonSchemaAttributes(fGrammarBucket); + + // seventh phase: store imported grammars + // for all grammars with s + for (int i = fAllTNSs.size() - 1; i >= 0; i--) { + // get its target namespace + String tns = (String)fAllTNSs.elementAt(i); + // get all namespaces it imports + Vector ins = (Vector)fImportMap.get(tns); + // get the grammar + SchemaGrammar sg = fGrammarBucket.getGrammar(emptyString2Null(tns)); + if (sg == null) + continue; + SchemaGrammar isg; + // for imported namespace + int count = 0; + for (int j = 0; j < ins.size(); j++) { + // get imported grammar + isg = fGrammarBucket.getGrammar((String)ins.elementAt(j)); + // reuse the same vector + if (isg != null) + ins.setElementAt(isg, count++); + } + ins.setSize(count); + // set the imported grammars + sg.setImportedGrammars(ins); + } + + /** validate annotations **/ + if (fValidateAnnotations && annotationInfo.size() > 0) { + validateAnnotations(annotationInfo); + } + + // and return. + return fGrammarBucket.getGrammar(fRoot.fTargetNamespace); + } // end parseSchema + + private void validateAnnotations(ArrayList annotationInfo) { + if (fAnnotationValidator == null) { + createAnnotationValidator(); + } + final int size = annotationInfo.size(); + final XMLInputSource src = new XMLInputSource(null, null, null); + fGrammarBucketAdapter.refreshGrammars(fGrammarBucket); + for (int i = 0; i < size; i += 2) { + src.setSystemId((String) annotationInfo.get(i)); + XSAnnotationInfo annotation = (XSAnnotationInfo) annotationInfo.get(i+1); + while (annotation != null) { + src.setCharacterStream(new StringReader(annotation.fAnnotation)); + try { + fAnnotationValidator.parse(src); + } + catch (IOException exc) {} + annotation = annotation.next; + } + } + } + + private void createAnnotationValidator() { + fAnnotationValidator = new XML11Configuration(); + fGrammarBucketAdapter = new XSAnnotationGrammarPool(); + fAnnotationValidator.setFeature(VALIDATION, true); + fAnnotationValidator.setFeature(XMLSCHEMA_VALIDATION, true); + fAnnotationValidator.setProperty(XMLGRAMMAR_POOL, fGrammarBucketAdapter); + /** Set error handler. **/ + XMLErrorHandler errorHandler = fErrorReporter.getErrorHandler(); + fAnnotationValidator.setProperty(ERROR_HANDLER, (errorHandler != null) ? errorHandler : new DefaultErrorHandler()); + /** Set locale. **/ + Locale locale = fErrorReporter.getLocale(); + fAnnotationValidator.setProperty(LOCALE, locale); + } + + /** + * Pull the grammar out of the bucket simply using + * its TNS as a key + */ + SchemaGrammar getGrammar(String tns) { + return fGrammarBucket.getGrammar(tns); + } + + /** + * First try to find a grammar in the bucket, if failed, consult the + * grammar pool. If a grammar is found in the pool, then add it (and all + * imported ones) into the bucket. + */ + protected SchemaGrammar findGrammar(XSDDescription desc, boolean ignoreConflict) { + SchemaGrammar sg = fGrammarBucket.getGrammar(desc.getTargetNamespace()); + if (sg == null) { + if (fGrammarPool != null) { + sg = (SchemaGrammar)fGrammarPool.retrieveGrammar(desc); + if (sg != null) { + // put this grammar into the bucket, along with grammars + // imported by it (directly or indirectly) + if (!fGrammarBucket.putGrammar(sg, true, ignoreConflict)) { + // REVISIT: a conflict between new grammar(s) and grammars + // in the bucket. What to do? A warning? An exception? + reportSchemaWarning("GrammarConflict", null, null); + sg = null; + } + } + } + } + return sg; + } + + // may wish to have setter methods for ErrorHandler, + // EntityResolver... + + private static final String[][] NS_ERROR_CODES = { + {"src-include.2.1", "src-include.2.1"}, + {"src-redefine.3.1", "src-redefine.3.1"}, + {"src-import.3.1", "src-import.3.2"}, + null, + {"TargetNamespace.1", "TargetNamespace.2"}, + {"TargetNamespace.1", "TargetNamespace.2"}, + {"TargetNamespace.1", "TargetNamespace.2"}, + {"TargetNamespace.1", "TargetNamespace.2"} + }; + + private static final String[] ELE_ERROR_CODES = { + "src-include.1", "src-redefine.2", "src-import.2", "schema_reference.4", + "schema_reference.4", "schema_reference.4", "schema_reference.4", "schema_reference.4" + }; + + // This method does several things: + // It constructs an instance of an XSDocumentInfo object using the + // schemaRoot node. Then, for each , + // , and children, it attempts to resolve the + // requested schema document, initiates a DOM parse, and calls + // itself recursively on that document's root. It also records in + // the DependencyMap object what XSDocumentInfo objects its XSDocumentInfo + // depends on. + // It also makes sure the targetNamespace of the schema it was + // called to parse is correct. + protected XSDocumentInfo constructTrees(Element schemaRoot, String locationHint, XSDDescription desc, boolean nsCollision) { + if (schemaRoot == null) return null; + String callerTNS = desc.getTargetNamespace(); + short referType = desc.getContextType(); + + XSDocumentInfo currSchemaInfo = null; + try { + // note that attributes are freed at end of traverseSchemas() + currSchemaInfo = new XSDocumentInfo(schemaRoot, fAttributeChecker, fSymbolTable); + } catch (XMLSchemaException se) { + reportSchemaError(ELE_ERROR_CODES[referType], + new Object[]{locationHint}, + schemaRoot); + return null; + } + // targetNamespace="" is not valid, issue a warning, and ignore it + if (currSchemaInfo.fTargetNamespace != null && + currSchemaInfo.fTargetNamespace.length() == 0) { + reportSchemaWarning("EmptyTargetNamespace", + new Object[]{locationHint}, + schemaRoot); + currSchemaInfo.fTargetNamespace = null; + } + + if (callerTNS != null) { + // the second index to the NS_ERROR_CODES array + // if the caller/expected NS is not absent, we use the first column + int secondIdx = 0; + // for include and redefine + if (referType == XSDDescription.CONTEXT_INCLUDE || + referType == XSDDescription.CONTEXT_REDEFINE) { + // if the referred document has no targetNamespace, + // it's a chameleon schema + if (currSchemaInfo.fTargetNamespace == null) { + currSchemaInfo.fTargetNamespace = callerTNS; + currSchemaInfo.fIsChameleonSchema = true; + } + // if the referred document has a target namespace differing + // from the caller, it's an error + else if (callerTNS != currSchemaInfo.fTargetNamespace) { + reportSchemaError(NS_ERROR_CODES[referType][secondIdx], + new Object [] {callerTNS, currSchemaInfo.fTargetNamespace}, + schemaRoot); + return null; + } + } + // for instance and import, the two NS's must be the same + else if (referType != XSDDescription.CONTEXT_PREPARSE && callerTNS != currSchemaInfo.fTargetNamespace) { + reportSchemaError(NS_ERROR_CODES[referType][secondIdx], + new Object [] {callerTNS, currSchemaInfo.fTargetNamespace}, + schemaRoot); + return null; + } + } + // now there is no caller/expected NS, it's an error for the referred + // document to have a target namespace, unless we are preparsing a schema + else if (currSchemaInfo.fTargetNamespace != null) { + // set the target namespace of the description + if (referType == XSDDescription.CONTEXT_PREPARSE) { + desc.setTargetNamespace(currSchemaInfo.fTargetNamespace); + callerTNS = currSchemaInfo.fTargetNamespace; + } + else { + // the second index to the NS_ERROR_CODES array + // if the caller/expected NS is absent, we use the second column + int secondIdx = 1; + reportSchemaError(NS_ERROR_CODES[referType][secondIdx], + new Object [] {callerTNS, currSchemaInfo.fTargetNamespace}, + schemaRoot); + return null; + } + } + // the other cases (callerTNS == currSchemaInfo.fTargetNamespce == null) + // are valid + + // a schema document can always access it's own target namespace + currSchemaInfo.addAllowedNS(currSchemaInfo.fTargetNamespace); + + SchemaGrammar sg = null; + + // we have a namespace collision + if (nsCollision) { + SchemaGrammar sg2 = fGrammarBucket.getGrammar(currSchemaInfo.fTargetNamespace); + if (sg2.isImmutable()) { + sg = new SchemaGrammar(sg2); + fGrammarBucket.putGrammar(sg); + // update all the grammars in the bucket to point to the new grammar. + updateImportListWith(sg); + } + else { + sg = sg2; + } + + // update import list of the new grammar + updateImportListFor(sg); + } + else if (referType == XSDDescription.CONTEXT_INCLUDE || + referType == XSDDescription.CONTEXT_REDEFINE) { + sg = fGrammarBucket.getGrammar(currSchemaInfo.fTargetNamespace); + } + else if(fHonourAllSchemaLocations && referType == XSDDescription.CONTEXT_IMPORT) { + sg = findGrammar(desc, false); + if(sg == null) { + sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace, desc.makeClone(), fSymbolTable); + fGrammarBucket.putGrammar(sg); + } + } + else { + sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace, desc.makeClone(), fSymbolTable); + fGrammarBucket.putGrammar(sg); + } + + // store the document and its location + // REVISIT: don't expose the DOM tree + sg.addDocument(null, (String)fDoc2SystemId.get(currSchemaInfo.fSchemaElement)); + + fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo); + Vector dependencies = new Vector(); + Element rootNode = schemaRoot; + + Element newSchemaRoot = null; + for (Element child = DOMUtil.getFirstChildElement(rootNode); + child != null; + child = DOMUtil.getNextSiblingElement(child)) { + String schemaNamespace=null; + String schemaHint=null; + String localName = DOMUtil.getLocalName(child); + + short refType = -1; + boolean importCollision = false; + + if (localName.equals(SchemaSymbols.ELT_ANNOTATION)) + continue; + else if (localName.equals(SchemaSymbols.ELT_IMPORT)) { + refType = XSDDescription.CONTEXT_IMPORT; + // have to handle some validation here too! + // call XSAttributeChecker to fill in attrs + Object[] importAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo); + schemaHint = (String)importAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION]; + schemaNamespace = (String)importAttrs[XSAttributeChecker.ATTIDX_NAMESPACE]; + if (schemaNamespace != null) + schemaNamespace = fSymbolTable.addSymbol(schemaNamespace); + + // check contents and process optional annotations + Element importChild = DOMUtil.getFirstChildElement(child); + if(importChild != null ) { + String importComponentType = DOMUtil.getLocalName(importChild); + if (importComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) { + // promoting annotations to parent component + sg.addAnnotation( + fElementTraverser.traverseAnnotationDecl(importChild, importAttrs, true, currSchemaInfo)); + } else { + reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", importComponentType}, child); + } + if(DOMUtil.getNextSiblingElement(importChild) != null) { + reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(importChild))}, child); + } + } + else { + String text = DOMUtil.getSyntheticAnnotation(child); + if (text != null) { + sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, importAttrs, true, currSchemaInfo)); + } + } + fAttributeChecker.returnAttrArray(importAttrs, currSchemaInfo); + + // a document can't import another document with the same namespace + if (schemaNamespace == currSchemaInfo.fTargetNamespace) { + reportSchemaError(schemaNamespace != null ? + "src-import.1.1" : "src-import.1.2", new Object [] {schemaNamespace}, child); + continue; + } + + // if this namespace has not been imported by this document, + // then import if multiple imports support is enabled. + if(currSchemaInfo.isAllowedNS(schemaNamespace)) { + if(!fHonourAllSchemaLocations && !fNamespaceGrowth) + continue; + } + else { + currSchemaInfo.addAllowedNS(schemaNamespace); + } + // also record the fact that one namespace imports another one + // convert null to "" + String tns = null2EmptyString(currSchemaInfo.fTargetNamespace); + // get all namespaces imported by this one + Vector ins = (Vector)fImportMap.get(tns); + // if no namespace was imported, create new Vector + if (ins == null) { + // record that this one imports other(s) + fAllTNSs.addElement(tns); + ins = new Vector(); + fImportMap.put(tns, ins); + ins.addElement(schemaNamespace); + } + else if (!ins.contains(schemaNamespace)){ + ins.addElement(schemaNamespace); + } + + fSchemaGrammarDescription.reset(); + fSchemaGrammarDescription.setContextType(XSDDescription.CONTEXT_IMPORT); + fSchemaGrammarDescription.setBaseSystemId(doc2SystemId(schemaRoot)); + fSchemaGrammarDescription.setLiteralSystemId(schemaHint); + fSchemaGrammarDescription.setLocationHints(new String[]{schemaHint}); + fSchemaGrammarDescription.setTargetNamespace(schemaNamespace); + + // if a grammar with the same namespace and location exists (or being + // built), ignore this one (don't traverse it). + SchemaGrammar isg = findGrammar(fSchemaGrammarDescription, fNamespaceGrowth); + if (isg != null) { + if (fNamespaceGrowth) { + try { + if (isg.getDocumentLocations().contains(XMLEntityManager.expandSystemId(schemaHint, fSchemaGrammarDescription.getBaseSystemId(), false))) { + continue; + } + else { + importCollision = true; + } + } + catch (MalformedURIException e) { + } + } + else if (!fHonourAllSchemaLocations || isExistingGrammar(fSchemaGrammarDescription, false)) { + continue; + } + } + //if ((!fHonourAllSchemaLocations && findGrammar(fSchemaGrammarDescription) != null) || isExistingGrammar(fSchemaGrammarDescription)) + // continue; + + // If "findGrammar" returns a grammar, then this is not the + // the first time we see a location for a given namespace. + // Don't consult the location pair hashtable in this case, + // otherwise the location will be ignored because it'll get + // resolved to the same location as the first hint. + newSchemaRoot = resolveSchema(fSchemaGrammarDescription, false, child, isg == null); + } + else if ((localName.equals(SchemaSymbols.ELT_INCLUDE)) || + (localName.equals(SchemaSymbols.ELT_REDEFINE))) { + // validation for redefine/include will be the same here; just + // make sure TNS is right (don't care about redef contents + // yet). + Object[] includeAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo); + schemaHint = (String)includeAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION]; + // store the namespace decls of the redefine element + if (localName.equals(SchemaSymbols.ELT_REDEFINE)) { + fRedefine2NSSupport.put(child, new SchemaNamespaceSupport(currSchemaInfo.fNamespaceSupport)); + } + + // check annotations. Must do this here to avoid having to + // re-parse attributes later + if(localName.equals(SchemaSymbols.ELT_INCLUDE)) { + Element includeChild = DOMUtil.getFirstChildElement(child); + if(includeChild != null ) { + String includeComponentType = DOMUtil.getLocalName(includeChild); + if (includeComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) { + // promoting annotations to parent component + sg.addAnnotation( + fElementTraverser.traverseAnnotationDecl(includeChild, includeAttrs, true, currSchemaInfo)); + } else { + reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", includeComponentType}, child); + } + if(DOMUtil.getNextSiblingElement(includeChild) != null) { + reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(includeChild))}, child); + } + } + else { + String text = DOMUtil.getSyntheticAnnotation(child); + if (text != null) { + sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, includeAttrs, true, currSchemaInfo)); + } + } + } + else { + for (Element redefinedChild = DOMUtil.getFirstChildElement(child); + redefinedChild != null; + redefinedChild = DOMUtil.getNextSiblingElement(redefinedChild)) { + String redefinedComponentType = DOMUtil.getLocalName(redefinedChild); + if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) { + // promoting annotations to parent component + sg.addAnnotation( + fElementTraverser.traverseAnnotationDecl(redefinedChild, includeAttrs, true, currSchemaInfo)); + DOMUtil.setHidden(redefinedChild, fHiddenNodes); + } + else { + String text = DOMUtil.getSyntheticAnnotation(child); + if (text != null) { + sg.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(child, text, includeAttrs, true, currSchemaInfo)); + } + } + // catch all other content errors later + } + } + fAttributeChecker.returnAttrArray(includeAttrs, currSchemaInfo); + // schemaLocation is required on and + if (schemaHint == null) { + reportSchemaError("s4s-att-must-appear", new Object [] { + " or ", "schemaLocation"}, + child); + } + // pass the systemId of the current document as the base systemId + boolean mustResolve = false; + refType = XSDDescription.CONTEXT_INCLUDE; + if(localName.equals(SchemaSymbols.ELT_REDEFINE)) { + mustResolve = nonAnnotationContent(child); + refType = XSDDescription.CONTEXT_REDEFINE; + } + fSchemaGrammarDescription.reset(); + fSchemaGrammarDescription.setContextType(refType); + fSchemaGrammarDescription.setBaseSystemId(doc2SystemId(schemaRoot)); + fSchemaGrammarDescription.setLocationHints(new String[]{schemaHint}); + fSchemaGrammarDescription.setTargetNamespace(callerTNS); + + boolean alreadyTraversed = false; + XMLInputSource schemaSource = resolveSchemaSource(fSchemaGrammarDescription, mustResolve, child, true); + if (fNamespaceGrowth && refType == XSDDescription.CONTEXT_INCLUDE) { + try { + final String schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId(), false); + alreadyTraversed = sg.getDocumentLocations().contains(schemaId); + } + catch(MalformedURIException e) { + + } + } + + if (!alreadyTraversed) { + newSchemaRoot = resolveSchema(schemaSource, fSchemaGrammarDescription, mustResolve, child); + schemaNamespace = currSchemaInfo.fTargetNamespace; + } + else { + fLastSchemaWasDuplicate = true; + } + } + else { + // no more possibility of schema references in well-formed + // schema... + break; + } + + // If the schema is duplicate, we needn't call constructTrees() again. + // To handle mutual s + XSDocumentInfo newSchemaInfo = null; + if (fLastSchemaWasDuplicate) { + newSchemaInfo = newSchemaRoot == null ? null : (XSDocumentInfo)fDoc2XSDocumentMap.get(newSchemaRoot); + } + else { + newSchemaInfo = constructTrees(newSchemaRoot, schemaHint, fSchemaGrammarDescription, importCollision); + } + + if (localName.equals(SchemaSymbols.ELT_REDEFINE) && + newSchemaInfo != null) { + // must record which schema we're redefining so that we can + // rename the right things later! + fRedefine2XSDMap.put(child, newSchemaInfo); + } + if (newSchemaRoot != null) { + if (newSchemaInfo != null) + dependencies.addElement(newSchemaInfo); + newSchemaRoot = null; + } + } + + fDependencyMap.put(currSchemaInfo, dependencies); + return currSchemaInfo; + } // end constructTrees + + private boolean isExistingGrammar(XSDDescription desc, boolean ignoreConflict) { + SchemaGrammar sg = fGrammarBucket.getGrammar(desc.getTargetNamespace()); + if (sg == null) { + return findGrammar(desc, ignoreConflict) != null; + } + else if (sg.isImmutable()) { + return true; + } + else { + try { + return sg.getDocumentLocations().contains(XMLEntityManager.expandSystemId(desc.getLiteralSystemId(), desc.getBaseSystemId(), false)); + } + catch (MalformedURIException e) { + return false; + } + } + } + + /** + * Namespace growth + * + * Go through the import list of a given grammar and for each imported + * grammar, check to see if the grammar bucket has a newer version. + * If a new instance is found, we update the import list with the + * newer version. + */ + private void updateImportListFor(SchemaGrammar grammar) { + Vector importedGrammars = grammar.getImportedGrammars(); + if (importedGrammars != null) { + for (int i=0; i). We + // also put names in a registry that we look through in + // case something needs renaming. Once we're done with a schema we + // set its Document node to hidden so that we don't try to traverse + // it again; then we look to its Dependency map entry. We keep a + // stack of schemas that we haven't yet finished processing; this + // is a depth-first traversal. + + Stack schemasToProcess = new Stack(); + schemasToProcess.push(fRoot); + + while (!schemasToProcess.empty()) { + XSDocumentInfo currSchemaDoc = + (XSDocumentInfo)schemasToProcess.pop(); + Element currDoc = currSchemaDoc.fSchemaElement; + if(DOMUtil.isHidden(currDoc, fHiddenNodes)){ + // must have processed this already! + continue; + } + + Element currRoot = currDoc; + // process this schema's global decls + boolean dependenciesCanOccur = true; + for (Element globalComp = + DOMUtil.getFirstChildElement(currRoot); + globalComp != null; + globalComp = DOMUtil.getNextSiblingElement(globalComp)) { + // this loop makes sure the element ordering is + // also valid. + if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_ANNOTATION)) { + //skip it; traverse it later + continue; + } + else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_INCLUDE) || + DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_IMPORT)) { + if (!dependenciesCanOccur) { + reportSchemaError("s4s-elt-invalid-content.3", new Object [] {DOMUtil.getLocalName(globalComp)}, globalComp); + } + DOMUtil.setHidden(globalComp, fHiddenNodes); + } + else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) { + if (!dependenciesCanOccur) { + reportSchemaError("s4s-elt-invalid-content.3", new Object [] {DOMUtil.getLocalName(globalComp)}, globalComp); + } + for (Element redefineComp = DOMUtil.getFirstChildElement(globalComp); + redefineComp != null; + redefineComp = DOMUtil.getNextSiblingElement(redefineComp)) { + String lName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME); + if (lName.length() == 0) // an error we'll catch later + continue; + String qName = currSchemaDoc.fTargetNamespace == null ? + ","+lName: + currSchemaDoc.fTargetNamespace +","+lName; + qName = XMLChar.trim(qName); + String componentType = DOMUtil.getLocalName(redefineComp); + if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { + checkForDuplicateNames(qName, ATTRIBUTEGROUP_TYPE, fUnparsedAttributeGroupRegistry, fUnparsedAttributeGroupRegistrySub, redefineComp, currSchemaDoc); + // the check will have changed our name; + String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER; + // and all we need to do is error-check+rename our kkids: + renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_ATTRIBUTEGROUP, + lName, targetLName); + } + else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) || + (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) { + checkForDuplicateNames(qName, TYPEDECL_TYPE, fUnparsedTypeRegistry, fUnparsedTypeRegistrySub, redefineComp, currSchemaDoc); + // the check will have changed our name; + String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME) + REDEF_IDENTIFIER; + // and all we need to do is error-check+rename our kkids: + if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { + renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_COMPLEXTYPE, + lName, targetLName); + } + else { // must be simpleType + renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_SIMPLETYPE, + lName, targetLName); + } + } + else if (componentType.equals(SchemaSymbols.ELT_GROUP)) { + checkForDuplicateNames(qName, GROUP_TYPE, fUnparsedGroupRegistry, fUnparsedGroupRegistrySub, redefineComp, currSchemaDoc); + // the check will have changed our name; + String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER; + // and all we need to do is error-check+rename our kids: + renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_GROUP, + lName, targetLName); + } + } // end march through children + // and now set as traversed + //DOMUtil.setHidden(globalComp); + } + else { + dependenciesCanOccur = false; + String lName = DOMUtil.getAttrValue(globalComp, SchemaSymbols.ATT_NAME); + if (lName.length() == 0) // an error we'll catch later + continue; + String qName = currSchemaDoc.fTargetNamespace == null? + ","+lName: + currSchemaDoc.fTargetNamespace +","+lName; + qName = XMLChar.trim(qName); + String componentType = DOMUtil.getLocalName(globalComp); + + if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) { + checkForDuplicateNames(qName, ATTRIBUTE_TYPE, fUnparsedAttributeRegistry, fUnparsedAttributeRegistrySub, globalComp, currSchemaDoc); + } + else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { + checkForDuplicateNames(qName, ATTRIBUTEGROUP_TYPE, fUnparsedAttributeGroupRegistry, fUnparsedAttributeGroupRegistrySub, globalComp, currSchemaDoc); + } + else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) || + (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) { + checkForDuplicateNames(qName, TYPEDECL_TYPE, fUnparsedTypeRegistry, fUnparsedTypeRegistrySub, globalComp, currSchemaDoc); + } + else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) { + checkForDuplicateNames(qName, ELEMENT_TYPE, fUnparsedElementRegistry, fUnparsedElementRegistrySub, globalComp, currSchemaDoc); + } + else if (componentType.equals(SchemaSymbols.ELT_GROUP)) { + checkForDuplicateNames(qName, GROUP_TYPE, fUnparsedGroupRegistry, fUnparsedGroupRegistrySub, globalComp, currSchemaDoc); + } + else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) { + checkForDuplicateNames(qName, NOTATION_TYPE, fUnparsedNotationRegistry, fUnparsedNotationRegistrySub, globalComp, currSchemaDoc); + } + } + } // end for + + // now we're done with this one! + DOMUtil.setHidden(currDoc, fHiddenNodes); + // now add the schemas this guy depends on + Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc); + for (int i = 0; i < currSchemaDepends.size(); i++) { + schemasToProcess.push(currSchemaDepends.elementAt(i)); + } + } // while + + } // end buildGlobalNameRegistries + + // Beginning at the first schema processing was requested for + // (fRoot), this method + // examines each child (global schema information item) of each + // schema document (and of each element) + // corresponding to an XSDocumentInfo object. If the + // readOnly field on that node has not been set, it calls an + // appropriate traverser to traverse it. Once all global decls in + // an XSDocumentInfo object have been traversed, it marks that object + // as traversed (or hidden) in order to avoid infinite loops. It completes + // when it has visited all XSDocumentInfo objects in the + // DependencyMap and marked them as traversed. + protected void traverseSchemas(ArrayList annotationInfo) { + // the process here is very similar to that in + // buildGlobalRegistries, except we can't set our schemas as + // hidden for a second time; so make them all visible again + // first! + setSchemasVisible(fRoot); + Stack schemasToProcess = new Stack(); + schemasToProcess.push(fRoot); + while (!schemasToProcess.empty()) { + XSDocumentInfo currSchemaDoc = + (XSDocumentInfo)schemasToProcess.pop(); + Element currDoc = currSchemaDoc.fSchemaElement; + + SchemaGrammar currSG = fGrammarBucket.getGrammar(currSchemaDoc.fTargetNamespace); + + if(DOMUtil.isHidden(currDoc, fHiddenNodes)) { + // must have processed this already! + continue; + } + Element currRoot = currDoc; + boolean sawAnnotation = false; + // traverse this schema's global decls + for (Element globalComp = + DOMUtil.getFirstVisibleChildElement(currRoot, fHiddenNodes); + globalComp != null; + globalComp = DOMUtil.getNextVisibleSiblingElement(globalComp, fHiddenNodes)) { + DOMUtil.setHidden(globalComp, fHiddenNodes); + String componentType = DOMUtil.getLocalName(globalComp); + // includes and imports will not show up here! + if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) { + // use the namespace decls for the redefine, instead of for the parent + currSchemaDoc.backupNSSupport((SchemaNamespaceSupport)fRedefine2NSSupport.get(globalComp)); + for (Element redefinedComp = DOMUtil.getFirstVisibleChildElement(globalComp, fHiddenNodes); + redefinedComp != null; + redefinedComp = DOMUtil.getNextVisibleSiblingElement(redefinedComp, fHiddenNodes)) { + String redefinedComponentType = DOMUtil.getLocalName(redefinedComp); + DOMUtil.setHidden(redefinedComp, fHiddenNodes); + if (redefinedComponentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { + fAttributeGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG); + } + else if (redefinedComponentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { + fComplexTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG); + } + else if (redefinedComponentType.equals(SchemaSymbols.ELT_GROUP)) { + fGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG); + } + else if (redefinedComponentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) { + fSimpleTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG); + } + // annotations will have been processed already; this is now + // unnecessary + //else if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) { + // fElementTraverser.traverseAnnotationDecl(redefinedComp, null, true, currSchemaDoc); + //} + else { + reportSchemaError("s4s-elt-must-match.1", new Object [] {DOMUtil.getLocalName(globalComp), "(annotation | (simpleType | complexType | group | attributeGroup))*", redefinedComponentType}, redefinedComp); + } + } // end march through children + currSchemaDoc.restoreNSSupport(); + } + else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) { + fAttributeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); + } + else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { + fAttributeGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); + } + else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { + fComplexTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); + } + else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) { + fElementTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); + } + else if (componentType.equals(SchemaSymbols.ELT_GROUP)) { + fGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); + } + else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) { + fNotationTraverser.traverse(globalComp, currSchemaDoc, currSG); + } + else if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) { + fSimpleTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG); + } + else if (componentType.equals(SchemaSymbols.ELT_ANNOTATION)) { + currSG.addAnnotation(fElementTraverser.traverseAnnotationDecl(globalComp, currSchemaDoc.getSchemaAttrs(), true, currSchemaDoc)); + sawAnnotation = true; + } + else { + reportSchemaError("s4s-elt-invalid-content.1", new Object [] {SchemaSymbols.ELT_SCHEMA, DOMUtil.getLocalName(globalComp)}, globalComp); + } + } // end for + + if (!sawAnnotation) { + String text = DOMUtil.getSyntheticAnnotation(currRoot); + if (text != null) { + currSG.addAnnotation(fElementTraverser.traverseSyntheticAnnotation(currRoot, text, currSchemaDoc.getSchemaAttrs(), true, currSchemaDoc)); + } + } + + /** Collect annotation information for validation. **/ + if (annotationInfo != null) { + XSAnnotationInfo info = currSchemaDoc.getAnnotations(); + /** Only add annotations to the list if there were any in this document. **/ + if (info != null) { + annotationInfo.add(doc2SystemId(currDoc)); + annotationInfo.add(info); + } + } + // now we're done with this one! + currSchemaDoc.returnSchemaAttrs(); + DOMUtil.setHidden(currDoc, fHiddenNodes); + + // now add the schemas this guy depends on + Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc); + for (int i = 0; i < currSchemaDepends.size(); i++) { + schemasToProcess.push(currSchemaDepends.elementAt(i)); + } + } // while + } // end traverseSchemas + + // store whether we have reported an error about that no grammar + // is found for the given namespace uri + private Vector fReportedTNS = null; + // check whether we need to report an error against the given uri. + // if we have reported an error, then we don't need to report again; + // otherwise we reported the error, and remember this fact. + private final boolean needReportTNSError(String uri) { + if (fReportedTNS == null) + fReportedTNS = new Vector(); + else if (fReportedTNS.contains(uri)) + return false; + fReportedTNS.addElement(uri); + return true; + } + + private static final String[] COMP_TYPE = { + null, // index 0 + "attribute declaration", + "attribute group", + "element declaration", + "group", + "identity constraint", + "notation", + "type definition", + }; + + private static final String[] CIRCULAR_CODES = { + "Internal-Error", + "Internal-Error", + "src-attribute_group.3", + "e-props-correct.6", + "mg-props-correct.2", + "Internal-Error", + "Internal-Error", + "st-props-correct.2", //or ct-props-correct.3 + }; + + // add a global attribute decl from a current schema load (only if no existing decl is found) + void addGlobalAttributeDecl(XSAttributeDecl decl) { + final String namespace = decl.getNamespace(); + final String declKey = (namespace == null || namespace.length() == 0) + ? "," + decl.getName() : namespace + "," + decl.getName(); + + if (fGlobalAttrDecls.get(declKey) == null) { + fGlobalAttrDecls.put(declKey, decl); + } + } + + // add a global attribute group decl from a current schema load (only if no existing decl is found) + void addGlobalAttributeGroupDecl(XSAttributeGroupDecl decl) { + final String namespace = decl.getNamespace(); + final String declKey = (namespace == null || namespace.length() == 0) + ? "," + decl.getName() : namespace + "," + decl.getName(); + + if (fGlobalAttrGrpDecls.get(declKey) == null) { + fGlobalAttrGrpDecls.put(declKey, decl); + } + } + + // add a global element decl from a current schema load (only if no existing decl is found) + void addGlobalElementDecl(XSElementDecl decl) { + final String namespace = decl.getNamespace(); + final String declKey = (namespace == null || namespace.length() == 0) + ? "," + decl.getName() : namespace + "," + decl.getName(); + + if (fGlobalElemDecls.get(declKey) == null) { + fGlobalElemDecls.put(declKey, decl); + } + } + + // add a global group decl from a current schema load (only if no existing decl is found) + void addGlobalGroupDecl(XSGroupDecl decl) { + final String namespace = decl.getNamespace(); + final String declKey = (namespace == null || namespace.length() == 0) + ? "," + decl.getName() : namespace + "," + decl.getName(); + + if (fGlobalGroupDecls.get(declKey) == null) { + fGlobalGroupDecls.put(declKey, decl); + } + } + + // add a global notation decl from a current schema load (only if no existing decl is found) + void addGlobalNotationDecl(XSNotationDecl decl) { + final String namespace = decl.getNamespace(); + final String declKey = (namespace == null || namespace.length() == 0) + ? "," + decl.getName() : namespace + "," + decl.getName(); + + if (fGlobalNotationDecls.get(declKey) == null) { + fGlobalNotationDecls.put(declKey, decl); + } + } + + // add a global type decl from a current schema load (only if no existing decl is found) + void addGlobalTypeDecl(XSTypeDefinition decl) { + final String namespace = decl.getNamespace(); + final String declKey = (namespace == null || namespace.length() == 0) + ? "," + decl.getName() : namespace + "," + decl.getName(); + + if (fGlobalTypeDecls.get(declKey) == null) { + fGlobalTypeDecls.put(declKey, decl); + } + } + + // add a identity constraint decl from a current schema load (only if no existing decl is found) + void addIDConstraintDecl(IdentityConstraint decl) { + final String namespace = decl.getNamespace(); + final String declKey = (namespace == null || namespace.length() == 0) + ? "," + decl.getIdentityConstraintName() : namespace + "," + decl.getIdentityConstraintName(); + + if (fGlobalIDConstraintDecls.get(declKey) == null) { + fGlobalIDConstraintDecls.put(declKey, decl); + } + } + + private XSAttributeDecl getGlobalAttributeDecl(String declKey) { + return (XSAttributeDecl)fGlobalAttrDecls.get(declKey); + } + + private XSAttributeGroupDecl getGlobalAttributeGroupDecl(String declKey) { + return (XSAttributeGroupDecl)fGlobalAttrGrpDecls.get(declKey); + } + + private XSElementDecl getGlobalElementDecl(String declKey) { + return (XSElementDecl)fGlobalElemDecls.get(declKey); + } + + private XSGroupDecl getGlobalGroupDecl(String declKey) { + return (XSGroupDecl)fGlobalGroupDecls.get(declKey); + } + + private XSNotationDecl getGlobalNotationDecl(String declKey) { + return (XSNotationDecl)fGlobalNotationDecls.get(declKey); + } + + private XSTypeDefinition getGlobalTypeDecl(String declKey) { + return (XSTypeDefinition)fGlobalTypeDecls.get(declKey); + } + + private IdentityConstraint getIDConstraintDecl(String declKey) { + return (IdentityConstraint)fGlobalIDConstraintDecls.get(declKey); + } + + // since it is forbidden for traversers to talk to each other + // directly (except wen a traverser encounters a local declaration), + // this provides a generic means for a traverser to call + // for the traversal of some declaration. An XSDocumentInfo is + // required because the XSDocumentInfo that the traverser is traversing + // may bear no relation to the one the handler is operating on. + // This method will: + // 1. See if a global definition matching declToTraverse exists; + // 2. if so, determine if there is a path from currSchema to the + // schema document where declToTraverse lives (i.e., do a lookup + // in DependencyMap); + // 3. depending on declType (which will be relevant to step 1 as + // well), call the appropriate traverser with the appropriate + // XSDocumentInfo object. + // This method returns whatever the traverser it called returned; + // this will be an Object of some kind + // that lives in the Grammar. + protected Object getGlobalDecl(XSDocumentInfo currSchema, + int declType, + QName declToTraverse, + Element elmNode) { + + if (DEBUG_NODE_POOL) { + System.out.println("TRAVERSE_GL: "+declToTraverse.toString()); + } + + // from the schema spec, all built-in types are present in all schemas, + // so if the requested component is a type, and could be found in the + // default schema grammar, we should return that type. + // otherwise (since we would support user-defined schema grammar) we'll + // use the normal way to get the decl + if (declToTraverse.uri != null && + declToTraverse.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) { + if (declType == TYPEDECL_TYPE) { + Object retObj = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(declToTraverse.localpart); + if (retObj != null) + return retObj; + } + } + + // now check whether this document can access the requsted namespace + if (!currSchema.isAllowedNS(declToTraverse.uri)) { + // cannot get to this schema from the one containing the requesting decl + if (currSchema.needReportTNSError(declToTraverse.uri)) { + String code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2"; + reportSchemaError(code, new Object[]{fDoc2SystemId.get(currSchema.fSchemaElement), declToTraverse.uri, declToTraverse.rawname}, elmNode); + } + // Recover and continue to look for the component. + // return null; + } + + // check whether there is grammar for the requested namespace + SchemaGrammar sGrammar = fGrammarBucket.getGrammar(declToTraverse.uri); + if (sGrammar == null) { + if (needReportTNSError(declToTraverse.uri)) + reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode); + return null; + } + + // if there is such grammar, check whether the requested component is in the grammar + Object retObj = getGlobalDeclFromGrammar(sGrammar, declType, declToTraverse.localpart); + String declKey = declToTraverse.uri == null? ","+declToTraverse.localpart: + declToTraverse.uri+","+declToTraverse.localpart; + + // if the component is parsed, return it + if (!fTolerateDuplicates) { + if (retObj != null) { + return retObj; + } + } + else { + Object retObj2 = getGlobalDecl(declKey, declType); + if (retObj2 != null) { + return retObj2; + } + } + + XSDocumentInfo schemaWithDecl = null; + Element decl = null; + XSDocumentInfo declDoc = null; + + // the component is not parsed, try to find a DOM element for it + switch (declType) { + case ATTRIBUTE_TYPE : + decl = (Element)fUnparsedAttributeRegistry.get(declKey); + declDoc = (XSDocumentInfo)fUnparsedAttributeRegistrySub.get(declKey); + break; + case ATTRIBUTEGROUP_TYPE : + decl = (Element)fUnparsedAttributeGroupRegistry.get(declKey); + declDoc = (XSDocumentInfo)fUnparsedAttributeGroupRegistrySub.get(declKey); + break; + case ELEMENT_TYPE : + decl = (Element)fUnparsedElementRegistry.get(declKey); + declDoc = (XSDocumentInfo)fUnparsedElementRegistrySub.get(declKey); + break; + case GROUP_TYPE : + decl = (Element)fUnparsedGroupRegistry.get(declKey); + declDoc = (XSDocumentInfo)fUnparsedGroupRegistrySub.get(declKey); + break; + case IDENTITYCONSTRAINT_TYPE : + decl = (Element)fUnparsedIdentityConstraintRegistry.get(declKey); + declDoc = (XSDocumentInfo)fUnparsedIdentityConstraintRegistrySub.get(declKey); + break; + case NOTATION_TYPE : + decl = (Element)fUnparsedNotationRegistry.get(declKey); + declDoc = (XSDocumentInfo)fUnparsedNotationRegistrySub.get(declKey); + break; + case TYPEDECL_TYPE : + decl = (Element)fUnparsedTypeRegistry.get(declKey); + declDoc = (XSDocumentInfo)fUnparsedTypeRegistrySub.get(declKey); + break; + default: + reportSchemaError("Internal-Error", new Object [] {"XSDHandler asked to locate component of type " + declType + "; it does not recognize this type!"}, elmNode); + } + + // no DOM element found, so the component can't be located + if (decl == null) { + if (retObj == null) { + reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode); + } + return retObj; + } + + // get the schema doc containing the component to be parsed + // it should always return non-null value, but since null-checking + // comes for free, let's be safe and check again + schemaWithDecl = findXSDocumentForDecl(currSchema, decl, declDoc); + if (schemaWithDecl == null) { + // cannot get to this schema from the one containing the requesting decl + if (retObj == null) { + String code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2"; + reportSchemaError(code, new Object[]{fDoc2SystemId.get(currSchema.fSchemaElement), declToTraverse.uri, declToTraverse.rawname}, elmNode); + } + return retObj; + } + + // a component is hidden, meaning either it's traversed, or being traversed. + // but we didn't find it in the grammar, so it's the latter case, and + // a circular reference. error! + if (DOMUtil.isHidden(decl, fHiddenNodes)) { + if (retObj == null) { + String code = CIRCULAR_CODES[declType]; + if (declType == TYPEDECL_TYPE) { + if (SchemaSymbols.ELT_COMPLEXTYPE.equals(DOMUtil.getLocalName(decl))) { + code = "ct-props-correct.3"; + } + } + // decl must not be null if we're here... + reportSchemaError(code, new Object [] {declToTraverse.prefix+":"+declToTraverse.localpart}, elmNode); + } + return retObj; + } + + return traverseGlobalDecl(declType, decl, schemaWithDecl, sGrammar); + } // getGlobalDecl(XSDocumentInfo, int, QName): Object + + // If we are tolerating duplicate declarations and allowing namespace growth + // use the declaration from the current schema load (if it exists) + protected Object getGlobalDecl(String declKey, int declType) { + Object retObj = null; + + switch (declType) { + case ATTRIBUTE_TYPE : + retObj = getGlobalAttributeDecl(declKey); + break; + case ATTRIBUTEGROUP_TYPE : + retObj = getGlobalAttributeGroupDecl(declKey); + break; + case ELEMENT_TYPE : + retObj = getGlobalElementDecl(declKey); + break; + case GROUP_TYPE : + retObj = getGlobalGroupDecl(declKey); + break; + case IDENTITYCONSTRAINT_TYPE : + retObj = getIDConstraintDecl(declKey); + break; + case NOTATION_TYPE : + retObj = getGlobalNotationDecl(declKey); + break; + case TYPEDECL_TYPE : + retObj = getGlobalTypeDecl(declKey); + break; + } + + return retObj; + } + + protected Object getGlobalDeclFromGrammar(SchemaGrammar sGrammar, int declType, String localpart) { + Object retObj = null; + + switch (declType) { + case ATTRIBUTE_TYPE : + retObj = sGrammar.getGlobalAttributeDecl(localpart); + break; + case ATTRIBUTEGROUP_TYPE : + retObj = sGrammar.getGlobalAttributeGroupDecl(localpart); + break; + case ELEMENT_TYPE : + retObj = sGrammar.getGlobalElementDecl(localpart); + break; + case GROUP_TYPE : + retObj = sGrammar.getGlobalGroupDecl(localpart); + break; + case IDENTITYCONSTRAINT_TYPE : + retObj = sGrammar.getIDConstraintDecl(localpart); + break; + case NOTATION_TYPE : + retObj = sGrammar.getGlobalNotationDecl(localpart); + break; + case TYPEDECL_TYPE : + retObj = sGrammar.getGlobalTypeDecl(localpart); + break; + } + + return retObj; + } + + protected Object getGlobalDeclFromGrammar(SchemaGrammar sGrammar, int declType, String localpart, String schemaLoc) { + Object retObj = null; + + switch (declType) { + case ATTRIBUTE_TYPE : + retObj = sGrammar.getGlobalAttributeDecl(localpart, schemaLoc); + break; + case ATTRIBUTEGROUP_TYPE : + retObj = sGrammar.getGlobalAttributeGroupDecl(localpart, schemaLoc); + break; + case ELEMENT_TYPE : + retObj = sGrammar.getGlobalElementDecl(localpart, schemaLoc); + break; + case GROUP_TYPE : + retObj = sGrammar.getGlobalGroupDecl(localpart, schemaLoc); + break; + case IDENTITYCONSTRAINT_TYPE : + retObj = sGrammar.getIDConstraintDecl(localpart, schemaLoc); + break; + case NOTATION_TYPE : + retObj = sGrammar.getGlobalNotationDecl(localpart, schemaLoc); + break; + case TYPEDECL_TYPE : + retObj = sGrammar.getGlobalTypeDecl(localpart, schemaLoc); + break; + } + + return retObj; + } + + protected Object traverseGlobalDecl(int declType, Element decl, XSDocumentInfo schemaDoc, SchemaGrammar grammar) { + Object retObj = null; + + DOMUtil.setHidden(decl, fHiddenNodes); + SchemaNamespaceSupport nsSupport = null; + // if the parent is use the namespace delcs for it. + Element parent = DOMUtil.getParent(decl); + if (DOMUtil.getLocalName(parent).equals(SchemaSymbols.ELT_REDEFINE)) + nsSupport = (SchemaNamespaceSupport)fRedefine2NSSupport.get(parent); + // back up the current SchemaNamespaceSupport, because we need to provide + // a fresh one to the traverseGlobal methods. + schemaDoc.backupNSSupport(nsSupport); + + // traverse the referenced global component + switch (declType) { + case TYPEDECL_TYPE : + if (DOMUtil.getLocalName(decl).equals(SchemaSymbols.ELT_COMPLEXTYPE)) { + retObj = fComplexTypeTraverser.traverseGlobal(decl, schemaDoc, grammar); + } + else { + retObj = fSimpleTypeTraverser.traverseGlobal(decl, schemaDoc, grammar); + } + break; + case ATTRIBUTE_TYPE : + retObj = fAttributeTraverser.traverseGlobal(decl, schemaDoc, grammar); + break; + case ELEMENT_TYPE : + retObj = fElementTraverser.traverseGlobal(decl, schemaDoc, grammar); + break; + case ATTRIBUTEGROUP_TYPE : + retObj = fAttributeGroupTraverser.traverseGlobal(decl, schemaDoc, grammar); + break; + case GROUP_TYPE : + retObj = fGroupTraverser.traverseGlobal(decl, schemaDoc, grammar); + break; + case NOTATION_TYPE : + retObj = fNotationTraverser.traverse(decl, schemaDoc, grammar); + break; + case IDENTITYCONSTRAINT_TYPE : + // identity constraints should have been parsed already... + // we should never get here + break; + } + + // restore the previous SchemaNamespaceSupport, so that the caller can get + // proper namespace binding. + schemaDoc.restoreNSSupport(); + + return retObj; + } + + public String schemaDocument2SystemId(XSDocumentInfo schemaDoc) { + return (String)fDoc2SystemId.get(schemaDoc.fSchemaElement); + } + + // This method determines whether there is a group + // (attributeGroup) which the given one has redefined by + // restriction. If so, it returns it; else it returns null. + // @param type: whether what's been redefined is an + // attributeGroup or a group; + // @param name: the QName of the component doing the redefining. + // @param currSchema: schema doc in which the redefining component lives. + // @return: Object representing decl redefined if present, null + // otherwise. + Object getGrpOrAttrGrpRedefinedByRestriction(int type, QName name, XSDocumentInfo currSchema, Element elmNode) { + String realName = name.uri != null?name.uri+","+name.localpart: + ","+name.localpart; + String nameToFind = null; + switch (type) { + case ATTRIBUTEGROUP_TYPE: + nameToFind = (String)fRedefinedRestrictedAttributeGroupRegistry.get(realName); + break; + case GROUP_TYPE: + nameToFind = (String)fRedefinedRestrictedGroupRegistry.get(realName); + break; + default: + return null; + } + if (nameToFind == null) return null; + int commaPos = nameToFind.indexOf(","); + QName qNameToFind = new QName(XMLSymbols.EMPTY_STRING, nameToFind.substring(commaPos+1), + nameToFind.substring(commaPos), (commaPos == 0)? null : nameToFind.substring(0, commaPos)); + Object retObj = getGlobalDecl(currSchema, type, qNameToFind, elmNode); + if(retObj == null) { + switch (type) { + case ATTRIBUTEGROUP_TYPE: + reportSchemaError("src-redefine.7.2.1", new Object []{name.localpart}, elmNode); + break; + case GROUP_TYPE: + reportSchemaError("src-redefine.6.2.1", new Object []{name.localpart}, elmNode); + break; + } + return null; + } + return retObj; + } // getGrpOrAttrGrpRedefinedByRestriction(int, QName, XSDocumentInfo): Object + + // Since ID constraints can occur in local elements, unless we + // wish to completely traverse all our DOM trees looking for ID + // constraints while we're building our global name registries, + // which seems terribly inefficient, we need to resolve keyrefs + // after all parsing is complete. This we can simply do by running through + // fIdentityConstraintRegistry and calling traverseKeyRef on all + // of the KeyRef nodes. This unfortunately removes this knowledge + // from the elementTraverser class (which must ignore keyrefs), + // but there seems to be no efficient way around this... + protected void resolveKeyRefs() { + for (int i=0; i to hidden before traversing it, + // because it has global scope + DOMUtil.setHidden(fKeyrefs[i], fHiddenNodes); + fKeyrefTraverser.traverse(fKeyrefs[i], fKeyrefElems[i], keyrefSchemaDoc, keyrefGrammar); + } + } // end resolveKeyRefs + + // an accessor method. Just makes sure callers + // who want the Identity constraint registry vaguely know what they're about. + protected Hashtable getIDRegistry() { + return fUnparsedIdentityConstraintRegistry; + } + // an accessor method. + protected Hashtable getIDRegistry_sub() { + return fUnparsedIdentityConstraintRegistrySub; + } + + + + // This method squirrels away declarations--along with the element + // decls and namespace bindings they might find handy. + protected void storeKeyRef (Element keyrefToStore, XSDocumentInfo schemaDoc, + XSElementDecl currElemDecl) { + String keyrefName = DOMUtil.getAttrValue(keyrefToStore, SchemaSymbols.ATT_NAME); + if (keyrefName.length() != 0) { + String keyrefQName = schemaDoc.fTargetNamespace == null? + "," + keyrefName: schemaDoc.fTargetNamespace+","+keyrefName; + checkForDuplicateNames(keyrefQName, IDENTITYCONSTRAINT_TYPE, fUnparsedIdentityConstraintRegistry, fUnparsedIdentityConstraintRegistrySub, keyrefToStore, schemaDoc); + } + // now set up all the registries we'll need... + + // check array sizes + if (fKeyrefStackPos == fKeyrefs.length) { + Element [] elemArray = new Element [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT]; + System.arraycopy(fKeyrefs, 0, elemArray, 0, fKeyrefStackPos); + fKeyrefs = elemArray; + XSElementDecl [] declArray = new XSElementDecl [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT]; + System.arraycopy(fKeyrefElems, 0, declArray, 0, fKeyrefStackPos); + fKeyrefElems = declArray; + String[][] stringArray = new String [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT][]; + System.arraycopy(fKeyrefNamespaceContext, 0, stringArray, 0, fKeyrefStackPos); + fKeyrefNamespaceContext = stringArray; + + XSDocumentInfo [] xsDocumentInfo = new XSDocumentInfo [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT]; + System.arraycopy(fKeyrefsMapXSDocumentInfo, 0, xsDocumentInfo, 0, fKeyrefStackPos); + fKeyrefsMapXSDocumentInfo = xsDocumentInfo; + + } + fKeyrefs[fKeyrefStackPos] = keyrefToStore; + fKeyrefElems[fKeyrefStackPos] = currElemDecl; + fKeyrefNamespaceContext[fKeyrefStackPos] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext(); + + fKeyrefsMapXSDocumentInfo[fKeyrefStackPos++] = schemaDoc; + } // storeKeyref (Element, XSDocumentInfo, XSElementDecl): void + + + /** + * resolveSchema method is responsible for resolving location of the schema (using XMLEntityResolver), + * and if it was succefully resolved getting the schema Document. + * @param desc + * @param mustResolve + * @param referElement + * @return A schema Element or null. + */ + private Element resolveSchema(XSDDescription desc, boolean mustResolve, + Element referElement, boolean usePairs) { + XMLInputSource schemaSource = null; + try { + Hashtable pairs = usePairs ? fLocationPairs : EMPTY_TABLE; + schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityResolver); + } + catch (IOException ex) { + if (mustResolve) { + reportSchemaError("schema_reference.4", + new Object[]{desc.getLocationHints()[0]}, + referElement); + } + else { + reportSchemaWarning("schema_reference.4", + new Object[]{desc.getLocationHints()[0]}, + referElement); + } + } + if (schemaSource instanceof DOMInputSource) { + return getSchemaDocument(desc.getTargetNamespace(), (DOMInputSource) schemaSource, mustResolve, desc.getContextType(), referElement); + } // DOMInputSource + else if (schemaSource instanceof SAXInputSource) { + return getSchemaDocument(desc.getTargetNamespace(), (SAXInputSource) schemaSource, mustResolve, desc.getContextType(), referElement); + } // SAXInputSource + else if (schemaSource instanceof StAXInputSource) { + return getSchemaDocument(desc.getTargetNamespace(), (StAXInputSource) schemaSource, mustResolve, desc.getContextType(), referElement); + } // StAXInputSource + else if (schemaSource instanceof XSInputSource) { + return getSchemaDocument((XSInputSource) schemaSource, desc); + } // XSInputSource + return getSchemaDocument(desc.getTargetNamespace(), schemaSource, mustResolve, desc.getContextType(), referElement); + } // getSchema(String, String, String, boolean, short): Document + + private Element resolveSchema(XMLInputSource schemaSource, XSDDescription desc, + boolean mustResolve, Element referElement) { + + if (schemaSource instanceof DOMInputSource) { + return getSchemaDocument(desc.getTargetNamespace(), (DOMInputSource) schemaSource, mustResolve, desc.getContextType(), referElement); + } // DOMInputSource + else if (schemaSource instanceof SAXInputSource) { + return getSchemaDocument(desc.getTargetNamespace(), (SAXInputSource) schemaSource, mustResolve, desc.getContextType(), referElement); + } // SAXInputSource + else if (schemaSource instanceof StAXInputSource) { + return getSchemaDocument(desc.getTargetNamespace(), (StAXInputSource) schemaSource, mustResolve, desc.getContextType(), referElement); + } // StAXInputSource + else if (schemaSource instanceof XSInputSource) { + return getSchemaDocument((XSInputSource) schemaSource, desc); + } // XSInputSource + return getSchemaDocument(desc.getTargetNamespace(), schemaSource, mustResolve, desc.getContextType(), referElement); + } + + private XMLInputSource resolveSchemaSource(XSDDescription desc, boolean mustResolve, + Element referElement, boolean usePairs) { + + XMLInputSource schemaSource = null; + try { + Hashtable pairs = usePairs ? fLocationPairs : EMPTY_TABLE; + schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityResolver); + } + catch (IOException ex) { + if (mustResolve) { + reportSchemaError("schema_reference.4", + new Object[]{desc.getLocationHints()[0]}, + referElement); + } + else { + reportSchemaWarning("schema_reference.4", + new Object[]{desc.getLocationHints()[0]}, + referElement); + } + } + + return schemaSource; + } + + /** + * getSchemaDocument method uses XMLInputSource to parse a schema document. + * @param schemaNamespace + * @param schemaSource + * @param mustResolve + * @param referType + * @param referElement + * @return A schema Element. + */ + private Element getSchemaDocument(String schemaNamespace, XMLInputSource schemaSource, + boolean mustResolve, short referType, Element referElement) { + + boolean hasInput = true; + IOException exception = null; + // contents of this method will depend on the system we adopt for entity resolution--i.e., XMLEntityHandler, EntityHandler, etc. + Element schemaElement = null; + try { + // when the system id and byte stream and character stream + // of the input source are all null, it's + // impossible to find the schema document. so we skip in + // this case. otherwise we'll receive some NPE or + // file not found errors. but schemaHint=="" is perfectly + // legal for import. + if (schemaSource != null && + (schemaSource.getSystemId() != null || + schemaSource.getByteStream() != null || + schemaSource.getCharacterStream() != null)) { + + // When the system id of the input source is used, first try to + // expand it, and check whether the same document has been + // parsed before. If so, return the document corresponding to + // that system id. + XSDKey key = null; + String schemaId = null; + if (referType != XSDDescription.CONTEXT_PREPARSE){ + schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId(), false); + key = new XSDKey(schemaId, referType, schemaNamespace); + if((schemaElement = (Element)fTraversed.get(key)) != null) { + fLastSchemaWasDuplicate = true; + return schemaElement; + } + } + + fSchemaParser.parse(schemaSource); + Document schemaDocument = fSchemaParser.getDocument(); + schemaElement = schemaDocument != null ? DOMUtil.getRoot(schemaDocument) : null; + return getSchemaDocument0(key, schemaId, schemaElement); + } + else { + hasInput = false; + } + } + catch (IOException ex) { + exception = ex; + } + return getSchemaDocument1(mustResolve, hasInput, schemaSource, referElement, exception); + } // getSchemaDocument(String, XMLInputSource, boolean, short, Element): Element + + /** + * getSchemaDocument method uses SAXInputSource to parse a schema document. + * @param schemaNamespace + * @param schemaSource + * @param mustResolve + * @param referType + * @param referElement + * @return A schema Element. + */ + private Element getSchemaDocument(String schemaNamespace, SAXInputSource schemaSource, + boolean mustResolve, short referType, Element referElement) { + XMLReader parser = schemaSource.getXMLReader(); + InputSource inputSource = schemaSource.getInputSource(); + boolean hasInput = true; + IOException exception = null; + Element schemaElement = null; + try { + if (inputSource != null && + (inputSource.getSystemId() != null || + inputSource.getByteStream() != null || + inputSource.getCharacterStream() != null)) { + + // check whether the same document has been parsed before. + // If so, return the document corresponding to that system id. + XSDKey key = null; + String schemaId = null; + if (referType != XSDDescription.CONTEXT_PREPARSE) { + schemaId = XMLEntityManager.expandSystemId(inputSource.getSystemId(), schemaSource.getBaseSystemId(), false); + key = new XSDKey(schemaId, referType, schemaNamespace); + if ((schemaElement = (Element) fTraversed.get(key)) != null) { + fLastSchemaWasDuplicate = true; + return schemaElement; + } + } + + boolean namespacePrefixes = false; + if (parser != null) { + try { + namespacePrefixes = parser.getFeature(NAMESPACE_PREFIXES); + } + catch (SAXException se) {} + } + else { + try { + parser = XMLReaderFactory.createXMLReader(); + } + // If something went wrong with the factory + // just use our own SAX parser. + catch (SAXException se) { + parser = new SAXParser(); + } + try { + parser.setFeature(NAMESPACE_PREFIXES, true); + namespacePrefixes = true; + // If this is a Xerces SAX parser set the security manager if there is one + if (parser instanceof SAXParser) { + Object securityManager = fSchemaParser.getProperty(SECURITY_MANAGER); + if (securityManager != null) { + parser.setProperty(SECURITY_MANAGER, securityManager); + } + } + } + catch (SAXException se) {} + } + // If XML names and Namespace URIs are already internalized we + // can avoid running them through the SymbolTable. + boolean stringsInternalized = false; + try { + stringsInternalized = parser.getFeature(STRING_INTERNING); + } + catch (SAXException exc) { + // The feature isn't recognized or getting it is not supported. + // In either case, assume that strings are not internalized. + } + if (fXSContentHandler == null) { + fXSContentHandler = new SchemaContentHandler(); + } + fXSContentHandler.reset(fSchemaParser, fSymbolTable, + namespacePrefixes, stringsInternalized); + parser.setContentHandler(fXSContentHandler); + parser.setErrorHandler(fErrorReporter.getSAXErrorHandler()); + + parser.parse(inputSource); + // Disconnect the schema loader and other objects from the XMLReader + try { + parser.setContentHandler(null); + parser.setErrorHandler(null); + } + // Ignore any exceptions thrown by the XMLReader. Old versions of SAX + // required an XMLReader to throw a NullPointerException if an attempt + // to set a handler to null was made. + catch (Exception e) {} + + Document schemaDocument = fXSContentHandler.getDocument(); + schemaElement = schemaDocument != null ? DOMUtil.getRoot(schemaDocument) : null; + return getSchemaDocument0(key, schemaId, schemaElement); + } + else { + hasInput = false; + } + } + catch (SAXParseException spe) { + throw SAX2XNIUtil.createXMLParseException0(spe); + } + catch (SAXException se) { + throw SAX2XNIUtil.createXNIException0(se); + } + catch (IOException ioe) { + exception = ioe; + } + return getSchemaDocument1(mustResolve, hasInput, schemaSource, referElement, exception); + } // getSchemaDocument(String, SAXInputSource, boolean, short, Element): Element + + /** + * getSchemaDocument method uses DOMInputSource to parse a schema document. + * @param schemaNamespace + * @param schemaSource + * @param mustResolve + * @param referType + * @param referElement + * @return A schema Element. + */ + private Element getSchemaDocument(String schemaNamespace, DOMInputSource schemaSource, + boolean mustResolve, short referType, Element referElement) { + boolean hasInput = true; + IOException exception = null; + Element schemaElement = null; + Element schemaRootElement = null; + + final Node node = schemaSource.getNode(); + short nodeType = -1; + if (node != null) { + nodeType = node.getNodeType(); + if (nodeType == Node.DOCUMENT_NODE) { + schemaRootElement = DOMUtil.getRoot((Document) node); + } + else if (nodeType == Node.ELEMENT_NODE) { + schemaRootElement = (Element) node; + } + } + + try { + if (schemaRootElement != null) { + // check whether the same document has been parsed before. + // If so, return the document corresponding to that system id. + XSDKey key = null; + String schemaId = null; + if (referType != XSDDescription.CONTEXT_PREPARSE) { + schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId(), false); + boolean isDocument = (nodeType == Node.DOCUMENT_NODE); + if (!isDocument) { + Node parent = schemaRootElement.getParentNode(); + if (parent != null) { + isDocument = (parent.getNodeType() == Node.DOCUMENT_NODE); + } + } + if (isDocument) { + key = new XSDKey(schemaId, referType, schemaNamespace); + if ((schemaElement = (Element) fTraversed.get(key)) != null) { + fLastSchemaWasDuplicate = true; + return schemaElement; + } + } + } + + schemaElement = schemaRootElement; + return getSchemaDocument0(key, schemaId, schemaElement); + } + else { + hasInput = false; + } + } + catch (IOException ioe) { + exception = ioe; + } + return getSchemaDocument1(mustResolve, hasInput, schemaSource, referElement, exception); + } // getSchemaDocument(String, DOMInputSource, boolean, short, Element): Element + + /** + * getSchemaDocument method uses StAXInputSource to parse a schema document. + * @param schemaNamespace + * @param schemaSource + * @param mustResolve + * @param referType + * @param referElement + * @return A schema Element. + */ + private Element getSchemaDocument(String schemaNamespace, StAXInputSource schemaSource, + boolean mustResolve, short referType, Element referElement) { + IOException exception = null; + Element schemaElement = null; + try { + final boolean consumeRemainingContent = schemaSource.shouldConsumeRemainingContent(); + final XMLStreamReader streamReader = schemaSource.getXMLStreamReader(); + final XMLEventReader eventReader = schemaSource.getXMLEventReader(); + + // check whether the same document has been parsed before. + // If so, return the document corresponding to that system id. + XSDKey key = null; + String schemaId = null; + if (referType != XSDDescription.CONTEXT_PREPARSE) { + schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId(), false); + boolean isDocument = consumeRemainingContent; + if (!isDocument) { + if (streamReader != null) { + isDocument = (streamReader.getEventType() == XMLStreamReader.START_DOCUMENT); + } + else { + isDocument = eventReader.peek().isStartDocument(); + } + } + if (isDocument) { + key = new XSDKey(schemaId, referType, schemaNamespace); + if ((schemaElement = (Element) fTraversed.get(key)) != null) { + fLastSchemaWasDuplicate = true; + return schemaElement; + } + } + } + + if (fStAXSchemaParser == null) { + fStAXSchemaParser = new StAXSchemaParser(); + } + fStAXSchemaParser.reset(fSchemaParser, fSymbolTable); + + if (streamReader != null) { + fStAXSchemaParser.parse(streamReader); + if (consumeRemainingContent) { + while (streamReader.hasNext()) { + streamReader.next(); + } + } + } + else { + fStAXSchemaParser.parse(eventReader); + if (consumeRemainingContent) { + while (eventReader.hasNext()) { + eventReader.nextEvent(); + } + } + } + Document schemaDocument = fStAXSchemaParser.getDocument(); + schemaElement = schemaDocument != null ? DOMUtil.getRoot(schemaDocument) : null; + return getSchemaDocument0(key, schemaId, schemaElement); + } + catch (XMLStreamException e) { + Throwable t = e.getNestedException(); + if (t instanceof IOException) { + exception = (IOException) t; + } + else { + StAXLocationWrapper slw = new StAXLocationWrapper(); + slw.setLocation(e.getLocation()); + throw new XMLParseException(slw, e.getMessage(), e); + } + } + catch (IOException e) { + exception = e; + } + return getSchemaDocument1(mustResolve, true, schemaSource, referElement, exception); + } // getSchemaDocument(String, StAXInputSource, boolean, short, Element): Element + + /** + * Code shared between the various getSchemaDocument() methods which + * stores mapping information for the document. + */ + private Element getSchemaDocument0(XSDKey key, String schemaId, Element schemaElement) { + // now we need to store the mapping information from system id + // to the document. also from the document to the system id. + if (key != null) { + fTraversed.put(key, schemaElement); + } + if (schemaId != null) { + fDoc2SystemId.put(schemaElement, schemaId); + } + fLastSchemaWasDuplicate = false; + return schemaElement; + } // getSchemaDocument0(XSDKey, String, Element): Element + + /** + * Error handling code shared between the various getSchemaDocument() methods. + */ + private Element getSchemaDocument1(boolean mustResolve, boolean hasInput, + XMLInputSource schemaSource, Element referElement, IOException ioe) { + // either an error occured (exception), or empty input source was + // returned, we need to report an error or a warning + if (mustResolve) { + if (hasInput) { + reportSchemaError("schema_reference.4", + new Object[]{schemaSource.getSystemId()}, + referElement, ioe); + } + else { + reportSchemaError("schema_reference.4", + new Object[]{schemaSource == null ? "" : schemaSource.getSystemId()}, + referElement, ioe); + } + } + else if (hasInput) { + reportSchemaWarning("schema_reference.4", + new Object[]{schemaSource.getSystemId()}, + referElement, ioe); + } + + fLastSchemaWasDuplicate = false; + return null; + } // getSchemaDocument1(boolean, boolean, XMLInputSource, Element): Element + + /** + * getSchemaDocument method uses XMLInputSource to parse a schema document. + * @param schemaNamespace + * @param schemaSource + * @param mustResolve + * @param referType + * @param referElement + * @return A schema Element. + */ + private Element getSchemaDocument(XSInputSource schemaSource, XSDDescription desc) { + + SchemaGrammar[] grammars = schemaSource.getGrammars(); + short referType = desc.getContextType(); + + if (grammars != null && grammars.length > 0) { + Vector expandedGrammars = expandGrammars(grammars); + // check for existing grammars in our bucket + // and if there exist any, and namespace growth is + // not enabled - we do nothing + if (fNamespaceGrowth || !existingGrammars(expandedGrammars)) { + addGrammars(expandedGrammars); + if (referType == XSDDescription.CONTEXT_PREPARSE) { + desc.setTargetNamespace(grammars[0].getTargetNamespace()); + } + } + } + else { + XSObject[] components = schemaSource.getComponents(); + if (components != null && components.length > 0) { + Hashtable importDependencies = new Hashtable(); + Vector expandedComponents = expandComponents(components, importDependencies); + if (fNamespaceGrowth || canAddComponents(expandedComponents)) { + addGlobalComponents(expandedComponents, importDependencies); + if (referType == XSDDescription.CONTEXT_PREPARSE) { + desc.setTargetNamespace(components[0].getNamespace()); + } + } + } + } + return null; + } // getSchemaDocument(String, XSInputSource, boolean, short, Element): Element + + private Vector expandGrammars(SchemaGrammar[] grammars) { + Vector currGrammars = new Vector(); + + for (int i=0; i= 0; j--) { + sg2 = (SchemaGrammar)gs.elementAt(j); + if (!currGrammars.contains(sg2)) { + currGrammars.addElement(sg2); + } + } + } + + return currGrammars; + } + + private boolean existingGrammars(Vector grammars) { + int length = grammars.size(); + final XSDDescription desc = new XSDDescription(); + + for (int i=0; i < length; i++) { + final SchemaGrammar sg1 = (SchemaGrammar)grammars.elementAt(i); + desc.setNamespace(sg1.getTargetNamespace()); + + final SchemaGrammar sg2 = findGrammar(desc, false); + if (sg2 != null) { + return true; + } + } + + return false; + } + + private boolean canAddComponents(Vector components) { + final int size = components.size(); + final XSDDescription desc = new XSDDescription(); + for (int i=0; i 0) { + for (int i=0; i 0) { + expandImportList(namespace, importList); + } + } + } + + private void expandImportList(String namespace, Vector namespaceList) { + SchemaGrammar sg = fGrammarBucket.getGrammar(namespace); + // shouldn't be null + if (sg != null) { + Vector isgs = sg.getImportedGrammars(); + if (isgs == null) { + isgs = new Vector(); + addImportList(sg, isgs, namespaceList); + sg.setImportedGrammars(isgs); + } + else { + updateImportList(sg, isgs, namespaceList); + } + } + } + + private void addImportList(SchemaGrammar sg, Vector importedGrammars, Vector namespaceList) { + final int size = namespaceList.size(); + SchemaGrammar isg; + + for (int i=0; is and s to ensure that information + // relating to implicit restrictions is preserved for those + // traversers. + private void renameRedefiningComponents(XSDocumentInfo currSchema, + Element child, String componentType, + String oldName, String newName) { + if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) { + Element grandKid = DOMUtil.getFirstChildElement(child); + if (grandKid == null) { + reportSchemaError("src-redefine.5.a.a", null, child); + } + else { + String grandKidName = DOMUtil.getLocalName(grandKid); + if (grandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) { + grandKid = DOMUtil.getNextSiblingElement(grandKid); + } + if (grandKid == null) { + reportSchemaError("src-redefine.5.a.a", null, child); + } + else { + grandKidName = DOMUtil.getLocalName(grandKid); + if (!grandKidName.equals(SchemaSymbols.ELT_RESTRICTION)) { + reportSchemaError("src-redefine.5.a.b", new Object[]{grandKidName}, child); + } + else { + Object[] attrs = fAttributeChecker.checkAttributes(grandKid, false, currSchema); + QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE]; + if (derivedBase == null || + derivedBase.uri != currSchema.fTargetNamespace || + !derivedBase.localpart.equals(oldName)) { + reportSchemaError("src-redefine.5.a.c", + new Object[]{grandKidName, + (currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace) + + "," + oldName}, + child); + } + else { + // now we have to do the renaming... + if (derivedBase.prefix != null && derivedBase.prefix.length() > 0) + grandKid.setAttribute( SchemaSymbols.ATT_BASE, + derivedBase.prefix + ":" + newName ); + else + grandKid.setAttribute( SchemaSymbols.ATT_BASE, newName ); + // return true; + } + fAttributeChecker.returnAttrArray(attrs, currSchema); + } + } + } + } + else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) { + Element grandKid = DOMUtil.getFirstChildElement(child); + if (grandKid == null) { + reportSchemaError("src-redefine.5.b.a", null, child); + } + else { + if (DOMUtil.getLocalName(grandKid).equals(SchemaSymbols.ELT_ANNOTATION)) { + grandKid = DOMUtil.getNextSiblingElement(grandKid); + } + if (grandKid == null) { + reportSchemaError("src-redefine.5.b.a", null, child); + } + else { + // have to go one more level down; let another pass worry whether complexType is valid. + Element greatGrandKid = DOMUtil.getFirstChildElement(grandKid); + if (greatGrandKid == null) { + reportSchemaError("src-redefine.5.b.b", null, grandKid); + } + else { + String greatGrandKidName = DOMUtil.getLocalName(greatGrandKid); + if (greatGrandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) { + greatGrandKid = DOMUtil.getNextSiblingElement(greatGrandKid); + } + if (greatGrandKid == null) { + reportSchemaError("src-redefine.5.b.b", null, grandKid); + } + else { + greatGrandKidName = DOMUtil.getLocalName(greatGrandKid); + if (!greatGrandKidName.equals(SchemaSymbols.ELT_RESTRICTION) && + !greatGrandKidName.equals(SchemaSymbols.ELT_EXTENSION)) { + reportSchemaError("src-redefine.5.b.c", new Object[]{greatGrandKidName}, greatGrandKid); + } + else { + Object[] attrs = fAttributeChecker.checkAttributes(greatGrandKid, false, currSchema); + QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE]; + if (derivedBase == null || + derivedBase.uri != currSchema.fTargetNamespace || + !derivedBase.localpart.equals(oldName)) { + reportSchemaError("src-redefine.5.b.d", + new Object[]{greatGrandKidName, + (currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace) + + "," + oldName}, + greatGrandKid); + } + else { + // now we have to do the renaming... + if (derivedBase.prefix != null && derivedBase.prefix.length() > 0) + greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE, + derivedBase.prefix + ":" + newName ); + else + greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE, + newName ); + // return true; + } + } + } + } + } + } + } + else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) { + String processedBaseName = (currSchema.fTargetNamespace == null)? + ","+oldName:currSchema.fTargetNamespace+","+oldName; + int attGroupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema); + if (attGroupRefsCount > 1) { + reportSchemaError("src-redefine.7.1", new Object []{new Integer(attGroupRefsCount)}, child); + } + else if (attGroupRefsCount == 1) { + // return true; + } + else + if (currSchema.fTargetNamespace == null) + fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, ","+newName); + else + fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName); + } + else if (componentType.equals(SchemaSymbols.ELT_GROUP)) { + String processedBaseName = (currSchema.fTargetNamespace == null)? + ","+oldName:currSchema.fTargetNamespace+","+oldName; + int groupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema); + if (groupRefsCount > 1) { + reportSchemaError("src-redefine.6.1.1", new Object []{new Integer(groupRefsCount)}, child); + } + else if (groupRefsCount == 1) { + // return true; + } + else { + if (currSchema.fTargetNamespace == null) + fRedefinedRestrictedGroupRegistry.put(processedBaseName, ","+newName); + else + fRedefinedRestrictedGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName); + } + } + else { + reportSchemaError("Internal-Error", new Object [] {"could not handle this particular ; please submit your schemas and instance document in a bug report!"}, child); + } + // if we get here then we must have reported an error and failed somewhere... + // return false; + } // renameRedefiningComponents(XSDocumentInfo, Element, String, String, String):void + + // this method takes a name of the form a:b, determines the URI mapped + // to by a in the current SchemaNamespaceSupport object, and returns this + // information in the form (nsURI,b) suitable for lookups in the global + // decl Hashtables. + // REVISIT: should have it return QName, instead of String. this would + // save lots of string concatenation time. we can use + // QName#equals() to compare two QNames, and use QName directly + // as a key to the SymbolHash. + // And when the DV's are ready to return compiled values from + // validate() method, we should just call QNameDV.validate() + // in this method. + private String findQName(String name, XSDocumentInfo schemaDoc) { + SchemaNamespaceSupport currNSMap = schemaDoc.fNamespaceSupport; + int colonPtr = name.indexOf(':'); + String prefix = XMLSymbols.EMPTY_STRING; + if (colonPtr > 0) + prefix = name.substring(0, colonPtr); + String uri = currNSMap.getURI(fSymbolTable.addSymbol(prefix)); + String localpart = (colonPtr == 0)?name:name.substring(colonPtr+1); + if (prefix == XMLSymbols.EMPTY_STRING && uri == null && schemaDoc.fIsChameleonSchema) + uri = schemaDoc.fTargetNamespace; + if (uri == null) + return ","+localpart; + return uri+","+localpart; + } // findQName(String, XSDocumentInfo): String + + // This function looks among the children of curr for an element of type elementSought. + // If it finds one, it evaluates whether its ref attribute contains a reference + // to originalQName. If it does, it returns 1 + the value returned by + // calls to itself on all other children. In all other cases it returns 0 plus + // the sum of the values returned by calls to itself on curr's children. + // It also resets the value of ref so that it will refer to the renamed type from the schema + // being redefined. + private int changeRedefineGroup(String originalQName, String elementSought, + String newName, Element curr, XSDocumentInfo schemaDoc) { + int result = 0; + for (Element child = DOMUtil.getFirstChildElement(curr); + child != null; child = DOMUtil.getNextSiblingElement(child)) { + String name = DOMUtil.getLocalName(child); + if (!name.equals(elementSought)) + result += changeRedefineGroup(originalQName, elementSought, newName, child, schemaDoc); + else { + String ref = child.getAttribute( SchemaSymbols.ATT_REF ); + if (ref.length() != 0) { + String processedRef = findQName(ref, schemaDoc); + if (originalQName.equals(processedRef)) { + String prefix = XMLSymbols.EMPTY_STRING; + int colonptr = ref.indexOf(":"); + if (colonptr > 0) { + prefix = ref.substring(0,colonptr); + child.setAttribute(SchemaSymbols.ATT_REF, prefix + ":" + newName); + } + else + child.setAttribute(SchemaSymbols.ATT_REF, newName); + result++; + if (elementSought.equals(SchemaSymbols.ELT_GROUP)) { + String minOccurs = child.getAttribute( SchemaSymbols.ATT_MINOCCURS ); + String maxOccurs = child.getAttribute( SchemaSymbols.ATT_MAXOCCURS ); + if (!((maxOccurs.length() == 0 || maxOccurs.equals("1")) + && (minOccurs.length() == 0 || minOccurs.equals("1")))) { + reportSchemaError("src-redefine.6.1.2", new Object [] {ref}, child); + } + } + } + } // if ref was null some other stage of processing will flag the error + } + } + return result; + } // changeRedefineGroup + + // this method returns the XSDocumentInfo object that contains the + // component corresponding to decl. If components from this + // document cannot be referred to from those of currSchema, this + // method returns null; it's up to the caller to throw an error. + // @param: currSchema: the XSDocumentInfo object containing the + // decl ref'ing us. + // @param: decl: the declaration being ref'd. + // this method is superficial now. ---Jack + private XSDocumentInfo findXSDocumentForDecl(XSDocumentInfo currSchema, + Element decl, XSDocumentInfo decl_Doc) { + + if (DEBUG_NODE_POOL) { + System.out.println("DOCUMENT NS:"+ currSchema.fTargetNamespace+" hashcode:"+ ((Object)currSchema.fSchemaElement).hashCode()); + } + Object temp = decl_Doc; + if (temp == null) { + // something went badly wrong; we don't know this doc? + return null; + } + XSDocumentInfo declDocInfo = (XSDocumentInfo)temp; + return declDocInfo; + /********* + Logic here is unnecessary after schema WG's recent decision to allow + schema components from one document to refer to components of any other, + so long as there's some include/import/redefine path amongst them. + If they rver reverse this decision the code's right here though... - neilg + // now look in fDependencyMap to see if this is reachable + if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) { + return declDocInfo; + } + // obviously the requesting doc didn't include, redefine or + // import the one containing decl... + return null; + **********/ + } // findXSDocumentForDecl(XSDocumentInfo, Element): XSDocumentInfo + + // returns whether more than s occur in children of elem + private boolean nonAnnotationContent(Element elem) { + for(Element child = DOMUtil.getFirstChildElement(elem); child != null; child = DOMUtil.getNextSiblingElement(child)) { + if(!(DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION))) return true; + } + return false; + } // nonAnnotationContent(Element): boolean + + private void setSchemasVisible(XSDocumentInfo startSchema) { + if (DOMUtil.isHidden(startSchema.fSchemaElement, fHiddenNodes)) { + // make it visible + DOMUtil.setVisible(startSchema.fSchemaElement, fHiddenNodes); + Vector dependingSchemas = (Vector)fDependencyMap.get(startSchema); + for (int i = 0; i < dependingSchemas.size(); i++) { + setSchemasVisible((XSDocumentInfo)dependingSchemas.elementAt(i)); + } + } + // if it's visible already than so must be its children + } // setSchemasVisible(XSDocumentInfo): void + + private SimpleLocator xl = new SimpleLocator(); + + /** + * Extract location information from an Element node, and create a + * new SimpleLocator object from such information. Returning null means + * no information can be retrieved from the element. + */ + public SimpleLocator element2Locator(Element e) { + if (!( e instanceof ElementImpl)) + return null; + + SimpleLocator l = new SimpleLocator(); + return element2Locator(e, l) ? l : null; + } + + /** + * Extract location information from an Element node, store such + * information in the passed-in SimpleLocator object, then return + * true. Returning false means can't extract or store such information. + */ + public boolean element2Locator(Element e, SimpleLocator l) { + if (l == null) + return false; + if (e instanceof ElementImpl) { + ElementImpl ele = (ElementImpl)e; + // get system id from document object + Document doc = ele.getOwnerDocument(); + String sid = (String)fDoc2SystemId.get(DOMUtil.getRoot(doc)); + // line/column numbers are stored in the element node + int line = ele.getLineNumber(); + int column = ele.getColumnNumber(); + l.setValues(sid, sid, line, column, ele.getCharacterOffset()); + return true; + } + return false; + } + + void reportSchemaError(String key, Object[] args, Element ele) { + reportSchemaError(key, args, ele, null); + } + + void reportSchemaError(String key, Object[] args, Element ele, Exception exception) { + if (element2Locator(ele, xl)) { + fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN, + key, args, XMLErrorReporter.SEVERITY_ERROR, exception); + } + else { + fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, + key, args, XMLErrorReporter.SEVERITY_ERROR, exception); + } + } + + void reportSchemaWarning(String key, Object[] args, Element ele) { + reportSchemaWarning(key, args, ele, null); + } + + void reportSchemaWarning(String key, Object[] args, Element ele, Exception exception) { + if (element2Locator(ele, xl)) { + fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN, + key, args, XMLErrorReporter.SEVERITY_WARNING, exception); + } + else { + fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, + key, args, XMLErrorReporter.SEVERITY_WARNING, exception); + } + } + + /** + * Grammar pool used for validating annotations. This will return all of the + * grammars from the grammar bucket. It will also return an object for the + * schema for schemas which will contain at least the relevant declarations + * for annotations. + */ + private static class XSAnnotationGrammarPool implements XMLGrammarPool { + + private XSGrammarBucket fGrammarBucket; + private Grammar [] fInitialGrammarSet; + + public Grammar[] retrieveInitialGrammarSet(String grammarType) { + if (grammarType == XMLGrammarDescription.XML_SCHEMA) { + if (fInitialGrammarSet == null) { + if (fGrammarBucket == null) { + fInitialGrammarSet = new Grammar [] {SchemaGrammar.Schema4Annotations.INSTANCE}; + } + else { + SchemaGrammar [] schemaGrammars = fGrammarBucket.getGrammars(); + /** + * If the grammar bucket already contains the schema for schemas + * then we already have the definitions for the parts relevant + * to annotations. + */ + for (int i = 0; i < schemaGrammars.length; ++i) { + if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(schemaGrammars[i].getTargetNamespace())) { + fInitialGrammarSet = schemaGrammars; + return fInitialGrammarSet; + } + } + Grammar [] grammars = new Grammar[schemaGrammars.length + 1]; + System.arraycopy(schemaGrammars, 0, grammars, 0, schemaGrammars.length); + grammars[grammars.length - 1] = SchemaGrammar.Schema4Annotations.INSTANCE; + fInitialGrammarSet = grammars; + } + } + return fInitialGrammarSet; + } + return new Grammar[0]; + } + + public void cacheGrammars(String grammarType, Grammar[] grammars) { + + } + + public Grammar retrieveGrammar(XMLGrammarDescription desc) { + if (desc.getGrammarType() == XMLGrammarDescription.XML_SCHEMA) { + final String tns = ((XMLSchemaDescription) desc).getTargetNamespace(); + if (fGrammarBucket != null) { + Grammar grammar = fGrammarBucket.getGrammar(tns); + if (grammar != null) { + return grammar; + } + } + if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(tns)) { + return SchemaGrammar.Schema4Annotations.INSTANCE; + } + } + return null; + } + + public void refreshGrammars(XSGrammarBucket gBucket) { + fGrammarBucket = gBucket; + fInitialGrammarSet = null; + } + + public void lockPool() {} + + public void unlockPool() {} + + public void clear() {} + } + + /** + * used to identify a reference to a schema document + * if the same document is referenced twice with the same key, then + * we only need to parse it once. + * + * When 2 XSDKey's are compared, the following table can be used to + * determine whether they are equal: + * inc red imp pre ins + * inc N/L ? N/L N/L N/L + * red ? N/L ? ? ? + * imp N/L ? N/P N/P N/P + * pre N/L ? N/P N/P N/P + * ins N/L ? N/P N/P N/P + * + * Where: N/L: duplicate when they have the same namespace and location. + * ? : not clear from the spec. + * REVISIT: to simplify the process, also considering + * it's very rare, we treat them as not duplicate. + * N/P: not possible. imp/pre/ins are referenced by namespace. + * when the first time we encounter a schema document for a + * namespace, we create a grammar and store it in the grammar + * bucket. when we see another reference to the same namespace, + * we first check whether a grammar with the same namespace is + * already in the bucket, which is true in this case, so we + * won't create another XSDKey. + * + * Conclusion from the table: two XSDKey's are duplicate only when all of + * the following are true: + * 1. They are both "redefine", or neither is "redefine"; + * 2. They have the same namespace; + * 3. They have the same non-null location. + * + * About 3: if neither has a non-null location, then it's the case where + * 2 input streams are provided, but no system ID is provided. We can't tell + * whether the 2 streams have the same content, so we treat them as not + * duplicate. + */ + private static class XSDKey { + String systemId; + short referType; + // for inclue/redefine, this is the enclosing namespace + // for import/preparse/instance, this is the target namespace + String referNS; + + XSDKey(String systemId, short referType, String referNS) { + this.systemId = systemId; + this.referType = referType; + this.referNS = referNS; + } + + public int hashCode() { + // according to the description at the beginning of this class, + // we use the hashcode of the namespace as the hashcoe of this key. + return referNS == null ? 0 : referNS.hashCode(); + } + + public boolean equals(Object obj) { + if (!(obj instanceof XSDKey)) { + return false; + } + XSDKey key = (XSDKey)obj; + + // condition 1: both are redefine + /** if (referType == XSDDescription.CONTEXT_REDEFINE || + key.referType == XSDDescription.CONTEXT_REDEFINE) { + if (referType != key.referType) + return false; + }**/ + + // condition 2: same namespace + if (referNS != key.referNS) + return false; + + // condition 3: same non-null location + if (systemId == null || !systemId.equals(key.systemId)) { + return false; + } + + return true; + } + } + + private static final class SAX2XNIUtil extends ErrorHandlerWrapper { + public static XMLParseException createXMLParseException0(SAXParseException exception) { + return createXMLParseException(exception); + } + public static XNIException createXNIException0(SAXException exception) { + return createXNIException(exception); + } + } + + /** + * @param state + */ + public void setGenerateSyntheticAnnotations(boolean state) { + fSchemaParser.setFeature(GENERATE_SYNTHETIC_ANNOTATIONS, state); + } + +} // XSDHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDKeyrefTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDKeyrefTraverser.java new file mode 100644 index 0000000..21dccff --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDKeyrefTraverser.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSElementDecl; +import org.apache.xerces.impl.xs.identity.IdentityConstraint; +import org.apache.xerces.impl.xs.identity.KeyRef; +import org.apache.xerces.impl.xs.identity.UniqueOrKey; +import org.apache.xerces.xni.QName; +import org.w3c.dom.Element; + +/** + * This class contains code that is used to traverse s. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +class XSDKeyrefTraverser extends XSDAbstractIDConstraintTraverser { + + public XSDKeyrefTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + void traverse(Element krElem, XSElementDecl element, + XSDocumentInfo schemaDoc, SchemaGrammar grammar) { + + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(krElem, false, schemaDoc); + + // create identity constraint + String krName = (String)attrValues[XSAttributeChecker.ATTIDX_NAME]; + if(krName == null){ + reportSchemaError("s4s-att-must-appear", new Object [] {SchemaSymbols.ELT_KEYREF , SchemaSymbols.ATT_NAME }, krElem); + //return this array back to pool + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return; + } + QName kName = (QName)attrValues[XSAttributeChecker.ATTIDX_REFER]; + if(kName == null){ + reportSchemaError("s4s-att-must-appear", new Object [] {SchemaSymbols.ELT_KEYREF , SchemaSymbols.ATT_REFER }, krElem); + //return this array back to pool + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return; + } + + UniqueOrKey key = null; + IdentityConstraint ret = (IdentityConstraint)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.IDENTITYCONSTRAINT_TYPE, kName, krElem); + // if ret == null, we've already reported an error in getGlobalDecl + // we report an error only when ret != null, and the return type keyref + if (ret != null) { + if (ret.getCategory() == IdentityConstraint.IC_KEY || + ret.getCategory() == IdentityConstraint.IC_UNIQUE) { + key = (UniqueOrKey)ret; + } else { + reportSchemaError("src-resolve", new Object[]{kName.rawname, "identity constraint key/unique"}, krElem); + } + } + + if(key == null) { + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return; + } + + KeyRef keyRef = new KeyRef(schemaDoc.fTargetNamespace, krName, element.fName, key); + + // If errors occurred in traversing the identity constraint, then don't + // add it to the schema, to avoid errors when processing the instance. + if (traverseIdentityConstraint(keyRef, krElem, schemaDoc, attrValues)) { + //Schema Component Constraint: Identity-constraint Definition Properties Correct + //2 If the {identity-constraint category} is keyref, the cardinality of the {fields} must equal that of the {fields} of the {referenced key}. + if(key.getFieldCount() != keyRef.getFieldCount()) { + reportSchemaError("c-props-correct.2" , new Object [] {krName,key.getIdentityConstraintName()}, krElem); + } else { + // add key reference to element decl + // and stuff this in the grammar + if (grammar.getIDConstraintDecl(keyRef.getIdentityConstraintName()) == null) { + grammar.addIDConstraintDecl(element, keyRef); + } + + // also add it to extended map + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final IdentityConstraint idc = grammar.getIDConstraintDecl(keyRef.getIdentityConstraintName(), loc); + if (idc == null) { + grammar.addIDConstraintDecl(element, keyRef, loc); + } + + // handle duplicates + if (fSchemaHandler.fTolerateDuplicates) { + if (idc != null) { + if (idc instanceof KeyRef) { + keyRef = (KeyRef) idc; + } + } + fSchemaHandler.addIDConstraintDecl(keyRef); + } + } + } + + // and put back attributes + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + } // traverse(Element,int,XSDocumentInfo, SchemaGrammar) +} // XSDKeyrefTraverser + diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDNotationTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDNotationTraverser.java new file mode 100644 index 0000000..0cd6921 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDNotationTraverser.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSNotationDecl; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.xs.XSObjectList; +import org.w3c.dom.Element; + +/** + * The notation declaration schema component traverser. + * + * + * Content: (annotation?) + * + * + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * @author Elena Litani, IBM + * @version $Id$ + */ +class XSDNotationTraverser extends XSDAbstractTraverser { + + XSDNotationTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + XSNotationDecl traverse(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking for elmNode + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, true, schemaDoc); + //get attributes + String nameAttr = (String) attrValues[XSAttributeChecker.ATTIDX_NAME]; + + String publicAttr = (String) attrValues[XSAttributeChecker.ATTIDX_PUBLIC]; + String systemAttr = (String) attrValues[XSAttributeChecker.ATTIDX_SYSTEM]; + if (nameAttr == null) { + reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_NOTATION, SchemaSymbols.ATT_NAME}, elmNode); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return null; + } + + if (systemAttr == null && publicAttr == null) { + reportSchemaError("PublicSystemOnNotation", null, elmNode); + publicAttr = "missing"; + } + + XSNotationDecl notation = new XSNotationDecl(); + notation.fName = nameAttr; + notation.fTargetNamespace = schemaDoc.fTargetNamespace; + notation.fPublicId = publicAttr; + notation.fSystemId = systemAttr; + + //check content + Element content = DOMUtil.getFirstChildElement(elmNode); + XSAnnotationImpl annotation = null; + + if (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(content, attrValues, false, schemaDoc); + content = DOMUtil.getNextSiblingElement(content); + } + else { + String text = DOMUtil.getSyntheticAnnotation(elmNode); + if (text != null) { + annotation = traverseSyntheticAnnotation(elmNode, text, attrValues, false, schemaDoc); + } + } + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl) annotations).addXSObject(annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + notation.fAnnotations = annotations; + if (content!=null){ + Object[] args = new Object [] {SchemaSymbols.ELT_NOTATION, "(annotation?)", DOMUtil.getLocalName(content)}; + reportSchemaError("s4s-elt-must-match.1", args, content); + + } + if (grammar.getGlobalNotationDecl(notation.fName) == null) { + grammar.addGlobalNotationDecl(notation); + } + + // also add it to extended map + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final XSNotationDecl notation2 = grammar.getGlobalNotationDecl(notation.fName, loc); + if (notation2 == null) { + grammar.addGlobalNotationDecl(notation, loc); + } + + // handle duplicates + if (fSchemaHandler.fTolerateDuplicates) { + if (notation2 != null) { + notation = notation2; + } + fSchemaHandler.addGlobalNotationDecl(notation); + } + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return notation; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDSimpleTypeTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDSimpleTypeTraverser.java new file mode 100644 index 0000000..7c64cb2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDSimpleTypeTraverser.java @@ -0,0 +1,517 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import java.util.ArrayList; +import java.util.Vector; + +import org.apache.xerces.impl.dv.InvalidDatatypeFacetException; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xs.XSConstants; +import org.apache.xerces.xs.XSObjectList; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.Element; + +/** + * The simple type definition schema component traverser. + * + * + * Content: (annotation?, (restriction | list | union)) + * + * + * + * Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*)) + * + * + * + * Content: (annotation?, (simpleType?)) + * + * + * + * Content: (annotation?, (simpleType*)) + * + * + * @xerces.internal + * + * @author Elena Litani, IBM + * @author Neeraj Bajaj, Sun Microsystems, Inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +class XSDSimpleTypeTraverser extends XSDAbstractTraverser { + + // whether the type being parsed is a S4S built-in type. + private boolean fIsBuiltIn = false; + + XSDSimpleTypeTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + //return qualified name of simpleType or empty string if error occured + XSSimpleType traverseGlobal(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, true, schemaDoc); + String nameAtt = (String)attrValues[XSAttributeChecker.ATTIDX_NAME]; + if (nameAtt == null) { + attrValues[XSAttributeChecker.ATTIDX_NAME] = NO_NAME; + } + XSSimpleType type = traverseSimpleTypeDecl(elmNode, attrValues, schemaDoc, grammar); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + // if it's a global type without a name, return null + if (nameAtt == null) { + reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, SchemaSymbols.ATT_NAME}, elmNode); + type = null; + } + + // don't add global components without name to the grammar + if (type != null) { + if (grammar.getGlobalTypeDecl(type.getName()) == null) { + grammar.addGlobalSimpleTypeDecl(type); + } + + // also add it to extended map + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final XSTypeDefinition type2 = grammar.getGlobalTypeDecl(type.getName(), loc); + if (type2 == null) { + grammar.addGlobalSimpleTypeDecl(type, loc); + } + + // handle duplicates + if (fSchemaHandler.fTolerateDuplicates) { + if (type2 != null) { + if (type2 instanceof XSSimpleType) { + type = (XSSimpleType) type2; + } + } + fSchemaHandler.addGlobalTypeDecl(type); + } + } + + return type; + } + + XSSimpleType traverseLocal(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, false, schemaDoc); + String name = genAnonTypeName(elmNode); + XSSimpleType type = getSimpleType (name, elmNode, attrValues, schemaDoc, grammar); + if (type instanceof XSSimpleTypeDecl) { + ((XSSimpleTypeDecl)type).setAnonymous(true); + } + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return type; + } + + private XSSimpleType traverseSimpleTypeDecl(Element simpleTypeDecl, + Object[] attrValues, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // get name and final values + String name = (String)attrValues[XSAttributeChecker.ATTIDX_NAME]; + return getSimpleType(name, simpleTypeDecl, attrValues, schemaDoc, grammar); + } + + /* + * Generate a name for an anonymous type + */ + private String genAnonTypeName(Element simpleTypeDecl) { + + // Generate a unique name for the anonymous type by concatenating together the + // names of parent nodes + // The name is quite good for debugging/error purposes, but we may want to + // revisit how this is done for performance reasons (LM). + StringBuffer typeName = new StringBuffer("#AnonType_"); + Element node = DOMUtil.getParent(simpleTypeDecl); + while (node != null && (node != DOMUtil.getRoot(DOMUtil.getDocument(node)))) { + typeName.append(node.getAttribute(SchemaSymbols.ATT_NAME)); + node = DOMUtil.getParent(node); + } + return typeName.toString(); + } + + /** + * @param name + * @param simpleTypeDecl + * @param attrValues + * @param schemaDoc + * @param grammar + * @return + */ + private XSSimpleType getSimpleType(String name, Element simpleTypeDecl, Object[] attrValues, XSDocumentInfo schemaDoc, SchemaGrammar grammar) { + XInt finalAttr = (XInt)attrValues[XSAttributeChecker.ATTIDX_FINAL]; + int finalProperty = finalAttr == null ? schemaDoc.fFinalDefault : finalAttr.intValue(); + // annotation?,(list|restriction|union) + Element child = DOMUtil.getFirstChildElement(simpleTypeDecl); + XSAnnotationImpl [] annotations = null; + if (child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + XSAnnotationImpl annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + if (annotation != null) + annotations = new XSAnnotationImpl [] {annotation}; + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(simpleTypeDecl); + if (text != null) { + XSAnnotationImpl annotation = traverseSyntheticAnnotation(simpleTypeDecl, text, attrValues, false, schemaDoc); + annotations = new XSAnnotationImpl[] {annotation}; + } + } + // (list|restriction|union) + if (child == null) { + reportSchemaError("s4s-elt-must-match.2", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))"}, simpleTypeDecl); + return errorType(name, schemaDoc.fTargetNamespace, XSConstants.DERIVATION_RESTRICTION); + } + // derivation type: restriction/list/union + String varietyProperty = DOMUtil.getLocalName(child); + short refType = XSConstants.DERIVATION_RESTRICTION; + boolean restriction = false, list = false, union = false; + if (varietyProperty.equals(SchemaSymbols.ELT_RESTRICTION)) { + refType = XSConstants.DERIVATION_RESTRICTION; + restriction = true; + } + else if (varietyProperty.equals(SchemaSymbols.ELT_LIST)) { + refType = XSConstants.DERIVATION_LIST; + list = true; + } + else if (varietyProperty.equals(SchemaSymbols.ELT_UNION)) { + refType = XSConstants.DERIVATION_UNION; + union = true; + } + else { + reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))", varietyProperty}, simpleTypeDecl); + return errorType(name, schemaDoc.fTargetNamespace, XSConstants.DERIVATION_RESTRICTION); + } + // nothing should follow this element + Element nextChild = DOMUtil.getNextSiblingElement(child); + if (nextChild != null) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_SIMPLETYPE, "(annotation?, (restriction | list | union))", DOMUtil.getLocalName(nextChild)}, nextChild); + } + // General Attribute Checking: get base/item/member types + Object[] contentAttrs = fAttrChecker.checkAttributes(child, false, schemaDoc); + QName baseTypeName = (QName)contentAttrs[restriction ? + XSAttributeChecker.ATTIDX_BASE : + XSAttributeChecker.ATTIDX_ITEMTYPE]; + Vector memberTypes = (Vector)contentAttrs[XSAttributeChecker.ATTIDX_MEMBERTYPES]; + //content = {annotation?,simpleType?...} + Element content = DOMUtil.getFirstChildElement(child); + //check content (annotation?, ...) + if (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_ANNOTATION)) { + XSAnnotationImpl annotation = traverseAnnotationDecl(content, contentAttrs, false, schemaDoc); + if (annotation != null ) { + if(annotations == null) { + annotations = new XSAnnotationImpl [] {annotation}; + } + else { + XSAnnotationImpl [] tempArray = new XSAnnotationImpl[2]; + tempArray[0] = annotations[0]; + annotations = tempArray; + annotations[1] = annotation; + } + } + content = DOMUtil.getNextSiblingElement(content); + } + else { + String text = DOMUtil.getSyntheticAnnotation(child); + if (text != null) { + XSAnnotationImpl annotation = traverseSyntheticAnnotation(child, text, contentAttrs, false, schemaDoc); + if (annotations == null) { + annotations = new XSAnnotationImpl [] {annotation}; + } + else { + XSAnnotationImpl [] tempArray = new XSAnnotationImpl[2]; + tempArray[0] = annotations[0]; + annotations = tempArray; + annotations[1] = annotation; + } + } + } + // get base type from "base" attribute + XSSimpleType baseValidator = null; + if ((restriction || list) && baseTypeName != null) { + baseValidator = findDTValidator(child, name, baseTypeName, refType, schemaDoc); + // if its the built-in type, return null from here + if (baseValidator == null && fIsBuiltIn) { + fIsBuiltIn = false; + return null; + } + } + // get types from "memberTypes" attribute + ArrayList dTValidators = null; + XSSimpleType dv = null; + XSObjectList dvs; + if (union && memberTypes != null && memberTypes.size() > 0) { + int size = memberTypes.size(); + dTValidators = new ArrayList(size); + // for each qname in the list + for (int i = 0; i < size; i++) { + // get the type decl + dv = findDTValidator(child, name, (QName)memberTypes.elementAt(i), + XSConstants.DERIVATION_UNION, schemaDoc); + if (dv != null) { + // if it's a union, expand it + if (dv.getVariety() == XSSimpleType.VARIETY_UNION) { + dvs = dv.getMemberTypes(); + for (int j = 0; j < dvs.getLength(); j++) + dTValidators.add(dvs.item(j)); + } else { + dTValidators.add(dv); + } + } + } + } + + // check if there is a child "simpleType" + if (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_SIMPLETYPE)) { + if (restriction || list) { + // it's an error for both "base" and "simpleType" to appear + if (baseTypeName != null) { + reportSchemaError(list ? "src-simple-type.3.a" : "src-simple-type.2.a", null, content); + } + if (baseValidator == null) { + // traverse this child to get the base type + baseValidator = traverseLocal(content, schemaDoc, grammar); + } + // get the next element + content = DOMUtil.getNextSiblingElement(content); + } + else if (union) { + if (dTValidators == null) { + dTValidators = new ArrayList(2); + } + do { + // traverse this child to get the member type + dv = traverseLocal(content, schemaDoc, grammar); + if (dv != null) { + // if it's a union, expand it + if (dv.getVariety() == XSSimpleType.VARIETY_UNION) { + dvs = dv.getMemberTypes(); + for (int j = 0; j < dvs.getLength(); j++) { + dTValidators.add(dvs.item(j)); + } + } + else { + dTValidators.add(dv); + } + } + // get the next element + content = DOMUtil.getNextSiblingElement(content); + } while (content != null && DOMUtil.getLocalName(content).equals(SchemaSymbols.ELT_SIMPLETYPE)); + } + } + else if ((restriction || list) && baseTypeName == null) { + // it's an error if neither "base/itemType" nor "simpleType" appears + reportSchemaError(list ? "src-simple-type.3.b" : "src-simple-type.2.b", null, child); + } + else if (union && (memberTypes == null || memberTypes.size() == 0)) { + // it's an error if "memberTypes" is empty and no "simpleType" appears + reportSchemaError("src-union-memberTypes-or-simpleTypes", null, child); + } + // error finding "base" or error traversing "simpleType". + // don't need to report an error, since some error has been reported. + if ((restriction || list) && baseValidator == null) { + fAttrChecker.returnAttrArray(contentAttrs, schemaDoc); + return errorType(name, schemaDoc.fTargetNamespace, + restriction ? XSConstants.DERIVATION_RESTRICTION : XSConstants.DERIVATION_LIST); + } + // error finding "memberTypes" or error traversing "simpleType". + // don't need to report an error, since some error has been reported. + if (union && (dTValidators == null || dTValidators.size() == 0)) { + fAttrChecker.returnAttrArray(contentAttrs, schemaDoc); + return errorType(name, schemaDoc.fTargetNamespace, + XSConstants.DERIVATION_UNION); + } + // item type of list types can't have list content + if (list && isListDatatype(baseValidator)) { + reportSchemaError("cos-st-restricts.2.1", new Object[]{name, baseValidator.getName()}, child); + fAttrChecker.returnAttrArray(contentAttrs, schemaDoc); + return errorType(name, schemaDoc.fTargetNamespace, + XSConstants.DERIVATION_LIST); + } + // create the simple type based on the "base" type + XSSimpleType newDecl = null; + if (restriction) { + newDecl = fSchemaHandler.fDVFactory.createTypeRestriction(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator, + annotations == null? null : new XSObjectListImpl(annotations, annotations.length)); + } + else if (list) { + newDecl = fSchemaHandler.fDVFactory.createTypeList(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator, + annotations == null? null : new XSObjectListImpl(annotations, annotations.length)); + } + else if (union) { + XSSimpleType[] memberDecls = (XSSimpleType[]) dTValidators.toArray(new XSSimpleType[dTValidators.size()]); + newDecl = fSchemaHandler.fDVFactory.createTypeUnion(name, schemaDoc.fTargetNamespace, (short)finalProperty, memberDecls, + annotations == null? null : new XSObjectListImpl(annotations, annotations.length)); + } + // now traverse facets, if it's derived by restriction + if (restriction && content != null) { + FacetInfo fi = traverseFacets(content, newDecl, baseValidator, schemaDoc); + content = fi.nodeAfterFacets; + + try { + fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport); + newDecl.applyFacets(fi.facetdata, fi.fPresentFacets, fi.fFixedFacets, fValidationState); + } catch (InvalidDatatypeFacetException ex) { + reportSchemaError(ex.getKey(), ex.getArgs(), child); + // Recreate the type, ignoring the facets + newDecl = fSchemaHandler.fDVFactory.createTypeRestriction(name, schemaDoc.fTargetNamespace, (short)finalProperty, baseValidator, + annotations == null? null : new XSObjectListImpl(annotations, annotations.length)); + } + } + // no element should appear after this point + if (content != null) { + if (restriction) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_RESTRICTION, "(annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*))", DOMUtil.getLocalName(content)}, content); + } + else if (list) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_LIST, "(annotation?, (simpleType?))", DOMUtil.getLocalName(content)}, content); + } + else if (union) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{SchemaSymbols.ELT_UNION, "(annotation?, (simpleType*))", DOMUtil.getLocalName(content)}, content); + } + } + fAttrChecker.returnAttrArray(contentAttrs, schemaDoc); + // return the new type + return newDecl; + } + + //@param: elm - top element + //@param: baseTypeStr - type (base/itemType/memberTypes) + //@param: baseRefContext: whether the caller is using this type as a base for restriction, union or list + //return XSSimpleType available for the baseTypeStr, null if not found or disallowed. + // also throws an error if the base type won't allow itself to be used in this context. + // REVISIT: can this code be re-used? + private XSSimpleType findDTValidator(Element elm, String refName, + QName baseTypeStr, short baseRefContext, + XSDocumentInfo schemaDoc) { + if (baseTypeStr == null) + return null; + + XSTypeDefinition baseType = (XSTypeDefinition)fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.TYPEDECL_TYPE, baseTypeStr, elm); + if (baseType == null) { + return null; + } + if (baseType.getTypeCategory() != XSTypeDefinition.SIMPLE_TYPE) { + reportSchemaError("cos-st-restricts.1.1", new Object[]{baseTypeStr.rawname, refName}, elm); + return null; + } + + // if it's a complex type, or if its restriction of anySimpleType + if (baseType == SchemaGrammar.fAnySimpleType && + baseRefContext == XSConstants.DERIVATION_RESTRICTION) { + // if the base type is anySimpleType and the current type is + // a S4S built-in type, return null. (not an error). + if (checkBuiltIn(refName, schemaDoc.fTargetNamespace)) { + return null; + } + reportSchemaError("cos-st-restricts.1.1", new Object[]{baseTypeStr.rawname, refName}, elm); + return null; + } + + if ((baseType.getFinal() & baseRefContext) != 0) { + if (baseRefContext == XSConstants.DERIVATION_RESTRICTION) { + reportSchemaError("st-props-correct.3", new Object[]{refName, baseTypeStr.rawname}, elm); + } + else if (baseRefContext == XSConstants.DERIVATION_LIST) { + reportSchemaError("cos-st-restricts.2.3.1.1", new Object[]{baseTypeStr.rawname, refName}, elm); + } + else if (baseRefContext == XSConstants.DERIVATION_UNION) { + reportSchemaError("cos-st-restricts.3.3.1.1", new Object[]{baseTypeStr.rawname, refName}, elm); + } + return null; + } + + return (XSSimpleType)baseType; + } + + // check whethe the type denoted by the name and namespace is a S4S + // built-in type. update fIsBuiltIn at the same time. + private final boolean checkBuiltIn(String name, String namespace) { + if (namespace != SchemaSymbols.URI_SCHEMAFORSCHEMA) + return false; + if (SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(name) != null) + fIsBuiltIn = true; + return fIsBuiltIn; + } + + // find if a datatype validator is a list or has list datatype member. + private boolean isListDatatype(XSSimpleType validator) { + if (validator.getVariety() == XSSimpleType.VARIETY_LIST) + return true; + + if (validator.getVariety() == XSSimpleType.VARIETY_UNION) { + XSObjectList temp = validator.getMemberTypes(); + for (int i = 0; i < temp.getLength(); i++) { + if (((XSSimpleType)temp.item(i)).getVariety() == XSSimpleType.VARIETY_LIST) { + return true; + } + } + } + + return false; + }//isListDatatype(XSSimpleTypeDecl):boolean + + private XSSimpleType errorType(String name, String namespace, short refType) { + XSSimpleType stringType = (XSSimpleType)SchemaGrammar.SG_SchemaNS.getTypeDefinition("string"); + switch (refType) { + case XSConstants.DERIVATION_RESTRICTION: + return fSchemaHandler.fDVFactory.createTypeRestriction(name, namespace, (short)0, + stringType, null); + case XSConstants.DERIVATION_LIST: + return fSchemaHandler.fDVFactory.createTypeList(name, namespace, (short)0, + stringType, null); + case XSConstants.DERIVATION_UNION: + return fSchemaHandler.fDVFactory.createTypeUnion(name, namespace, (short)0, + new XSSimpleType[]{stringType}, null); + } + + return null; + } + +}//class XSDSimpleTypeTraverser diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDUniqueOrKeyTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDUniqueOrKeyTraverser.java new file mode 100644 index 0000000..78f3216 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDUniqueOrKeyTraverser.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSElementDecl; +import org.apache.xerces.impl.xs.identity.IdentityConstraint; +import org.apache.xerces.impl.xs.identity.UniqueOrKey; +import org.apache.xerces.util.DOMUtil; +import org.w3c.dom.Element; + +/** + * This class contains code that is used to traverse both s and + * s. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +class XSDUniqueOrKeyTraverser extends XSDAbstractIDConstraintTraverser { + + public XSDUniqueOrKeyTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + + void traverse(Element uElem, XSElementDecl element, + XSDocumentInfo schemaDoc, SchemaGrammar grammar) { + + // General Attribute Checking + Object[] attrValues = fAttrChecker.checkAttributes(uElem, false, schemaDoc); + + // create identity constraint + String uName = (String)attrValues[XSAttributeChecker.ATTIDX_NAME]; + + if(uName == null){ + reportSchemaError("s4s-att-must-appear", new Object [] {DOMUtil.getLocalName(uElem) , SchemaSymbols.ATT_NAME }, uElem); + //return this array back to pool + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + return; + } + + UniqueOrKey uniqueOrKey = null; + if(DOMUtil.getLocalName(uElem).equals(SchemaSymbols.ELT_UNIQUE)) { + uniqueOrKey = new UniqueOrKey(schemaDoc.fTargetNamespace, uName, element.fName, IdentityConstraint.IC_UNIQUE); + } else { + uniqueOrKey = new UniqueOrKey(schemaDoc.fTargetNamespace, uName, element.fName, IdentityConstraint.IC_KEY); + } + // it's XSDElementTraverser's job to ensure that there's no + // duplication (or if there is that restriction is involved + // and there's identity). + + // If errors occurred in traversing the identity constraint, then don't + // add it to the schema, to avoid errors when processing the instance. + if (traverseIdentityConstraint(uniqueOrKey, uElem, schemaDoc, attrValues)) { + // and stuff this in the grammar + if (grammar.getIDConstraintDecl(uniqueOrKey.getIdentityConstraintName()) == null) { + grammar.addIDConstraintDecl(element, uniqueOrKey); + } + + final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc); + final IdentityConstraint idc = grammar.getIDConstraintDecl(uniqueOrKey.getIdentityConstraintName(), loc); + if (idc == null) { + grammar.addIDConstraintDecl(element, uniqueOrKey, loc); + } + + // handle duplicates + if (fSchemaHandler.fTolerateDuplicates) { + if (idc != null) { + if (idc instanceof UniqueOrKey) { + uniqueOrKey = (UniqueOrKey) uniqueOrKey; + } + } + fSchemaHandler.addIDConstraintDecl(uniqueOrKey); + } + } + + // and fix up attributeChecker + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + } // traverse(Element,XSDElementDecl,XSDocumentInfo, SchemaGrammar) +} // XSDUniqueOrKeyTraverser diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDWildcardTraverser.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDWildcardTraverser.java new file mode 100644 index 0000000..311a85b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDWildcardTraverser.java @@ -0,0 +1,199 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XSAnnotationImpl; +import org.apache.xerces.impl.xs.XSParticleDecl; +import org.apache.xerces.impl.xs.XSWildcardDecl; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.impl.xs.util.XSObjectListImpl; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.xs.XSObjectList; +import org.w3c.dom.Element; + +/** + * The wildcard schema component traverser. + * + * <any + * id = ID + * maxOccurs = (nonNegativeInteger | unbounded) : 1 + * minOccurs = nonNegativeInteger : 1 + * namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) : ##any + * processContents = (lax | skip | strict) : strict + * {any attributes with non-schema namespace . . .}> + * Content: (annotation?) + * </any> + * + * <anyAttribute + * id = ID + * namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) : ##any + * processContents = (lax | skip | strict) : strict + * {any attributes with non-schema namespace . . .}> + * Content: (annotation?) + * </anyAttribute> + * + * @xerces.internal + * + * @author Rahul Srivastava, Sun Microsystems Inc. + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +class XSDWildcardTraverser extends XSDAbstractTraverser { + + /** + * constructor + * + * @param handler + * @param errorReporter + * @param gAttrCheck + */ + XSDWildcardTraverser (XSDHandler handler, + XSAttributeChecker gAttrCheck) { + super(handler, gAttrCheck); + } + + + /** + * Traverse <any> + * + * @param elmNode + * @param schemaDoc + * @param grammar + * @return the wildcard node index + */ + XSParticleDecl traverseAny(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking for elmNode + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, false, schemaDoc); + XSWildcardDecl wildcard = traverseWildcardDecl(elmNode, attrValues, schemaDoc, grammar); + + // for , need to create a new particle to reflect the min/max values + XSParticleDecl particle = null; + if (wildcard != null) { + int min = ((XInt)attrValues[XSAttributeChecker.ATTIDX_MINOCCURS]).intValue(); + int max = ((XInt)attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS]).intValue(); + if (max != 0) { + if (fSchemaHandler.fDeclPool !=null) { + particle = fSchemaHandler.fDeclPool.getParticleDecl(); + } else { + particle = new XSParticleDecl(); + } + particle.fType = XSParticleDecl.PARTICLE_WILDCARD; + particle.fValue = wildcard; + particle.fMinOccurs = min; + particle.fMaxOccurs = max; + particle.fAnnotations = wildcard.fAnnotations; + } + } + + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return particle; + } + + + /** + * Traverse <anyAttribute> + * + * @param elmNode + * @param schemaDoc + * @param grammar + * @return the wildcard node index + */ + XSWildcardDecl traverseAnyAttribute(Element elmNode, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + // General Attribute Checking for elmNode + Object[] attrValues = fAttrChecker.checkAttributes(elmNode, false, schemaDoc); + XSWildcardDecl wildcard = traverseWildcardDecl(elmNode, attrValues, schemaDoc, grammar); + fAttrChecker.returnAttrArray(attrValues, schemaDoc); + + return wildcard; + } + + + /** + * + * @param elmNode + * @param attrValues + * @param schemaDoc + * @param grammar + * @return the wildcard node index + */ + XSWildcardDecl traverseWildcardDecl(Element elmNode, + Object[] attrValues, + XSDocumentInfo schemaDoc, + SchemaGrammar grammar) { + + //get all attributes + XSWildcardDecl wildcard = new XSWildcardDecl(); + // namespace type + XInt namespaceTypeAttr = (XInt) attrValues[XSAttributeChecker.ATTIDX_NAMESPACE]; + wildcard.fType = namespaceTypeAttr.shortValue(); + // namespace list + wildcard.fNamespaceList = (String[])attrValues[XSAttributeChecker.ATTIDX_NAMESPACE_LIST]; + // process contents + XInt processContentsAttr = (XInt) attrValues[XSAttributeChecker.ATTIDX_PROCESSCONTENTS]; + wildcard.fProcessContents = processContentsAttr.shortValue(); + + //check content + Element child = DOMUtil.getFirstChildElement(elmNode); + XSAnnotationImpl annotation = null; + if (child != null) + { + if (DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { + annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); + child = DOMUtil.getNextSiblingElement(child); + } + else { + String text = DOMUtil.getSyntheticAnnotation(elmNode); + if (text != null) { + annotation = traverseSyntheticAnnotation(elmNode, text, attrValues, false, schemaDoc); + } + } + + if (child != null) { + reportSchemaError("s4s-elt-must-match.1", new Object[]{"wildcard", "(annotation?)", DOMUtil.getLocalName(child)}, elmNode); + } + } + else { + String text = DOMUtil.getSyntheticAnnotation(elmNode); + if (text != null) { + annotation = traverseSyntheticAnnotation(elmNode, text, attrValues, false, schemaDoc); + } + } + XSObjectList annotations; + if (annotation != null) { + annotations = new XSObjectListImpl(); + ((XSObjectListImpl) annotations).addXSObject(annotation); + } else { + annotations = XSObjectListImpl.EMPTY_LIST; + } + wildcard.fAnnotations = annotations; + + return wildcard; + + } // traverseWildcardDecl + +} // XSDWildcardTraverser diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDocumentInfo.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDocumentInfo.java new file mode 100644 index 0000000..99057d5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/traversers/XSDocumentInfo.java @@ -0,0 +1,225 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.traversers; + +import java.util.Stack; +import java.util.Vector; + +import org.apache.xerces.impl.validation.ValidationState; +import org.apache.xerces.impl.xs.SchemaNamespaceSupport; +import org.apache.xerces.impl.xs.SchemaSymbols; +import org.apache.xerces.impl.xs.XMLSchemaException; +import org.apache.xerces.impl.xs.util.XInt; +import org.apache.xerces.util.SymbolTable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Objects of this class hold all information pecular to a + * particular XML Schema document. This is needed because + * namespace bindings and other settings on the element + * affect the contents of that schema document alone. + * + * @xerces.internal + * + * @author Neil Graham, IBM + * @version $Id$ + */ +class XSDocumentInfo { + + // Data + protected SchemaNamespaceSupport fNamespaceSupport; + protected SchemaNamespaceSupport fNamespaceSupportRoot; + protected Stack SchemaNamespaceSupportStack = new Stack(); + + // schema's attributeFormDefault + protected boolean fAreLocalAttributesQualified; + + // elementFormDefault + protected boolean fAreLocalElementsQualified; + + // [block | final]Default + protected short fBlockDefault; + protected short fFinalDefault; + + // targetNamespace + String fTargetNamespace; + + // represents whether this is a chameleon schema (i.e., whether its TNS is natural or comes from without) + protected boolean fIsChameleonSchema; + + // the root of the schema Document tree itself + protected Element fSchemaElement; + + // all namespaces that this document can refer to + Vector fImportedNS = new Vector(); + + protected ValidationState fValidationContext = new ValidationState(); + + SymbolTable fSymbolTable = null; + + // attribute checker to which we'll return the attributes + // once we've been told that we're done with them + protected XSAttributeChecker fAttrChecker; + + // array of objects on the schema's root element. This is null + // once returnSchemaAttrs has been called. + protected Object [] fSchemaAttrs; + + // list of annotations contained in the schema document. This is null + // once removeAnnotations has been called. + protected XSAnnotationInfo fAnnotations = null; + + // note that the caller must ensure to call returnSchemaAttrs() + // to avoid memory leaks! + XSDocumentInfo (Element schemaRoot, XSAttributeChecker attrChecker, SymbolTable symbolTable) + throws XMLSchemaException { + + fSchemaElement = schemaRoot; + fNamespaceSupport = new SchemaNamespaceSupport(schemaRoot, symbolTable); + fNamespaceSupport.reset(); + fIsChameleonSchema = false; + + fSymbolTable = symbolTable; + fAttrChecker = attrChecker; + + if (schemaRoot != null) { + Element root = schemaRoot; + fSchemaAttrs = attrChecker.checkAttributes(root, true, this); + // schemaAttrs == null means it's not an element + // throw an exception, but we don't know the document systemId, + // so we leave that to the caller. + if (fSchemaAttrs == null) { + throw new XMLSchemaException(null, null); + } + fAreLocalAttributesQualified = + ((XInt)fSchemaAttrs[XSAttributeChecker.ATTIDX_AFORMDEFAULT]).intValue() == SchemaSymbols.FORM_QUALIFIED; + fAreLocalElementsQualified = + ((XInt)fSchemaAttrs[XSAttributeChecker.ATTIDX_EFORMDEFAULT]).intValue() == SchemaSymbols.FORM_QUALIFIED; + fBlockDefault = + ((XInt)fSchemaAttrs[XSAttributeChecker.ATTIDX_BLOCKDEFAULT]).shortValue(); + fFinalDefault = + ((XInt)fSchemaAttrs[XSAttributeChecker.ATTIDX_FINALDEFAULT]).shortValue(); + fTargetNamespace = + (String)fSchemaAttrs[XSAttributeChecker.ATTIDX_TARGETNAMESPACE]; + if (fTargetNamespace != null) + fTargetNamespace = symbolTable.addSymbol(fTargetNamespace); + + fNamespaceSupportRoot = new SchemaNamespaceSupport(fNamespaceSupport); + + //set namespace support + fValidationContext.setNamespaceSupport(fNamespaceSupport); + fValidationContext.setSymbolTable(symbolTable); + // pass null as the schema document, so that the namespace + // context is not popped. + + // don't return the attribute array yet! + //attrChecker.returnAttrArray(schemaAttrs, null); + } + } + + // backup the current ns support, and use the one passed-in. + // if no ns support is passed-in, use the one for element + void backupNSSupport(SchemaNamespaceSupport nsSupport) { + SchemaNamespaceSupportStack.push(fNamespaceSupport); + if (nsSupport == null) + nsSupport = fNamespaceSupportRoot; + fNamespaceSupport = new SchemaNamespaceSupport(nsSupport); + + fValidationContext.setNamespaceSupport(fNamespaceSupport); + } + + void restoreNSSupport() { + fNamespaceSupport = (SchemaNamespaceSupport)SchemaNamespaceSupportStack.pop(); + fValidationContext.setNamespaceSupport(fNamespaceSupport); + } + + // some Object methods + public String toString() { + StringBuffer buf = new StringBuffer(); + if (fTargetNamespace == null) { + buf.append("no targetNamspace"); + } + else { + buf.append("targetNamespace is "); + buf.append(fTargetNamespace); + } + Document doc = (fSchemaElement != null) ? fSchemaElement.getOwnerDocument() : null; + if (doc instanceof org.apache.xerces.impl.xs.opti.SchemaDOM) { + String documentURI = doc.getDocumentURI(); + if (documentURI != null && documentURI.length() > 0) { + buf.append(" :: schemaLocation is "); + buf.append(documentURI); + } + } + return buf.toString(); + } + + public void addAllowedNS(String namespace) { + fImportedNS.addElement(namespace == null ? "" : namespace); + } + + public boolean isAllowedNS(String namespace) { + return fImportedNS.contains(namespace == null ? "" : namespace); + } + + // store whether we have reported an error about that this document + // can't access components from the given namespace + private Vector fReportedTNS = null; + // check whether we need to report an error against the given uri. + // if we have reported an error, then we don't need to report again; + // otherwise we reported the error, and remember this fact. + final boolean needReportTNSError(String uri) { + if (fReportedTNS == null) + fReportedTNS = new Vector(); + else if (fReportedTNS.contains(uri)) + return false; + fReportedTNS.addElement(uri); + return true; + } + + // return the attributes on the schema element itself: + Object [] getSchemaAttrs () { + return fSchemaAttrs; + } + + // deallocate the storage set aside for the schema element's + // attributes + void returnSchemaAttrs () { + fAttrChecker.returnAttrArray (fSchemaAttrs, null); + fSchemaAttrs = null; + } + + // adds an annotation to the list of annotations + void addAnnotation(XSAnnotationInfo info) { + info.next = fAnnotations; + fAnnotations = info; + } + + // returns the list of annotations conatined in the + // schema document or null if the document contained no annotations. + XSAnnotationInfo getAnnotations() { + return fAnnotations; + } + + // removes reference to annotation list + void removeAnnotations() { + fAnnotations = null; + } + +} // XSDocumentInfo diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/LSInputListImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/LSInputListImpl.java new file mode 100644 index 0000000..54b77b6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/LSInputListImpl.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import java.lang.reflect.Array; +import java.util.AbstractList; + +import org.apache.xerces.xs.LSInputList; +import org.w3c.dom.ls.LSInput; + +/** + * Contains a list of LSInputs. + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class LSInputListImpl extends AbstractList implements LSInputList { + + /** + * An immutable empty list. + */ + public static final LSInputListImpl EMPTY_LIST = new LSInputListImpl(new LSInput[0], 0); + + // The array to hold all data + private final LSInput[] fArray; + // Number of elements in this list + private final int fLength; + + /** + * Construct an LSInputList implementation + * + * @param array the data array + * @param length the number of elements + */ + public LSInputListImpl(LSInput[] array, int length) { + fArray = array; + fLength = length; + } + + /** + * The number of LSInputs in the list. The range of valid + * child object indices is 0 to length-1 inclusive. + */ + public int getLength() { + return fLength; + } + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The LSInput at the indexth + * position in the LSInputList, or null if + * the index specified is not valid. + */ + public LSInput item(int index) { + if (index < 0 || index >= fLength) { + return null; + } + return fArray[index]; + } + + /* + * List methods + */ + + public Object get(int index) { + if (index >= 0 && index < fLength) { + return fArray[index]; + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + + public Object[] toArray() { + Object[] a = new Object[fLength]; + toArray0(a); + return a; + } + + public Object[] toArray(Object[] a) { + if (a.length < fLength) { + Class arrayClass = a.getClass(); + Class componentType = arrayClass.getComponentType(); + a = (Object[]) Array.newInstance(componentType, fLength); + } + toArray0(a); + if (a.length > fLength) { + a[fLength] = null; + } + return a; + } + + private void toArray0(Object[] a) { + if (fLength > 0) { + System.arraycopy(fArray, 0, a, 0, fLength); + } + } + +} // LSInputListImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/ObjectListImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/ObjectListImpl.java new file mode 100644 index 0000000..6ca7c24 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/ObjectListImpl.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import java.lang.reflect.Array; +import java.util.AbstractList; + +import org.apache.xerces.xs.datatypes.ObjectList; + +/** + * Contains a list of Objects. + * + * @xerces.internal + * + * @version $Id$ + */ +public final class ObjectListImpl extends AbstractList implements ObjectList { + + /** + * An immutable empty list. + */ + public static final ObjectListImpl EMPTY_LIST = new ObjectListImpl(new Object[0], 0); + + // The array to hold all data + private final Object[] fArray; + + // Number of elements in this list + private final int fLength; + + public ObjectListImpl(Object[] array, int length) { + fArray = array; + fLength = length; + } + + public int getLength() { + return fLength; + } + + public boolean contains(Object item) { + if (item == null) { + for (int i = 0; i < fLength; i++) { + if (fArray[i] == null) + return true; + } + } + else { + for (int i = 0; i < fLength; i++) { + if (item.equals(fArray[i])) + return true; + } + } + return false; + } + + public Object item(int index) { + if (index < 0 || index >= fLength) { + return null; + } + return fArray[index]; + } + + /* + * List methods + */ + public Object get(int index) { + if (index >= 0 && index < fLength) { + return fArray[index]; + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + + public Object[] toArray() { + Object[] a = new Object[fLength]; + toArray0(a); + return a; + } + + public Object[] toArray(Object[] a) { + if (a.length < fLength) { + Class arrayClass = a.getClass(); + Class componentType = arrayClass.getComponentType(); + a = (Object[]) Array.newInstance(componentType, fLength); + } + toArray0(a); + if (a.length > fLength) { + a[fLength] = null; + } + return a; + } + + private void toArray0(Object[] a) { + if (fLength > 0) { + System.arraycopy(fArray, 0, a, 0, fLength); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/ShortListImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/ShortListImpl.java new file mode 100644 index 0000000..2158108 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/ShortListImpl.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import java.util.AbstractList; + +import org.apache.xerces.xs.ShortList; +import org.apache.xerces.xs.XSException; + +/** + * Contains a list of shorts. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public final class ShortListImpl extends AbstractList implements ShortList { + + /** + * An immutable empty list. + */ + public static final ShortListImpl EMPTY_LIST = new ShortListImpl(new short[0], 0); + + // The array to hold all data + private final short[] fArray; + // Number of elements in this list + private final int fLength; + + /** + * Construct an XSObjectList implementation + * + * @param array the data array + * @param length the number of elements + */ + public ShortListImpl(short[] array, int length) { + fArray = array; + fLength = length; + } + + /** + * The number of Objects in the list. The range of valid + * child node indices is 0 to length-1 inclusive. + */ + public int getLength() { + return fLength; + } + + /** + * Checks if the unsigned short item is a + * member of this list. + * @param item unsigned short whose presence in this list + * is to be tested. + * @return True if this list contains the unsigned short + * item. + */ + public boolean contains(short item) { + for (int i = 0; i < fLength; i++) { + if (fArray[i] == item) { + return true; + } + } + return false; + } + + public short item(int index) throws XSException { + if (index < 0 || index >= fLength) { + throw new XSException(XSException.INDEX_SIZE_ERR, null); + } + return fArray[index]; + } + + public boolean equals(Object obj) { + if (obj == null || !(obj instanceof ShortList)) { + return false; + } + ShortList rhs = (ShortList)obj; + + if (fLength != rhs.getLength()) { + return false; + } + for (int i = 0;i < fLength; ++i) { + if (fArray[i] != rhs.item(i)) { + return false; + } + } + return true; + } + + /* + * List methods + */ + + public Object get(int index) { + if (index >= 0 && index < fLength) { + return new Short(fArray[index]); + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + +} // class ShortListImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/SimpleLocator.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/SimpleLocator.java new file mode 100644 index 0000000..886494e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/SimpleLocator.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import org.apache.xerces.xni.XMLLocator; + +/** + * An XMLLocator implementation used for schema error reporting. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @version $Id$ + */ +public final class SimpleLocator implements XMLLocator { + + private String lsid; + private String esid; + private int line; + private int column; + private int charOffset; + + public SimpleLocator() { + } + + public SimpleLocator(String lsid, String esid, int line, int column) { + this(lsid, esid, line, column, -1); + } + + public void setValues(String lsid, String esid, int line, int column) { + setValues(lsid, esid, line, column, -1); + } + + public SimpleLocator(String lsid, String esid, int line, int column, int offset) { + this.line = line; + this.column = column; + this.lsid = lsid; + this.esid = esid; + charOffset = offset; + } + + public void setValues(String lsid, String esid, int line, int column, int offset) { + this.line = line; + this.column = column; + this.lsid = lsid; + this.esid = esid; + charOffset = offset; + } + + public int getLineNumber() { + return line; + } + + public int getColumnNumber() { + return column; + } + + public int getCharacterOffset() { + return charOffset; + } + + public String getPublicId() { + return null; + } + + public String getExpandedSystemId() { + return esid; + } + + public String getLiteralSystemId() { + return lsid; + } + + public String getBaseSystemId() { + return null; + } + + public void setColumnNumber(int col) { + this.column = col; + } + + public void setLineNumber(int line) { + this.line = line; + } + + public void setCharacterOffset(int offset) { + charOffset = offset; + } + + /** + * @see org.apache.xerces.xni.XMLResourceIdentifier#setBaseSystemId(String) + */ + public void setBaseSystemId(String systemId) {} + + /** + * @see org.apache.xerces.xni.XMLResourceIdentifier#setExpandedSystemId(String) + */ + public void setExpandedSystemId(String systemId) { + esid = systemId; + } + + /** + * @see org.apache.xerces.xni.XMLResourceIdentifier#setLiteralSystemId(String) + */ + public void setLiteralSystemId(String systemId) { + lsid = systemId; + } + + /** + * @see org.apache.xerces.xni.XMLResourceIdentifier#setPublicId(String) + */ + public void setPublicId(String publicId) {} + + /** + * Returns the encoding of the current entity. + * Since these locators are used in the construction of + * XMLParseExceptions, which know nothing about encodings, there is + * no point in having this object deal intelligently + * with encoding information. + */ + public String getEncoding() { + return null; + } + + public String getXMLVersion() { + return null; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/StringListImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/StringListImpl.java new file mode 100644 index 0000000..8cf7243 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/StringListImpl.java @@ -0,0 +1,163 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import java.lang.reflect.Array; +import java.util.AbstractList; +import java.util.Vector; + +import org.apache.xerces.xs.StringList; + +/** + * Contains a list of Strings. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public final class StringListImpl extends AbstractList implements StringList { + + /** + * An immutable empty list. + */ + public static final StringListImpl EMPTY_LIST = new StringListImpl(new String[0], 0); + + // The array to hold all data + private final String[] fArray; + // Number of elements in this list + private final int fLength; + + // REVISIT: this is temp solution. In general we need to use this class + // instead of the Vector. + private final Vector fVector; + + public StringListImpl(Vector v) { + fVector = v; + fLength = (v == null) ? 0 : v.size(); + fArray = null; + } + + /** + * Construct an XSObjectList implementation + * + * @param array the data array + * @param length the number of elements + */ + public StringListImpl(String[] array, int length) { + fArray = array; + fLength = length; + fVector = null; + } + + /** + * The number of Objects in the list. The range of valid + * child node indices is 0 to length-1 inclusive. + */ + public int getLength() { + return fLength; + } + + /** + * Checks if the GenericString item is a member + * of this list. + * @param item GenericString whose presence in this list is + * to be tested. + * @return True if this list contains the GenericString + * item. + */ + public boolean contains(String item) { + if (fVector != null) { + return fVector.contains(item); + } + if (item == null) { + for (int i = 0; i < fLength; i++) { + if (fArray[i] == null) + return true; + } + } + else { + for (int i = 0; i < fLength; i++) { + if (item.equals(fArray[i])) + return true; + } + } + return false; + } + + public String item(int index) { + if (index < 0 || index >= fLength) { + return null; + } + if (fVector != null) { + return (String)fVector.elementAt(index); + } + return fArray[index]; + } + + /* + * List methods + */ + + public Object get(int index) { + if (index >= 0 && index < fLength) { + if (fVector != null) { + return fVector.elementAt(index); + } + return fArray[index]; + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + + public Object[] toArray() { + if (fVector != null) { + return fVector.toArray(); + } + Object[] a = new Object[fLength]; + toArray0(a); + return a; + } + + public Object[] toArray(Object[] a) { + if (fVector != null) { + return fVector.toArray(a); + } + if (a.length < fLength) { + Class arrayClass = a.getClass(); + Class componentType = arrayClass.getComponentType(); + a = (Object[]) Array.newInstance(componentType, fLength); + } + toArray0(a); + if (a.length > fLength) { + a[fLength] = null; + } + return a; + } + + private void toArray0(Object[] a) { + if (fLength > 0) { + System.arraycopy(fArray, 0, a, 0, fLength); + } + } + +} // class StringListImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XInt.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XInt.java new file mode 100644 index 0000000..0a949d1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XInt.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +/** + * @xerces.internal + * + * @author Henry Zongaro, IBM + * @version $Id$ + */ + +public final class XInt { + + private final int fValue; + + XInt(int value) { + fValue = value; + } + + public final int intValue() { + return fValue; + } + + public final short shortValue() { + return (short)fValue; + } + + public final boolean equals(XInt compareVal) { + return (this.fValue == compareVal.fValue); + } + + public String toString() { + return Integer.toString(fValue); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XIntPool.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XIntPool.java new file mode 100644 index 0000000..e416726 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XIntPool.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +/** + * @xerces.internal + * + * @author Henry Zongaro, IBM + * @version $Id$ + */ +public final class XIntPool { + private static final short POOL_SIZE = 10; + private static final XInt[] fXIntPool = new XInt[POOL_SIZE]; + + static { + for (int i = 0; i < POOL_SIZE; i++) + fXIntPool[i] = new XInt(i); + } + + public final XInt getXInt(int value) { + if (value >= 0 && value < fXIntPool.length) + return fXIntPool[value]; + else + return new XInt(value); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XS10TypeHelper.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XS10TypeHelper.java new file mode 100644 index 0000000..9d51db9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XS10TypeHelper.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl; +import org.apache.xerces.impl.xs.XSComplexTypeDecl; +import org.apache.xerces.xs.XSSimpleTypeDefinition; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * Class defining utility/helper methods to support XML Schema 1.0 implementation. + * + * @xerces.internal + * + * @author Mukul Gandhi, IBM + * @version $Id$ + */ +public class XS10TypeHelper { + + /* + * Class constructor. + */ + private XS10TypeHelper() { + // a private constructor, to prohibit instantiating this class from an outside class/application. + // this is a good practice, since all methods of this class are "static". + } + + /* + * Get name of an XSD type definition as a string value (which will typically be the value of "name" attribute of a + * type definition, or an internal name determined by the validator for anonymous types). + */ + public static String getSchemaTypeName(XSTypeDefinition typeDefn) { + + String typeNameStr = ""; + if (typeDefn instanceof XSSimpleTypeDefinition) { + typeNameStr = ((XSSimpleTypeDecl) typeDefn).getTypeName(); + } + else { + typeNameStr = ((XSComplexTypeDecl) typeDefn).getTypeName(); + } + + return typeNameStr; + + } // getSchemaTypeName + + +} // class XS10TypeHelper diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSGrammarPool.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSGrammarPool.java new file mode 100644 index 0000000..995f2c6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSGrammarPool.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import java.util.ArrayList; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.XSModelImpl; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xs.XSModel; + +/** + * Add a method that return an XSModel that represents components in + * the schema grammars in this pool implementation. + * + * @xerces.internal + * + * @version $Id$ + */ +public class XSGrammarPool extends XMLGrammarPoolImpl { + + /** + * Return an XSModel that represents components in + * the schema grammars in this pool implementation. + * + * @return an XSModel representing this schema grammar + */ + public XSModel toXSModel() { + return toXSModel(Constants.SCHEMA_VERSION_1_0); + } + + public XSModel toXSModel(short schemaVersion) { + ArrayList list = new ArrayList(); + for (int i = 0; i < fGrammars.length; i++) { + for (Entry entry = fGrammars[i] ; entry != null ; entry = entry.next) { + if (entry.desc.getGrammarType().equals(XMLGrammarDescription.XML_SCHEMA)) { + list.add(entry.grammar); + } + } + } + int size = list.size(); + if (size == 0) { + return toXSModel(new SchemaGrammar[0], schemaVersion); + } + SchemaGrammar[] gs = (SchemaGrammar[])list.toArray(new SchemaGrammar[size]); + return toXSModel(gs, schemaVersion); + } + + protected XSModel toXSModel(SchemaGrammar[] grammars, short schemaVersion) { + return new XSModelImpl(grammars, schemaVersion); + } + +} // class XSGrammarPool diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSInputSource.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSInputSource.java new file mode 100644 index 0000000..fd20527 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSInputSource.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xs.XSObject; + +/** + * @xerces.internal + * + * @version $Id$ + */ +public final class XSInputSource extends XMLInputSource { + + private SchemaGrammar[] fGrammars; + private XSObject[] fComponents; + + public XSInputSource(SchemaGrammar[] grammars) { + super(null, null, null); + fGrammars = grammars; + fComponents = null; + } + + public XSInputSource(XSObject[] component) { + super(null, null, null); + fGrammars = null; + fComponents = component; + } + + public SchemaGrammar[] getGrammars() { + return fGrammars; + } + + public void setGrammars(SchemaGrammar[] grammars) { + fGrammars = grammars; + } + + public XSObject[] getComponents() { + return fComponents; + } + + public void setComponents(XSObject[] components) { + fComponents = components; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSNamedMap4Types.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSNamedMap4Types.java new file mode 100644 index 0000000..7c26c77 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSNamedMap4Types.java @@ -0,0 +1,140 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.xs.XSObject; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + * Contains the map between qnames and XSObject's. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public final class XSNamedMap4Types extends XSNamedMapImpl { + + // the type of component stored here: complex or simple type + private final short fType; + + /** + * Construct an XSNamedMap implementation for one namespace + * + * @param namespace the namespace to which the components belong + * @param map the map from local names to components + * @param type the type of components + */ + public XSNamedMap4Types(String namespace, SymbolHash map, short type) { + super(namespace, map); + fType = type; + } + + /** + * Construct an XSNamedMap implementation for a list of namespaces + * + * @param namespaces the namespaces to which the components belong + * @param maps the maps from local names to components + * @param num the number of namespaces + * @param type the type of components + */ + public XSNamedMap4Types(String[] namespaces, SymbolHash[] maps, int num, short type) { + super(namespaces, maps, num); + fType = type; + } + + /** + * The number of XSObjects in the XSObjectList. The + * range of valid child node indices is 0 to length-1 + * inclusive. + */ + public synchronized int getLength() { + if (fLength == -1) { + // first get the number of components for all types + int length = 0; + for (int i = 0; i < fNSNum; i++) { + length += fMaps[i].getLength(); + } + // then copy all types to an temporary array + int pos = 0; + XSObject[] array = new XSObject[length]; + for (int i = 0; i < fNSNum; i++) { + pos += fMaps[i].getValues(array, pos); + } + // then copy either simple or complex types to fArray, + // depending on which kind is required + fLength = 0; + fArray = new XSObject[length]; + XSTypeDefinition type; + for (int i = 0; i < length; i++) { + type = (XSTypeDefinition)array[i]; + if (type.getTypeCategory() == fType) { + fArray[fLength++] = type; + } + } + } + return fLength; + } + + /** + * Retrieves an XSObject specified by local name and namespace + * URI. + * @param namespace The namespace URI of the XSObject to + * retrieve. + * @param localName The local name of the XSObject to retrieve. + * @return A XSObject (of any type) with the specified local + * name and namespace URI, or null if they do not + * identify any XSObject in this map. + */ + public XSObject itemByName(String namespace, String localName) { + for (int i = 0; i < fNSNum; i++) { + if (isEqual(namespace, fNamespaces[i])) { + XSTypeDefinition type = (XSTypeDefinition)fMaps[i].get(localName); + // only return it if it matches the required type + if (type != null && type.getTypeCategory() == fType) { + return type; + } + return null; + } + } + return null; + } + + /** + * Returns the indexth item in the map. The index starts at + * 0. If index is greater than or equal to the number of + * nodes in the list, this returns null. + * @param index The position in the map from which the item is to be + * retrieved. + * @return The XSObject at the indexth position + * in the XSNamedMap, or null if that is + * not a valid index. + */ + public synchronized XSObject item(int index) { + if (fArray == null) { + getLength(); + } + if (index < 0 || index >= fLength) { + return null; + } + return fArray[index]; + } + +} // class XSNamedMapImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSNamedMapImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSNamedMapImpl.java new file mode 100644 index 0000000..c2590ba --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSNamedMapImpl.java @@ -0,0 +1,300 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; + +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.xs.XSNamedMap; +import org.apache.xerces.xs.XSObject; + +/** + * Contains the map between qnames and XSObject's. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XSNamedMapImpl extends AbstractMap implements XSNamedMap { + + /** + * An immutable empty map. + */ + public static final XSNamedMapImpl EMPTY_MAP = new XSNamedMapImpl(new XSObject[0], 0); + + // components of these namespaces are stored in this map + final String[] fNamespaces; + // number of namespaces + final int fNSNum; + // each entry contains components in one namespace + final SymbolHash[] fMaps; + // store all components from all namespace. + // used when this map is accessed as a list. + XSObject[] fArray = null; + // store the number of components. + // used when this map is accessed as a list. + int fLength = -1; + // Set of Map.Entry for the java.util.Map methods + private Set fEntrySet = null; + + /** + * Construct an XSNamedMap implementation for one namespace + * + * @param namespace the namespace to which the components belong + * @param map the map from local names to components + */ + public XSNamedMapImpl(String namespace, SymbolHash map) { + fNamespaces = new String[] {namespace}; + fMaps = new SymbolHash[] {map}; + fNSNum = 1; + } + + /** + * Construct an XSNamedMap implementation for a list of namespaces + * + * @param namespaces the namespaces to which the components belong + * @param maps the maps from local names to components + * @param num the number of namespaces + */ + public XSNamedMapImpl(String[] namespaces, SymbolHash[] maps, int num) { + fNamespaces = namespaces; + fMaps = maps; + fNSNum = num; + } + + /** + * Construct an XSNamedMap implementation one namespace from an array + * + * @param array containing all components + * @param length number of components + */ + public XSNamedMapImpl(XSObject[] array, int length) { + if (length == 0) { + fNamespaces = null; + fMaps = null; + fNSNum = 0; + fArray = array; + fLength = 0; + return; + } + // because all components are from the same target namesapce, + // get the namespace from the first one. + fNamespaces = new String[]{array[0].getNamespace()}; + fMaps = null; + fNSNum = 1; + // copy elements to the Vector + fArray = array; + fLength = length; + } + + /** + * The number of XSObjects in the XSObjectList. + * The range of valid child object indices is 0 to length-1 + * inclusive. + */ + public synchronized int getLength() { + if (fLength == -1) { + fLength = 0; + for (int i = 0; i < fNSNum; i++) { + fLength += fMaps[i].getLength(); + } + } + return fLength; + } + + /** + * Retrieves an XSObject specified by local name and + * namespace URI. + *
Per XML Namespaces, applications must use the value null as the + * namespace parameter for methods if they wish to specify + * no namespace. + * @param namespace The namespace URI of the XSObject to + * retrieve, or null if the XSObject has no + * namespace. + * @param localName The local name of the XSObject to + * retrieve. + * @return A XSObject (of any type) with the specified local + * name and namespace URI, or null if they do not + * identify any object in this map. + */ + public XSObject itemByName(String namespace, String localName) { + for (int i = 0; i < fNSNum; i++) { + if (isEqual(namespace, fNamespaces[i])) { + // when this map is created from SymbolHash's + // get the component from SymbolHash + if (fMaps != null) { + return (XSObject)fMaps[i].get(localName); + } + // Otherwise (it's created from an array) + // go through the array to find a matching name + XSObject ret; + for (int j = 0; j < fLength; j++) { + ret = fArray[j]; + if (ret.getName().equals(localName)) { + return ret; + } + } + return null; + } + } + return null; + } + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The XSObject at the indexth + * position in the XSObjectList, or null if + * the index specified is not valid. + */ + public synchronized XSObject item(int index) { + if (fArray == null) { + // calculate the total number of elements + getLength(); + fArray = new XSObject[fLength]; + int pos = 0; + // get components from all SymbolHashes + for (int i = 0; i < fNSNum; i++) { + pos += fMaps[i].getValues(fArray, pos); + } + } + if (index < 0 || index >= fLength) { + return null; + } + return fArray[index]; + } + + static boolean isEqual(String one, String two) { + return (one != null) ? one.equals(two) : (two == null); + } + + /* + * java.util.Map methods + */ + + public boolean containsKey(Object key) { + return (get(key) != null); + } + + public Object get(Object key) { + if (key instanceof QName) { + final QName name = (QName) key; + String namespaceURI = name.getNamespaceURI(); + if (XMLConstants.NULL_NS_URI.equals(namespaceURI)) { + namespaceURI = null; + } + String localPart = name.getLocalPart(); + return itemByName(namespaceURI, localPart); + } + return null; + } + + public int size() { + return getLength(); + } + + public synchronized Set entrySet() { + // Defer creation of the entry set until it is actually needed. + if (fEntrySet == null) { + final int length = getLength(); + final XSNamedMapEntry[] entries = new XSNamedMapEntry[length]; + for (int i = 0; i < length; ++i) { + XSObject xso = item(i); + entries[i] = new XSNamedMapEntry(new QName(xso.getNamespace(), xso.getName()), xso); + } + // Create a view of this immutable map. + fEntrySet = new AbstractSet() { + public Iterator iterator() { + return new Iterator() { + private int index = 0; + public boolean hasNext() { + return (index < length); + } + public Object next() { + if (index < length) { + return entries[index++]; + } + throw new NoSuchElementException(); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + public int size() { + return length; + } + }; + } + return fEntrySet; + } + + /** An entry in the XSNamedMap. **/ + private static final class XSNamedMapEntry implements Map.Entry { + private final QName key; + private final XSObject value; + public XSNamedMapEntry(QName key, XSObject value) { + this.key = key; + this.value = value; + } + public Object getKey() { + return key; + } + public Object getValue() { + return value; + } + public Object setValue(Object value) { + throw new UnsupportedOperationException(); + } + public boolean equals(Object o) { + if (o instanceof Map.Entry) { + Map.Entry e = (Map.Entry) o; + Object otherKey = e.getKey(); + Object otherValue = e.getValue(); + return (key == null ? otherKey == null : key.equals(otherKey)) && + (value == null ? otherValue == null : value.equals(otherValue)); + } + return false; + } + public int hashCode() { + return (key == null ? 0 : key.hashCode()) + ^ (value == null ? 0 : value.hashCode()); + } + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(String.valueOf(key)); + buffer.append('='); + buffer.append(String.valueOf(value)); + return buffer.toString(); + } + } + +} // class XSNamedMapImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSObjectListImpl.java b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSObjectListImpl.java new file mode 100644 index 0000000..1d50b94 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/impl/xs/util/XSObjectListImpl.java @@ -0,0 +1,264 @@ +/* + * 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. + */ + +package org.apache.xerces.impl.xs.util; + +import java.lang.reflect.Array; +import java.util.AbstractList; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.apache.xerces.xs.XSObject; +import org.apache.xerces.xs.XSObjectList; + +/** + * Contains a list of XSObjects. + * + * @xerces.internal + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public class XSObjectListImpl extends AbstractList implements XSObjectList { + + /** + * An immutable empty list. + */ + public static final XSObjectListImpl EMPTY_LIST = new XSObjectListImpl(new XSObject[0], 0); + private static final ListIterator EMPTY_ITERATOR = new ListIterator() { + public boolean hasNext() { + return false; + } + public Object next() { + throw new NoSuchElementException(); + } + public boolean hasPrevious() { + return false; + } + public Object previous() { + throw new NoSuchElementException(); + } + public int nextIndex() { + return 0; + } + public int previousIndex() { + return -1; + } + public void remove() { + throw new UnsupportedOperationException(); + } + public void set(Object object) { + throw new UnsupportedOperationException(); + } + public void add(Object object) { + throw new UnsupportedOperationException(); + } + }; + + private static final int DEFAULT_SIZE = 4; + + // The array to hold all data + private XSObject[] fArray = null; + // Number of elements in this list + private int fLength = 0; + + public XSObjectListImpl() { + fArray = new XSObject[DEFAULT_SIZE]; + fLength = 0; + } + + /** + * Construct an XSObjectList implementation + * + * @param array the data array + * @param length the number of elements + */ + public XSObjectListImpl(XSObject[] array, int length) { + fArray = array; + fLength = length; + } + + /** + * The number of XSObjects in the list. The range of valid + * child node indices is 0 to length-1 inclusive. + */ + public int getLength() { + return fLength; + } + + /** + * Returns the indexth item in the collection. The index + * starts at 0. If index is greater than or equal to the + * number of nodes in the list, this returns null. + * @param index index into the collection. + * @return The XSObject at the indexth position in the + * XSObjectList, or null if that is not a + * valid index. + */ + public XSObject item(int index) { + if (index < 0 || index >= fLength) { + return null; + } + return fArray[index]; + } + + // clear this object + public void clearXSObjectList() { + for (int i=0; i= 0 && index < fLength) { + return fArray[index]; + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + public int size() { + return getLength(); + } + + public Iterator iterator() { + return listIterator0(0); + } + + public ListIterator listIterator() { + return listIterator0(0); + } + + public ListIterator listIterator(int index) { + if (index >= 0 && index < fLength) { + return listIterator0(index); + } + throw new IndexOutOfBoundsException("Index: " + index); + } + + private ListIterator listIterator0(int index) { + return fLength == 0 ? EMPTY_ITERATOR : new XSObjectListIterator(index); + } + + private boolean containsObject(Object value) { + for (int i = fLength - 1; i >= 0; --i) { + if (value.equals(fArray[i])) { + return true; + } + } + return false; + } + + private boolean containsNull() { + for (int i = fLength - 1; i >= 0; --i) { + if (fArray[i] == null) { + return true; + } + } + return false; + } + + public Object[] toArray() { + Object[] a = new Object[fLength]; + toArray0(a); + return a; + } + + public Object[] toArray(Object[] a) { + if (a.length < fLength) { + Class arrayClass = a.getClass(); + Class componentType = arrayClass.getComponentType(); + a = (Object[]) Array.newInstance(componentType, fLength); + } + toArray0(a); + if (a.length > fLength) { + a[fLength] = null; + } + return a; + } + + private void toArray0(Object[] a) { + if (fLength > 0) { + System.arraycopy(fArray, 0, a, 0, fLength); + } + } + + private final class XSObjectListIterator implements ListIterator { + private int index; + public XSObjectListIterator(int index) { + this.index = index; + } + public boolean hasNext() { + return (index < fLength); + } + public Object next() { + if (index < fLength) { + return fArray[index++]; + } + throw new NoSuchElementException(); + } + public boolean hasPrevious() { + return (index > 0); + } + public Object previous() { + if (index > 0) { + return fArray[--index]; + } + throw new NoSuchElementException(); + } + public int nextIndex() { + return index; + } + public int previousIndex() { + return index - 1; + } + public void remove() { + throw new UnsupportedOperationException(); + } + public void set(Object o) { + throw new UnsupportedOperationException(); + } + public void add(Object o) { + throw new UnsupportedOperationException(); + } + } + +} // class XSObjectListImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/DefaultValidationErrorHandler.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/DefaultValidationErrorHandler.java new file mode 100644 index 0000000..63f1950 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/DefaultValidationErrorHandler.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * @version $Id$ + */ + +class DefaultValidationErrorHandler extends DefaultHandler { + static private int ERROR_COUNT_LIMIT = 10; + private int errorCount = 0; + + // XXX Fix message i18n + public void error(SAXParseException e) throws SAXException { + if (errorCount >= ERROR_COUNT_LIMIT) { + // Ignore all errors after reaching the limit + return; + } else if (errorCount == 0) { + // Print a warning before the first error + System.err.println("Warning: validation was turned on but an org.xml.sax.ErrorHandler was not"); + System.err.println("set, which is probably not what is desired. Parser will use a default"); + System.err.println("ErrorHandler to print the first " + + ERROR_COUNT_LIMIT + " errors. Please call"); + System.err.println("the 'setErrorHandler' method to fix this."); + } + + String systemId = e.getSystemId(); + if (systemId == null) { + systemId = "null"; + } + String message = "Error: URI=" + systemId + + " Line=" + e.getLineNumber() + + ": " + e.getMessage(); + System.err.println(message); + errorCount++; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/DocumentBuilderFactoryImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/DocumentBuilderFactoryImpl.java new file mode 100644 index 0000000..22d3634 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/DocumentBuilderFactoryImpl.java @@ -0,0 +1,294 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp; + +import java.util.Hashtable; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.validation.Schema; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.util.SAXMessageFormatter; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * @author Rajiv Mordani + * @author Edwin Goei + * @version $Id$ + */ +public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory { + + /** Feature identifier: namespaces. */ + private static final String NAMESPACES_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: validation */ + private static final String VALIDATION_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: XInclude processing */ + private static final String XINCLUDE_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE; + + /** Feature identifier: include ignorable white space. */ + private static final String INCLUDE_IGNORABLE_WHITESPACE = + Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE; + + /** Feature identifier: create entiry ref nodes feature. */ + private static final String CREATE_ENTITY_REF_NODES_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE; + + /** Feature identifier: include comments feature. */ + private static final String INCLUDE_COMMENTS_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE; + + /** Feature identifier: create cdata nodes feature. */ + private static final String CREATE_CDATA_NODES_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE; + + /** These are DocumentBuilderFactory attributes not DOM attributes */ + private Hashtable attributes; + private Hashtable features; + private Schema grammar; + private boolean isXIncludeAware; + + /** + * State of the secure processing feature, initially false + */ + private boolean fSecureProcess = false; + + /** + * Creates a new instance of a {@link javax.xml.parsers.DocumentBuilder} + * using the currently configured parameters. + */ + public DocumentBuilder newDocumentBuilder() + throws ParserConfigurationException + { + /** Check that if a Schema has been specified that neither of the schema properties have been set. */ + if (grammar != null && attributes != null) { + if (attributes.containsKey(JAXPConstants.JAXP_SCHEMA_LANGUAGE)) { + throw new ParserConfigurationException( + SAXMessageFormatter.formatMessage(null, + "schema-already-specified", new Object[] {JAXPConstants.JAXP_SCHEMA_LANGUAGE})); + } + else if (attributes.containsKey(JAXPConstants.JAXP_SCHEMA_SOURCE)) { + throw new ParserConfigurationException( + SAXMessageFormatter.formatMessage(null, + "schema-already-specified", new Object[] {JAXPConstants.JAXP_SCHEMA_SOURCE})); + } + } + + try { + return new DocumentBuilderImpl(this, attributes, features, fSecureProcess); + } catch (SAXException se) { + // Handles both SAXNotSupportedException, SAXNotRecognizedException + throw new ParserConfigurationException(se.getMessage()); + } + } + + /** + * Allows the user to set specific attributes on the underlying + * implementation. + * @param name name of attribute + * @param value null means to remove attribute + */ + public void setAttribute(String name, Object value) + throws IllegalArgumentException + { + // This handles removal of attributes + if (value == null) { + if (attributes != null) { + attributes.remove(name); + } + // Unrecognized attributes do not cause an exception + return; + } + + // This is ugly. We have to collect the attributes and then + // later create a DocumentBuilderImpl to verify the attributes. + + // Create Hashtable if none existed before + if (attributes == null) { + attributes = new Hashtable(); + } + + attributes.put(name, value); + + // Test the attribute name by possibly throwing an exception + try { + new DocumentBuilderImpl(this, attributes, features); + } catch (Exception e) { + attributes.remove(name); + throw new IllegalArgumentException(e.getMessage()); + } + } + + /** + * Allows the user to retrieve specific attributes on the underlying + * implementation. + */ + public Object getAttribute(String name) + throws IllegalArgumentException + { + // See if it's in the attributes Hashtable + if (attributes != null) { + Object val = attributes.get(name); + if (val != null) { + return val; + } + } + + DOMParser domParser = null; + try { + // We create a dummy DocumentBuilderImpl in case the attribute + // name is not one that is in the attributes hashtable. + domParser = + new DocumentBuilderImpl(this, attributes, features).getDOMParser(); + return domParser.getProperty(name); + } catch (SAXException se1) { + // assert(name is not recognized or not supported), try feature + try { + boolean result = domParser.getFeature(name); + // Must have been a feature + return result ? Boolean.TRUE : Boolean.FALSE; + } catch (SAXException se2) { + // Not a property or a feature + throw new IllegalArgumentException(se1.getMessage()); + } + } + } + + public Schema getSchema() { + return grammar; + } + + public void setSchema(Schema grammar) { + this.grammar = grammar; + } + + public boolean isXIncludeAware() { + return this.isXIncludeAware; + } + + public void setXIncludeAware(boolean state) { + this.isXIncludeAware = state; + } + + public boolean getFeature(String name) + throws ParserConfigurationException { + if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { + return fSecureProcess; + } + else if (name.equals(NAMESPACES_FEATURE)) { + return isNamespaceAware(); + } + else if (name.equals(VALIDATION_FEATURE)) { + return isValidating(); + } + else if (name.equals(XINCLUDE_FEATURE)) { + return isXIncludeAware(); + } + else if (name.equals(INCLUDE_IGNORABLE_WHITESPACE)) { + return !isIgnoringElementContentWhitespace(); + } + else if (name.equals(CREATE_ENTITY_REF_NODES_FEATURE)) { + return !isExpandEntityReferences(); + } + else if (name.equals(INCLUDE_COMMENTS_FEATURE)) { + return !isIgnoringComments(); + } + else if (name.equals(CREATE_CDATA_NODES_FEATURE)) { + return !isCoalescing(); + } + // See if it's in the features Hashtable + if (features != null) { + Object val = features.get(name); + if (val != null) { + return ((Boolean) val).booleanValue(); + } + } + try { + DOMParser domParser = new DocumentBuilderImpl(this, attributes, features).getDOMParser(); + return domParser.getFeature(name); + } + catch (SAXException e) { + throw new ParserConfigurationException(e.getMessage()); + } + } + + public void setFeature(String name, boolean value) + throws ParserConfigurationException { + // If this is the secure processing feature, save it then return. + if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { + fSecureProcess = value; + return; + } + // Keep built-in settings in synch with the feature values. + else if (name.equals(NAMESPACES_FEATURE)) { + setNamespaceAware(value); + return; + } + else if (name.equals(VALIDATION_FEATURE)) { + setValidating(value); + return; + } + else if (name.equals(XINCLUDE_FEATURE)) { + setXIncludeAware(value); + return; + } + else if (name.equals(INCLUDE_IGNORABLE_WHITESPACE)) { + setIgnoringElementContentWhitespace(!value); + return; + } + else if (name.equals(CREATE_ENTITY_REF_NODES_FEATURE)) { + setExpandEntityReferences(!value); + return; + } + else if (name.equals(INCLUDE_COMMENTS_FEATURE)) { + setIgnoringComments(!value); + return; + } + else if (name.equals(CREATE_CDATA_NODES_FEATURE)) { + setCoalescing(!value); + return; + } + + if (features == null) { + features = new Hashtable(); + } + features.put(name, value ? Boolean.TRUE : Boolean.FALSE); + // Test the feature by possibly throwing SAX exceptions + try { + new DocumentBuilderImpl(this, attributes, features); + } + catch (SAXNotSupportedException e) { + features.remove(name); + throw new ParserConfigurationException(e.getMessage()); + } + catch (SAXNotRecognizedException e) { + features.remove(name); + throw new ParserConfigurationException(e.getMessage()); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/DocumentBuilderImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/DocumentBuilderImpl.java new file mode 100644 index 0000000..bb23052 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/DocumentBuilderImpl.java @@ -0,0 +1,372 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.validation.Schema; + +import org.apache.xerces.dom.DOMImplementationImpl; +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.jaxp.validation.XSGrammarPoolContainer; +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * @author Rajiv Mordani + * @author Edwin Goei + * @version $Id$ + */ +public class DocumentBuilderImpl extends DocumentBuilder + implements JAXPConstants +{ + /** Feature identifier: namespaces. */ + private static final String NAMESPACES_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: include ignorable white space. */ + private static final String INCLUDE_IGNORABLE_WHITESPACE = + Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE; + + /** Feature identifier: create entiry ref nodes feature. */ + private static final String CREATE_ENTITY_REF_NODES_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE; + + /** Feature identifier: include comments feature. */ + private static final String INCLUDE_COMMENTS_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE; + + /** Feature identifier: create cdata nodes feature. */ + private static final String CREATE_CDATA_NODES_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE; + + /** Feature identifier: XInclude processing */ + private static final String XINCLUDE_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE; + + /** feature identifier: XML Schema validation */ + private static final String XMLSCHEMA_VALIDATION_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** Feature identifier: validation */ + private static final String VALIDATION_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Property identifier: security manager. */ + private static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + private final DOMParser domParser; + private final Schema grammar; + + private final XMLComponent fSchemaValidator; + private final XMLComponentManager fSchemaValidatorComponentManager; + private final ValidationManager fSchemaValidationManager; + private final UnparsedEntityHandler fUnparsedEntityHandler; + + /** Initial ErrorHandler */ + private final ErrorHandler fInitErrorHandler; + + /** Initial EntityResolver */ + private final EntityResolver fInitEntityResolver; + + DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Hashtable dbfAttrs, Hashtable features) + throws SAXNotRecognizedException, SAXNotSupportedException { + this(dbf, dbfAttrs, features, false); + } + + DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Hashtable dbfAttrs, Hashtable features, boolean secureProcessing) + throws SAXNotRecognizedException, SAXNotSupportedException + { + domParser = new DOMParser(); + + // If validating, provide a default ErrorHandler that prints + // validation errors with a warning telling the user to set an + // ErrorHandler + if (dbf.isValidating()) { + fInitErrorHandler = new DefaultValidationErrorHandler(); + setErrorHandler(fInitErrorHandler); + } + else { + fInitErrorHandler = domParser.getErrorHandler(); + } + + domParser.setFeature(VALIDATION_FEATURE, dbf.isValidating()); + + // "namespaceAware" == SAX Namespaces feature + domParser.setFeature(NAMESPACES_FEATURE, dbf.isNamespaceAware()); + + // Set various parameters obtained from DocumentBuilderFactory + domParser.setFeature(INCLUDE_IGNORABLE_WHITESPACE, + !dbf.isIgnoringElementContentWhitespace()); + domParser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, + !dbf.isExpandEntityReferences()); + domParser.setFeature(INCLUDE_COMMENTS_FEATURE, + !dbf.isIgnoringComments()); + domParser.setFeature(CREATE_CDATA_NODES_FEATURE, + !dbf.isCoalescing()); + + // Avoid setting the XInclude processing feature if the value is false. + // This will keep the configuration from throwing an exception if it + // does not support XInclude. + if (dbf.isXIncludeAware()) { + domParser.setFeature(XINCLUDE_FEATURE, true); + } + + // If the secure processing feature is on set a security manager. + if (secureProcessing) { + domParser.setProperty(SECURITY_MANAGER, new SecurityManager()); + } + + this.grammar = dbf.getSchema(); + if (grammar != null) { + XMLParserConfiguration config = domParser.getXMLParserConfiguration(); + XMLComponent validatorComponent = null; + /** For Xerces grammars, use built-in schema validator. **/ + if (grammar instanceof XSGrammarPoolContainer) { + validatorComponent = new XMLSchemaValidator(); + fSchemaValidationManager = new ValidationManager(); + fUnparsedEntityHandler = new UnparsedEntityHandler(fSchemaValidationManager); + config.setDTDHandler(fUnparsedEntityHandler); + fUnparsedEntityHandler.setDTDHandler(domParser); + domParser.setDTDSource(fUnparsedEntityHandler); + fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(config, + (XSGrammarPoolContainer) grammar, fSchemaValidationManager); + } + /** For third party grammars, use the JAXP validator component. **/ + else { + validatorComponent = new JAXPValidatorComponent(grammar.newValidatorHandler()); + fSchemaValidationManager = null; + fUnparsedEntityHandler = null; + fSchemaValidatorComponentManager = config; + } + config.addRecognizedFeatures(validatorComponent.getRecognizedFeatures()); + config.addRecognizedProperties(validatorComponent.getRecognizedProperties()); + config.setDocumentHandler((XMLDocumentHandler) validatorComponent); + ((XMLDocumentSource)validatorComponent).setDocumentHandler(domParser); + domParser.setDocumentSource((XMLDocumentSource) validatorComponent); + fSchemaValidator = validatorComponent; + } + else { + fSchemaValidationManager = null; + fUnparsedEntityHandler = null; + fSchemaValidatorComponentManager = null; + fSchemaValidator = null; + } + + // Set features + setFeatures(features); + + // Set attributes + setDocumentBuilderFactoryAttributes(dbfAttrs); + + // Initial EntityResolver + fInitEntityResolver = domParser.getEntityResolver(); + } + + private void setFeatures(Hashtable features) + throws SAXNotSupportedException, SAXNotRecognizedException { + if (features != null) { + Iterator entries = features.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + String feature = (String) entry.getKey(); + boolean value = ((Boolean) entry.getValue()).booleanValue(); + domParser.setFeature(feature, value); + } + } + } + + /** + * Set any DocumentBuilderFactory attributes of our underlying DOMParser + * + * Note: code does not handle possible conflicts between DOMParser + * attribute names and JAXP specific attribute names, + * eg. DocumentBuilderFactory.setValidating() + */ + private void setDocumentBuilderFactoryAttributes(Hashtable dbfAttrs) + throws SAXNotSupportedException, SAXNotRecognizedException + { + if (dbfAttrs == null) { + // Nothing to do + return; + } + + Iterator entries = dbfAttrs.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + String name = (String) entry.getKey(); + Object val = entry.getValue(); + if (val instanceof Boolean) { + // Assume feature + domParser.setFeature(name, ((Boolean)val).booleanValue()); + } else { + // Assume property + if (JAXP_SCHEMA_LANGUAGE.equals(name)) { + // JAXP 1.2 support + //None of the properties will take effect till the setValidating(true) has been called + if ( W3C_XML_SCHEMA.equals(val) ) { + if( isValidating() ) { + domParser.setFeature(XMLSCHEMA_VALIDATION_FEATURE, true); + // this should allow us not to emit DTD errors, as expected by the + // spec when schema validation is enabled + domParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); + } + } + } else if(JAXP_SCHEMA_SOURCE.equals(name)){ + if( isValidating() ) { + String value=(String)dbfAttrs.get(JAXP_SCHEMA_LANGUAGE); + if(value !=null && W3C_XML_SCHEMA.equals(value)){ + domParser.setProperty(name, val); + }else{ + throw new IllegalArgumentException( + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, + "jaxp-order-not-supported", + new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE})); + } + } + } else { + // Let Xerces code handle the property + domParser.setProperty(name, val); + } + } + } + } + + /** + * Non-preferred: use the getDOMImplementation() method instead of this + * one to get a DOM Level 2 DOMImplementation object and then use DOM + * Level 2 methods to create a DOM Document object. + */ + public Document newDocument() { + return new org.apache.xerces.dom.DocumentImpl(); + } + + public DOMImplementation getDOMImplementation() { + return DOMImplementationImpl.getDOMImplementation(); + } + + public Document parse(InputSource is) throws SAXException, IOException { + if (is == null) { + throw new IllegalArgumentException( + DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, + "jaxp-null-input-source", null)); + } + if (fSchemaValidator != null) { + if (fSchemaValidationManager != null) { + fSchemaValidationManager.reset(); + fUnparsedEntityHandler.reset(); + } + resetSchemaValidator(); + } + domParser.parse(is); + Document doc = domParser.getDocument(); + domParser.dropDocumentReferences(); + return doc; + } + + public boolean isNamespaceAware() { + try { + return domParser.getFeature(NAMESPACES_FEATURE); + } + catch (SAXException x) { + throw new IllegalStateException(x.getMessage()); + } + } + + public boolean isValidating() { + try { + return domParser.getFeature(VALIDATION_FEATURE); + } + catch (SAXException x) { + throw new IllegalStateException(x.getMessage()); + } + } + + /** + * Gets the XInclude processing mode for this parser + * @return the state of XInclude processing mode + */ + public boolean isXIncludeAware() { + try { + return domParser.getFeature(XINCLUDE_FEATURE); + } + catch (SAXException exc) { + return false; + } + } + + public void setEntityResolver(EntityResolver er) { + domParser.setEntityResolver(er); + } + + public void setErrorHandler(ErrorHandler eh) { + domParser.setErrorHandler(eh); + } + + public Schema getSchema() { + return grammar; + } + + public void reset() { + /** Restore the initial error handler. **/ + if (domParser.getErrorHandler() != fInitErrorHandler) { + domParser.setErrorHandler(fInitErrorHandler); + } + /** Restore the initial entity resolver. **/ + if (domParser.getEntityResolver() != fInitEntityResolver) { + domParser.setEntityResolver(fInitEntityResolver); + } + } + + // package private + DOMParser getDOMParser() { + return domParser; + } + + private void resetSchemaValidator() throws SAXException { + try { + fSchemaValidator.reset(fSchemaValidatorComponentManager); + } + // This should never be thrown from the schema validator. + catch (XMLConfigurationException e) { + throw new SAXException(e); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/JAXPConstants.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/JAXPConstants.java new file mode 100644 index 0000000..94069e4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/JAXPConstants.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + + +package org.apache.xerces.jaxp; + +/** + * This interface holds JAXP constant property/attribute names and values. + * Since JAXP 1.2 is a maintenance release of JAXP 1.1, no public + * signatures are allowed so these values cannot be exposed in the + * javax.xml.parsers package. Once equivalent constants have been defined + * in future JAXP spec versions, this interface can be removed. + * + * @author Edwin Goei + * @version $Id$ + */ +public interface JAXPConstants { + static final String JAXP_SCHEMA_LANGUAGE = + "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + static final String W3C_XML_SCHEMA = + "http://www.w3.org/2001/XMLSchema"; + + static final String JAXP_SCHEMA_SOURCE = + "http://java.sun.com/xml/jaxp/properties/schemaSource"; +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/JAXPValidatorComponent.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/JAXPValidatorComponent.java new file mode 100644 index 0000000..bc4970a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/JAXPValidatorComponent.java @@ -0,0 +1,597 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp; + +import java.io.IOException; + +import javax.xml.validation.TypeInfoProvider; +import javax.xml.validation.ValidatorHandler; + +import org.apache.xerces.dom.DOMInputImpl; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.xs.opti.DefaultXMLDocumentHandler; +import org.apache.xerces.util.AttributesProxy; +import org.apache.xerces.util.AugmentationsImpl; +import org.apache.xerces.util.ErrorHandlerProxy; +import org.apache.xerces.util.ErrorHandlerWrapper; +import org.apache.xerces.util.LocatorProxy; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLResourceIdentifierImpl; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Runs events through a {@link javax.xml.validation.ValidatorHandler} + * and performs validation/infoset-augmentation by an external validator. + * + *

+ * This component sets up the pipeline as follows: + * + * + *

+ *             __                                           __
+ *            /  |==> XNI2SAX --> Validator --> SAX2XNI ==>|  
+ *           /   |                                         |   
+ *       ==>| Tee|                                         | next
+ *           \   |                                         |  component
+ *            \  |============other XNI events============>|  
+ *             ~~                                           ~~
+ * 
+ *

+ * only those events that need to go through Validator will go the 1st route, + * and other events go the 2nd direct route. + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * @version $Id$ + */ +final class JAXPValidatorComponent + extends TeeXMLDocumentFilterImpl implements XMLComponent { + + /** Property identifier: entity manager. */ + private static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier: error reporter. */ + private static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: symbol table. */ + private static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + // pipeline parts + private final ValidatorHandler validator; + private final XNI2SAX xni2sax = new XNI2SAX(); + private final SAX2XNI sax2xni = new SAX2XNI(); + + // never be null + private final TypeInfoProvider typeInfoProvider; + + /** + * Used to store the {@link Augmentations} associated with the + * current event, so that we can pick it up again + * when the event is forwarded by the {@link ValidatorHandler}. + * + * UGLY HACK. + */ + private Augmentations fCurrentAug; + + /** + * {@link XMLAttributes} version of {@link #fCurrentAug}. + */ + private XMLAttributes fCurrentAttributes; + + // components obtained from a manager / property + + private SymbolTable fSymbolTable; + private XMLErrorReporter fErrorReporter; + private XMLEntityResolver fEntityResolver; + + /** + * @param validatorHandler may not be null. + */ + public JAXPValidatorComponent( ValidatorHandler validatorHandler ) { + this.validator = validatorHandler; + TypeInfoProvider tip = validatorHandler.getTypeInfoProvider(); + if(tip==null) tip = noInfoProvider; + this.typeInfoProvider = tip; + + // configure wiring between internal components. + xni2sax.setContentHandler(validator); + validator.setContentHandler(sax2xni); + this.setSide(xni2sax); + + // configure validator with proper EntityResolver/ErrorHandler. + validator.setErrorHandler(new ErrorHandlerProxy() { + protected XMLErrorHandler getErrorHandler() { + XMLErrorHandler handler = fErrorReporter.getErrorHandler(); + if(handler!=null) return handler; + return new ErrorHandlerWrapper(DraconianErrorHandler.getInstance()); + } + }); + validator.setResourceResolver(new LSResourceResolver() { + public LSInput resolveResource(String type,String ns, String publicId, String systemId, String baseUri) { + if(fEntityResolver==null) return null; + try { + XMLInputSource is = fEntityResolver.resolveEntity( + new XMLResourceIdentifierImpl(publicId,systemId,baseUri,null)); + if(is==null) return null; + + LSInput di = new DOMInputImpl(); + di.setBaseURI(is.getBaseSystemId()); + di.setByteStream(is.getByteStream()); + di.setCharacterStream(is.getCharacterStream()); + di.setEncoding(is.getEncoding()); + di.setPublicId(is.getPublicId()); + di.setSystemId(is.getSystemId()); + + return di; + } catch( IOException e ) { + // erors thrown by the callback is not supposed to be + // reported to users. + throw new XNIException(e); + } + } + }); + } + + + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { + fCurrentAttributes = attributes; + fCurrentAug = augs; + xni2sax.startElement(element,attributes,null); + fCurrentAttributes = null; // mostly to make it easy to find any bug. + } + + public void endElement(QName element, Augmentations augs) throws XNIException { + fCurrentAug = augs; + xni2sax.endElement(element,null); + } + + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { + startElement(element,attributes,augs); + endElement(element,augs); + } + + + public void characters(XMLString text, Augmentations augs) throws XNIException { + // since a validator may change the contents, + // let this one go through a validator + fCurrentAug = augs; + xni2sax.characters(text,null); + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + // since a validator may change the contents, + // let this one go through a validator + fCurrentAug = augs; + xni2sax.ignorableWhitespace(text,null); + } + + public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { + // obtain references from the manager + fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE); + fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); + try { + fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER); + } + catch (XMLConfigurationException e) { + fEntityResolver = null; + } + } + + /** + * + * Uses {@link DefaultHandler} as a default implementation of + * {@link ContentHandler}. + * + *

+ * We only forward certain events from a {@link ValidatorHandler}. + * Other events should go "the 2nd direct route". + */ + private final class SAX2XNI extends DefaultHandler { + + /** + * {@link Augmentations} to send along with events. + * We reuse one object for efficiency. + */ + private final Augmentations fAugmentations = new AugmentationsImpl(); + + /** + * {@link QName} to send along events. + * we reuse one QName for efficiency. + */ + private final QName fQName = new QName(); + + public void characters(char[] ch, int start, int len) throws SAXException { + try { + handler().characters(new XMLString(ch,start,len),aug()); + } catch( XNIException e ) { + throw toSAXException(e); + } + } + + public void ignorableWhitespace(char[] ch, int start, int len) throws SAXException { + try { + handler().ignorableWhitespace(new XMLString(ch,start,len),aug()); + } catch( XNIException e ) { + throw toSAXException(e); + } + } + + public void startElement(String uri, String localName, String qname, Attributes atts) throws SAXException { + try { + updateAttributes(atts); + handler().startElement(toQName(uri,localName,qname), fCurrentAttributes, elementAug()); + } catch( XNIException e ) { + throw toSAXException(e); + } + } + + public void endElement(String uri, String localName, String qname) throws SAXException { + try { + handler().endElement(toQName(uri,localName,qname),aug()); + } catch( XNIException e ) { + throw toSAXException(e); + } + } + + private Augmentations elementAug() { + Augmentations aug = aug(); + /** aug.putItem(Constants.TYPEINFO,typeInfoProvider.getElementTypeInfo()); **/ + return aug; + } + + + /** + * Gets the {@link Augmentations} that should be associated with + * the current event. + */ + private Augmentations aug() { + if( fCurrentAug!=null ) { + Augmentations r = fCurrentAug; + fCurrentAug = null; // we "consumed" this augmentation. + return r; + } + fAugmentations.removeAllItems(); + return fAugmentations; + } + + /** + * Get the handler to which we should send events. + */ + private XMLDocumentHandler handler() { + return JAXPValidatorComponent.this.getDocumentHandler(); + } + + /** + * Converts the {@link XNIException} received from a downstream + * component to a {@link SAXException}. + */ + private SAXException toSAXException( XNIException xe ) { + Exception e = xe.getException(); + if( e==null ) e = xe; + if( e instanceof SAXException ) return (SAXException)e; + return new SAXException(e); + } + + /** + * Creates a proper {@link QName} object from 3 parts. + *

+ * This method does the symbolization. + */ + private QName toQName( String uri, String localName, String qname ) { + String prefix = null; + int idx = qname.indexOf(':'); + if( idx>0 ) + prefix = symbolize(qname.substring(0,idx)); + + localName = symbolize(localName); + qname = symbolize(qname); + uri = symbolize(uri); + + // notify handlers + fQName.setValues(prefix, localName, qname, uri); + return fQName; + } + } + + /** + * Converts {@link XNI} events to {@link ContentHandler} events. + * + *

+ * Deriving from {@link DefaultXMLDocumentHandler} + * to reuse its default {@link org.apache.xerces.xni.XMLDocumentHandler} + * implementation. + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + */ + private static final class XNI2SAX extends DefaultXMLDocumentHandler { + + private ContentHandler fContentHandler; + + private String fVersion; + + /** Namespace context */ + protected NamespaceContext fNamespaceContext; + + /** + * For efficiency, we reuse one instance. + */ + private final AttributesProxy fAttributesProxy = new AttributesProxy(null); + + public void setContentHandler( ContentHandler handler ) { + this.fContentHandler = handler; + } + + public ContentHandler getContentHandler() { + return fContentHandler; + } + + + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException { + this.fVersion = version; + } + + public void startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException { + fNamespaceContext = namespaceContext; + fContentHandler.setDocumentLocator(new LocatorProxy(locator)); + try { + fContentHandler.startDocument(); + } catch (SAXException e) { + throw new XNIException(e); + } + } + + public void endDocument(Augmentations augs) throws XNIException { + try { + fContentHandler.endDocument(); + } catch (SAXException e) { + throw new XNIException(e); + } + } + + public void processingInstruction(String target, XMLString data, Augmentations augs) throws XNIException { + try { + fContentHandler.processingInstruction(target,data.toString()); + } catch (SAXException e) { + throw new XNIException(e); + } + } + + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { + try { + // start namespace prefix mappings + int count = fNamespaceContext.getDeclaredPrefixCount(); + if (count > 0) { + String prefix = null; + String uri = null; + for (int i = 0; i < count; i++) { + prefix = fNamespaceContext.getDeclaredPrefixAt(i); + uri = fNamespaceContext.getURI(prefix); + fContentHandler.startPrefixMapping(prefix, (uri == null)?"":uri); + } + } + + String uri = element.uri != null ? element.uri : ""; + String localpart = element.localpart; + fAttributesProxy.setAttributes(attributes); + fContentHandler.startElement(uri, localpart, element.rawname, fAttributesProxy); + } catch( SAXException e ) { + throw new XNIException(e); + } + } + + public void endElement(QName element, Augmentations augs) throws XNIException { + try { + String uri = element.uri != null ? element.uri : ""; + String localpart = element.localpart; + fContentHandler.endElement(uri, localpart, element.rawname); + + // send endPrefixMapping events + int count = fNamespaceContext.getDeclaredPrefixCount(); + if (count > 0) { + for (int i = 0; i < count; i++) { + fContentHandler.endPrefixMapping(fNamespaceContext.getDeclaredPrefixAt(i)); + } + } + } catch( SAXException e ) { + throw new XNIException(e); + } + } + + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { + startElement(element,attributes,augs); + endElement(element,augs); + } + + public void characters(XMLString text, Augmentations augs) throws XNIException { + try { + fContentHandler.characters(text.ch,text.offset,text.length); + } catch (SAXException e) { + throw new XNIException(e); + } + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + try { + fContentHandler.ignorableWhitespace(text.ch,text.offset,text.length); + } catch (SAXException e) { + throw new XNIException(e); + } + } + } + + private static final class DraconianErrorHandler implements ErrorHandler { + + /** + * Singleton instance. + */ + private static final DraconianErrorHandler ERROR_HANDLER_INSTANCE + = new DraconianErrorHandler(); + + private DraconianErrorHandler() {} + + /** Returns the one and only instance of this error handler. */ + public static DraconianErrorHandler getInstance() { + return ERROR_HANDLER_INSTANCE; + } + + /** Warning: Ignore. */ + public void warning(SAXParseException e) throws SAXException { + // noop + } + + /** Error: Throws back SAXParseException. */ + public void error(SAXParseException e) throws SAXException { + throw e; + } + + /** Fatal Error: Throws back SAXParseException. */ + public void fatalError(SAXParseException e) throws SAXException { + throw e; + } + + } // DraconianErrorHandler + + + /** + * Compares the given {@link Attributes} with {@link #fCurrentAttributes} + * and update the latter accordingly. + */ + private void updateAttributes( Attributes atts ) { + int len = atts.getLength(); + for( int i=0; ijavax.xml.parsers.SAXParserFactory. This is the platform + * default implementation for the platform. + * + * @author Rajiv Mordani + * @author Edwin Goei + * + * @version $Id$ + */ +public class SAXParserFactoryImpl extends SAXParserFactory { + + /** Feature identifier: namespaces. */ + private static final String NAMESPACES_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: validation. */ + private static final String VALIDATION_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: XInclude processing */ + private static final String XINCLUDE_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE; + + private Hashtable features; + private Schema grammar; + private boolean isXIncludeAware; + + /** + * State of the secure processing feature, initially false + */ + private boolean fSecureProcess = false; + + /** + * Creates a new instance of SAXParser using the currently + * configured factory parameters. + * @return javax.xml.parsers.SAXParser + */ + public SAXParser newSAXParser() + throws ParserConfigurationException { + + SAXParser saxParserImpl; + try { + saxParserImpl = new SAXParserImpl(this, features, fSecureProcess); + } + catch (SAXException se) { + // Translate to ParserConfigurationException + throw new ParserConfigurationException(se.getMessage()); + } + return saxParserImpl; + } + + /** + * Common code for translating exceptions + */ + private SAXParserImpl newSAXParserImpl() + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException { + + SAXParserImpl saxParserImpl; + try { + saxParserImpl = new SAXParserImpl(this, features); + } catch (SAXNotSupportedException e) { + throw e; + } catch (SAXNotRecognizedException e) { + throw e; + } catch (SAXException se) { + throw new ParserConfigurationException(se.getMessage()); + } + return saxParserImpl; + } + + /** + * Sets the particular feature in the underlying implementation of + * org.xml.sax.XMLReader. + */ + public void setFeature(String name, boolean value) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(); + } + // If this is the secure processing feature, save it then return. + if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { + fSecureProcess = value; + return; + } + // Keep built-in settings in synch with the feature values. + else if (name.equals(NAMESPACES_FEATURE)) { + setNamespaceAware(value); + return; + } + else if (name.equals(VALIDATION_FEATURE)) { + setValidating(value); + return; + } + else if (name.equals(XINCLUDE_FEATURE)) { + setXIncludeAware(value); + return; + } + + // XXX This is ugly. We have to collect the features and then + // later create an XMLReader to verify the features. + if (features == null) { + features = new Hashtable(); + } + features.put(name, value ? Boolean.TRUE : Boolean.FALSE); + + // Test the feature by possibly throwing SAX exceptions + try { + newSAXParserImpl(); + } + catch (SAXNotSupportedException e) { + features.remove(name); + throw e; + } + catch (SAXNotRecognizedException e) { + features.remove(name); + throw e; + } + } + + /** + * returns the particular property requested for in the underlying + * implementation of org.xml.sax.XMLReader. + */ + public boolean getFeature(String name) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(); + } + if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { + return fSecureProcess; + } + else if (name.equals(NAMESPACES_FEATURE)) { + return isNamespaceAware(); + } + else if (name.equals(VALIDATION_FEATURE)) { + return isValidating(); + } + else if (name.equals(XINCLUDE_FEATURE)) { + return isXIncludeAware(); + } + // Check for valid name by creating a dummy XMLReader to get + // feature value + return newSAXParserImpl().getXMLReader().getFeature(name); + } + + public Schema getSchema() { + return grammar; + } + + public void setSchema(Schema grammar) { + this.grammar = grammar; + } + + public boolean isXIncludeAware() { + return this.isXIncludeAware; + } + + public void setXIncludeAware(boolean state) { + this.isXIncludeAware = state; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/SAXParserImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/SAXParserImpl.java new file mode 100644 index 0000000..3218b2a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/SAXParserImpl.java @@ -0,0 +1,655 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +import javax.xml.XMLConstants; +import javax.xml.validation.Schema; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.jaxp.validation.XSGrammarPoolContainer; +import org.apache.xerces.util.SAXMessageFormatter; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.PSVIProvider; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.HandlerBase; +import org.xml.sax.InputSource; +import org.xml.sax.Parser; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +/** + * This is the implementation specific class for the + * javax.xml.parsers.SAXParser. + * + * @author Rajiv Mordani + * @author Edwin Goei + * + * @version $Id$ + */ +public class SAXParserImpl extends javax.xml.parsers.SAXParser + implements JAXPConstants, PSVIProvider { + + /** Feature identifier: namespaces. */ + private static final String NAMESPACES_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: namespace prefixes. */ + private static final String NAMESPACE_PREFIXES_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE; + + /** Feature identifier: validation. */ + private static final String VALIDATION_FEATURE = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: XML Schema validation */ + private static final String XMLSCHEMA_VALIDATION_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** Feature identifier: XInclude processing */ + private static final String XINCLUDE_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE; + + /** Property identifier: security manager. */ + private static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + private final JAXPSAXParser xmlReader; + private String schemaLanguage = null; // null means DTD + private final Schema grammar; + + private final XMLComponent fSchemaValidator; + private final XMLComponentManager fSchemaValidatorComponentManager; + private final ValidationManager fSchemaValidationManager; + private final UnparsedEntityHandler fUnparsedEntityHandler; + + /** Initial ErrorHandler */ + private final ErrorHandler fInitErrorHandler; + + /** Initial EntityResolver */ + private final EntityResolver fInitEntityResolver; + + /** + * Create a SAX parser with the associated features + * @param features Hashtable of SAX features, may be null + */ + SAXParserImpl(SAXParserFactoryImpl spf, Hashtable features) + throws SAXException { + this(spf, features, false); + } + + /** + * Create a SAX parser with the associated features + * @param features Hashtable of SAX features, may be null + */ + SAXParserImpl(SAXParserFactoryImpl spf, Hashtable features, boolean secureProcessing) + throws SAXException + { + // Instantiate a SAXParser directly and not through SAX so that we use the right ClassLoader + xmlReader = new JAXPSAXParser(this); + + // JAXP "namespaceAware" == SAX Namespaces feature + // Note: there is a compatibility problem here with default values: + // JAXP default is false while SAX 2 default is true! + xmlReader.setFeature0(NAMESPACES_FEATURE, spf.isNamespaceAware()); + + // SAX "namespaces" and "namespace-prefixes" features should not + // both be false. We make them opposite for backward compatibility + // since JAXP 1.0 apps may want to receive xmlns* attributes. + xmlReader.setFeature0(NAMESPACE_PREFIXES_FEATURE, !spf.isNamespaceAware()); + + // Avoid setting the XInclude processing feature if the value is false. + // This will keep the configuration from throwing an exception if it + // does not support XInclude. + if (spf.isXIncludeAware()) { + xmlReader.setFeature0(XINCLUDE_FEATURE, true); + } + + // If the secure processing feature is on set a security manager. + if (secureProcessing) { + xmlReader.setProperty0(SECURITY_MANAGER, new SecurityManager()); + } + + // Set application's features, followed by validation features. + setFeatures(features); + + // If validating, provide a default ErrorHandler that prints + // validation errors with a warning telling the user to set an + // ErrorHandler. + if (spf.isValidating()) { + fInitErrorHandler = new DefaultValidationErrorHandler(); + xmlReader.setErrorHandler(fInitErrorHandler); + } + else { + fInitErrorHandler = xmlReader.getErrorHandler(); + } + xmlReader.setFeature0(VALIDATION_FEATURE, spf.isValidating()); + + // Get the Schema object from the factory + this.grammar = spf.getSchema(); + if (grammar != null) { + XMLParserConfiguration config = xmlReader.getXMLParserConfiguration(); + XMLComponent validatorComponent = null; + /** For Xerces grammars, use built-in schema validator. **/ + if (grammar instanceof XSGrammarPoolContainer) { + validatorComponent = new XMLSchemaValidator(); + fSchemaValidationManager = new ValidationManager(); + fUnparsedEntityHandler = new UnparsedEntityHandler(fSchemaValidationManager); + config.setDTDHandler(fUnparsedEntityHandler); + fUnparsedEntityHandler.setDTDHandler(xmlReader); + xmlReader.setDTDSource(fUnparsedEntityHandler); + fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(config, + (XSGrammarPoolContainer) grammar, fSchemaValidationManager); + } + /** For third party grammars, use the JAXP validator component. **/ + else { + validatorComponent = new JAXPValidatorComponent(grammar.newValidatorHandler()); + fSchemaValidationManager = null; + fUnparsedEntityHandler = null; + fSchemaValidatorComponentManager = config; + } + config.addRecognizedFeatures(validatorComponent.getRecognizedFeatures()); + config.addRecognizedProperties(validatorComponent.getRecognizedProperties()); + config.setDocumentHandler((XMLDocumentHandler) validatorComponent); + ((XMLDocumentSource)validatorComponent).setDocumentHandler(xmlReader); + xmlReader.setDocumentSource((XMLDocumentSource) validatorComponent); + fSchemaValidator = validatorComponent; + } + else { + fSchemaValidationManager = null; + fUnparsedEntityHandler = null; + fSchemaValidatorComponentManager = null; + fSchemaValidator = null; + } + + // Initial EntityResolver + fInitEntityResolver = xmlReader.getEntityResolver(); + } + + /** + * Set any features of our XMLReader based on any features set on the + * SAXParserFactory. + * + * XXX Does not handle possible conflicts between SAX feature names and + * JAXP specific feature names, eg. SAXParserFactory.isValidating() + */ + private void setFeatures(Hashtable features) + throws SAXNotSupportedException, SAXNotRecognizedException { + if (features != null) { + Iterator entries = features.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + String feature = (String) entry.getKey(); + boolean value = ((Boolean) entry.getValue()).booleanValue(); + xmlReader.setFeature0(feature, value); + } + } + } + + public Parser getParser() throws SAXException { + // Xerces2 AbstractSAXParser implements SAX1 Parser + // assert(xmlReader instanceof Parser); + return (Parser) xmlReader; + } + + /** + * Returns the XMLReader that is encapsulated by the implementation of + * this class. + */ + public XMLReader getXMLReader() { + return xmlReader; + } + + public boolean isNamespaceAware() { + try { + return xmlReader.getFeature(NAMESPACES_FEATURE); + } + catch (SAXException x) { + throw new IllegalStateException(x.getMessage()); + } + } + + public boolean isValidating() { + try { + return xmlReader.getFeature(VALIDATION_FEATURE); + } + catch (SAXException x) { + throw new IllegalStateException(x.getMessage()); + } + } + + /** + * Gets the XInclude processing mode for this parser + * @return the state of XInclude processing mode + */ + public boolean isXIncludeAware() { + try { + return xmlReader.getFeature(XINCLUDE_FEATURE); + } + catch (SAXException exc) { + return false; + } + } + + /** + * Sets the particular property in the underlying implementation of + * org.xml.sax.XMLReader. + */ + public void setProperty(String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + xmlReader.setProperty(name, value); + } + + /** + * returns the particular property requested for in the underlying + * implementation of org.xml.sax.XMLReader. + */ + public Object getProperty(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + return xmlReader.getProperty(name); + } + + public void parse(InputSource is, DefaultHandler dh) + throws SAXException, IOException { + if (is == null) { + throw new IllegalArgumentException(); + } + if (dh != null) { + xmlReader.setContentHandler(dh); + xmlReader.setEntityResolver(dh); + xmlReader.setErrorHandler(dh); + xmlReader.setDTDHandler(dh); + xmlReader.setDocumentHandler(null); + } + xmlReader.parse(is); + } + + public void parse(InputSource is, HandlerBase hb) + throws SAXException, IOException { + if (is == null) { + throw new IllegalArgumentException(); + } + if (hb != null) { + xmlReader.setDocumentHandler(hb); + xmlReader.setEntityResolver(hb); + xmlReader.setErrorHandler(hb); + xmlReader.setDTDHandler(hb); + xmlReader.setContentHandler(null); + } + xmlReader.parse(is); + } + + public Schema getSchema() { + return grammar; + } + + public void reset() { + try { + /** Restore initial values of features and properties. **/ + xmlReader.restoreInitState(); + } + catch (SAXException exc) { + // This should never happen. We only store recognized + // features and properties in the hash maps. For now + // just ignore it. + } + /** Restore various handlers. **/ + xmlReader.setContentHandler(null); + xmlReader.setDTDHandler(null); + if (xmlReader.getErrorHandler() != fInitErrorHandler) { + xmlReader.setErrorHandler(fInitErrorHandler); + } + if (xmlReader.getEntityResolver() != fInitEntityResolver) { + xmlReader.setEntityResolver(fInitEntityResolver); + } + } + + /* + * PSVIProvider methods + */ + + public ElementPSVI getElementPSVI() { + return ((PSVIProvider)xmlReader).getElementPSVI(); + } + + public AttributePSVI getAttributePSVI(int index) { + return ((PSVIProvider)xmlReader).getAttributePSVI(index); + } + + public AttributePSVI getAttributePSVIByName(String uri, String localname) { + return ((PSVIProvider)xmlReader).getAttributePSVIByName(uri, localname); + } + + /** + * Extension of SAXParser. This class tracks changes to + * features and properties to allow the parser to be reset to + * its initial state. + */ + public static class JAXPSAXParser extends org.apache.xerces.parsers.SAXParser { + + private final HashMap fInitFeatures = new HashMap(); + private final HashMap fInitProperties = new HashMap(); + private final SAXParserImpl fSAXParser; + + public JAXPSAXParser() { + this(null); + } + + JAXPSAXParser(SAXParserImpl saxParser) { + super(); + fSAXParser = saxParser; + } + + /** + * Override SAXParser's setFeature method to track the initial state + * of features. This keeps us from affecting the performance of the + * SAXParser when it is created with XMLReaderFactory. + */ + public synchronized void setFeature(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + // TODO: Add localized error message. + throw new NullPointerException(); + } + if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { + try { + setProperty(SECURITY_MANAGER, value ? new SecurityManager() : null); + } + catch (SAXNotRecognizedException exc) { + // If the property is not supported + // re-throw the exception if the value is true. + if (value) { + throw exc; + } + } + catch (SAXNotSupportedException exc) { + // If the property is not supported + // re-throw the exception if the value is true. + if (value) { + throw exc; + } + } + return; + } + if (!fInitFeatures.containsKey(name)) { + boolean current = super.getFeature(name); + fInitFeatures.put(name, current ? Boolean.TRUE : Boolean.FALSE); + } + /** Forward feature to the schema validator if there is one. **/ + if (fSAXParser != null && fSAXParser.fSchemaValidator != null) { + setSchemaValidatorFeature(name, value); + } + super.setFeature(name, value); + } + + public synchronized boolean getFeature(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + // TODO: Add localized error message. + throw new NullPointerException(); + } + if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { + try { + return (super.getProperty(SECURITY_MANAGER) != null); + } + // If the property is not supported the value must be false. + catch (SAXException exc) { + return false; + } + } + return super.getFeature(name); + } + + /** + * Override SAXParser's setProperty method to track the initial state + * of properties. This keeps us from affecting the performance of the + * SAXParser when it is created with XMLReaderFactory. + */ + public synchronized void setProperty(String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + // TODO: Add localized error message. + throw new NullPointerException(); + } + if (fSAXParser != null) { + // JAXP 1.2 support + if (JAXP_SCHEMA_LANGUAGE.equals(name)) { + // The spec says if a schema is given via SAXParserFactory + // the JAXP 1.2 properties shouldn't be allowed. + if (fSAXParser.grammar != null) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), "schema-already-specified", new Object[] {name})); + } + if ( W3C_XML_SCHEMA.equals(value) ) { + //None of the properties will take effect till the setValidating(true) has been called + if( fSAXParser.isValidating() ) { + fSAXParser.schemaLanguage = W3C_XML_SCHEMA; + setFeature(XMLSCHEMA_VALIDATION_FEATURE, true); + // this will allow the parser not to emit DTD-related + // errors, as the spec demands + if (!fInitProperties.containsKey(JAXP_SCHEMA_LANGUAGE)) { + fInitProperties.put(JAXP_SCHEMA_LANGUAGE, super.getProperty(JAXP_SCHEMA_LANGUAGE)); + } + super.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); + } + + } + else if (value == null) { + fSAXParser.schemaLanguage = null; + setFeature(XMLSCHEMA_VALIDATION_FEATURE, false); + } + else { + // REVISIT: It would be nice if we could format this message + // using a user specified locale as we do in the underlying + // XMLReader -- mrglavas + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), "schema-not-supported", null)); + } + return; + } + else if (JAXP_SCHEMA_SOURCE.equals(name)) { + // The spec says if a schema is given via SAXParserFactory + // the JAXP 1.2 properties shouldn't be allowed. + if (fSAXParser.grammar != null) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), "schema-already-specified", new Object[] {name})); + } + String val = (String)getProperty(JAXP_SCHEMA_LANGUAGE); + if ( val != null && W3C_XML_SCHEMA.equals(val) ) { + if (!fInitProperties.containsKey(JAXP_SCHEMA_SOURCE)) { + fInitProperties.put(JAXP_SCHEMA_SOURCE, super.getProperty(JAXP_SCHEMA_SOURCE)); + } + super.setProperty(name, value); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "jaxp-order-not-supported", + new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE})); + } + return; + } + } + if (!fInitProperties.containsKey(name)) { + fInitProperties.put(name, super.getProperty(name)); + } + /** Forward property to the schema validator if there is one. **/ + if (fSAXParser != null && fSAXParser.fSchemaValidator != null) { + setSchemaValidatorProperty(name, value); + } + super.setProperty(name, value); + } + + public synchronized Object getProperty(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + // TODO: Add localized error message. + throw new NullPointerException(); + } + if (fSAXParser != null && JAXP_SCHEMA_LANGUAGE.equals(name)) { + // JAXP 1.2 support + return fSAXParser.schemaLanguage; + } + return super.getProperty(name); + } + + synchronized void restoreInitState() + throws SAXNotRecognizedException, SAXNotSupportedException { + Iterator iter; + if (!fInitFeatures.isEmpty()) { + iter = fInitFeatures.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String name = (String) entry.getKey(); + boolean value = ((Boolean) entry.getValue()).booleanValue(); + super.setFeature(name, value); + } + fInitFeatures.clear(); + } + if (!fInitProperties.isEmpty()) { + iter = fInitProperties.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String name = (String) entry.getKey(); + Object value = entry.getValue(); + super.setProperty(name, value); + } + fInitProperties.clear(); + } + } + + public void parse(InputSource inputSource) + throws SAXException, IOException { + if (fSAXParser != null && fSAXParser.fSchemaValidator != null) { + if (fSAXParser.fSchemaValidationManager != null) { + fSAXParser.fSchemaValidationManager.reset(); + fSAXParser.fUnparsedEntityHandler.reset(); + } + resetSchemaValidator(); + } + super.parse(inputSource); + } + + public void parse(String systemId) + throws SAXException, IOException { + if (fSAXParser != null && fSAXParser.fSchemaValidator != null) { + if (fSAXParser.fSchemaValidationManager != null) { + fSAXParser.fSchemaValidationManager.reset(); + fSAXParser.fUnparsedEntityHandler.reset(); + } + resetSchemaValidator(); + } + super.parse(systemId); + } + + XMLParserConfiguration getXMLParserConfiguration() { + return fConfiguration; + } + + void setFeature0(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException { + super.setFeature(name, value); + } + + boolean getFeature0(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + return super.getFeature(name); + } + + void setProperty0(String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + super.setProperty(name, value); + } + + Object getProperty0(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + return super.getProperty(name); + } + + private void setSchemaValidatorFeature(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException { + try { + fSAXParser.fSchemaValidator.setFeature(name, value); + } + // This should never be thrown from the schema validator. + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + } + + private void setSchemaValidatorProperty(String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + try { + fSAXParser.fSchemaValidator.setProperty(name, value); + } + // This should never be thrown from the schema validator. + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + } + + private void resetSchemaValidator() throws SAXException { + try { + fSAXParser.fSchemaValidator.reset(fSAXParser.fSchemaValidatorComponentManager); + } + // This should never be thrown from the schema validator. + catch (XMLConfigurationException e) { + throw new SAXException(e); + } + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/SchemaValidatorConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/SchemaValidatorConfiguration.java new file mode 100644 index 0000000..c90379d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/SchemaValidatorConfiguration.java @@ -0,0 +1,152 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.jaxp.validation.XSGrammarPoolContainer; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; + +/** + *

Parser configuration for Xerces' XMLSchemaValidator.

+ * + * @version $Id$ + */ +final class SchemaValidatorConfiguration implements XMLComponentManager { + + // feature identifiers + + /** Feature identifier: schema validation. */ + private static final String SCHEMA_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** Feature identifier: validation. */ + private static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: use grammar pool only. */ + private static final String USE_GRAMMAR_POOL_ONLY = + Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + + /** Feature identifier: parser settings. */ + private static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + // property identifiers + + /** Property identifier: error reporter. */ + private static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: validation manager. */ + private static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: grammar pool. */ + private static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + // + // Data + // + + /** Parent component manager. **/ + private final XMLComponentManager fParentComponentManager; + + /** The Schema's grammar pool. **/ + private final XMLGrammarPool fGrammarPool; + + /** + * Tracks whether the validator should use components from + * the grammar pool to the exclusion of all others. + */ + private final boolean fUseGrammarPoolOnly; + + /** Validation manager. */ + private final ValidationManager fValidationManager; + + public SchemaValidatorConfiguration(XMLComponentManager parentManager, + XSGrammarPoolContainer grammarContainer, ValidationManager validationManager) { + fParentComponentManager = parentManager; + fGrammarPool = grammarContainer.getGrammarPool(); + fUseGrammarPoolOnly = grammarContainer.isFullyComposed(); + fValidationManager = validationManager; + // add schema message formatter to error reporter + try { + XMLErrorReporter errorReporter = (XMLErrorReporter) fParentComponentManager.getProperty(ERROR_REPORTER); + if (errorReporter != null) { + errorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter()); + } + } + // Ignore exception. + catch (XMLConfigurationException exc) {} + } + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * @return true if the feature is supported + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + if (PARSER_SETTINGS.equals(featureId)) { + return fParentComponentManager.getFeature(featureId); + } + else if (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId)) { + return true; + } + else if (USE_GRAMMAR_POOL_ONLY.equals(featureId)) { + return fUseGrammarPoolOnly; + } + return fParentComponentManager.getFeature(featureId); + } + + /** + * Returns the value of a property. + * + * @param propertyId The property identifier. + * @return the value of the property + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException { + if (XMLGRAMMAR_POOL.equals(propertyId)) { + return fGrammarPool; + } + else if (VALIDATION_MANAGER.equals(propertyId)) { + return fValidationManager; + } + return fParentComponentManager.getProperty(propertyId); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/TeeXMLDocumentFilterImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/TeeXMLDocumentFilterImpl.java new file mode 100644 index 0000000..9ae79f3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/TeeXMLDocumentFilterImpl.java @@ -0,0 +1,174 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp; + +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDocumentFilter; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + *

XMLDocumentHandler which forks the pipeline to two other components.

+ * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * @version $Id$ + */ +class TeeXMLDocumentFilterImpl implements XMLDocumentFilter { + + /** + * The next component in the pipeline who receives the event. + * This component receives events after the "side" handler + * receives them. + */ + private XMLDocumentHandler next; + + /** + * The component who intercepts events. + */ + private XMLDocumentHandler side; + + /** + * The source of the event. + */ + private XMLDocumentSource source; + + public XMLDocumentHandler getSide() { + return side; + } + + public void setSide(XMLDocumentHandler side) { + this.side = side; + } + + public XMLDocumentSource getDocumentSource() { + return source; + } + + public void setDocumentSource(XMLDocumentSource source) { + this.source = source; + } + + public XMLDocumentHandler getDocumentHandler() { + return next; + } + + public void setDocumentHandler(XMLDocumentHandler handler) { + next = handler; + } + + // + // + // XMLDocumentHandler implementation + // + // + + public void characters(XMLString text, Augmentations augs) throws XNIException { + side.characters(text, augs); + next.characters(text, augs); + } + + public void comment(XMLString text, Augmentations augs) throws XNIException { + side.comment(text, augs); + next.comment(text, augs); + } + + public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) + throws XNIException { + side.doctypeDecl(rootElement, publicId, systemId, augs); + next.doctypeDecl(rootElement, publicId, systemId, augs); + } + + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { + side.emptyElement(element, attributes, augs); + next.emptyElement(element, attributes, augs); + } + + public void endCDATA(Augmentations augs) throws XNIException { + side.endCDATA(augs); + next.endCDATA(augs); + } + + public void endDocument(Augmentations augs) throws XNIException { + side.endDocument(augs); + next.endDocument(augs); + } + + public void endElement(QName element, Augmentations augs) throws XNIException { + side.endElement(element, augs); + next.endElement(element, augs); + } + + public void endGeneralEntity(String name, Augmentations augs) throws XNIException { + side.endGeneralEntity(name, augs); + next.endGeneralEntity(name, augs); + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + side.ignorableWhitespace(text, augs); + next.ignorableWhitespace(text, augs); + } + + public void processingInstruction(String target, XMLString data, Augmentations augs) throws XNIException { + side.processingInstruction(target, data, augs); + next.processingInstruction(target, data, augs); + } + + public void startCDATA(Augmentations augs) throws XNIException { + side.startCDATA(augs); + next.startCDATA(augs); + } + + public void startDocument( + XMLLocator locator, + String encoding, + NamespaceContext namespaceContext, + Augmentations augs) + throws XNIException { + side.startDocument(locator, encoding, namespaceContext, augs); + next.startDocument(locator, encoding, namespaceContext, augs); + } + + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { + side.startElement(element, attributes, augs); + next.startElement(element, attributes, augs); + } + + public void startGeneralEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs) + throws XNIException { + side.startGeneralEntity(name, identifier, encoding, augs); + next.startGeneralEntity(name, identifier, encoding, augs); + } + + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { + side.textDecl(version, encoding, augs); + next.textDecl(version, encoding, augs); + } + + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException { + side.xmlDecl(version, encoding, standalone, augs); + next.xmlDecl(version, encoding, standalone, augs); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/UnparsedEntityHandler.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/UnparsedEntityHandler.java new file mode 100644 index 0000000..0f0c845 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/UnparsedEntityHandler.java @@ -0,0 +1,259 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp; + +import java.util.HashMap; + +import org.apache.xerces.impl.validation.EntityState; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDTDFilter; +import org.apache.xerces.xni.parser.XMLDTDSource; + +/** + *

This filter records which unparsed entities have been + * declared in the DTD and provides this information to a ValidationManager. + * Events are forwarded to the registered XMLDTDHandler without modification.

+ * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class UnparsedEntityHandler implements XMLDTDFilter, EntityState { + + /** DTD source and handler. **/ + private XMLDTDSource fDTDSource; + private XMLDTDHandler fDTDHandler; + + /** Validation manager. */ + private final ValidationManager fValidationManager; + + /** Map for tracking unparsed entities. */ + private HashMap fUnparsedEntities = null; + + UnparsedEntityHandler(ValidationManager manager) { + fValidationManager = manager; + } + + /* + * XMLDTDHandler methods + */ + + public void startDTD(XMLLocator locator, Augmentations augmentations) + throws XNIException { + fValidationManager.setEntityState(this); + if (fDTDHandler != null) { + fDTDHandler.startDTD(locator, augmentations); + } + } + + public void startParameterEntity(String name, + XMLResourceIdentifier identifier, String encoding, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startParameterEntity(name, identifier, encoding, augmentations); + } + } + + public void textDecl(String version, String encoding, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.textDecl(version, encoding, augmentations); + } + } + + public void endParameterEntity(String name, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endParameterEntity(name, augmentations); + } + } + + public void startExternalSubset(XMLResourceIdentifier identifier, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startExternalSubset(identifier, augmentations); + } + } + + public void endExternalSubset(Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endExternalSubset(augmentations); + } + } + + public void comment(XMLString text, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.comment(text, augmentations); + } + } + + public void processingInstruction(String target, XMLString data, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.processingInstruction(target, data, augmentations); + } + } + + public void elementDecl(String name, String contentModel, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.elementDecl(name, contentModel, augmentations); + } + } + + public void startAttlist(String elementName, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startAttlist(elementName, augmentations); + } + } + + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, String defaultType, + XMLString defaultValue, XMLString nonNormalizedDefaultValue, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.attributeDecl(elementName, attributeName, + type, enumeration, defaultType, + defaultValue, nonNormalizedDefaultValue, + augmentations); + } + } + + public void endAttlist(Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endAttlist(augmentations); + } + } + + public void internalEntityDecl(String name, XMLString text, + XMLString nonNormalizedText, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.internalEntityDecl(name, text, + nonNormalizedText, augmentations); + } + } + + public void externalEntityDecl(String name, + XMLResourceIdentifier identifier, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.externalEntityDecl(name, identifier, augmentations); + } + } + + public void unparsedEntityDecl(String name, + XMLResourceIdentifier identifier, String notation, + Augmentations augmentations) throws XNIException { + if (fUnparsedEntities == null) { + fUnparsedEntities = new HashMap(); + } + fUnparsedEntities.put(name, name); + if (fDTDHandler != null) { + fDTDHandler.unparsedEntityDecl(name, identifier, notation, augmentations); + } + } + + public void notationDecl(String name, XMLResourceIdentifier identifier, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.notationDecl(name, identifier, augmentations); + } + } + + public void startConditional(short type, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startConditional(type, augmentations); + } + } + + public void ignoredCharacters(XMLString text, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.ignoredCharacters(text, augmentations); + } + + } + + public void endConditional(Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endConditional(augmentations); + } + } + + public void endDTD(Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endDTD(augmentations); + } + } + + public void setDTDSource(XMLDTDSource source) { + fDTDSource = source; + } + + public XMLDTDSource getDTDSource() { + return fDTDSource; + } + + /* + * XMLDTDSource methods + */ + + public void setDTDHandler(XMLDTDHandler handler) { + fDTDHandler = handler; + } + + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } + + /* + * EntityState methods + */ + + public boolean isEntityDeclared(String name) { + return false; + } + + public boolean isEntityUnparsed(String name) { + if (fUnparsedEntities != null) { + return fUnparsedEntities.containsKey(name); + } + return false; + } + + /* + * Other methods + */ + + public void reset() { + if (fUnparsedEntities != null && !fUnparsedEntities.isEmpty()) { + // should only clear this if the last document contained unparsed entities + fUnparsedEntities.clear(); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/DatatypeFactoryImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/DatatypeFactoryImpl.java new file mode 100644 index 0000000..0e3c768 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/DatatypeFactoryImpl.java @@ -0,0 +1,392 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.datatype; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.GregorianCalendar; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; + +/** + *

Factory that creates new javax.xml.datatype Objects that map XML to/from Java Objects.

+ * + *

{@link #newInstance()} is used to create a new DatatypeFactory. + * The following implementation resolution mechanisms are used in the following order:

+ *
    + *
  1. + * If the system property specified by {@link #DATATYPEFACTORY_PROPERTY}, "javax.xml.datatype.DatatypeFactory", + * exists, a class with the name of the property's value is instantiated. + * Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}. + *
  2. + *
  3. + * If the file ${JAVA_HOME}/lib/jaxp.properties exists, it is loaded in a {@link java.util.Properties} Object. + * The Properties Object is then queried for the property as documented in the prior step + * and processed as documented in the prior step. + *
  4. + *
  5. + * The services resolution mechanism is used, e.g. META-INF/services/java.xml.datatype.DatatypeFactory. + * Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}. + *
  6. + *
  7. + * The final mechanism is to attempt to instantiate the Class specified by + * {@link #DATATYPEFACTORY_IMPLEMENTATION_CLASS}, "javax.xml.datatype.DatatypeFactoryImpl". + * Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}. + *
  8. + *
+ * + * @author Joseph Fialli + * @author Jeff Suttor + * @version $Id$ + */ +public class DatatypeFactoryImpl extends DatatypeFactory { + + /** + *

Public constructor is empty..

+ * + *

Use {@link DatatypeFactory#newInstance()} to create a DatatypeFactory.

+ */ + public DatatypeFactoryImpl() {} + + /** + *

Obtain a new instance of a Duration + * specifying the Duration as its string representation, "PnYnMnDTnHnMnS", + * as defined in XML Schema 1.0 section 3.2.6.1.

+ * + *

XML Schema Part 2: Datatypes, 3.2.6 duration, defines duration as:

+ *
+ * duration represents a duration of time. + * The value space of duration is a six-dimensional space where the coordinates designate the + * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively. + * These components are ordered in their significance by their order of appearance i.e. as + * year, month, day, hour, minute, and second. + *
+ *

All six values are set and availabe from the created {@link Duration}

+ * + *

The XML Schema specification states that values can be of an arbitrary size. + * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. + * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits + * if implementation capacities are exceeded.

+ * + * @param lexicalRepresentation String representation of a Duration. + * + * @return New Duration created from parsing the lexicalRepresentation. + * + * @throws IllegalArgumentException If lexicalRepresentation is not a valid representation of a Duration. + * @throws UnsupportedOperationException If implementation cannot support requested values. + * @throws NullPointerException if lexicalRepresentation is null. + */ + public Duration newDuration(final String lexicalRepresentation) { + + return new DurationImpl(lexicalRepresentation); + } + + /** + *

Obtain a new instance of a Duration + * specifying the Duration as milliseconds.

+ * + *

XML Schema Part 2: Datatypes, 3.2.6 duration, defines duration as:

+ *
+ * duration represents a duration of time. + * The value space of duration is a six-dimensional space where the coordinates designate the + * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively. + * These components are ordered in their significance by their order of appearance i.e. as + * year, month, day, hour, minute, and second. + *
+ *

All six values are set by computing their values from the specified milliseconds + * and are availabe using the get methods of the created {@link Duration}. + * The values conform to and are defined by:

+ * + * + *

The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., + * {@link java.util.Calendar#YEAR} = 1970, + * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, + * {@link java.util.Calendar#DATE} = 1, etc. + * This is important as there are variations in the Gregorian Calendar, + * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} + * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced.

+ * + * @param durationInMilliseconds Duration in milliseconds to create. + * + * @return New Duration representing durationInMilliseconds. + */ + public Duration newDuration(final long durationInMilliseconds) { + + return new DurationImpl(durationInMilliseconds); + } + + /** + *

Obtain a new instance of a Duration + * specifying the Duration as isPositive, years, months, days, hours, minutes, seconds.

+ * + *

The XML Schema specification states that values can be of an arbitrary size. + * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. + * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits + * if implementation capacities are exceeded.

+ * + * @param isPositive Set to false to create a negative duration. When the length + * of the duration is zero, this parameter will be ignored. + * @param years of this Duration + * @param months of this Duration + * @param days of this Duration + * @param hours of this Duration + * @param minutes of this Duration + * @param seconds of this Duration + * + * @return New Duration created from the specified values. + * + * @throws IllegalArgumentException If values are not a valid representation of a Duration. + * @throws UnsupportedOperationException If implementation cannot support requested values. + * @throws NullPointerException If any values are null. + * + * @see #newDuration(boolean isPositive, BigInteger years, BigInteger months, BigInteger days, + * BigInteger hours, BigInteger minutes, BigDecimal seconds) + */ + public Duration newDuration( + final boolean isPositive, + final BigInteger years, + final BigInteger months, + final BigInteger days, + final BigInteger hours, + final BigInteger minutes, + final BigDecimal seconds) { + + return new DurationImpl( + isPositive, + years, + months, + days, + hours, + minutes, + seconds + ); + } + + /** + *

Create a new instance of an XMLGregorianCalendar.

+ * + *

All date/time datatype fields set to {@link DatatypeConstants#FIELD_UNDEFINED} or null.

+ * + * @return New XMLGregorianCalendar with all date/time datatype fields set to + * {@link DatatypeConstants#FIELD_UNDEFINED} or null. + */ + public XMLGregorianCalendar newXMLGregorianCalendar() { + + return new XMLGregorianCalendarImpl(); + } + + /** + *

Create a new XMLGregorianCalendar by parsing the String as a lexical representation.

+ * + *

Parsing the lexical string representation is defined in + * XML Schema 1.0 Part 2, Section 3.2.[7-14].1, + * Lexical Representation.

+ * + *

The string representation may not have any leading and trailing whitespaces.

+ * + *

The parsing is done field by field so that + * the following holds for any lexically correct String x:

+ *
+     * newXMLGregorianCalendar(x).toXMLFormat().equals(x)
+     * 
+ *

Except for the noted lexical/canonical representation mismatches + * listed in + * XML Schema 1.0 errata, Section 3.2.7.2.

+ * + * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes. + * + * @return XMLGregorianCalendar created from the lexicalRepresentation. + * + * @throws IllegalArgumentException If the lexicalRepresentation is not a valid XMLGregorianCalendar. + * @throws NullPointerException If lexicalRepresentation is null. + */ + public XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation) { + + return new XMLGregorianCalendarImpl(lexicalRepresentation); + } + + /** + *

Create an XMLGregorianCalendar from a {@link GregorianCalendar}.

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * Field by Field Conversion from + * {@link GregorianCalendar} to an {@link XMLGregorianCalendar} + *
java.util.GregorianCalendar fieldjavax.xml.datatype.XMLGregorianCalendar field
ERA == GregorianCalendar.BC ? -YEAR : YEAR{@link XMLGregorianCalendar#setYear(int year)}
MONTH + 1{@link XMLGregorianCalendar#setMonth(int month)}
DAY_OF_MONTH{@link XMLGregorianCalendar#setDay(int day)}
HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}
+ * (ZONE_OFFSET + DST_OFFSET) / (60*1000)
+ * (in minutes) + *
{@link XMLGregorianCalendar#setTimezone(int offset)}* + *
+ *

*conversion loss of information. It is not possible to represent + * a java.util.GregorianCalendar daylight savings timezone id in the + * XML Schema 1.0 date/time datatype representation.

+ * + *

To compute the return value's TimeZone field, + *

    + *
  • when this.getTimezone() != FIELD_UNDEFINED, + * create a java.util.TimeZone with a custom timezone id + * using the this.getTimezone().
  • + *
  • else use the GregorianCalendar default timezone value + * for the host is defined as specified by + * java.util.TimeZone.getDefault().
  • + * + * @param cal java.util.GregorianCalendar used to create XMLGregorianCalendar + * + * @return XMLGregorianCalendar created from java.util.GregorianCalendar + * + * @throws NullPointerException If cal is null. + */ + public XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal) { + + return new XMLGregorianCalendarImpl(cal); + } + + /** + *

    Constructor of value spaces that a + * java.util.GregorianCalendar instance would need to convert to an + * XMLGregorianCalendar instance.

    + * + *

    XMLGregorianCalendar eon and + * fractionalSecond are set to null

    + * + *

    A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field isnot set.

    + * + * @param year of XMLGregorianCalendar to be created. + * @param month of XMLGregorianCalendar to be created. + * @param day of XMLGregorianCalendar to be created. + * @param hour of XMLGregorianCalendar to be created. + * @param minute of XMLGregorianCalendar to be created. + * @param second of XMLGregorianCalendar to be created. + * @param millisecond of XMLGregorianCalendar to be created. + * @param timezone of XMLGregorianCalendar to be created. + * + * @return XMLGregorianCalendar created from specified values. + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalid XMLGregorianCalendar instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendar( + final int year, + final int month, + final int day, + final int hour, + final int minute, + final int second, + final int millisecond, + final int timezone) { + return XMLGregorianCalendarImpl.createDateTime( + year, + month, + day, + hour, + minute, + second, + millisecond, + timezone); + } + + /** + *

    Constructor allowing for complete value spaces allowed by + * W3C XML Schema 1.0 recommendation for xsd:dateTime and related + * builtin datatypes. Note that year parameter supports + * arbitrarily large numbers and fractionalSecond has infinite + * precision.

    + * + * @param year of XMLGregorianCalendar to be created. + * @param month of XMLGregorianCalendar to be created. + * @param day of XMLGregorianCalendar to be created. + * @param hour of XMLGregorianCalendar to be created. + * @param minute of XMLGregorianCalendar to be created. + * @param second of XMLGregorianCalendar to be created. + * @param fractionalSecond of XMLGregorianCalendar to be created. + * @param timezone of XMLGregorianCalendar to be created. + * + * @return XMLGregorianCalendar created from specified values. + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalid XMLGregorianCalendar instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + * @throws NullPointerException If any parameters are null. + * + */ + public XMLGregorianCalendar newXMLGregorianCalendar( + final BigInteger year, + final int month, + final int day, + final int hour, + final int minute, + final int second, + final BigDecimal fractionalSecond, + final int timezone) { + + return new XMLGregorianCalendarImpl( + year, + month, + day, + hour, + minute, + second, + fractionalSecond, + timezone + ); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/DurationImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/DurationImpl.java new file mode 100644 index 0000000..d43a006 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/DurationImpl.java @@ -0,0 +1,1968 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.datatype; + +import java.io.IOException; +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.xerces.util.DatatypeMessageFormatter; + +/** + *

    Immutable representation of a time span as defined in + * the W3C XML Schema 1.0 specification.

    + * + *

    A Duration object represents a period of Gregorian time, + * which consists of six fields (years, months, days, hours, + * minutes, and seconds) plus a sign (+/-) field.

    + * + *

    The first five fields have non-negative (>=0) integers or null + * (which represents that the field is not set), + * and the seconds field has a non-negative decimal or null. + * A negative sign indicates a negative duration.

    + * + *

    This class provides a number of methods that make it easy + * to use for the duration datatype of XML Schema 1.0 with + * the errata.

    + * + *

    Order relationship

    + *

    Duration objects only have partial order, where two values A and B + * maybe either:

    + *
      + *
    1. A<B (A is shorter than B) + *
    2. A>B (A is longer than B) + *
    3. A==B (A and B are of the same duration) + *
    4. A<>B (Comparison between A and B is indeterminate) + *
    + *

    For example, 30 days cannot be meaningfully compared to one month. + * The {@link #compare(Duration)} method implements this + * relationship.

    + * + *

    See the {@link #isLongerThan(Duration)} method for details about + * the order relationship among {@link Duration} objects.

    + * + * + * + *

    Operations over Duration

    + *

    This class provides a set of basic arithmetic operations, such + * as addition, subtraction and multiplication. + * Because durations don't have total order, an operation could + * fail for some combinations of operations. For example, you cannot + * subtract 15 days from 1 month. See the javadoc of those methods + * for detailed conditions where this could happen.

    + * + *

    Also, division of a duration by a number is not provided because + * the {@link Duration} class can only deal with finite precision + * decimal numbers. For example, one cannot represent 1 sec divided by 3.

    + * + *

    However, you could substitute a division by 3 with multiplying + * by numbers such as 0.3 or 0.333.

    + * + * + * + *

    Range of allowed values

    + *

    + * Because some operations of {@link Duration} rely on {@link Calendar} + * even though {@link Duration} can hold very large or very small values, + * some of the methods may not work correctly on such {@link Duration}s. + * The impacted methods document their dependency on {@link Calendar}. + * + * + * @author Kohsuke Kawaguchi + * @author Joseph Fialli + * @version $Id$ + * @see XMLGregorianCalendar#add(Duration) + */ +class DurationImpl + extends Duration + implements Serializable { + + /** + *

    Stream Unique Identifier.

    + */ + private static final long serialVersionUID = -2650025807136350131L; + + /** + *

    Internal array of value Fields.

    + */ + private static final DatatypeConstants.Field[] FIELDS = new DatatypeConstants.Field[]{ + DatatypeConstants.YEARS, + DatatypeConstants.MONTHS, + DatatypeConstants.DAYS, + DatatypeConstants.HOURS, + DatatypeConstants.MINUTES, + DatatypeConstants.SECONDS + }; + + /** + *

    BigDecimal value of 0.

    + */ + private static final BigDecimal ZERO = BigDecimal.valueOf(0); + + /** + *

    Indicates the sign. -1, 0 or 1 if the duration is negative, + * zero, or positive.

    + */ + private final int signum; + + /** + *

    Years of this Duration.

    + */ + private final BigInteger years; + + /** + *

    Months of this Duration.

    + */ + private final BigInteger months; + + /** + *

    Days of this Duration.

    + */ + private final BigInteger days; + + /** + *

    Hours of this Duration.

    + */ + private final BigInteger hours; + + /** + *

    Minutes of this Duration.

    + */ + private final BigInteger minutes; + + /** + *

    Seconds of this Duration.

    + */ + private final BigDecimal seconds; + + /** + * Returns the sign of this duration in -1,0, or 1. + * + * @return + * -1 if this duration is negative, 0 if the duration is zero, + * and 1 if the duration is postive. + */ + public int getSign() { + + return signum; + } + + /** + * TODO: Javadoc + * @param isPositive Sign. + * + * @return 1 if positive, else -1. + */ + private int calcSignum(boolean isPositive) { + if ((years == null || years.signum() == 0) + && (months == null || months.signum() == 0) + && (days == null || days.signum() == 0) + && (hours == null || hours.signum() == 0) + && (minutes == null || minutes.signum() == 0) + && (seconds == null || seconds.signum() == 0)) { + return 0; + } + + if (isPositive) { + return 1; + } + else { + return -1; + } + } + + /** + *

    Constructs a new Duration object by specifying each field individually.

    + * + *

    All the parameters are optional as long as at least one field is present. + * If specified, parameters have to be zero or positive.

    + * + * @param isPositive Set to false to create a negative duration. When the length + * of the duration is zero, this parameter will be ignored. + * @param years of this Duration + * @param months of this Duration + * @param days of this Duration + * @param hours of this Duration + * @param minutes of this Duration + * @param seconds of this Duration + * + * @throws IllegalArgumentException + * If years, months, days, hours, minutes and + * seconds parameters are all null. Or if any + * of those parameters are negative. + */ + protected DurationImpl( + boolean isPositive, + BigInteger years, + BigInteger months, + BigInteger days, + BigInteger hours, + BigInteger minutes, + BigDecimal seconds) { + + this.years = years; + this.months = months; + this.days = days; + this.hours = hours; + this.minutes = minutes; + this.seconds = seconds; + + this.signum = calcSignum(isPositive); + + // sanity check + if (years == null + && months == null + && days == null + && hours == null + && minutes == null + && seconds == null) { + throw new IllegalArgumentException( + //"all the fields are null" + DatatypeMessageFormatter.formatMessage(null, "AllFieldsNull", null) + ); + } + testNonNegative(years, DatatypeConstants.YEARS); + testNonNegative(months, DatatypeConstants.MONTHS); + testNonNegative(days, DatatypeConstants.DAYS); + testNonNegative(hours, DatatypeConstants.HOURS); + testNonNegative(minutes, DatatypeConstants.MINUTES); + testNonNegative(seconds, DatatypeConstants.SECONDS); + } + + /** + *

    Makes sure that the given number is non-negative. If it is not, + * throw {@link IllegalArgumentException}.

    + * + * @param n Number to test. + * @param f Field to test. + */ + private static void testNonNegative(BigInteger n, DatatypeConstants.Field f) { + if (n != null && n.signum() < 0) { + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object[]{f.toString()}) + ); + } + } + + /** + *

    Makes sure that the given number is non-negative. If it is not, + * throw {@link IllegalArgumentException}.

    + * + * @param n Number to test. + * @param f Field to test. + */ + private static void testNonNegative(BigDecimal n, DatatypeConstants.Field f) { + if (n != null && n.signum() < 0) { + + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object[]{f.toString()}) + ); + } + } + + /** + *

    Constructs a new Duration object by specifying each field + * individually.

    + * + *

    This method is functionally equivalent to + * invoking another constructor by wrapping + * all non-zero parameters into {@link BigInteger} and {@link BigDecimal}. + * Zero value of int parameter is equivalent of null value of + * the corresponding field.

    + * + * @see #DurationImpl(boolean, BigInteger, BigInteger, BigInteger, BigInteger, + * BigInteger, BigDecimal) + */ + protected DurationImpl( + final boolean isPositive, + final int years, + final int months, + final int days, + final int hours, + final int minutes, + final int seconds) { + this( + isPositive, + wrap(years), + wrap(months), + wrap(days), + wrap(hours), + wrap(minutes), + seconds != 0 ? BigDecimal.valueOf(seconds) : null); + } + + /** + * TODO: Javadoc + * + * @param i int to convert to BigInteger. + * + * @return BigInteger representation of int. + */ + private static BigInteger wrap(final int i) { + // field may not be set + if (i == DatatypeConstants.FIELD_UNDEFINED) { + return null; + } + + // int -> BigInteger + return BigInteger.valueOf(i); + } + + /** + *

    Constructs a new Duration object by specifying the duration + * in milliseconds.

    + * + *

    The DAYS, HOURS, MINUTES and SECONDS fields are used to + * represent the specifed duration in a reasonable way. + * That is, the constructed object x satisfies + * the following conditions:

    + *
      + *
    • x.getHours()<24 + *
    • x.getMinutes()<60 + *
    • x.getSeconds()<60 + *
    + * + * @param durationInMilliSeconds + * The length of the duration in milliseconds. + */ + protected DurationImpl(final long durationInMilliSeconds) { + + boolean is0x8000000000000000L = false; + long l = durationInMilliSeconds; + + if (l > 0) { + signum = 1; + } + else if (l < 0) { + signum = -1; + if (l == 0x8000000000000000L) { + // negating 0x8000000000000000L causes an overflow + l++; + is0x8000000000000000L = true; + } + l *= -1; + } + else { + signum = 0; + } + + this.years = null; + this.months = null; + + this.seconds = + BigDecimal.valueOf((l % 60000L) + (is0x8000000000000000L ? 1 : 0), 3); + + l /= 60000L; + this.minutes = (l == 0) ? null : BigInteger.valueOf(l % 60L); + + l /= 60L; + this.hours = (l == 0) ? null : BigInteger.valueOf(l % 24L); + + l /= 24L; + this.days = (l == 0) ? null : BigInteger.valueOf(l); + } + + + /** + * Constructs a new Duration object by + * parsing its string representation + * "PnYnMnDTnHnMnS" as defined in XML Schema 1.0 section 3.2.6.1. + * + *

    + * The string representation may not have any leading + * and trailing whitespaces. + * + *

    + * For example, this method parses strings like + * "P1D" (1 day), "-PT100S" (-100 sec.), "P1DT12H" (1 days and 12 hours). + * + *

    + * The parsing is done field by field so that + * the following holds for any lexically correct string x: + *

    +     * new Duration(x).toString().equals(x)
    +     * 
    + * + * Returns a non-null valid duration object that holds the value + * indicated by the lexicalRepresentation parameter. + * + * @param lexicalRepresentation + * Lexical representation of a duration. + * @throws IllegalArgumentException + * If the given string does not conform to the aforementioned + * specification. + * @throws NullPointerException + * If the given string is null. + */ + protected DurationImpl(String lexicalRepresentation) + throws IllegalArgumentException { + // only if I could use the JDK1.4 regular expression .... + + final String s = lexicalRepresentation; + boolean positive; + int[] idx = new int[1]; + int length = s.length(); + boolean timeRequired = false; + + if (lexicalRepresentation == null) { + throw new NullPointerException(); + } + + idx[0] = 0; + if (length != idx[0] && s.charAt(idx[0]) == '-') { + idx[0]++; + positive = false; + } + else { + positive = true; + } + + if (length != idx[0] && s.charAt(idx[0]++) != 'P') { + throw new IllegalArgumentException(s); //,idx[0]-1); + } + + + // phase 1: chop the string into chunks + // (where a chunk is '' + //-------------------------------------- + int dateLen = 0; + String[] dateParts = new String[3]; + int[] datePartsIndex = new int[3]; + while (length != idx[0] + && isDigit(s.charAt(idx[0])) + && dateLen < 3) { + datePartsIndex[dateLen] = idx[0]; + dateParts[dateLen++] = parsePiece(s, idx); + } + + if (length != idx[0]) { + if (s.charAt(idx[0]++) == 'T') { + timeRequired = true; + } + else { + throw new IllegalArgumentException(s); // ,idx[0]-1); + } + } + + int timeLen = 0; + String[] timeParts = new String[3]; + int[] timePartsIndex = new int[3]; + while (length != idx[0] + && isDigitOrPeriod(s.charAt(idx[0])) + && timeLen < 3) { + timePartsIndex[timeLen] = idx[0]; + timeParts[timeLen++] = parsePiece(s, idx); + } + + if (timeRequired && timeLen == 0) { + throw new IllegalArgumentException(s); // ,idx[0]); + } + + if (length != idx[0]) { + throw new IllegalArgumentException(s); // ,idx[0]); + } + if (dateLen == 0 && timeLen == 0) { + throw new IllegalArgumentException(s); // ,idx[0]); + } + + // phase 2: check the ordering of chunks + //-------------------------------------- + organizeParts(s, dateParts, datePartsIndex, dateLen, "YMD"); + organizeParts(s, timeParts, timePartsIndex, timeLen, "HMS"); + + // parse into numbers + years = parseBigInteger(s, dateParts[0], datePartsIndex[0]); + months = parseBigInteger(s, dateParts[1], datePartsIndex[1]); + days = parseBigInteger(s, dateParts[2], datePartsIndex[2]); + hours = parseBigInteger(s, timeParts[0], timePartsIndex[0]); + minutes = parseBigInteger(s, timeParts[1], timePartsIndex[1]); + seconds = parseBigDecimal(s, timeParts[2], timePartsIndex[2]); + signum = calcSignum(positive); + } + + + /** + * TODO: Javadoc + * + * @param ch char to test. + * + * @return true if ch is a digit, else false. + */ + private static boolean isDigit(char ch) { + return '0' <= ch && ch <= '9'; + } + + /** + * TODO: Javadoc + * + * @param ch to test. + * + * @return true if ch is a digit or a period, else false. + */ + private static boolean isDigitOrPeriod(char ch) { + return isDigit(ch) || ch == '.'; + } + + /** + * TODO: Javadoc + * + * @param whole String to parse. + * @param idx TODO: ??? + * + * @return Result of parsing. + * + * @throws IllegalArgumentException If whole cannot be parsed. + */ + private static String parsePiece(String whole, int[] idx) + throws IllegalArgumentException { + int start = idx[0]; + while (idx[0] < whole.length() + && isDigitOrPeriod(whole.charAt(idx[0]))) { + idx[0]++; + } + if (idx[0] == whole.length()) { + throw new IllegalArgumentException(whole); // ,idx[0]); + } + + idx[0]++; + + return whole.substring(start, idx[0]); + } + + /** + * TODO: Javadoc. + * + * @param whole TODO: ??? + * @param parts TODO: ??? + * @param partsIndex TODO: ??? + * @param len TODO: ??? + * @param tokens TODO: ??? + * + * @throws IllegalArgumentException TODO: ??? + */ + private static void organizeParts( + String whole, + String[] parts, + int[] partsIndex, + int len, + String tokens) + throws IllegalArgumentException { + + int idx = tokens.length(); + for (int i = len - 1; i >= 0; i--) { + if (parts[i] == null) { + throw new IllegalArgumentException(whole); + } + int nidx = + tokens.lastIndexOf( + parts[i].charAt(parts[i].length() - 1), + idx - 1); + if (nidx == -1) { + throw new IllegalArgumentException(whole); + // ,partsIndex[i]+parts[i].length()-1); + } + + for (int j = nidx + 1; j < idx; j++) { + parts[j] = null; + } + idx = nidx; + parts[idx] = parts[i]; + partsIndex[idx] = partsIndex[i]; + } + for (idx--; idx >= 0; idx--) { + parts[idx] = null; + } + } + + /** + * TODO: Javadoc + * + * @param whole TODO: ???. + * @param part TODO: ???. + * @param index TODO: ???. + * + * @return TODO: ???. + * + * @throws IllegalArgumentException TODO: ???. + */ + private static BigInteger parseBigInteger( + String whole, + String part, + int index) + throws IllegalArgumentException { + if (part == null) { + return null; + } + part = part.substring(0, part.length() - 1); + // try { + return new BigInteger(part); + // } catch( NumberFormatException e ) { + // throw new ParseException( whole, index ); + // } + } + + /** + * TODO: Javadoc. + * + * @param whole TODO: ???. + * @param part TODO: ???. + * @param index TODO: ???. + * + * @return TODO: ???. + * + * @throws IllegalArgumentException TODO: ???. + */ + private static BigDecimal parseBigDecimal( + String whole, + String part, + int index) + throws IllegalArgumentException { + if (part == null) { + return null; + } + part = part.substring(0, part.length() - 1); + // NumberFormatException is IllegalArgumentException + // try { + return new BigDecimal(part); + // } catch( NumberFormatException e ) { + // throw new ParseException( whole, index ); + // } + } + + /** + *

    Four constants defined for the comparison of durations.

    + */ + private static final XMLGregorianCalendar[] TEST_POINTS = new XMLGregorianCalendar[] { + XMLGregorianCalendarImpl.parse("1696-09-01T00:00:00Z"), + XMLGregorianCalendarImpl.parse("1697-02-01T00:00:00Z"), + XMLGregorianCalendarImpl.parse("1903-03-01T00:00:00Z"), + XMLGregorianCalendarImpl.parse("1903-07-01T00:00:00Z") + }; + + /** + *

    Partial order relation comparison with this Duration instance.

    + * + *

    Comparison result must be in accordance with + * W3C XML Schema 1.0 Part 2, Section 3.2.7.6.2, + * Order relation on duration.

    + * + *

    Return:

    + *
      + *
    • {@link DatatypeConstants#LESSER} if this Duration is shorter than duration parameter
    • + *
    • {@link DatatypeConstants#EQUAL} if this Duration is equal to duration parameter
    • + *
    • {@link DatatypeConstants#GREATER} if this Duration is longer than duration parameter
    • + *
    • {@link DatatypeConstants#INDETERMINATE} if a conclusive partial order relation cannot be determined
    • + *
    + * + * @param duration to compare + * + * @return the relationship between this Durationand duration parameter as + * {@link DatatypeConstants#LESSER}, {@link DatatypeConstants#EQUAL}, {@link DatatypeConstants#GREATER} + * or {@link DatatypeConstants#INDETERMINATE}. + * + * @throws UnsupportedOperationException If the underlying implementation + * cannot reasonably process the request, e.g. W3C XML Schema allows for + * arbitrarily large/small/precise values, the request may be beyond the + * implementations capability. + * @throws NullPointerException if duration is null. + * + * @see #isShorterThan(Duration) + * @see #isLongerThan(Duration) + */ + public int compare(Duration rhs) { + + BigInteger maxintAsBigInteger = BigInteger.valueOf(Integer.MAX_VALUE); + + // check for fields that are too large in this Duration + if (years != null && years.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.YEARS.toString(), years.toString()}) + //this.getClass().getName() + "#compare(Duration duration)" + //+ " years too large to be supported by this implementation " + //+ years.toString() + ); + } + if (months != null && months.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MONTHS.toString(), months.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " months too large to be supported by this implementation " + //+ months.toString() + ); + } + if (days != null && days.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.DAYS.toString(), days.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " days too large to be supported by this implementation " + //+ days.toString() + ); + } + if (hours != null && hours.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.HOURS.toString(), hours.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " hours too large to be supported by this implementation " + //+ hours.toString() + ); + } + if (minutes != null && minutes.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MINUTES.toString(), minutes.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " minutes too large to be supported by this implementation " + //+ minutes.toString() + ); + } + if (seconds != null && seconds.toBigInteger().compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), toString(seconds)}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " seconds too large to be supported by this implementation " + //+ seconds.toString() + ); + } + + // check for fields that are too large in rhs Duration + BigInteger rhsYears = (BigInteger) rhs.getField(DatatypeConstants.YEARS); + if (rhsYears != null && rhsYears.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.YEARS.toString(), rhsYears.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " years too large to be supported by this implementation " + //+ rhsYears.toString() + ); + } + BigInteger rhsMonths = (BigInteger) rhs.getField(DatatypeConstants.MONTHS); + if (rhsMonths != null && rhsMonths.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MONTHS.toString(), rhsMonths.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " months too large to be supported by this implementation " + //+ rhsMonths.toString() + ); + } + BigInteger rhsDays = (BigInteger) rhs.getField(DatatypeConstants.DAYS); + if (rhsDays != null && rhsDays.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.DAYS.toString(), rhsDays.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " days too large to be supported by this implementation " + //+ rhsDays.toString() + ); + } + BigInteger rhsHours = (BigInteger) rhs.getField(DatatypeConstants.HOURS); + if (rhsHours != null && rhsHours.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.HOURS.toString(), rhsHours.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " hours too large to be supported by this implementation " + //+ rhsHours.toString() + ); + } + BigInteger rhsMinutes = (BigInteger) rhs.getField(DatatypeConstants.MINUTES); + if (rhsMinutes != null && rhsMinutes.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MINUTES.toString(), rhsMinutes.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " minutes too large to be supported by this implementation " + //+ rhsMinutes.toString() + ); + } + BigDecimal rhsSecondsAsBigDecimal = (BigDecimal) rhs.getField(DatatypeConstants.SECONDS); + BigInteger rhsSeconds = null; + if ( rhsSecondsAsBigDecimal != null ) { + rhsSeconds = rhsSecondsAsBigDecimal.toBigInteger(); + } + if (rhsSeconds != null && rhsSeconds.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), rhsSeconds.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " seconds too large to be supported by this implementation " + //+ rhsSeconds.toString() + ); + } + + // turn this Duration into a GregorianCalendar + GregorianCalendar lhsCalendar = new GregorianCalendar( + 1970, + 1, + 1, + 0, + 0, + 0); + lhsCalendar.add(GregorianCalendar.YEAR, getYears() * getSign()); + lhsCalendar.add(GregorianCalendar.MONTH, getMonths() * getSign()); + lhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, getDays() * getSign()); + lhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, getHours() * getSign()); + lhsCalendar.add(GregorianCalendar.MINUTE, getMinutes() * getSign()); + lhsCalendar.add(GregorianCalendar.SECOND, getSeconds() * getSign()); + + // turn compare Duration into a GregorianCalendar + GregorianCalendar rhsCalendar = new GregorianCalendar( + 1970, + 1, + 1, + 0, + 0, + 0); + rhsCalendar.add(GregorianCalendar.YEAR, rhs.getYears() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.MONTH, rhs.getMonths() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, rhs.getDays() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, rhs.getHours() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.MINUTE, rhs.getMinutes() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.SECOND, rhs.getSeconds() * rhs.getSign()); + + + if (lhsCalendar.equals(rhsCalendar)) { + return DatatypeConstants.EQUAL; + } + + return compareDates(this, rhs); + } + + /** + * Compares 2 given durations. (refer to W3C Schema Datatypes "3.2.6 duration") + * + * @param duration1 Unnormalized duration + * @param duration2 Unnormalized duration + * @return INDETERMINATE if the order relationship between date1 and date2 is indeterminate. + * EQUAL if the order relation between date1 and date2 is EQUAL. + * If the strict parameter is true, return LESS_THAN if date1 is less than date2 and + * return GREATER_THAN if date1 is greater than date2. + * If the strict parameter is false, return LESS_THAN if date1 is less than OR equal to date2 and + * return GREATER_THAN if date1 is greater than OR equal to date2 + */ + private int compareDates(Duration duration1, Duration duration2) { + + int resultA = DatatypeConstants.INDETERMINATE; + int resultB = DatatypeConstants.INDETERMINATE; + + XMLGregorianCalendar tempA = (XMLGregorianCalendar)TEST_POINTS[0].clone(); + XMLGregorianCalendar tempB = (XMLGregorianCalendar)TEST_POINTS[0].clone(); + + //long comparison algorithm is required + tempA.add(duration1); + tempB.add(duration2); + resultA = tempA.compare(tempB); + if ( resultA == DatatypeConstants.INDETERMINATE ) { + return DatatypeConstants.INDETERMINATE; + } + + tempA = (XMLGregorianCalendar)TEST_POINTS[1].clone(); + tempB = (XMLGregorianCalendar)TEST_POINTS[1].clone(); + + tempA.add(duration1); + tempB.add(duration2); + resultB = tempA.compare(tempB); + resultA = compareResults(resultA, resultB); + if (resultA == DatatypeConstants.INDETERMINATE) { + return DatatypeConstants.INDETERMINATE; + } + + tempA = (XMLGregorianCalendar)TEST_POINTS[2].clone(); + tempB = (XMLGregorianCalendar)TEST_POINTS[2].clone(); + + tempA.add(duration1); + tempB.add(duration2); + resultB = tempA.compare(tempB); + resultA = compareResults(resultA, resultB); + if (resultA == DatatypeConstants.INDETERMINATE) { + return DatatypeConstants.INDETERMINATE; + } + + tempA = (XMLGregorianCalendar)TEST_POINTS[3].clone(); + tempB = (XMLGregorianCalendar)TEST_POINTS[3].clone(); + + tempA.add(duration1); + tempB.add(duration2); + resultB = tempA.compare(tempB); + resultA = compareResults(resultA, resultB); + + return resultA; + } + + private int compareResults(int resultA, int resultB) { + + if ( resultB == DatatypeConstants.INDETERMINATE ) { + return DatatypeConstants.INDETERMINATE; + } + else if ( resultA!=resultB) { + return DatatypeConstants.INDETERMINATE; + } + return resultA; + } + + /** + * Returns a hash code consistent with the definition of the equals method. + * + * @see Object#hashCode() + */ + public int hashCode() { + // component wise hash is not correct because 1day = 24hours + Calendar cal = TEST_POINTS[0].toGregorianCalendar(); + this.addTo(cal); + return (int) getCalendarTimeInMillis(cal); + } + + /** + * Returns a string representation of this duration object. + * + *

    + * The result is formatter according to the XML Schema 1.0 + * spec and can be always parsed back later into the + * equivalent duration object by + * the {@link #DurationImpl(String)} constructor. + * + *

    + * Formally, the following holds for any {@link Duration} + * object x. + *

    +     * new Duration(x.toString()).equals(x)
    +     * 
    + * + * @return + * Always return a non-null valid String object. + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + if (signum < 0) { + buf.append('-'); + } + buf.append('P'); + + if (years != null) { + buf.append(years).append('Y'); + } + if (months != null) { + buf.append(months).append('M'); + } + if (days != null) { + buf.append(days).append('D'); + } + + if (hours != null || minutes != null || seconds != null) { + buf.append('T'); + if (hours != null) { + buf.append(hours).append('H'); + } + if (minutes != null) { + buf.append(minutes).append('M'); + } + if (seconds != null) { + buf.append(toString(seconds)).append('S'); + } + } + + return buf.toString(); + } + + /** + *

    Turns {@link BigDecimal} to a string representation.

    + * + *

    Due to a behavior change in the {@link BigDecimal#toString()} + * method in JDK1.5, this had to be implemented here.

    + * + * @param bd BigDecimal to format as a String + * + * @return String representation of BigDecimal + */ + private String toString(BigDecimal bd) { + String intString = bd.unscaledValue().toString(); + int scale = bd.scale(); + + if (scale == 0) { + return intString; + } + + /* Insert decimal point */ + StringBuffer buf; + int insertionPoint = intString.length() - scale; + if (insertionPoint == 0) { /* Point goes right before intVal */ + return "0." + intString; + } + else if (insertionPoint > 0) { /* Point goes inside intVal */ + buf = new StringBuffer(intString); + buf.insert(insertionPoint, '.'); + } + else { /* We must insert zeros between point and intVal */ + buf = new StringBuffer(3 - insertionPoint + intString.length()); + buf.append("0."); + for (int i = 0; i < -insertionPoint; i++) { + buf.append('0'); + } + buf.append(intString); + } + return buf.toString(); + } + + /** + * Checks if a field is set. + * + * A field of a duration object may or may not be present. + * This method can be used to test if a field is present. + * + * @param field + * one of the six Field constants (YEARS,MONTHS,DAYS,HOURS, + * MINUTES, or SECONDS.) + * @return + * true if the field is present. false if not. + * + * @throws NullPointerException + * If the field parameter is null. + */ + public boolean isSet(DatatypeConstants.Field field) { + + if (field == null) { + String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field)" ; + throw new NullPointerException( + //"cannot be called with field == null" + DatatypeMessageFormatter.formatMessage(null, "FieldCannotBeNull", new Object[]{methodName}) + ); + } + + if (field == DatatypeConstants.YEARS) { + return years != null; + } + + if (field == DatatypeConstants.MONTHS) { + return months != null; + } + + if (field == DatatypeConstants.DAYS) { + return days != null; + } + + if (field == DatatypeConstants.HOURS) { + return hours != null; + } + + if (field == DatatypeConstants.MINUTES) { + return minutes != null; + } + + if (field == DatatypeConstants.SECONDS) { + return seconds != null; + } + String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field)"; + + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object[]{methodName, field.toString()}) + ); + + } + + /** + * Gets the value of a field. + * + * Fields of a duration object may contain arbitrary large value. + * Therefore this method is designed to return a {@link Number} object. + * + * In case of YEARS, MONTHS, DAYS, HOURS, and MINUTES, the returned + * number will be a non-negative integer. In case of seconds, + * the returned number may be a non-negative decimal value. + * + * @param field + * one of the six Field constants (YEARS,MONTHS,DAYS,HOURS, + * MINUTES, or SECONDS.) + * @return + * If the specified field is present, this method returns + * a non-null non-negative {@link Number} object that + * represents its value. If it is not present, return null. + * For YEARS, MONTHS, DAYS, HOURS, and MINUTES, this method + * returns a {@link BigInteger} object. For SECONDS, this + * method returns a {@link BigDecimal}. + * + * @throws NullPointerException + * If the field parameter is null. + */ + public Number getField(DatatypeConstants.Field field) { + + if (field == null) { + String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field) " ; + + throw new NullPointerException( + DatatypeMessageFormatter.formatMessage(null,"FieldCannotBeNull", new Object[]{methodName}) + ); + } + + if (field == DatatypeConstants.YEARS) { + return years; + } + + if (field == DatatypeConstants.MONTHS) { + return months; + } + + if (field == DatatypeConstants.DAYS) { + return days; + } + + if (field == DatatypeConstants.HOURS) { + return hours; + } + + if (field == DatatypeConstants.MINUTES) { + return minutes; + } + + if (field == DatatypeConstants.SECONDS) { + return seconds; + } + /** + throw new IllegalArgumentException( + "javax.xml.datatype.Duration" + + "#(getSet(DatatypeConstants.Field field) called with an unknown field: " + + field.toString() + ); + */ + String methodName = "javax.xml.datatype.Duration" + "#(getSet(DatatypeConstants.Field field)"; + + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object[]{methodName, field.toString()}) + ); + + } + + /** + * Obtains the value of the YEARS field as an integer value, + * or 0 if not present. + * + *

    + * This method is a convenience method around the + * {@link #getField(DatatypeConstants.Field)} method. + * + *

    + * Note that since this method returns int, this + * method will return an incorrect value for {@link Duration}s + * with the year field that goes beyond the range of int. + * Use getField(YEARS) to avoid possible loss of precision.

    + * + * @return + * If the YEARS field is present, return + * its value as an integer by using the {@link Number#intValue()} + * method. If the YEARS field is not present, return 0. + */ + public int getYears() { + return getInt(DatatypeConstants.YEARS); + } + + /** + * Obtains the value of the MONTHS field as an integer value, + * or 0 if not present. + * + * This method works just like {@link #getYears()} except + * that this method works on the MONTHS field. + * + * @return Months of this Duration. + */ + public int getMonths() { + return getInt(DatatypeConstants.MONTHS); + } + + /** + * Obtains the value of the DAYS field as an integer value, + * or 0 if not present. + * + * This method works just like {@link #getYears()} except + * that this method works on the DAYS field. + * + * @return Days of this Duration. + */ + public int getDays() { + return getInt(DatatypeConstants.DAYS); + } + + /** + * Obtains the value of the HOURS field as an integer value, + * or 0 if not present. + * + * This method works just like {@link #getYears()} except + * that this method works on the HOURS field. + * + * @return Hours of this Duration. + * + */ + public int getHours() { + return getInt(DatatypeConstants.HOURS); + } + + /** + * Obtains the value of the MINUTES field as an integer value, + * or 0 if not present. + * + * This method works just like {@link #getYears()} except + * that this method works on the MINUTES field. + * + * @return Minutes of this Duration. + * + */ + public int getMinutes() { + return getInt(DatatypeConstants.MINUTES); + } + + /** + * Obtains the value of the SECONDS field as an integer value, + * or 0 if not present. + * + * This method works just like {@link #getYears()} except + * that this method works on the SECONDS field. + * + * @return seconds in the integer value. The fraction of seconds + * will be discarded (for example, if the actual value is 2.5, + * this method returns 2) + */ + public int getSeconds() { + return getInt(DatatypeConstants.SECONDS); + } + + /** + *

    Return the requested field value as an int.

    + * + *

    If field is not set, i.e. == null, 0 is returned.

    + * + * @param field To get value for. + * + * @return int value of field or 0 if field is not set. + */ + private int getInt(DatatypeConstants.Field field) { + Number n = getField(field); + if (n == null) { + return 0; + } + else { + return n.intValue(); + } + } + + /** + *

    Returns the length of the duration in milli-seconds.

    + * + *

    If the seconds field carries more digits than milli-second order, + * those will be simply discarded (or in other words, rounded to zero.) + * For example, for any Calendar value x,

    + *
    +     * new Duration("PT10.00099S").getTimeInMills(x) == 10000.
    +     * new Duration("-PT10.00099S").getTimeInMills(x) == -10000.
    +     * 
    + * + *

    + * Note that this method uses the {@link #addTo(Calendar)} method, + * which may work incorectly with {@link Duration} objects with + * very large values in its fields. See the {@link #addTo(Calendar)} + * method for details. + * + * @param startInstant + * The length of a month/year varies. The startInstant is + * used to disambiguate this variance. Specifically, this method + * returns the difference between startInstant and + * startInstant+duration + * + * @return milliseconds between startInstant and + * startInstant plus this Duration + * + * @throws NullPointerException if startInstant parameter + * is null. + * + */ + public long getTimeInMillis(final Calendar startInstant) { + Calendar cal = (Calendar) startInstant.clone(); + addTo(cal); + return getCalendarTimeInMillis(cal) - getCalendarTimeInMillis(startInstant); + } + + /** + *

    Returns the length of the duration in milli-seconds.

    + * + *

    If the seconds field carries more digits than milli-second order, + * those will be simply discarded (or in other words, rounded to zero.) + * For example, for any Date value x,

    + *
    +     * new Duration("PT10.00099S").getTimeInMills(x) == 10000.
    +     * new Duration("-PT10.00099S").getTimeInMills(x) == -10000.
    +     * 
    + * + *

    + * Note that this method uses the {@link #addTo(Date)} method, + * which may work incorectly with {@link Duration} objects with + * very large values in its fields. See the {@link #addTo(Date)} + * method for details. + * + * @param startInstant + * The length of a month/year varies. The startInstant is + * used to disambiguate this variance. Specifically, this method + * returns the difference between startInstant and + * startInstant+duration. + * + * @throws NullPointerException + * If the startInstant parameter is null. + * + * @return milliseconds between startInstant and + * startInstant plus this Duration + * + * @see #getTimeInMillis(Calendar) + */ + public long getTimeInMillis(final Date startInstant) { + Calendar cal = new GregorianCalendar(); + cal.setTime(startInstant); + this.addTo(cal); + return getCalendarTimeInMillis(cal) - startInstant.getTime(); + } + +// /** +// * Returns an equivalent but "normalized" duration value. +// * +// * Intuitively, the normalization moves YEARS into +// * MONTHS (by x12) and moves DAYS, HOURS, and MINUTES fields +// * into SECONDS (by x86400, x3600, and x60 respectively.) +// * +// * +// * Formally, this method satisfies the following conditions: +// *

      +// *
    • x.normalize().equals(x) +// *
    • !x.normalize().isSet(Duration.YEARS) +// *
    • !x.normalize().isSet(Duration.DAYS) +// *
    • !x.normalize().isSet(Duration.HOURS) +// *
    • !x.normalize().isSet(Duration.MINUTES) +// *
    +// * +// * @return +// * always return a non-null valid value. +// */ +// public Duration normalize() { +// return null; +// } + + /** + *

    Converts the years and months fields into the days field + * by using a specific time instant as the reference point.

    + * + *

    For example, duration of one month normalizes to 31 days + * given the start time instance "July 8th 2003, 17:40:32".

    + * + *

    Formally, the computation is done as follows:

    + *
      + *
    1. The given Calendar object is cloned. + *
    2. The years, months and days fields will be added to + * the {@link Calendar} object + * by using the {@link Calendar#add(int,int)} method. + *
    3. The difference between two Calendars are computed in terms of days. + *
    4. The computed days, along with the hours, minutes and seconds + * fields of this duration object is used to construct a new + * Duration object. + *
    + * + *

    Note that since the Calendar class uses int to + * hold the value of year and month, this method may produce + * an unexpected result if this duration object holds + * a very large value in the years or months fields.

    + * + * @param startTimeInstant Calendar reference point. + * + * @return Duration of years and months of this Duration as days. + * + * @throws NullPointerException If the startTimeInstant parameter is null. + */ + public Duration normalizeWith(Calendar startTimeInstant) { + + Calendar c = (Calendar) startTimeInstant.clone(); + + // using int may cause overflow, but + // Calendar internally treats value as int anyways. + c.add(Calendar.YEAR, getYears() * signum); + c.add(Calendar.MONTH, getMonths() * signum); + c.add(Calendar.DAY_OF_MONTH, getDays() * signum); + + // obtain the difference in terms of days + long diff = getCalendarTimeInMillis(c) - getCalendarTimeInMillis(startTimeInstant); + int days = (int) (diff / (1000L * 60L * 60L * 24L)); + + return new DurationImpl( + days >= 0, + null, + null, + wrap(Math.abs(days)), + (BigInteger) getField(DatatypeConstants.HOURS), + (BigInteger) getField(DatatypeConstants.MINUTES), + (BigDecimal) getField(DatatypeConstants.SECONDS)); + } + + /** + *

    Computes a new duration whose value is factor times + * longer than the value of this duration.

    + * + *

    This method is provided for the convenience. + * It is functionally equivalent to the following code:

    + *
    +     * multiply(new BigDecimal(String.valueOf(factor)))
    +     * 
    + * + * @param factor Factor times longer of new Duration to create. + * + * @return New Duration that is factortimes longer than this Duration. + * + * @see #multiply(BigDecimal) + */ + public Duration multiply(int factor) { + return multiply(BigDecimal.valueOf(factor)); + } + + /** + * Computes a new duration whose value is factor times + * longer than the value of this duration. + * + *

    + * For example, + *

    +     * "P1M" (1 month) * "12" = "P12M" (12 months)
    +     * "PT1M" (1 min) * "0.3" = "PT18S" (18 seconds)
    +     * "P1M" (1 month) * "1.5" = IllegalStateException
    +     * 
    + * + *

    + * Since the {@link Duration} class is immutable, this method + * doesn't change the value of this object. It simply computes + * a new Duration object and returns it. + * + *

    + * The operation will be performed field by field with the precision + * of {@link BigDecimal}. Since all the fields except seconds are + * restricted to hold integers, + * any fraction produced by the computation will be + * carried down toward the next lower unit. For example, + * if you multiply "P1D" (1 day) with "0.5", then it will be 0.5 day, + * which will be carried down to "PT12H" (12 hours). + * When fractions of month cannot be meaningfully carried down + * to days, or year to months, this will cause an + * {@link IllegalStateException} to be thrown. + * For example if you multiple one month by 0.5.

    + * + *

    + * To avoid {@link IllegalStateException}, use + * the {@link #normalizeWith(Calendar)} method to remove the years + * and months fields. + * + * @param factor to multiply by + * + * @return + * returns a non-null valid {@link Duration} object + * + * @throws IllegalStateException if operation produces fraction in + * the months field. + * + * @throws NullPointerException if the factor parameter is + * null. + * + */ + public Duration multiply(BigDecimal factor) { + BigDecimal carry = ZERO; + int factorSign = factor.signum(); + factor = factor.abs(); + + BigDecimal[] buf = new BigDecimal[6]; + + for (int i = 0; i < 5; i++) { + BigDecimal bd = getFieldAsBigDecimal(FIELDS[i]); + bd = bd.multiply(factor).add(carry); + + buf[i] = bd.setScale(0, BigDecimal.ROUND_DOWN); + + bd = bd.subtract(buf[i]); + if (i == 1) { + if (bd.signum() != 0) { + throw new IllegalStateException(); // illegal carry-down + } else { + carry = ZERO; + } + } + else { + carry = bd.multiply(FACTORS[i]); + } + } + + if (seconds != null) { + buf[5] = seconds.multiply(factor).add(carry); + } + else { + buf[5] = carry; + } + + return new DurationImpl( + this.signum * factorSign >= 0, + toBigInteger(buf[0], null == years), + toBigInteger(buf[1], null == months), + toBigInteger(buf[2], null == days), + toBigInteger(buf[3], null == hours), + toBigInteger(buf[4], null == minutes), + (buf[5].signum() == 0 && seconds == null) ? null : buf[5]); + } + + /** + *

    Gets the value of the field as a {@link BigDecimal}.

    + * + *

    If the field is unset, return 0.

    + * + * @param f Field to get value for. + * + * @return non-null valid {@link BigDecimal}. + */ + private BigDecimal getFieldAsBigDecimal(DatatypeConstants.Field f) { + if (f == DatatypeConstants.SECONDS) { + if (seconds != null) { + return seconds; + } + else { + return ZERO; + } + } + else { + BigInteger bi = (BigInteger) getField(f); + if (bi == null) { + return ZERO; + } + else { + return new BigDecimal(bi); + } + } + } + + /** + *

    BigInteger value of BigDecimal value.

    + * + * @param value Value to convert. + * @param canBeNull Can returned value be null? + * + * @return BigInteger value of BigDecimal, possibly null. + */ + private static BigInteger toBigInteger( + BigDecimal value, + boolean canBeNull) { + if (canBeNull && value.signum() == 0) { + return null; + } + else { + return value.unscaledValue(); + } + } + + /** + * 1 unit of FIELDS[i] is equivalent to FACTORS[i] unit of + * FIELDS[i+1]. + */ + private static final BigDecimal[] FACTORS = new BigDecimal[] { + BigDecimal.valueOf(12), + null/*undefined*/, + BigDecimal.valueOf(24), + BigDecimal.valueOf(60), + BigDecimal.valueOf(60) + }; + + /** + *

    Computes a new duration whose value is this+rhs.

    + * + *

    For example,

    + *
    +     * "1 day" + "-3 days" = "-2 days"
    +     * "1 year" + "1 day" = "1 year and 1 day"
    +     * "-(1 hour,50 minutes)" + "-20 minutes" = "-(1 hours,70 minutes)"
    +     * "15 hours" + "-3 days" = "-(2 days,9 hours)"
    +     * "1 year" + "-1 day" = IllegalStateException
    +     * 
    + * + *

    Since there's no way to meaningfully subtract 1 day from 1 month, + * there are cases where the operation fails in + * {@link IllegalStateException}.

    + * + *

    + * Formally, the computation is defined as follows.

    + *

    + * Firstly, we can assume that two {@link Duration}s to be added + * are both positive without losing generality (i.e., + * (-X)+Y=Y-X, X+(-Y)=X-Y, + * (-X)+(-Y)=-(X+Y)) + * + *

    + * Addition of two positive {@link Duration}s are simply defined as + * field by field addition where missing fields are treated as 0. + *

    + * A field of the resulting {@link Duration} will be unset if and + * only if respective fields of two input {@link Duration}s are unset. + *

    + * Note that lhs.add(rhs) will be always successful if + * lhs.signum()*rhs.signum()!=-1 or both of them are + * normalized.

    + * + * @param rhs Duration to add to this Duration + * + * @return + * non-null valid Duration object. + * + * @throws NullPointerException + * If the rhs parameter is null. + * @throws IllegalStateException + * If two durations cannot be meaningfully added. For + * example, adding negative one day to one month causes + * this exception. + * + * + * @see #subtract(Duration) + */ + public Duration add(final Duration rhs) { + Duration lhs = this; + BigDecimal[] buf = new BigDecimal[6]; + + buf[0] = sanitize((BigInteger) lhs.getField(DatatypeConstants.YEARS), + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.YEARS), rhs.getSign())); + buf[1] = sanitize((BigInteger) lhs.getField(DatatypeConstants.MONTHS), + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.MONTHS), rhs.getSign())); + buf[2] = sanitize((BigInteger) lhs.getField(DatatypeConstants.DAYS), + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.DAYS), rhs.getSign())); + buf[3] = sanitize((BigInteger) lhs.getField(DatatypeConstants.HOURS), + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.HOURS), rhs.getSign())); + buf[4] = sanitize((BigInteger) lhs.getField(DatatypeConstants.MINUTES), + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.MINUTES), rhs.getSign())); + buf[5] = sanitize((BigDecimal) lhs.getField(DatatypeConstants.SECONDS), + lhs.getSign()).add(sanitize((BigDecimal) rhs.getField(DatatypeConstants.SECONDS), rhs.getSign())); + + // align sign + alignSigns(buf, 0, 2); // Y,M + alignSigns(buf, 2, 6); // D,h,m,s + + // make sure that the sign bit is consistent across all 6 fields. + int s = 0; + for (int i = 0; i < 6; i++) { + if (s * buf[i].signum() < 0) { + throw new IllegalStateException(); + } + if (s == 0) { + s = buf[i].signum(); + } + } + + return new DurationImpl( + s >= 0, + toBigInteger(sanitize(buf[0], s), + lhs.getField(DatatypeConstants.YEARS) == null && rhs.getField(DatatypeConstants.YEARS) == null), + toBigInteger(sanitize(buf[1], s), + lhs.getField(DatatypeConstants.MONTHS) == null && rhs.getField(DatatypeConstants.MONTHS) == null), + toBigInteger(sanitize(buf[2], s), + lhs.getField(DatatypeConstants.DAYS) == null && rhs.getField(DatatypeConstants.DAYS) == null), + toBigInteger(sanitize(buf[3], s), + lhs.getField(DatatypeConstants.HOURS) == null && rhs.getField(DatatypeConstants.HOURS) == null), + toBigInteger(sanitize(buf[4], s), + lhs.getField(DatatypeConstants.MINUTES) == null && rhs.getField(DatatypeConstants.MINUTES) == null), + (buf[5].signum() == 0 + && lhs.getField(DatatypeConstants.SECONDS) == null + && rhs.getField(DatatypeConstants.SECONDS) == null) ? null : sanitize(buf[5], s)); + } + + private static void alignSigns(BigDecimal[] buf, int start, int end) { + // align sign + boolean touched; + + do { // repeat until all the sign bits become consistent + touched = false; + int s = 0; // sign of the left fields + + for (int i = start; i < end; i++) { + if (s * buf[i].signum() < 0) { + // this field has different sign than its left field. + touched = true; + + // compute the number of unit that needs to be borrowed. + BigDecimal borrow = + buf[i].abs().divide( + FACTORS[i - 1], + BigDecimal.ROUND_UP); + if (buf[i].signum() > 0) { + borrow = borrow.negate(); + } + + // update values + buf[i - 1] = buf[i - 1].subtract(borrow); + buf[i] = buf[i].add(borrow.multiply(FACTORS[i - 1])); + } + if (buf[i].signum() != 0) { + s = buf[i].signum(); + } + } + } while (touched); + } + + /** + * Compute value*signum where value==null is treated as + * value==0. + * @param value Value to sanitize. + * @param signum 0 to sanitize to 0, > 0 to sanitize to value, < 0 to sanitize to negative value. + * + * @return non-null {@link BigDecimal}. + */ + private static BigDecimal sanitize(BigInteger value, int signum) { + if (signum == 0 || value == null) { + return ZERO; + } + if (signum > 0) { + return new BigDecimal(value); + } + return new BigDecimal(value.negate()); + } + + /** + *

    Compute value*signum where value==null is treated as value==0

    . + * + * @param value Value to sanitize. + * @param signum 0 to sanitize to 0, > 0 to sanitize to value, < 0 to sanitize to negative value. + * + * @return non-null {@link BigDecimal}. + */ + static BigDecimal sanitize(BigDecimal value, int signum) { + if (signum == 0 || value == null) { + return ZERO; + } + if (signum > 0) { + return value; + } + return value.negate(); + } + + /** + *

    Computes a new duration whose value is this-rhs.

    + * + *

    For example:

    + *
    +     * "1 day" - "-3 days" = "4 days"
    +     * "1 year" - "1 day" = IllegalStateException
    +     * "-(1 hour,50 minutes)" - "-20 minutes" = "-(1hours,30 minutes)"
    +     * "15 hours" - "-3 days" = "3 days and 15 hours"
    +     * "1 year" - "-1 day" = "1 year and 1 day"
    +     * 
    + * + *

    Since there's no way to meaningfully subtract 1 day from 1 month, + * there are cases where the operation fails in {@link IllegalStateException}.

    + * + *

    Formally the computation is defined as follows. + * First, we can assume that two {@link Duration}s are both positive + * without losing generality. (i.e., + * (-X)-Y=-(X+Y), X-(-Y)=X+Y, + * (-X)-(-Y)=-(X-Y))

    + * + *

    Then two durations are subtracted field by field. + * If the sign of any non-zero field F is different from + * the sign of the most significant field, + * 1 (if F is negative) or -1 (otherwise) + * will be borrowed from the next bigger unit of F.

    + * + *

    This process is repeated until all the non-zero fields have + * the same sign.

    + * + *

    If a borrow occurs in the days field (in other words, if + * the computation needs to borrow 1 or -1 month to compensate + * days), then the computation fails by throwing an + * {@link IllegalStateException}.

    + * + * @param rhs Duration to substract from this Duration. + * + * @return New Duration created from subtracting rhs from this Duration. + * + * @throws IllegalStateException + * If two durations cannot be meaningfully subtracted. For + * example, subtracting one day from one month causes + * this exception. + * + * @throws NullPointerException + * If the rhs parameter is null. + * + * @see #add(Duration) + */ + public Duration subtract(final Duration rhs) { + return add(rhs.negate()); + } + + /** + * Returns a new {@link Duration} object whose + * value is -this. + * + *

    + * Since the {@link Duration} class is immutable, this method + * doesn't change the value of this object. It simply computes + * a new Duration object and returns it. + * + * @return + * always return a non-null valid {@link Duration} object. + */ + public Duration negate() { + return new DurationImpl( + signum <= 0, + years, + months, + days, + hours, + minutes, + seconds); + } + + /** + * Returns the sign of this duration in -1,0, or 1. + * + * @return + * -1 if this duration is negative, 0 if the duration is zero, + * and 1 if the duration is postive. + */ + public int signum() { + return signum; + } + + + /** + * Adds this duration to a {@link Calendar} object. + * + *

    + * Calls {@link java.util.Calendar#add(int,int)} in the + * order of YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, and MILLISECONDS + * if those fields are present. Because the {@link Calendar} class + * uses int to hold values, there are cases where this method + * won't work correctly (for example if values of fields + * exceed the range of int.) + *

    + * + *

    + * Also, since this duration class is a Gregorian duration, this + * method will not work correctly if the given {@link Calendar} + * object is based on some other calendar systems. + *

    + * + *

    + * Any fractional parts of this {@link Duration} object + * beyond milliseconds will be simply ignored. For example, if + * this duration is "P1.23456S", then 1 is added to SECONDS, + * 234 is added to MILLISECONDS, and the rest will be unused. + *

    + * + *

    + * Note that because {@link Calendar#add(int, int)} is using + * int, {@link Duration} with values beyond the + * range of int in its fields + * will cause overflow/underflow to the given {@link Calendar}. + * {@link XMLGregorianCalendar#add(Duration)} provides the same + * basic operation as this method while avoiding + * the overflow/underflow issues. + * + * @param calendar + * A calendar object whose value will be modified. + * @throws NullPointerException + * if the calendar parameter is null. + */ + public void addTo(Calendar calendar) { + calendar.add(Calendar.YEAR, getYears() * signum); + calendar.add(Calendar.MONTH, getMonths() * signum); + calendar.add(Calendar.DAY_OF_MONTH, getDays() * signum); + calendar.add(Calendar.HOUR, getHours() * signum); + calendar.add(Calendar.MINUTE, getMinutes() * signum); + calendar.add(Calendar.SECOND, getSeconds() * signum); + + if (seconds != null) { + BigDecimal fraction = + seconds.subtract(seconds.setScale(0, BigDecimal.ROUND_DOWN)); + int millisec = fraction.movePointRight(3).intValue(); + calendar.add(Calendar.MILLISECOND, millisec * signum); + } + } + + /** + * Adds this duration to a {@link Date} object. + * + *

    + * The given date is first converted into + * a {@link java.util.GregorianCalendar}, then the duration + * is added exactly like the {@link #addTo(Calendar)} method. + * + *

    + * The updated time instant is then converted back into a + * {@link Date} object and used to update the given {@link Date} object. + * + *

    + * This somewhat redundant computation is necessary to unambiguously + * determine the duration of months and years. + * + * @param date + * A date object whose value will be modified. + * @throws NullPointerException + * if the date parameter is null. + */ + public void addTo(Date date) { + Calendar cal = new GregorianCalendar(); + cal.setTime(date); // this will throw NPE if date==null + this.addTo(cal); + date.setTime(getCalendarTimeInMillis(cal)); + } + + /** + * Calls the {@link Calendar#getTimeInMillis} method. + * Prior to JDK1.4, this method was protected and therefore + * cannot be invoked directly. + * + * In future, this should be replaced by + * cal.getTimeInMillis() + */ + private static long getCalendarTimeInMillis(Calendar cal) { + return cal.getTime().getTime(); + } + + /** + * Writes {@link Duration} as a lexical representation + * for maximum future compatibility. + * + * @return + * An object that encapsulates the string + * returned by this.toString(). + */ + private Object writeReplace() throws IOException { + return new SerializedDuration(toString()); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/SerializedDuration.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/SerializedDuration.java new file mode 100644 index 0000000..9a5e035 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/SerializedDuration.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.datatype; + +import java.io.ObjectStreamException; +import java.io.Serializable; + +/** + *

    Serialized form of javax.xml.datatype.Duration.

    + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class SerializedDuration implements Serializable { + + private static final long serialVersionUID = 3897193592341225793L; + private final String lexicalValue; + + public SerializedDuration(String lexicalValue) { + this.lexicalValue = lexicalValue; + } + + private Object readResolve() throws ObjectStreamException { + return new DatatypeFactoryImpl().newDuration(lexicalValue); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/SerializedXMLGregorianCalendar.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/SerializedXMLGregorianCalendar.java new file mode 100644 index 0000000..f843d2c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/SerializedXMLGregorianCalendar.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.datatype; + +import java.io.ObjectStreamException; +import java.io.Serializable; + +/** + *

    Serialized form of javax.xml.datatype.XMLGregorianCalendar.

    + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class SerializedXMLGregorianCalendar implements Serializable { + + private static final long serialVersionUID = -7752272381890705397L; + private final String lexicalValue; + + public SerializedXMLGregorianCalendar(String lexicalValue) { + this.lexicalValue = lexicalValue; + } + + private Object readResolve() throws ObjectStreamException { + return new DatatypeFactoryImpl().newXMLGregorianCalendar(lexicalValue); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/XMLGregorianCalendarImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/XMLGregorianCalendarImpl.java new file mode 100644 index 0000000..47f6983 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/XMLGregorianCalendarImpl.java @@ -0,0 +1,3193 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.datatype; + +import java.io.IOException; +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.namespace.QName; + +import org.apache.xerces.util.DatatypeMessageFormatter; + +/** + *

    Representation for W3C XML Schema 1.0 date/time datatypes. + * Specifically, these date/time datatypes are + * {@link DatatypeConstants#DATETIME dateTime}, + * {@link DatatypeConstants#TIME time}, + * {@link DatatypeConstants#DATE date}, + * {@link DatatypeConstants#GYEARMONTH gYearMonth}, + * {@link DatatypeConstants#GMONTHDAY gMonthDay}, + * {@link DatatypeConstants#GYEAR gYear}, + * {@link DatatypeConstants#GMONTH gMonth} and + * {@link DatatypeConstants#GDAY gDay} + * defined in the XML Namespace + * "http://www.w3.org/2001/XMLSchema". + * These datatypes are normatively defined in + * W3C XML Schema 1.0 Part 2, Section 3.2.7-14.

    + * + *

    The table below defines the mapping between XML Schema 1.0 + * date/time datatype fields and this class' fields. It also summarizes + * the value constraints for the date and time fields defined in + * W3C XML Schema 1.0 Part 2, Appendix D, + * ISO 8601 Date and Time Formats.

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    + * Date/time datatype field mapping between XML Schema 1.0 and Java representation + *
    XML Schema 1.0
    + * datatype
    + * field
    Related
    XMLGregorianCalendar
    Accessor(s)
    Value Range
    year {@link #getYear()} + {@link #getEon()} or
    + * {@link #getEonAndYear} + *
    getYear() is a value between -(10^9-1) to (10^9)-1 + * or {@link DatatypeConstants#FIELD_UNDEFINED}.
    + * {@link #getEon()} is high order year value in billion of years.
    + * getEon() has values greater than or equal to (10^9) or less than or equal to -(10^9). + * A value of null indicates field is undefined.
    + * Given that XML Schema 1.0 errata states that the year zero + * will be a valid lexical value in a future version of XML Schema, + * this class allows the year field to be set to zero. Otherwise, + * the year field value is handled exactly as described + * in the errata and [ISO-8601-1988]. Note that W3C XML Schema 1.0 + * validation does not allow for the year field to have a value of zero. + *
    month {@link #getMonth()} 1 to 12 or {@link DatatypeConstants#FIELD_UNDEFINED}
    day {@link #getDay()} Independent of month, max range is 1 to 31 or {@link DatatypeConstants#FIELD_UNDEFINED}.
    + * The normative value constraint stated relative to month + * field's value is in W3C XML Schema 1.0 Part 2, Appendix D. + *
    hour {@link #getHour()} + * 0 to 24 or {@link DatatypeConstants#FIELD_UNDEFINED} + * For a value of 24, the minute and second field must be zero. + *
    minute {@link #getMinute()} 0 to 59 or {@link DatatypeConstants#FIELD_UNDEFINED}
    second + * {@link #getSecond()} + {@link #getMillisecond()}/1000 or
    + * {@link #getSecond()} + {@link #getFractionalSecond()} + *
    + * {@link #getSecond()} from 0 to 60 or {@link DatatypeConstants#FIELD_UNDEFINED}.
    + * (Note: 60 only allowable for leap second.)
    + * {@link #getFractionalSecond()} allows for infinite precision over the range from 0.0 to 1.0 when + * the {@link #getSecond()} is defined.
    + * FractionalSecond is optional and has a value of null when it is undefined.
    + * {@link #getMillisecond()} is the convenience + * millisecond precision of value of {@link #getFractionalSecond()}. + *
    timezone {@link #getTimezone()} Number of minutes or {@link DatatypeConstants#FIELD_UNDEFINED}. + * Value range from -14 hours (-14 * 60 minutes) to 14 hours (14 * 60 minutes). + *
    + * + *

    All maximum value space constraints listed for the fields in the table + * above are checked by factory methods, setter methods and parse methods of + * this class. IllegalArgumentException is thrown when + * parameter's value is outside the maximum value constraint for the field. + * Validation checks, for example, whether days in month should be + * limited to 29, 30 or 31 days, that are dependent on the values of other + * fields are not checked by these methods. + *

    + * + *

    The following operations are defined for this class: + *

    + *

    + * + * @author Kohsuke Kawaguchi + * @author Joseph Fialli + * @version $Id$ + * @see javax.xml.datatype.Duration + */ +class XMLGregorianCalendarImpl + extends XMLGregorianCalendar + implements Serializable, Cloneable { + + /** + *

    Stream Unique Identifier.

    + */ + private static final long serialVersionUID = 3905403108073447394L; + + /** Backup values **/ + private BigInteger orig_eon; + private int orig_year = DatatypeConstants.FIELD_UNDEFINED; + private int orig_month = DatatypeConstants.FIELD_UNDEFINED; + private int orig_day = DatatypeConstants.FIELD_UNDEFINED; + private int orig_hour = DatatypeConstants.FIELD_UNDEFINED; + private int orig_minute = DatatypeConstants.FIELD_UNDEFINED; + private int orig_second = DatatypeConstants.FIELD_UNDEFINED; + private BigDecimal orig_fracSeconds; + private int orig_timezone = DatatypeConstants.FIELD_UNDEFINED; + + /** + *

    Eon of this XMLGregorianCalendar.

    + */ + private BigInteger eon = null; + + /** + *

    Year of this XMLGregorianCalendar.

    + */ + private int year = DatatypeConstants.FIELD_UNDEFINED; + + /** + *

    Month of this XMLGregorianCalendar.

    + */ + private int month = DatatypeConstants.FIELD_UNDEFINED; + + /** + *

    Day of this XMLGregorianCalendar.

    + */ + private int day = DatatypeConstants.FIELD_UNDEFINED; + + /** + *

    Timezone of this XMLGregorianCalendar in minutes.

    + */ + private int timezone = DatatypeConstants.FIELD_UNDEFINED; + + /** + *

    Hour of this XMLGregorianCalendar.

    + */ + private int hour = DatatypeConstants.FIELD_UNDEFINED; + + /** + *

    Minute of this XMLGregorianCalendar.

    + */ + private int minute = DatatypeConstants.FIELD_UNDEFINED; + + /** + *

    Second of this XMLGregorianCalendar.

    + */ + private int second = DatatypeConstants.FIELD_UNDEFINED ; + + /** + *

    Fractional second of this XMLGregorianCalendar.

    + */ + private BigDecimal fractionalSecond = null; + + /** + *

    BigInteger constant; representing a billion.

    + */ + private static final BigInteger BILLION_B = BigInteger.valueOf(1000000000); + + /** + *

    int constant; representing a billion.

    + */ + private static final int BILLION_I = 1000000000; + + /** + *

    Obtain a pure Gregorian Calendar by calling + * GregorianCalendar.setChange(PURE_GREGORIAN_CHANGE).

    + */ + private static final Date PURE_GREGORIAN_CHANGE = new Date(Long.MIN_VALUE); + + /** + * Year index for MIN_ and MAX_FIELD_VALUES. + */ + private static final int YEAR = 0; + + /** + * Month index for MIN_ and MAX_FIELD_VALUES. + */ + private static final int MONTH = 1; + + /** + * Day index for MIN_ and MAX_FIELD_VALUES. + */ + private static final int DAY = 2; + + /** + * Hour index for MIN_ and MAX_FIELD_VALUES. + */ + private static final int HOUR = 3; + + /** + * Minute index for MIN_ and MAX_FIELD_VALUES. + */ + private static final int MINUTE = 4; + + /** + * Second index for MIN_ and MAX_FIELD_VALUES. + */ + private static final int SECOND = 5; + + /** + * Second index for MIN_ and MAX_FIELD_VALUES. + */ + private static final int MILLISECOND = 6; + + /** + * Timezone index for MIN_ and MAX_FIELD_VALUES + */ + private static final int TIMEZONE = 7; + + /** + * Minimum field values indexed by YEAR..TIMEZONE. + */ + private static final int MIN_FIELD_VALUE[] = { + Integer.MIN_VALUE, //Year field can be smaller than this, + // only constraint on integer value of year. + DatatypeConstants.JANUARY, + 1, //day of month + 0, //hour + 0, //minute + 0, //second + 0, //millisecond + -14 * 60 //timezone + }; + + /** + * Maximum field values indexed by YEAR..TIMEZONE. + */ + private static final int MAX_FIELD_VALUE[] = { + Integer.MAX_VALUE, // Year field can be bigger than this, + // only constraint on integer value of year. + DatatypeConstants.DECEMBER, + 31, //day of month + 24, //hour + 59, //minute + 60, //second (leap second allows for 60) + 999, //millisecond + 14 * 60 //timezone + }; + + /** + * field names indexed by YEAR..TIMEZONE. + */ + private static final String FIELD_NAME[] = { + "Year", + "Month", + "Day", + "Hour", + "Minute", + "Second", + "Millisecond", + "Timezone" + }; + + /** + *

    Use as a template for default field values when + * converting to a {@link GregorianCalendar}, set to a leap + * year date of January 1, 0400 at midnight.

    + * + *

    Fields that are optional for an xsd:dateTime instances are defaulted to not being set to any value. + * XMLGregorianCalendar fields millisecond, fractional second and timezone return the value indicating + * that the field is not set, {@link DatatypeConstants#FIELD_UNDEFINED} for millisecond and timezone + * and null for fractional second.

    + * + * @see #toGregorianCalendar(TimeZone, Locale, XMLGregorianCalendar) + */ + public static final XMLGregorianCalendar LEAP_YEAR_DEFAULT = + createDateTime( + 400, //year + DatatypeConstants.JANUARY, //month + 1, // day + 0, // hour + 0, // minute + 0, // second + DatatypeConstants.FIELD_UNDEFINED, // milliseconds + DatatypeConstants.FIELD_UNDEFINED // timezone + ); + + // Constructors + + /** + * Constructs a new XMLGregorianCalendar object. + * + * String parsing documented by {@link #parse(String)}. + * + * Returns a non-null valid XMLGregorianCalendar object that holds the + * value indicated by the lexicalRepresentation parameter. + * + * @param lexicalRepresentation + * Lexical representation of one the eight + * XML Schema date/time datatypes. + * @throws IllegalArgumentException + * If the given string does not conform as documented in + * {@link #parse(String)}. + * @throws NullPointerException + * If the given string is null. + */ + protected XMLGregorianCalendarImpl(String lexicalRepresentation) + throws IllegalArgumentException { + + // compute format string for this lexical representation. + String format = null; + String lexRep = lexicalRepresentation; + final int NOT_FOUND = -1; + int lexRepLength = lexRep.length(); + + // current parser needs a format string, + // use following heuristics to figure out what xml schema date/time + // datatype this lexical string could represent. + if (lexRep.indexOf('T') != NOT_FOUND) { + // found Date Time separater, must be xsd:DateTime + format = "%Y-%M-%DT%h:%m:%s" + "%z"; + } + else if (lexRepLength >= 3 && lexRep.charAt(2) == ':') { + // found ":", must be xsd:Time + format = "%h:%m:%s" +"%z"; + } + else if (lexRep.startsWith("--")) { + // check for GDay || GMonth || GMonthDay + if (lexRepLength >= 3 && lexRep.charAt(2) == '-') { + // GDAY + // Fix 4971612: invalid SCCS macro substitution in data string + format = "---%D" + "%z"; + } + else if (lexRepLength == 4 || (lexRepLength >= 6 && (lexRep.charAt(4) == '+' || (lexRep.charAt(4) == '-' && (lexRep.charAt(5) == '-' || lexRepLength == 10))))) { + // GMonth + // Fix 4971612: invalid SCCS macro substitution in data string + format = "--%M--%z"; + Parser p = new Parser(format, lexRep); + try { + p.parse(); + // check for validity + if (!isValid()) { + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null,"InvalidXGCRepresentation", new Object[]{lexicalRepresentation}) + //"\"" + lexicalRepresentation + "\" is not a valid representation of an XML Gregorian Calendar value." + ); + } + save(); + return; + } + catch(IllegalArgumentException e) { + format = "--%M%z"; + } + } + else { + // GMonthDay or invalid lexicalRepresentation + format = "--%M-%D" + "%z"; + } + } + else { + // check for Date || GYear | GYearMonth + int countSeparator = 0; + + // start at index 1 to skip potential negative sign for year. + + + int timezoneOffset = lexRep.indexOf(':'); + if (timezoneOffset != NOT_FOUND) { + + // found timezone, strip it off for distinguishing + // between Date, GYear and GYearMonth so possible + // negative sign in timezone is not mistaken as + // a separator. + lexRepLength -= 6; + } + + for (int i=1; i < lexRepLength; i++) { + if (lexRep.charAt(i) == '-') { + countSeparator++; + } + } + if (countSeparator == 0) { + // GYear + format = "%Y" + "%z"; + } + else if (countSeparator == 1) { + // GYearMonth + format = "%Y-%M" + "%z"; + } + else { + // Date or invalid lexicalRepresentation + // Fix 4971612: invalid SCCS macro substitution in data string + format = "%Y-%M-%D" + "%z"; + } + } + Parser p = new Parser(format, lexRep); + p.parse(); + + // check for validity + if (!isValid()) { + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null,"InvalidXGCRepresentation", new Object[]{lexicalRepresentation}) + //"\"" + lexicalRepresentation + "\" is not a valid representation of an XML Gregorian Calendar value." + ); + } + save(); + } + + /** + * + */ + private void save() { + orig_eon = eon; + orig_year = year; + orig_month = month; + orig_day = day; + orig_hour = hour; + orig_minute = minute; + orig_second = second; + orig_fracSeconds = fractionalSecond; + orig_timezone = timezone; + } + + /** + *

    Create an instance with all date/time datatype fields set to + * {@link DatatypeConstants#FIELD_UNDEFINED} or null respectively.

    + */ + public XMLGregorianCalendarImpl() { + + // field initializers already do the correct initialization. + } + + /** + *

    Private constructor allowing for complete value spaces allowed by + * W3C XML Schema 1.0 recommendation for xsd:dateTime and related + * builtin datatypes. Note that year parameter supports + * arbitrarily large numbers and fractionalSecond has infinite + * precision.

    + * + * @param year of XMLGregorianCalendar to be created. + * @param month of XMLGregorianCalendar to be created. + * @param day of XMLGregorianCalendar to be created. + * @param hour of XMLGregorianCalendar to be created. + * @param minute of XMLGregorianCalendar to be created. + * @param second of XMLGregorianCalendar to be created. + * @param fractionalSecond of XMLGregorianCalendar to be created. + * @param timezone of XMLGregorianCalendar to be created. + * + */ + protected XMLGregorianCalendarImpl( + BigInteger year, + int month, + int day, + int hour, + int minute, + int second, + BigDecimal fractionalSecond, + int timezone) { + + setYear(year); + setMonth(month); + setDay(day); + setTime(hour, minute, second, fractionalSecond); + setTimezone(timezone); + + // check for validity + if (!isValid()) { + + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null, + "InvalidXGCValue-fractional", + new Object[] { year, new Integer(month), new Integer(day), + new Integer(hour), new Integer(minute), new Integer(second), + fractionalSecond, new Integer(timezone)}) + ); + + /** + String yearString = "null"; + if (year != null) { + yearString = year.toString(); + } + String fractionalSecondString = "null"; + if (fractionalSecond != null) { + fractionalSecondString = fractionalSecond.toString(); + } + + throw new IllegalArgumentException( + "year = " + yearString + + ", month = " + month + + ", day = " + day + + ", hour = " + hour + + ", minute = " + minute + + ", second = " + second + + ", fractionalSecond = " + fractionalSecondString + + ", timezone = " + timezone + + ", is not a valid representation of an XML Gregorian Calendar value." + ); + */ + + } + + save(); + + } + + /** + *

    Private constructor of value spaces that a + * java.util.GregorianCalendar instance would need to convert to an + * XMLGregorianCalendar instance.

    + * + *

    XMLGregorianCalendar eon and + * fractionalSecond are set to null

    + * + * @param year of XMLGregorianCalendar to be created. + * @param month of XMLGregorianCalendar to be created. + * @param day of XMLGregorianCalendar to be created. + * @param hour of XMLGregorianCalendar to be created. + * @param minute of XMLGregorianCalendar to be created. + * @param second of XMLGregorianCalendar to be created. + * @param millisecond of XMLGregorianCalendar to be created. + * @param timezone of XMLGregorianCalendar to be created. + */ + private XMLGregorianCalendarImpl( + int year, + int month, + int day, + int hour, + int minute, + int second, + int millisecond, + int timezone) { + + setYear(year); + setMonth(month); + setDay(day); + setTime(hour, minute, second); + setTimezone(timezone); + BigDecimal realMilliseconds = null; + if (millisecond != DatatypeConstants.FIELD_UNDEFINED) { + realMilliseconds = BigDecimal.valueOf(millisecond, 3); + } + setFractionalSecond(realMilliseconds); + + if (!isValid()) { + + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null, + "InvalidXGCValue-milli", + new Object[] { new Integer(year), new Integer(month), new Integer(day), + new Integer(hour), new Integer(minute), new Integer(second), + new Integer(millisecond), new Integer(timezone)}) + ); + /* + throw new IllegalArgumentException( + "year = " + year + + ", month = " + month + + ", day = " + day + + ", hour = " + hour + + ", minute = " + minute + + ", second = " + second + + ", millisecond = " + millisecond + + ", timezone = " + timezone + + ", is not a valid representation of an XML Gregorian Calendar value." + ); + */ + + } + save(); + } + + /** + *

    Convert a java.util.GregorianCalendar to XML Schema 1.0 + * representation.

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    + * Field by Field Conversion from + * java.util.GregorianCalendar to this class + *
    javax.xml.datatype.XMLGregorianCalendar fieldjava.util.GregorianCalendar field
    {@link #setYear(int)}ERA == GregorianCalendar.BC ? -YEAR : YEAR
    {@link #setMonth(int)}MONTH + 1
    {@link #setDay(int)}DAY_OF_MONTH
    {@link #setTime(int,int,int, BigDecimal)}HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND
    {@link #setTimezone(int)}*(ZONE_OFFSET + DST_OFFSET) / (60*1000)
    + * (in minutes) + *
    + *

    *conversion loss of information. It is not possible to represent + * a java.util.GregorianCalendar daylight savings timezone id in the + * XML Schema 1.0 date/time datatype representation.

    + * + *

    To compute the return value's TimeZone field, + *

      + *
    • when this.getTimezone() != DatatypeConstants.FIELD_UNDEFINED, + * create a java.util.TimeZone with a custom timezone id + * using the this.getTimezone().
    • + *
    • else use the GregorianCalendar default timezone value + * for the host is defined as specified by + * java.util.TimeZone.getDefault().
    • + * + * @param cal java.util.GregorianCalendar used to create XMLGregorianCalendar + */ + public XMLGregorianCalendarImpl(GregorianCalendar cal) { + + int year = cal.get(Calendar.YEAR); + if (cal.get(Calendar.ERA) == GregorianCalendar.BC) { + year = -year; + } + this.setYear(year); + + // Calendar.MONTH is zero based, XSD Date datatype's month field starts + // with JANUARY as 1. + this.setMonth(cal.get(Calendar.MONTH) + 1); + this.setDay(cal.get(Calendar.DAY_OF_MONTH)); + this.setTime( + cal.get(Calendar.HOUR_OF_DAY), + cal.get(Calendar.MINUTE), + cal.get(Calendar.SECOND), + cal.get(Calendar.MILLISECOND)); + + // Calendar ZONE_OFFSET and DST_OFFSET fields are in milliseconds. + int offsetInMinutes = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000); + this.setTimezone(offsetInMinutes); + save(); + } + + // Factories + + /** + *

      Create a Java representation of XML Schema builtin datatype dateTime. + * All possible fields are specified for this factory method.

      + * + * @param year represents both high-order eons and low-order year. + * @param month of dateTime + * @param day of dateTime + * @param hours of dateTime + * @param minutes of dateTime + * @param seconds of dateTime + * @param fractionalSecond value of null indicates optional field is absent. + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException if any parameter is outside value + * constraints for the field as specified in + * date/time field mapping table. + */ + public static XMLGregorianCalendar createDateTime( + BigInteger year, + int month, + int day, + int hours, + int minutes, + int seconds, + BigDecimal fractionalSecond, + int timezone) { + + return new XMLGregorianCalendarImpl( + year, + month, + day, + hours, + minutes, + seconds, + fractionalSecond, + timezone); + } + + /** + *

      Create a Java instance of XML Schema builtin datatype dateTime.

      + * + * @param year represents both high-order eons and low-order year. + * @param month of dateTime + * @param day of dateTime + * @param hour of dateTime + * @param minute of dateTime + * @param second of dateTime + * + * @return XMLGregorianCalendar created from parameter values. + * + * @throws IllegalArgumentException if any parameter is outside value constraints for the field as specified in + * date/time field mapping table. + * + * @see DatatypeConstants#FIELD_UNDEFINED + */ + public static XMLGregorianCalendar createDateTime( + int year, + int month, + int day, + int hour, + int minute, + int second) { + + return new XMLGregorianCalendarImpl( + year, + month, + day, + hour, + minute, + second, + DatatypeConstants.FIELD_UNDEFINED, //millisecond + DatatypeConstants.FIELD_UNDEFINED //timezone + ); + } + + /** + *

      Create a Java representation of XML Schema builtin datatype dateTime. + * All possible fields are specified for this factory method.

      + * + * @param year represents low-order year. + * @param month of dateTime + * @param day of dateTime + * @param hours of dateTime + * @param minutes of dateTime + * @param seconds of dateTime + * @param milliseconds of dateTime. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @throws IllegalArgumentException if any parameter is outside value constraints for the field as specified in + * date/time field mapping table. + * + * @see DatatypeConstants#FIELD_UNDEFINED + */ + public static XMLGregorianCalendar createDateTime( + int year, + int month, + int day, + int hours, + int minutes, + int seconds, + int milliseconds, + int timezone) { + + return new XMLGregorianCalendarImpl( + year, + month, + day, + hours, + minutes, + seconds, + milliseconds, + timezone); + } + + /** + *

      Create a Java representation of XML Schema builtin datatype date or g*.

      + * + *

      For example, an instance of gYear can be created invoking this factory + * with month and day parameters set to + * {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + * @param year of XMLGregorianCalendar to be created. + * @param month of XMLGregorianCalendar to be created. + * @param day of XMLGregorianCalendar to be created. + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException if any parameter is outside value + * constraints for the field as specified in + * date/time field mapping table. + */ + public static XMLGregorianCalendar createDate( + int year, + int month, + int day, + int timezone) { + + return new XMLGregorianCalendarImpl( + year, + month, + day, + DatatypeConstants.FIELD_UNDEFINED, // hour + DatatypeConstants.FIELD_UNDEFINED, // minute + DatatypeConstants.FIELD_UNDEFINED, // second + DatatypeConstants.FIELD_UNDEFINED, // millisecond + timezone); + } + + /** + * Create a Java instance of XML Schema builtin datatype time. + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException if any parameter is outside value + * constraints for the field as specified in + * date/time field mapping table. + */ + public static XMLGregorianCalendar createTime( + int hours, + int minutes, + int seconds, + int timezone) { + + return new XMLGregorianCalendarImpl( + DatatypeConstants.FIELD_UNDEFINED, // Year + DatatypeConstants.FIELD_UNDEFINED, // Month + DatatypeConstants.FIELD_UNDEFINED, // Day + hours, + minutes, + seconds, + DatatypeConstants.FIELD_UNDEFINED, //Millisecond + timezone); + } + + /** + *

      Create a Java instance of XML Schema builtin datatype time.

      + * + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param fractionalSecond value of null indicates that this optional field is not set. + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException if any parameter is outside value + * constraints for the field as specified in + * date/time field mapping table. + */ + public static XMLGregorianCalendar createTime( + int hours, + int minutes, + int seconds, + BigDecimal fractionalSecond, + int timezone) { + + return new XMLGregorianCalendarImpl( + null, // Year + DatatypeConstants.FIELD_UNDEFINED, // month + DatatypeConstants.FIELD_UNDEFINED, // day + hours, + minutes, + seconds, + fractionalSecond, + timezone); + } + + /** + *

      Create a Java instance of XML Schema builtin datatype time.

      + * + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param milliseconds number of milliseconds + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException if any parameter is outside value + * constraints for the field as specified in + * date/time field mapping table. + */ + public static XMLGregorianCalendar createTime( + int hours, + int minutes, + int seconds, + int milliseconds, + int timezone) { + + return new XMLGregorianCalendarImpl( + DatatypeConstants.FIELD_UNDEFINED, // year + DatatypeConstants.FIELD_UNDEFINED, // month + DatatypeConstants.FIELD_UNDEFINED, // day + hours, + minutes, + seconds, + milliseconds, + timezone); + } + + // Accessors + + /** + *

      Return high order component for XML Schema 1.0 dateTime datatype field for + * year. + * null if this optional part of the year field is not defined.

      + * + *

      Value constraints for this value are summarized in + * year field of date/time field mapping table.

      + * @return eon of this XMLGregorianCalendar. The value + * returned is an integer multiple of 10^9. + * + * @see #getYear() + * @see #getEonAndYear() + */ + public BigInteger getEon() { + return eon; + } + + /** + *

      Return low order component for XML Schema 1.0 dateTime datatype field for + * year or {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + *

      Value constraints for this value are summarized in + * year field of date/time field mapping table.

      + * + * @return year of this XMLGregorianCalendar. + * + * @see #getEon() + * @see #getEonAndYear() + */ + public int getYear() { + return year; + } + + /** + *

      Return XML Schema 1.0 dateTime datatype field for + * year.

      + * + *

      Value constraints for this value are summarized in + * year field of date/time field mapping table.

      + * + * @return sum of eon and BigInteger.valueOf(year) + * when both fields are defined. When only year is defined, + * return it. When both eon and year are not + * defined, return null. + * + * @see #getEon() + * @see #getYear() + */ + public BigInteger getEonAndYear() { + + // both are defined + if (year != DatatypeConstants.FIELD_UNDEFINED + && eon != null) { + + return eon.add(BigInteger.valueOf((long) year)); + } + + // only year is defined + if (year != DatatypeConstants.FIELD_UNDEFINED + && eon == null) { + + return BigInteger.valueOf((long) year); + } + + // neither are defined + // or only eon is defined which is not valid without a year + return null; + } + + /** + *

      Return number of month or {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + *

      Value constraints for this value are summarized in + * month field of date/time field mapping table.

      + * + * @return year of this XMLGregorianCalendar. + * + */ + public int getMonth() { + return month; + } + + /** + * Return day in month or {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + *

      Value constraints for this value are summarized in + * day field of date/time field mapping table.

      + * + * @see #setDay(int) + */ + public int getDay() { + return day; + } + + /** + * Return timezone offset in minutes or + * {@link DatatypeConstants#FIELD_UNDEFINED} if this optional field is not defined. + * + *

      Value constraints for this value are summarized in + * timezone field of date/time field mapping table.

      + * + * @see #setTimezone(int) + */ + public int getTimezone() { + return timezone; + } + + /** + * Return hours or {@link DatatypeConstants#FIELD_UNDEFINED}. + * Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined. + * + *

      Value constraints for this value are summarized in + * hour field of date/time field mapping table.

      + * @see #setTime(int, int, int) + */ + public int getHour() { + return hour; + } + + /** + * Return minutes or {@link DatatypeConstants#FIELD_UNDEFINED}.<\p> + * Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined. + * + *

      Value constraints for this value are summarized in + * minute field of date/time field mapping table.

      + * @see #setTime(int, int, int) + */ + public int getMinute() { + return minute; + } + + /** + *

      Return seconds or {@link DatatypeConstants#FIELD_UNDEFINED}.<\p> + * + *

      Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined. + * When this field is not defined, the optional xs:dateTime + * fractional seconds field, represented by + * {@link #getFractionalSecond()} and {@link #getMillisecond()}, + * must not be defined.

      + * + *

      Value constraints for this value are summarized in + * second field of date/time field mapping table.

      + * + * @return Second of this XMLGregorianCalendar. + * + * @see #getFractionalSecond() + * @see #getMillisecond() + * @see #setTime(int, int, int) + */ + public int getSecond() { + return second; + } + + /** + * @return result of adding second and fractional second field + */ + private BigDecimal getSeconds() { + + if (second == DatatypeConstants.FIELD_UNDEFINED) { + return DECIMAL_ZERO; + } + BigDecimal result = BigDecimal.valueOf((long)second); + if (fractionalSecond != null){ + return result.add(fractionalSecond); + } + else { + return result; + } + } + + /** + *

      Return millisecond precision of {@link #getFractionalSecond()}.<\p> + * + *

      This method represents a convenience accessor to infinite + * precision fractional second value returned by + * {@link #getFractionalSecond()}. The returned value is the rounded + * down to milliseconds value of + * {@link #getFractionalSecond()}. When {@link #getFractionalSecond()} + * returns null, this method must return + * {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + *

      Value constraints for this value are summarized in + * second field of date/time field mapping table.

      + * + * @return Millisecond of this XMLGregorianCalendar. + * + * @see #getFractionalSecond() + * @see #setTime(int, int, int) + */ + public int getMillisecond() { + if (fractionalSecond == null) { + return DatatypeConstants.FIELD_UNDEFINED; + } + else { + // TODO: Non-optimal solution for now. + // Efficient implementation would only store as BigDecimal + // when needed and millisecond otherwise. + return fractionalSecond.movePointRight(3).intValue(); + } + } + + /** + *

      Return fractional seconds.

      + * + *

      null is returned when this optional field is not defined.

      + * + *

      Value constraints are detailed in + * second field of date/time field mapping table.

      + * + *

      This optional field can only have a defined value when the + * xs:dateTime second field, represented by ({@link #getSecond()}, + * does not return {@link DatatypeConstants#FIELD_UNDEFINED}).

      + * + * @return fractional seconds of this XMLGregorianCalendar. + * + * @see #getSecond() + * @see #setTime(int, int, int, BigDecimal) + */ + public BigDecimal getFractionalSecond() { + return fractionalSecond; + } + + // setters + + /** + *

      Set low and high order component of XSD dateTime year field.

      + * + *

      Unset this field by invoking the setter with a parameter value of null.

      + * + * @param year value constraints summarized in year field of date/time field mapping table. + * + * @throws IllegalArgumentException if year parameter is + * outside value constraints for the field as specified in + * date/time field mapping table. + */ + public void setYear(BigInteger year) { + if (year == null) { + this.eon = null; + this.year = DatatypeConstants.FIELD_UNDEFINED; + } + else { + BigInteger temp = year.remainder(BILLION_B); + this.year = temp.intValue(); + setEon(year.subtract(temp)); + } + } + + /** + *

      Set year of XSD dateTime year field.

      + * + *

      Unset this field by invoking the setter with a parameter value of + * {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + *

      Note: if the absolute value of the year parameter + * is less than 10^9, the eon component of the XSD year field is set to + * null by this method.

      + * + * @param year value constraints are summarized in year field of date/time field mapping table. + * If year is {@link DatatypeConstants#FIELD_UNDEFINED}, then eon is set to null. + */ + public void setYear(int year) { + if (year == DatatypeConstants.FIELD_UNDEFINED) { + this.year = DatatypeConstants.FIELD_UNDEFINED; + this.eon = null; + } + else if (Math.abs(year) < BILLION_I) { + this.year = year; + this.eon = null; + } + else { + BigInteger theYear = BigInteger.valueOf((long) year); + BigInteger remainder = theYear.remainder(BILLION_B); + this.year = remainder.intValue(); + setEon(theYear.subtract(remainder)); + } + } + + /** + *

      Set high order part of XSD dateTime year field.

      + * + *

      Unset this field by invoking the setter with a parameter value of + * null.

      + * + * @param eon value constraints summarized in year field of date/time field mapping table. + */ + private void setEon(BigInteger eon) { + if (eon != null && eon.compareTo(BigInteger.ZERO) == 0) { + // Treat ZERO as field being undefined. + this.eon = null; + } + else { + this.eon = eon; + } + } + + /** + *

      Set month.

      + * + *

      Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + * @param month value constraints summarized in month field of date/time field mapping table. + * + * @throws IllegalArgumentException if month parameter is + * outside value constraints for the field as specified in + * date/time field mapping table. + */ + public void setMonth(int month) { + checkFieldValueConstraint(MONTH, month); + this.month = month; + } + + /** + *

      Set days in month.

      + * + *

      Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + * @param day value constraints summarized in day field of date/time field mapping table. + * + * @throws IllegalArgumentException if day parameter is + * outside value constraints for the field as specified in + * date/time field mapping table. + */ + public void setDay(int day) { + checkFieldValueConstraint(DAY, day); + this.day = day; + } + + /** + *

      Set the number of minutes in the timezone offset.

      + * + *

      Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.

      + * + * @param offset value constraints summarized in + * timezone field of date/time field mapping table. + * + * @throws IllegalArgumentException if offset parameter is + * outside value constraints for the field as specified in + * date/time field mapping table. + */ + public void setTimezone(int offset) { + checkFieldValueConstraint(TIMEZONE, offset); + this.timezone = offset; + } + + /** + *

      Set time as one unit.

      + * + * @param hour value constraints are summarized in + * hour field of date/time field mapping table. + * @param minute value constraints are summarized in + * minute field of date/time field mapping table. + * @param second value constraints are summarized in + * second field of date/time field mapping table. + * + * @see #setTime(int, int, int, BigDecimal) + * + * @throws IllegalArgumentException if any parameter is + * outside value constraints for the field as specified in + * date/time field mapping table. + */ + public void setTime(int hour, int minute, int second) { + setTime(hour, minute, second, null); + } + + private void checkFieldValueConstraint(int field, int value) + throws IllegalArgumentException { + if ((value < MIN_FIELD_VALUE[field] && value != DatatypeConstants.FIELD_UNDEFINED) || + value > MAX_FIELD_VALUE[field]) { + /** + throw new IllegalArgumentException("invalid value " + value + + " for " + FIELD_NAME[field] + + " field"); + */ + throw new IllegalArgumentException( + DatatypeMessageFormatter.formatMessage(null, "InvalidFieldValue", new Object[]{ new Integer(value), FIELD_NAME[field]}) + ); + } + } + + public void setHour(int hour) { + checkFieldValueConstraint(HOUR, hour); + this.hour = hour; + } + + public void setMinute(int minute) { + checkFieldValueConstraint(MINUTE, minute); + this.minute = minute; + } + + public void setSecond(int second) { + checkFieldValueConstraint(SECOND, second); + this.second = second; + } + + /** + *

      Set time as one unit, including the optional infinite precison + * fractional seconds.

      + * + * @param hour value constraints are summarized in + * hour field of date/time field mapping table. + * @param minute value constraints are summarized in + * minute field of date/time field mapping table. + * @param second value constraints are summarized in + * second field of date/time field mapping table. + * @param fractional value of null indicates this optional + * field is not set. + * + * @throws IllegalArgumentException if any parameter is + * outside value constraints for the field as specified in + * date/time field mapping table. + */ + public void setTime( + int hour, + int minute, + int second, + BigDecimal fractional) { + setHour(hour); + setMinute(minute); + setSecond(second); + setFractionalSecond(fractional); + } + + /** + *

      Set time as one unit, including optional milliseconds.

      + * + * @param hour value constraints are summarized in + * hour field of date/time field mapping table. + * @param minute value constraints are summarized in + * minute field of date/time field mapping table. + * @param second value constraints are summarized in + * second field of date/time field mapping table. + * @param millisecond value of {@link DatatypeConstants#FIELD_UNDEFINED} indicates this + * optional field is not set. + * + * @throws IllegalArgumentException if any parameter is + * outside value constraints for the field as specified in + * date/time field mapping table. + */ + public void setTime(int hour, int minute, int second, int millisecond) { + setHour(hour); + setMinute(minute); + setSecond(second); + setMillisecond(millisecond); + } + + // comparisons + /** + *

      Compare two instances of W3C XML Schema 1.0 date/time datatypes + * according to partial order relation defined in + * W3C XML Schema 1.0 Part 2, Section 3.2.7.3, + * Order relation on dateTime.

      + * + *

      xsd:dateTime datatype field mapping to accessors of + * this class are defined in + * date/time field mapping table.

      + * + * @param rhs instance of XMLGregorianCalendar to compare + * + * @return the relationship between lhs and rhs as + * {@link DatatypeConstants#LESSER}, + * {@link DatatypeConstants#EQUAL}, + * {@link DatatypeConstants#GREATER} or + * {@link DatatypeConstants#INDETERMINATE}. + * + * @throws NullPointerException if lhs or rhs + * parameters are null. + */ + public int compare(XMLGregorianCalendar rhs) { + + //MLGregorianCalendar lhs = this; + + int result = DatatypeConstants.INDETERMINATE; + XMLGregorianCalendar P = this; + XMLGregorianCalendar Q = rhs; + + if (P.getTimezone() == Q.getTimezone()) { + // Optimization: + // both instances are in same timezone or + // both are FIELD_UNDEFINED. + // Avoid costly normalization of timezone to 'Z' time. + return internalCompare(P, Q); + + } + else if (P.getTimezone() != DatatypeConstants.FIELD_UNDEFINED && + Q.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) { + + // Both instances have different timezones. + // Normalize to UTC time and compare. + P = (XMLGregorianCalendarImpl) P.normalize(); + Q = (XMLGregorianCalendarImpl) Q.normalize(); + return internalCompare(P, Q); + } + else if (P.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) { + + if (P.getTimezone() != 0) { + P = (XMLGregorianCalendarImpl) P.normalize(); + } + + // C. step 1 + XMLGregorianCalendar MinQ = normalizeToTimezone(Q, DatatypeConstants.MIN_TIMEZONE_OFFSET); + result = internalCompare(P, MinQ); + if (result == DatatypeConstants.LESSER) { + return result; + } + + // C. step 2 + XMLGregorianCalendar MaxQ = normalizeToTimezone(Q, DatatypeConstants.MAX_TIMEZONE_OFFSET); + result = internalCompare(P, MaxQ); + if (result == DatatypeConstants.GREATER) { + return result; + } + else { + // C. step 3 + return DatatypeConstants.INDETERMINATE; + } + } + else { // Q.getTimezone() != DatatypeConstants.FIELD_UNDEFINED + // P has no timezone and Q does. + if (Q.getTimezone() != 0 ) { + Q = (XMLGregorianCalendarImpl) normalizeToTimezone(Q, Q.getTimezone()); + } + + // D. step 1 + XMLGregorianCalendar MaxP = normalizeToTimezone(P, DatatypeConstants.MAX_TIMEZONE_OFFSET); + result = internalCompare(MaxP, Q); + if (result == DatatypeConstants.LESSER) { + return result; + } + + // D. step 2 + XMLGregorianCalendar MinP = normalizeToTimezone(P, DatatypeConstants.MIN_TIMEZONE_OFFSET); + result = internalCompare(MinP, Q); + if (result == DatatypeConstants.GREATER) { + return result; + } + else { + // D. step 3 + return DatatypeConstants.INDETERMINATE; + } + } + } + + /** + *

      Normalize this instance to UTC.

      + * + *

      2000-03-04T23:00:00+03:00 normalizes to 2000-03-04T20:00:00Z

      + *

      Implements W3C XML Schema Part 2, Section 3.2.7.3 (A).

      + */ + public XMLGregorianCalendar normalize() { + + XMLGregorianCalendar normalized = normalizeToTimezone(this, timezone); + + // if timezone was undefined, leave it undefined + if (getTimezone() == DatatypeConstants.FIELD_UNDEFINED) { + normalized.setTimezone(DatatypeConstants.FIELD_UNDEFINED); + } + + // if milliseconds was undefined, leave it undefined + if (getMillisecond() == DatatypeConstants.FIELD_UNDEFINED) { + normalized.setMillisecond(DatatypeConstants.FIELD_UNDEFINED); + } + + return normalized; + } + + /** + *

      Normalize this instance to UTC.

      + * + *

      2000-03-04T23:00:00+03:00 normalizes to 2000-03-04T20:00:00Z

      + *

      Implements W3C XML Schema Part 2, Section 3.2.7.3 (A).

      + */ + private XMLGregorianCalendar normalizeToTimezone(XMLGregorianCalendar cal, int timezone) { + + int minutes = timezone; + XMLGregorianCalendar result = (XMLGregorianCalendar) cal.clone(); + + // normalizing to UTC time negates the timezone offset before + // addition. + minutes = -minutes; + Duration d = new DurationImpl(minutes >= 0, // isPositive + 0, //years + 0, //months + 0, //days + 0, //hours + minutes < 0 ? -minutes : minutes, // absolute + 0 //seconds + ); + result.add(d); + + // set to zulu UTC time. + result.setTimezone(0); + return result; + } + + /** + * + *

      Implements Step B from http://www.w3.org/TR/xmlschema-2/#dateTime-order

      + * @param P calendar instance with normalized timezone offset or + * having same timezone as Q + * @param Q calendar instance with normalized timezone offset or + * having same timezone as P + * + * @return result of comparing P and Q, value of + * {@link DatatypeConstants#EQUAL}, + * {@link DatatypeConstants#LESSER}, + * {@link DatatypeConstants#GREATER} or + * {@link DatatypeConstants#INDETERMINATE}. + */ + private static int internalCompare(XMLGregorianCalendar P, + XMLGregorianCalendar Q) { + + int result; + + // compare Year. + if (P.getEon() == Q.getEon()) { + // Eon field is only equal when null. + // optimized case for comparing year not requiring eon field. + result = compareField(P.getYear(), Q.getYear()); + if (result != DatatypeConstants.EQUAL) { + return result; + } + } + else { + result = compareField(P.getEonAndYear(), Q.getEonAndYear()); + if (result != DatatypeConstants.EQUAL) { + return result; + } + } + + result = compareField(P.getMonth(), Q.getMonth()); + if (result != DatatypeConstants.EQUAL) { + return result; + } + + result = compareField(P.getDay(), Q.getDay()); + if (result != DatatypeConstants.EQUAL) { + return result; + } + + result = compareField(P.getHour(), Q.getHour()); + if (result != DatatypeConstants.EQUAL) { + return result; + } + + result = compareField(P.getMinute(), Q.getMinute()); + if (result != DatatypeConstants.EQUAL) { + return result; + } + result = compareField(P.getSecond(), Q.getSecond()); + if (result != DatatypeConstants.EQUAL) { + return result; + } + + result = compareField(P.getFractionalSecond(), Q.getFractionalSecond()); + return result; + } + + /** + *

      Implement Step B from + * http://www.w3.org/TR/xmlschema-2/#dateTime-order.

      + */ + private static int compareField(int Pfield, int Qfield) { + if (Pfield == Qfield) { + //fields are either equal in value or both undefined. + // Step B. 1.1 AND optimized result of performing 1.1-1.4. + return DatatypeConstants.EQUAL; + } + else { + if (Pfield == DatatypeConstants.FIELD_UNDEFINED || Qfield == DatatypeConstants.FIELD_UNDEFINED) { + // Step B. 1.2 + return DatatypeConstants.INDETERMINATE; + } + else { + // Step B. 1.3-4. + return (Pfield < Qfield ? DatatypeConstants.LESSER : DatatypeConstants.GREATER); + } + } + } + + private static int compareField(BigInteger Pfield, BigInteger Qfield) { + if (Pfield == null) { + return (Qfield == null ? DatatypeConstants.EQUAL : DatatypeConstants.INDETERMINATE); + } + if (Qfield == null) { + return DatatypeConstants.INDETERMINATE; + } + return Pfield.compareTo(Qfield); + } + + private static int compareField(BigDecimal Pfield, BigDecimal Qfield) { + // optimization. especially when both arguments are null. + if (Pfield == Qfield) { + return DatatypeConstants.EQUAL; + } + + if (Pfield == null) { + Pfield = DECIMAL_ZERO; + } + + if (Qfield == null) { + Qfield = DECIMAL_ZERO; + } + + return Pfield.compareTo(Qfield); + } + + /** + *

      Indicates whether parameter obj is "equal to" this one.

      + * + * @param obj to compare. + * + * @return true when compare(this,(XMLGregorianCalendar)obj) == EQUAL.. + */ + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof XMLGregorianCalendar) { + return compare((XMLGregorianCalendar) obj) == DatatypeConstants.EQUAL; + } + return false; + } + + /** + *

      Returns a hash code consistent with the definition of the equals method.

      + * + * @return hash code of this object. + */ + public int hashCode() { + + // Following two dates compare to EQUALS since in different timezones. + // 2000-01-15T12:00:00-05:00 == 2000-01-15T13:00:00-04:00 + // + // Must ensure both instances generate same hashcode by normalizing + // this to UTC timezone. + int timezone = getTimezone(); + if (timezone == DatatypeConstants.FIELD_UNDEFINED) { + timezone = 0; + } + XMLGregorianCalendar gc = this; + if (timezone != 0) { + gc = normalizeToTimezone(this, getTimezone()); + } + return gc.getYear() + gc.getMonth() + gc.getDay() + + gc.getHour() + gc.getMinute() + gc.getSecond(); + } + + + /** + *

      Constructs a new XMLGregorianCalendar object by + * parsing its lexical string representation as defined in + * XML Schema 1.0 Part 2, Section 3.2.[7-14].1, + * Lexical Representation.

      + * + *

      The string representation may not have any leading and trailing whitespaces.

      + * + *

      The parsing is done field by field so that + * the following holds for any lexically correct string x:

      + *
      +     * new XMLGregorianCalendar(x).toXMLFormat().equals(x)
      +     * 
      + * Except for the noted lexical/canonical representation mismatches + * listed in + * XML Schema 1.0 errata, Section 3.2.7.2. + * + *

      Returns a non-null valid XMLGregorianCalendar object that holds the value + * indicated by the lexicalRepresentation parameter.

      + * + * @param lexicalRepresentation Lexical representation of one the 8 XML Schema calendar datatypes. + * + * @return XMLGregorianCalendar created from parsing lexicalRepresentation parameter. + * + * @throws IllegalArgumentException + * If the given string does not conform to the aforementioned + * specification. + * @throws NullPointerException + * If the given string is null. + */ + public static XMLGregorianCalendar parse(String lexicalRepresentation) { + + return new XMLGregorianCalendarImpl(lexicalRepresentation); + } + + /** + *

      Return the lexical representation of this instance. + * The format is specified in + * XML Schema 1.0 Part 2, Section 3.2.[7-14].1, + * Lexical Representation".

      + * + *

      Specific target lexical representation format is determined by + * {@link #getXMLSchemaType()}.

      + * + * @return XML, as String, representation of this XMLGregorianCalendar + * + * @throws java.lang.IllegalStateException if the combination of set fields + * does not match one of the eight defined XML Schema builtin date/time datatypes. + */ + public String toXMLFormat() { + + QName typekind = getXMLSchemaType(); + + String formatString = null; + if (typekind == DatatypeConstants.DATETIME) { + formatString = "%Y-%M-%DT%h:%m:%s"+ "%z"; + } + else if (typekind == DatatypeConstants.DATE) { + // Fix 4971612: invalid SCCS macro substitution in data string + formatString = "%Y-%M-%D" +"%z"; + } + else if (typekind == DatatypeConstants.TIME) { + formatString = "%h:%m:%s"+ "%z"; + } + else if (typekind == DatatypeConstants.GMONTH) { + formatString = "--%M--%z"; + } + else if (typekind == DatatypeConstants.GDAY) { + // Fix 4971612: invalid SCCS macro substitution in data string + formatString = "---%D" + "%z"; + } + else if (typekind == DatatypeConstants.GYEAR) { + formatString = "%Y" + "%z"; + } + else if (typekind == DatatypeConstants.GYEARMONTH) { + // Fix 4971612: invalid SCCS macro substitution in data string + formatString = "%Y-%M" + "%z"; + } + else if (typekind == DatatypeConstants.GMONTHDAY) { + // Fix 4971612: invalid SCCS macro substitution in data string + formatString = "--%M-%D" +"%z"; + } + return format(formatString); + } + + /** + *

      Return the name of the XML Schema date/time type that this instance + * maps to. Type is computed based on fields that are set.

      + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      + * Required fields for XML Schema 1.0 Date/Time Datatypes.
      + * (timezone is optional for all date/time datatypes) + *
      Datatypeyearmonthdayhourminutesecond
      {@link DatatypeConstants#DATETIME}XXXXXX
      {@link DatatypeConstants#DATE}XXX
      {@link DatatypeConstants#TIME}XXX
      {@link DatatypeConstants#GYEARMONTH}XX
      {@link DatatypeConstants#GMONTHDAY}XX
      {@link DatatypeConstants#GYEAR}X
      {@link DatatypeConstants#GMONTH}X
      {@link DatatypeConstants#GDAY}X
      + * + * @throws java.lang.IllegalStateException if the combination of set fields + * does not match one of the eight defined XML Schema builtin + * date/time datatypes. + * @return One of the following class constants: + * {@link DatatypeConstants#DATETIME}, + * {@link DatatypeConstants#TIME}, + * {@link DatatypeConstants#DATE}, + * {@link DatatypeConstants#GYEARMONTH}, + * {@link DatatypeConstants#GMONTHDAY}, + * {@link DatatypeConstants#GYEAR}, + * {@link DatatypeConstants#GMONTH} or + * {@link DatatypeConstants#GDAY}. + */ + public QName getXMLSchemaType() { + + // DATETIME + if (year != DatatypeConstants.FIELD_UNDEFINED + && month != DatatypeConstants.FIELD_UNDEFINED + && day != DatatypeConstants.FIELD_UNDEFINED + && hour != DatatypeConstants.FIELD_UNDEFINED + && minute != DatatypeConstants.FIELD_UNDEFINED + && second != DatatypeConstants.FIELD_UNDEFINED) { + return DatatypeConstants.DATETIME; + } + + // DATE + if (year != DatatypeConstants.FIELD_UNDEFINED + && month != DatatypeConstants.FIELD_UNDEFINED + && day != DatatypeConstants.FIELD_UNDEFINED + && hour == DatatypeConstants.FIELD_UNDEFINED + && minute == DatatypeConstants.FIELD_UNDEFINED + && second == DatatypeConstants.FIELD_UNDEFINED) { + return DatatypeConstants.DATE; + } + + // TIME + if (year == DatatypeConstants.FIELD_UNDEFINED + && month == DatatypeConstants.FIELD_UNDEFINED + && day == DatatypeConstants.FIELD_UNDEFINED + && hour != DatatypeConstants.FIELD_UNDEFINED + && minute != DatatypeConstants.FIELD_UNDEFINED + && second != DatatypeConstants.FIELD_UNDEFINED) { + return DatatypeConstants.TIME; + } + + + // GYEARMONTH + if (year != DatatypeConstants.FIELD_UNDEFINED + && month != DatatypeConstants.FIELD_UNDEFINED + && day == DatatypeConstants.FIELD_UNDEFINED + && hour == DatatypeConstants.FIELD_UNDEFINED + && minute == DatatypeConstants.FIELD_UNDEFINED + && second == DatatypeConstants.FIELD_UNDEFINED) { + return DatatypeConstants.GYEARMONTH; + } + + // GMONTHDAY + if (year == DatatypeConstants.FIELD_UNDEFINED + && month != DatatypeConstants.FIELD_UNDEFINED + && day != DatatypeConstants.FIELD_UNDEFINED + && hour == DatatypeConstants.FIELD_UNDEFINED + && minute == DatatypeConstants.FIELD_UNDEFINED + && second == DatatypeConstants.FIELD_UNDEFINED) { + return DatatypeConstants.GMONTHDAY; + } + + // GYEAR + if (year != DatatypeConstants.FIELD_UNDEFINED + && month == DatatypeConstants.FIELD_UNDEFINED + && day == DatatypeConstants.FIELD_UNDEFINED + && hour == DatatypeConstants.FIELD_UNDEFINED + && minute == DatatypeConstants.FIELD_UNDEFINED + && second == DatatypeConstants.FIELD_UNDEFINED) { + return DatatypeConstants.GYEAR; + } + + // GMONTH + if (year == DatatypeConstants.FIELD_UNDEFINED + && month != DatatypeConstants.FIELD_UNDEFINED + && day == DatatypeConstants.FIELD_UNDEFINED + && hour == DatatypeConstants.FIELD_UNDEFINED + && minute == DatatypeConstants.FIELD_UNDEFINED + && second == DatatypeConstants.FIELD_UNDEFINED) { + return DatatypeConstants.GMONTH; + } + + // GDAY + if (year == DatatypeConstants.FIELD_UNDEFINED + && month == DatatypeConstants.FIELD_UNDEFINED + && day != DatatypeConstants.FIELD_UNDEFINED + && hour == DatatypeConstants.FIELD_UNDEFINED + && minute == DatatypeConstants.FIELD_UNDEFINED + && second == DatatypeConstants.FIELD_UNDEFINED) { + return DatatypeConstants.GDAY; + } + + // unknown + throw new IllegalStateException( + this.getClass().getName() + + "#getXMLSchemaType() :" + + DatatypeMessageFormatter.formatMessage(null, "InvalidXGCFields", null) + ); + } + + + /** + * Validate instance by getXMLSchemaType() constraints. + * @return true if data values are valid. + */ + public boolean isValid() { + // since setters do not allow for invalid values, + // (except for exceptional case of year field of zero), + // no need to check for anything except for constraints + // between fields. + + // check if days in month is valid. Can be dependent on leap year. + if (month != DatatypeConstants.FIELD_UNDEFINED && day != DatatypeConstants.FIELD_UNDEFINED) { + if (year != DatatypeConstants.FIELD_UNDEFINED) { + if (eon == null) { + if (day > maximumDayInMonthFor(year, month)) { + return false; + } + } + else if (day > maximumDayInMonthFor(getEonAndYear(), month)) { + return false; + } + } + // Use 2000 as a default since it's a leap year. + else if (day > maximumDayInMonthFor(2000, month)) { + return false; + } + } + + // http://www.w3.org/2001/05/xmlschema-errata#e2-45 + if (hour == 24 && (minute != 0 || second != 0 || + (fractionalSecond != null && fractionalSecond.compareTo(DECIMAL_ZERO) != 0))) { + return false; + } + + // XML Schema 1.0 specification defines year value of zero as + // invalid. Allow this class to set year field to zero + // since XML Schema 1.0 errata states that lexical zero will + // be allowed in next version and treated as 1 B.C.E. + if (eon == null && year == 0) { + return false; + } + return true; + } + + /** + *

      Add duration to this instance.<\p> + * + *

      The computation is specified in + * XML Schema 1.0 Part 2, Appendix E, + * Adding durations to dateTimes>. + * date/time field mapping table + * defines the mapping from XML Schema 1.0 dateTime fields + * to this class' representation of those fields.

      + * + * @param duration Duration to add to this XMLGregorianCalendar. + * + * @throws NullPointerException when duration parameter is null. + */ + public void add(Duration duration) { + + /* + * Extracted from + * http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes + * to ensure implemented properly. See spec for definitions of methods + * used in algorithm. + * + * Given a dateTime S and a duration D, specifies how to compute a + * dateTime E where E is the end of the time period with start S and + * duration D i.e. E = S + D. + * + * The following is the precise specification. + * These steps must be followed in the same order. + * If a field in D is not specified, it is treated as if it were zero. + * If a field in S is not specified, it is treated in the calculation + * as if it were the minimum allowed value in that field, however, + * after the calculation is concluded, the corresponding field in + * E is removed (set to unspecified). + * + * Months (may be modified additionally below) + * temp := S[month] + D[month] + * E[month] := modulo(temp, 1, 13) + * carry := fQuotient(temp, 1, 13) + */ + + boolean fieldUndefined[] = { + false, + false, + false, + false, + false, + false + }; + + int signum = duration.getSign(); + + int startMonth = getMonth(); + if (startMonth == DatatypeConstants.FIELD_UNDEFINED) { + startMonth = MIN_FIELD_VALUE[MONTH]; + fieldUndefined[MONTH] = true; + } + + BigInteger dMonths = sanitize(duration.getField(DatatypeConstants.MONTHS), signum); + BigInteger temp = BigInteger.valueOf((long) startMonth).add(dMonths); + setMonth(temp.subtract(BigInteger.ONE).mod(TWELVE).intValue() + 1); + BigInteger carry = + new BigDecimal(temp.subtract(BigInteger.ONE)).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_FLOOR).toBigInteger(); + + /* Years (may be modified additionally below) + * E[year] := S[year] + D[year] + carry + */ + BigInteger startYear = getEonAndYear(); + if (startYear == null) { + fieldUndefined[YEAR] = true; + startYear = BigInteger.ZERO; + } + BigInteger dYears = sanitize(duration.getField(DatatypeConstants.YEARS), signum); + BigInteger endYear = startYear.add(dYears).add(carry); + setYear(endYear); + + /* Zone + * E[zone] := S[zone] + * + * no-op since adding to this, not to a new end point. + */ + + /* Seconds + * temp := S[second] + D[second] + * E[second] := modulo(temp, 60) + * carry := fQuotient(temp, 60) + */ + BigDecimal startSeconds; + if (getSecond() == DatatypeConstants.FIELD_UNDEFINED) { + fieldUndefined[SECOND] = true; + startSeconds = DECIMAL_ZERO; + } + else { + // seconds + fractionalSeconds + startSeconds = getSeconds(); + } + + // Duration seconds is SECONDS + FRACTIONALSECONDS. + BigDecimal dSeconds = DurationImpl.sanitize((BigDecimal) duration.getField(DatatypeConstants.SECONDS), signum); + BigDecimal tempBD = startSeconds.add(dSeconds); + BigDecimal fQuotient = + new BigDecimal(new BigDecimal(tempBD.toBigInteger()).divide(DECIMAL_SIXTY, BigDecimal.ROUND_FLOOR).toBigInteger()); + BigDecimal endSeconds = tempBD.subtract(fQuotient.multiply(DECIMAL_SIXTY)); + + carry = fQuotient.toBigInteger(); + setSecond(endSeconds.intValue()); + BigDecimal tempFracSeconds = endSeconds.subtract(new BigDecimal(BigInteger.valueOf((long) getSecond()))); + if (tempFracSeconds.compareTo(DECIMAL_ZERO) < 0) { + setFractionalSecond(DECIMAL_ONE.add(tempFracSeconds)); + if (getSecond() == 0) { + setSecond(59); + carry = carry.subtract(BigInteger.ONE); + } + else { + setSecond(getSecond() - 1); + } + } + else { + setFractionalSecond(tempFracSeconds); + } + + /* Minutes + * temp := S[minute] + D[minute] + carry + * E[minute] := modulo(temp, 60) + * carry := fQuotient(temp, 60) + */ + int startMinutes = getMinute(); + if (startMinutes == DatatypeConstants.FIELD_UNDEFINED) { + fieldUndefined[MINUTE] = true; + startMinutes = MIN_FIELD_VALUE[MINUTE]; + } + BigInteger dMinutes = sanitize(duration.getField(DatatypeConstants.MINUTES), signum); + + temp = BigInteger.valueOf(startMinutes).add(dMinutes).add(carry); + setMinute(temp.mod(SIXTY).intValue()); + carry = new BigDecimal(temp).divide(DECIMAL_SIXTY, BigDecimal.ROUND_FLOOR).toBigInteger(); + + /* Hours + * temp := S[hour] + D[hour] + carry + * E[hour] := modulo(temp, 24) + * carry := fQuotient(temp, 24) + */ + int startHours = getHour(); + if (startHours == DatatypeConstants.FIELD_UNDEFINED) { + fieldUndefined[HOUR] = true; + startHours = MIN_FIELD_VALUE[HOUR]; + } + BigInteger dHours = sanitize(duration.getField(DatatypeConstants.HOURS), signum); + + temp = BigInteger.valueOf(startHours).add(dHours).add(carry); + setHour(temp.mod(TWENTY_FOUR).intValue()); + carry = new BigDecimal(temp).divide(new BigDecimal(TWENTY_FOUR), BigDecimal.ROUND_FLOOR).toBigInteger(); + + /* Days + * if S[day] > maximumDayInMonthFor(E[year], E[month]) + * + tempDays := maximumDayInMonthFor(E[year], E[month]) + * else if S[day] < 1 + * + tempDays := 1 + * else + * + tempDays := S[day] + * E[day] := tempDays + D[day] + carry + * START LOOP + * + IF E[day] < 1 + * # E[day] := E[day] + + * maximumDayInMonthFor(E[year], E[month] - 1) + * # carry := -1 + * + ELSE IF E[day] > maximumDayInMonthFor(E[year], E[month]) + * # E[day] := + * E[day] - maximumDayInMonthFor(E[year], E[month]) + * # carry := 1 + * + ELSE EXIT LOOP + * + temp := E[month] + carry + * + E[month] := modulo(temp, 1, 13) + * + E[year] := E[year] + fQuotient(temp, 1, 13) + * + GOTO START LOOP + */ + BigInteger tempDays; + int startDay = getDay(); + if (startDay == DatatypeConstants.FIELD_UNDEFINED) { + fieldUndefined[DAY] = true; + startDay = MIN_FIELD_VALUE[DAY]; + } + BigInteger dDays = sanitize(duration.getField(DatatypeConstants.DAYS), signum); + int maxDayInMonth = maximumDayInMonthFor(getEonAndYear(), getMonth()); + if (startDay > maxDayInMonth) { + tempDays = BigInteger.valueOf(maxDayInMonth); + } + else if (startDay < 1) { + tempDays = BigInteger.ONE; + } + else { + tempDays = BigInteger.valueOf(startDay); + } + BigInteger endDays = tempDays.add(dDays).add(carry); + int monthCarry; + int intTemp; + while (true) { + if (endDays.compareTo(BigInteger.ONE) < 0) { + // calculate days in previous month, watch for month roll over + BigInteger mdimf = null; + if (month >= 2) { + mdimf = BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear(), getMonth() - 1)); + } + else { + // roll over to December of previous year + mdimf = BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear().subtract(BigInteger.valueOf((long) 1)), 12)); + } + endDays = endDays.add(mdimf); + monthCarry = -1; + } + else if (endDays.compareTo(BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear(), getMonth()))) > 0) { + endDays = endDays.add(BigInteger.valueOf(-maximumDayInMonthFor(getEonAndYear(), getMonth()))); + monthCarry = 1; + } + else { + break; + } + + intTemp = getMonth() + monthCarry; + int endMonth = (intTemp - 1) % (13 - 1); + int quotient; + if (endMonth < 0) { + endMonth = (13 - 1) + endMonth + 1; + quotient = BigDecimal.valueOf(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue(); + } + else { + quotient = (intTemp - 1) / (13 - 1); + endMonth += 1; + } + setMonth(endMonth); + if (quotient != 0) { + setYear(getEonAndYear().add(BigInteger.valueOf(quotient))); + } + } + setDay(endDays.intValue()); + + // set fields that where undefined before this addition, back to undefined. + for (int i = YEAR; i <= SECOND; i++) { + if (fieldUndefined[i]) { + switch (i) { + case YEAR: + setYear(DatatypeConstants.FIELD_UNDEFINED); + break; + case MONTH: + setMonth(DatatypeConstants.FIELD_UNDEFINED); + break; + case DAY: + setDay(DatatypeConstants.FIELD_UNDEFINED); + break; + case HOUR: + setHour(DatatypeConstants.FIELD_UNDEFINED); + break; + case MINUTE: + setMinute(DatatypeConstants.FIELD_UNDEFINED); + break; + case SECOND: + setSecond(DatatypeConstants.FIELD_UNDEFINED); + setFractionalSecond(null); + break; + } + } + } + } + + private static final BigInteger FOUR = BigInteger.valueOf(4); + private static final BigInteger HUNDRED = BigInteger.valueOf(100); + private static final BigInteger FOUR_HUNDRED = BigInteger.valueOf(400); + private static final BigInteger SIXTY = BigInteger.valueOf(60); + private static final BigInteger TWENTY_FOUR = BigInteger.valueOf(24); + private static final BigInteger TWELVE = BigInteger.valueOf(12); + private static final BigDecimal DECIMAL_ZERO = BigDecimal.valueOf(0); + private static final BigDecimal DECIMAL_ONE = BigDecimal.valueOf(1); + private static final BigDecimal DECIMAL_SIXTY = BigDecimal.valueOf(60); + + private static class DaysInMonth { + private static final int [] table = { 0, // XML Schema months start at 1. + 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + } + + private static int maximumDayInMonthFor(BigInteger year, int month) { + if (month != DatatypeConstants.FEBRUARY) { + return DaysInMonth.table[month]; + } + else { + if (year.mod(FOUR_HUNDRED).equals(BigInteger.ZERO) || + (!year.mod(HUNDRED).equals(BigInteger.ZERO) && + year.mod(FOUR).equals(BigInteger.ZERO))) { + // is a leap year. + return 29; + } + else { + return DaysInMonth.table[month]; + } + } + } + + private static int maximumDayInMonthFor(int year, int month) { + if (month != DatatypeConstants.FEBRUARY) { + return DaysInMonth.table[month]; + } + else { + if ( ((year %400) == 0) || + ( ((year % 100) != 0) && ((year % 4) == 0))) { + // is a leap year. + return 29; + } + else { + return DaysInMonth.table[DatatypeConstants.FEBRUARY]; + } + } + } + + /** + *

      Convert this to java.util.GregorianCalendar.

      + * + *

      When this instance has an undefined field, this + * conversion relies on the java.util.GregorianCalendar default + * for its corresponding field. A notable difference between + * XML Schema 1.0 date/time datatypes and java.util.GregorianCalendar + * is that Timezone value is optional for date/time datatypes and it is + * a required field for java.util.GregorianCalendar. See javadoc + * for java.util.TimeZone.getDefault() on how the default + * is determined. To explicitly specify the TimeZone + * instance, see + * {@link #toGregorianCalendar(TimeZone, Locale, XMLGregorianCalendar)}.

      + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      + * Field by Field Conversion from this class to + * java.util.GregorianCalendar + *
      java.util.GregorianCalendar fieldjavax.xml.datatype.XMLGregorianCalendar field
      ERA{@link #getEonAndYear()}.signum() < 0 ? GregorianCalendar.BC : GregorianCalendar.AD
      YEAR{@link #getEonAndYear()}.abs().intValue()*
      MONTH{@link #getMonth()} - 1
      DAY_OF_MONTH{@link #getDay()}
      AM_PM{@link #getHour()} < 12 : Calendar.AM : Calendar.PM
      HOUR_OF_DAY{@link #getHour()}
      MINUTE{@link #getMinute()}
      SECOND{@link #getSecond()}
      MILLISECONDget millisecond order from {@link #getFractionalSecond()}*
      GregorianCalendar.setTimeZone(TimeZone){@link #getTimezone()} formatted into Custom timezone id
      + * * designates possible loss of precision during the conversion due + * to source datatype having higer precison than target datatype. + * + *

      To ensure consistency in conversion implementations, the new + * GregorianCalendar should be instantiated in following + * manner. + *

        + *
      • Using timeZone value as defined above, create a new + * java.util.GregorianCalendar(timeZone,Locale.getDefault()). + *
      • + *
      • Initialize all GregorianCalendar fields by calling {(@link GegorianCalendar#clear()}.
      • + *
      • Obtain a pure Gregorian Calendar by invoking + * GregorianCalendar.setGregorianChange( + * new Date(Long.MIN_VALUE)).
      • + *
      • Its fields ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY, + * MINUTE, SECOND and MILLISECOND are set using the method + * Calendar.set(int,int)
      • + *
      + *

      + * + * @see #toGregorianCalendar(java.util.TimeZone, java.util.Locale, XMLGregorianCalendar) + */ + public java.util.GregorianCalendar toGregorianCalendar() { + + GregorianCalendar result = null; + final int DEFAULT_TIMEZONE_OFFSET = DatatypeConstants.FIELD_UNDEFINED; + TimeZone tz = getTimeZone(DEFAULT_TIMEZONE_OFFSET); + Locale locale = java.util.Locale.getDefault(); + + result = new GregorianCalendar(tz, locale); + result.clear(); + result.setGregorianChange(PURE_GREGORIAN_CHANGE); + + // if year( and eon) are undefined, leave default Calendar values + if (year != DatatypeConstants.FIELD_UNDEFINED) { + if (eon == null) { + result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, Math.abs(year)); + } + else { + BigInteger eonAndYear = getEonAndYear(); + result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, eonAndYear.abs().intValue()); + } + } + + // only set month if it is set + if (month != DatatypeConstants.FIELD_UNDEFINED) { + // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not. + result.set(Calendar.MONTH, month - 1); + } + + // only set day if it is set + if (day != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.DAY_OF_MONTH, day); + } + + // only set hour if it is set + if (hour != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.HOUR_OF_DAY, hour); + } + + // only set minute if it is set + if (minute != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.MINUTE, minute); + } + + // only set second if it is set + if (second != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.SECOND, second); + } + + // only set millisend if it is set + if (fractionalSecond != null) { + result.set(Calendar.MILLISECOND, getMillisecond()); + } + + return result; + } + + /** + *

      Convert this along with provided parameters + * to java.util.GregorianCalendar instance.

      + * + *

      Since XML Schema 1.0 date/time datetypes has no concept of + * timezone ids or daylight savings timezone ids, this conversion operation + * allows the user to explicitly specify one with + * timezone parameter.

      + * + *

      To compute the return value's TimeZone field, + *

        + *
      • when parameter timeZone is non-null, + * it is the timezone field.
      • + *
      • else when this.getTimezone() != DatatypeConstants.FIELD_UNDEFINED, + * create a java.util.TimeZone with a custom timezone id + * using the this.getTimezone().
      • + *
      • else when defaults.getTimezone() != DatatypeConstants.FIELD_UNDEFINED, + * create a java.util.TimeZone with a custom timezone id + * using defaults.getTimezone().
      • + *
      • else use the GregorianCalendar default timezone value + * for the host is definedas specified by + * java.util.TimeZone.getDefault().
      • + * + *

        To ensure consistency in conversion implementations, the new + * GregorianCalendar should be instantiated in following + * manner. + *

          + *
        • Create a new java.util.GregorianCalendar(TimeZone, + * Locale) with TimeZone set as specified above and the + * Locale parameter. + *
        • + *
        • Initialize all GregorianCalendar fields by calling {(@link GegorianCalendar#clear()}.
        • + *
        • Obtain a pure Gregorian Calendar by invoking + * GregorianCalendar.setGregorianChange( + * new Date(Long.MIN_VALUE)).
        • + *
        • Its fields ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY, + * MINUTE, SECOND and MILLISECOND are set using the method + * Calendar.set(int,int)
        • + *
        + * + * @param timezone provide Timezone. null is a legal value. + * @param aLocale provide explicit Locale. Use default GregorianCalendar locale if + * value is null. + * @param defaults provide default field values to use when corresponding + * field for this instance is DatatypeConstants.FIELD_UNDEFINED or null. + * If defaultsis null or a field + * within the specified defaults is undefined, + * just use java.util.GregorianCalendar defaults. + * @return a java.util.GregorianCalendar conversion of this instance. + * + * @see #LEAP_YEAR_DEFAULT + */ + public GregorianCalendar toGregorianCalendar(java.util.TimeZone timezone, + java.util.Locale aLocale, + XMLGregorianCalendar defaults) { + GregorianCalendar result = null; + TimeZone tz = timezone; + if (tz == null) { + int defaultZoneoffset = DatatypeConstants.FIELD_UNDEFINED; + if (defaults != null) { + defaultZoneoffset = defaults.getTimezone(); + } + tz = getTimeZone(defaultZoneoffset); + } + if (aLocale == null) { + aLocale = java.util.Locale.getDefault(); + } + result = new GregorianCalendar(tz, aLocale); + result.clear(); + result.setGregorianChange(PURE_GREGORIAN_CHANGE); + + // if year( and eon) are undefined, leave default Calendar values + if (year != DatatypeConstants.FIELD_UNDEFINED) { + if (eon == null) { + result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, Math.abs(year)); + } + else { + final BigInteger eonAndYear = getEonAndYear(); + result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, eonAndYear.abs().intValue()); + } + } + else { + // use default if set + if (defaults != null) { + final int defaultYear = defaults.getYear(); + if (defaultYear != DatatypeConstants.FIELD_UNDEFINED) { + if (defaults.getEon() == null) { + result.set(Calendar.ERA, defaultYear < 0 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, Math.abs(defaultYear)); + } + else { + final BigInteger defaultEonAndYear = defaults.getEonAndYear(); + result.set(Calendar.ERA, defaultEonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, defaultEonAndYear.abs().intValue()); + } + } + } + } + + // only set month if it is set + if (month != DatatypeConstants.FIELD_UNDEFINED) { + // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not. + result.set(Calendar.MONTH, month - 1); + } + else { + // use default if set + final int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED; + if (defaultMonth != DatatypeConstants.FIELD_UNDEFINED) { + // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not. + result.set(Calendar.MONTH, defaultMonth - 1); + } + } + + // only set day if it is set + if (day != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.DAY_OF_MONTH, day); + } + else { + // use default if set + final int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED; + if (defaultDay != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.DAY_OF_MONTH, defaultDay); + } + } + + // only set hour if it is set + if (hour != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.HOUR_OF_DAY, hour); + } + else { + // use default if set + int defaultHour = (defaults != null) ? defaults.getHour() : DatatypeConstants.FIELD_UNDEFINED; + if (defaultHour != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.HOUR_OF_DAY, defaultHour); + } + } + + // only set minute if it is set + if (minute != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.MINUTE, minute); + } + else { + // use default if set + final int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED; + if (defaultMinute != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.MINUTE, defaultMinute); + } + } + + // only set second if it is set + if (second != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.SECOND, second); + } + else { + // use default if set + final int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED; + if (defaultSecond != DatatypeConstants.FIELD_UNDEFINED) { + result.set(Calendar.SECOND, defaultSecond); + } + } + + // only set millisend if it is set + if (fractionalSecond != null) { + result.set(Calendar.MILLISECOND, getMillisecond()); + } + else { + // use default if set + final BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null; + if (defaultFractionalSecond != null) { + result.set(Calendar.MILLISECOND, defaults.getMillisecond()); + } + } + + return result; + } + + /** + *

        Returns a java.util.TimeZone for this class.

        + * + *

        If timezone field is defined for this instance, + * returns TimeZone initialized with custom timezone id + * of zoneoffset. If timezone field is undefined, + * try the defaultZoneoffset that was passed in. + * If defaultZoneoffset is DatatypeConstants.FIELD_UNDEFINED, return + * default timezone for this host. + * (Same default as java.util.GregorianCalendar).

        + * + * @param defaultZoneoffset default zoneoffset if this zoneoffset is + * {@link DatatypeConstants#FIELD_UNDEFINED}. + * + * @return TimeZone for this. + */ + public TimeZone getTimeZone(int defaultZoneoffset) { + TimeZone result = null; + int zoneoffset = getTimezone(); + + if (zoneoffset == DatatypeConstants.FIELD_UNDEFINED) { + zoneoffset = defaultZoneoffset; + } + if (zoneoffset == DatatypeConstants.FIELD_UNDEFINED) { + result = TimeZone.getDefault(); + } + else { + // zoneoffset is in minutes. Convert to custom timezone id format. + char sign = zoneoffset < 0 ? '-' : '+'; + if (sign == '-') { + zoneoffset = -zoneoffset; + } + int hour = zoneoffset / 60; + int minutes = zoneoffset - (hour * 60); + + // Javadoc for java.util.TimeZone documents max length + // for customTimezoneId is 8 when optional ':' is not used. + // Format is + // "GMT" ('-'|''+') (digit digit?) (digit digit)? + // hour minutes + StringBuffer customTimezoneId = new StringBuffer(8); + customTimezoneId.append("GMT"); + customTimezoneId.append(sign); + customTimezoneId.append(hour); + if (minutes != 0) { + if (minutes < 10) { + customTimezoneId.append('0'); + } + customTimezoneId.append(minutes); + } + result = TimeZone.getTimeZone(customTimezoneId.toString()); + } + return result; + } + + /** + *

        Creates and returns a copy of this object.

        + * + * @return copy of this Object + */ + public Object clone() { + // Both this.eon and this.fractionalSecond are instances + // of immutable classes, so they do not need to be cloned. + return new XMLGregorianCalendarImpl(getEonAndYear(), + this.month, this.day, + this.hour, this.minute, this.second, + this.fractionalSecond, + this.timezone); + } + + /** + *

        Unset all fields to undefined.

        + * + *

        Set all int fields to {@link DatatypeConstants#FIELD_UNDEFINED} and reference fields + * to null.

        + */ + public void clear() { + eon = null; + year = DatatypeConstants.FIELD_UNDEFINED; + month = DatatypeConstants.FIELD_UNDEFINED; + day = DatatypeConstants.FIELD_UNDEFINED; + timezone = DatatypeConstants.FIELD_UNDEFINED; // in minutes + hour = DatatypeConstants.FIELD_UNDEFINED; + minute = DatatypeConstants.FIELD_UNDEFINED; + second = DatatypeConstants.FIELD_UNDEFINED; + fractionalSecond = null; + } + + public void setMillisecond(int millisecond) { + if (millisecond == DatatypeConstants.FIELD_UNDEFINED) { + fractionalSecond = null; + } + else { + checkFieldValueConstraint(MILLISECOND, millisecond); + fractionalSecond = BigDecimal.valueOf(millisecond, 3); + } + } + + public void setFractionalSecond(BigDecimal fractional) { + if (fractional != null) { + if ((fractional.compareTo(DECIMAL_ZERO) < 0) || + (fractional.compareTo(DECIMAL_ONE) > 0)) { + throw new IllegalArgumentException(DatatypeMessageFormatter.formatMessage(null, + "InvalidFractional", new Object[]{fractional})); + } + } + this.fractionalSecond = fractional; + } + + private final class Parser { + private final String format; + private final String value; + + private final int flen; + private final int vlen; + + private int fidx; + private int vidx; + + private Parser(String format, String value) { + this.format = format; + this.value = value; + this.flen = format.length(); + this.vlen = value.length(); + } + + /** + *

        Parse a formated String into an XMLGregorianCalendar.

        + * + *

        If String is not formated as a legal XMLGregorianCalendar value, + * an IllegalArgumentException is thrown.

        + * + * @throws IllegalArgumentException If String is not formated as a legal XMLGregorianCalendar value. + */ + public void parse() throws IllegalArgumentException { + while (fidx < flen) { + char fch = format.charAt(fidx++); + + if (fch != '%') { // not a meta character + skip(fch); + continue; + } + + // seen meta character. we don't do error check against the format + switch (format.charAt(fidx++)) { + case 'Y' : // year + parseYear(); + break; + + case 'M' : // month + setMonth(parseInt(2, 2)); + break; + + case 'D' : // days + setDay(parseInt(2, 2)); + break; + + case 'h' : // hours + setHour(parseInt(2, 2)); + break; + + case 'm' : // minutes + setMinute(parseInt(2, 2)); + break; + + case 's' : // parse seconds. + setSecond(parseInt(2, 2)); + + if (peek() == '.') { + setFractionalSecond(parseBigDecimal()); + } + break; + + case 'z' : // time zone. missing, 'Z', or [+-]nn:nn + char vch = peek(); + if (vch == 'Z') { + vidx++; + setTimezone(0); + } + else if (vch == '+' || vch == '-') { + vidx++; + int h = parseInt(2, 2); + skip(':'); + int m = parseInt(2, 2); + setTimezone((h * 60 + m) * (vch == '+' ? 1 : -1)); + } + break; + + default : + // illegal meta character. impossible. + throw new InternalError(); + } + } + + if (vidx != vlen) { + // some tokens are left in the input + throw new IllegalArgumentException(value); //,vidx); + } + } + + private char peek() throws IllegalArgumentException { + if (vidx == vlen) { + return (char) -1; + } + return value.charAt(vidx); + } + + private char read() throws IllegalArgumentException { + if (vidx == vlen) { + throw new IllegalArgumentException(value); //,vidx); + } + return value.charAt(vidx++); + } + + private void skip(char ch) throws IllegalArgumentException { + if (read() != ch) { + throw new IllegalArgumentException(value); //,vidx-1); + } + } + + private void parseYear() + throws IllegalArgumentException { + int vstart = vidx; + int sign = 0; + + // skip leading negative, if it exists + if (peek() == '-') { + vidx++; + sign = 1; + } + while (isDigit(peek())) { + vidx++; + } + final int digits = vidx - vstart - sign; + if (digits < 4) { + // we are expecting more digits + throw new IllegalArgumentException(value); //,vidx); + } + final String yearString = value.substring(vstart, vidx); + if (digits < 10) { + setYear(Integer.parseInt(yearString)); + } + else { + setYear(new BigInteger(yearString)); + } + } + + private int parseInt(int minDigits, int maxDigits) + throws IllegalArgumentException { + int vstart = vidx; + while (isDigit(peek()) && (vidx - vstart) < maxDigits) { + vidx++; + } + if ((vidx - vstart) < minDigits) { + // we are expecting more digits + throw new IllegalArgumentException(value); //,vidx); + } + + // NumberFormatException is IllegalArgumentException + // try { + return Integer.parseInt(value.substring(vstart, vidx)); + // } catch( NumberFormatException e ) { + // // if the value is too long for int, NumberFormatException is thrown + // throw new IllegalArgumentException(value,vstart); + // } + } + + private BigDecimal parseBigDecimal() + throws IllegalArgumentException { + int vstart = vidx; + + if (peek() == '.') { + vidx++; + } else { + throw new IllegalArgumentException(value); + } + while (isDigit(peek())) { + vidx++; + } + return new BigDecimal(value.substring(vstart, vidx)); + } + } + + private static boolean isDigit(char ch) { + return '0' <= ch && ch <= '9'; + } + + private String format( String format ) { + StringBuffer buf = new StringBuffer(); + int fidx=0,flen=format.length(); + + while(fidxTurns {@link BigDecimal} to a string representation.

        + * + *

        Due to a behavior change in the {@link BigDecimal#toString()} + * method in JDK1.5, this had to be implemented here.

        + * + * @param bd BigDecimal to format as a String + * + * @return String representation of BigDecimal + */ + private String toString(BigDecimal bd) { + String intString = bd.unscaledValue().toString(); + int scale = bd.scale(); + + if (scale == 0) { + return intString; + } + + /* Insert decimal point */ + StringBuffer buf; + int insertionPoint = intString.length() - scale; + if (insertionPoint == 0) { /* Point goes right before intVal */ + return "0." + intString; + } + else if (insertionPoint > 0) { /* Point goes inside intVal */ + buf = new StringBuffer(intString); + buf.insert(insertionPoint, '.'); + } + else { /* We must insert zeros between point and intVal */ + buf = new StringBuffer(3 - insertionPoint + intString.length()); + buf.append("0."); + for (int i = 0; i < -insertionPoint; i++) { + buf.append('0'); + } + buf.append(intString); + } + return buf.toString(); + } + + /** + * Compute value*signum where value==null is treated as + * value==0. + * @return non-null {@link BigInteger}. + */ + static BigInteger sanitize(Number value, int signum) { + if (signum == 0 || value == null) { + return BigInteger.ZERO; + } + return (signum < 0)? ((BigInteger)value).negate() : (BigInteger)value; + } + + /**

        reset() is designed to allow the reuse of existing + * XMLGregorianCalendars thus saving resources associated + * with the creation of new XMLGregorianCalendars.

        + */ + public void reset() { + eon = orig_eon; + year = orig_year; + month = orig_month; + day = orig_day; + hour = orig_hour; + minute = orig_minute; + second = orig_second; + fractionalSecond = orig_fracSeconds; + timezone = orig_timezone; + } + + /** + * Writes {@link XMLGregorianCalendar} as a lexical representation + * for maximum future compatibility. + * + * @return + * An object that encapsulates the string + * returned by this.toXMLFormat(). + */ + private Object writeReplace() throws IOException { + return new SerializedXMLGregorianCalendar(toXMLFormat()); + } +} + diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/javax.xml.datatype.DatatypeFactory b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/javax.xml.datatype.DatatypeFactory new file mode 100644 index 0000000..c1c1855 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/datatype/javax.xml.datatype.DatatypeFactory @@ -0,0 +1 @@ +org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/javax.xml.parsers.DocumentBuilderFactory b/resources/xerces2-j-src/org/apache/xerces/jaxp/javax.xml.parsers.DocumentBuilderFactory new file mode 100644 index 0000000..3845cc1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/javax.xml.parsers.DocumentBuilderFactory @@ -0,0 +1 @@ +org.apache.xerces.jaxp.DocumentBuilderFactoryImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/javax.xml.parsers.SAXParserFactory b/resources/xerces2-j-src/org/apache/xerces/jaxp/javax.xml.parsers.SAXParserFactory new file mode 100644 index 0000000..88b247c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/javax.xml.parsers.SAXParserFactory @@ -0,0 +1 @@ +org.apache.xerces.jaxp.SAXParserFactoryImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/AbstractXMLSchema.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/AbstractXMLSchema.java new file mode 100644 index 0000000..17d6fb3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/AbstractXMLSchema.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.util.HashMap; + +import javax.xml.validation.Schema; +import javax.xml.validation.Validator; +import javax.xml.validation.ValidatorHandler; + +/** + *

        Abstract implementation of Schema for W3C XML Schemas.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +abstract class AbstractXMLSchema extends Schema implements + XSGrammarPoolContainer { + + /** + * Map containing the initial values of features for + * validators created using this grammar pool container. + */ + private final HashMap fFeatures; + + public AbstractXMLSchema() { + fFeatures = new HashMap(); + } + + /* + * Schema methods + */ + + /* + * @see javax.xml.validation.Schema#newValidator() + */ + public final Validator newValidator() { + return new ValidatorImpl(this); + } + + /* + * @see javax.xml.validation.Schema#newValidatorHandler() + */ + public final ValidatorHandler newValidatorHandler() { + return new ValidatorHandlerImpl(this); + } + + /* + * XSGrammarPoolContainer methods + */ + + /** + * Returns the initial value of a feature for validators created + * using this grammar pool container or null if the validators + * should use the default value. + */ + public final Boolean getFeature(String featureId) { + return (Boolean) fFeatures.get(featureId); + } + + /* + * Other methods + */ + + final void setFeature(String featureId, boolean state) { + fFeatures.put(featureId, state ? Boolean.TRUE : Boolean.FALSE); + } + +} // AbstractXMLSchema diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMDocumentHandler.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMDocumentHandler.java new file mode 100644 index 0000000..dc471d3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMDocumentHandler.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import javax.xml.transform.dom.DOMResult; + +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XNIException; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +/** + *

        An extension to XMLDocumentHandler for building DOM structures.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +interface DOMDocumentHandler extends XMLDocumentHandler { + + /** + *

        Sets the DOMResult object which + * receives the constructed DOM nodes.

        + * + * @param result the object which receives the constructed DOM nodes + */ + public void setDOMResult(DOMResult result); + + /** + * A document type declaration. + * + * @param node a DocumentType node + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void doctypeDecl(DocumentType node) throws XNIException; + + public void characters(Text node) throws XNIException; + + public void cdata(CDATASection node) throws XNIException; + + /** + * A comment. + * + * @param node a Comment node + * + * @exception XNIException Thrown by application to signal an error. + */ + public void comment(Comment node) throws XNIException; + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param node a ProcessingInstruction node + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(ProcessingInstruction node) throws XNIException; + + public void setIgnoringCharacters(boolean ignore); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMResultAugmentor.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMResultAugmentor.java new file mode 100644 index 0000000..71c330e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMResultAugmentor.java @@ -0,0 +1,256 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import javax.xml.transform.dom.DOMResult; + +import org.apache.xerces.dom.AttrImpl; +import org.apache.xerces.dom.CoreDocumentImpl; +import org.apache.xerces.dom.ElementImpl; +import org.apache.xerces.dom.ElementNSImpl; +import org.apache.xerces.dom.PSVIAttrNSImpl; +import org.apache.xerces.dom.PSVIDocumentImpl; +import org.apache.xerces.dom.PSVIElementNSImpl; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +/** + *

        DOM result augmentor.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class DOMResultAugmentor implements DOMDocumentHandler { + + // + // Data + // + + private final DOMValidatorHelper fDOMValidatorHelper; + + private Document fDocument; + private CoreDocumentImpl fDocumentImpl; + private boolean fStorePSVI; + + private boolean fIgnoreChars; + + private final QName fAttributeQName = new QName(); + + public DOMResultAugmentor(DOMValidatorHelper helper) { + fDOMValidatorHelper = helper; + } + + public void setDOMResult(DOMResult result) { + fIgnoreChars = false; + if (result != null) { + final Node target = result.getNode(); + fDocument = (target.getNodeType() == Node.DOCUMENT_NODE) ? (Document) target : target.getOwnerDocument(); + fDocumentImpl = (fDocument instanceof CoreDocumentImpl) ? (CoreDocumentImpl) fDocument : null; + fStorePSVI = (fDocument instanceof PSVIDocumentImpl); + return; + } + fDocument = null; + fDocumentImpl = null; + fStorePSVI = false; + } + + public void doctypeDecl(DocumentType node) throws XNIException {} + + public void characters(Text node) throws XNIException {} + + public void cdata(CDATASection node) throws XNIException {} + + public void comment(Comment node) throws XNIException {} + + public void processingInstruction(ProcessingInstruction node) + throws XNIException {} + + public void setIgnoringCharacters(boolean ignore) { + fIgnoreChars = ignore; + } + + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException {} + + public void xmlDecl(String version, String encoding, String standalone, + Augmentations augs) throws XNIException {} + + public void doctypeDecl(String rootElement, String publicId, + String systemId, Augmentations augs) throws XNIException {} + + public void comment(XMLString text, Augmentations augs) throws XNIException {} + + public void processingInstruction(String target, XMLString data, + Augmentations augs) throws XNIException {} + + public void startElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + final Element currentElement = (Element) fDOMValidatorHelper.getCurrentElement(); + final NamedNodeMap attrMap = currentElement.getAttributes(); + + final int oldLength = attrMap.getLength(); + // If it's a Xerces DOM store type information for attributes, set idness, etc.. + if (fDocumentImpl != null) { + AttrImpl attr; + for (int i = 0; i < oldLength; ++i) { + attr = (AttrImpl) attrMap.item(i); + + // write type information to this attribute + AttributePSVI attrPSVI = (AttributePSVI) attributes.getAugmentations(i).getItem (Constants.ATTRIBUTE_PSVI); + if (attrPSVI != null) { + if (processAttributePSVI(attr, attrPSVI)) { + ((ElementImpl) currentElement).setIdAttributeNode (attr, true); + } + } + } + } + + final int newLength = attributes.getLength(); + // Add default/fixed attributes + if (newLength > oldLength) { + if (fDocumentImpl == null) { + for (int i = oldLength; i < newLength; ++i) { + attributes.getName(i, fAttributeQName); + currentElement.setAttributeNS(fAttributeQName.uri, fAttributeQName.rawname, attributes.getValue(i)); + } + } + // If it's a Xerces DOM store type information for attributes, set idness, etc.. + else { + for (int i = oldLength; i < newLength; ++i) { + attributes.getName(i, fAttributeQName); + AttrImpl attr = (AttrImpl) fDocumentImpl.createAttributeNS(fAttributeQName.uri, + fAttributeQName.rawname, fAttributeQName.localpart); + attr.setValue(attributes.getValue(i)); + currentElement.setAttributeNodeNS(attr); + + // write type information to this attribute + AttributePSVI attrPSVI = (AttributePSVI) attributes.getAugmentations(i).getItem (Constants.ATTRIBUTE_PSVI); + if (attrPSVI != null) { + if (processAttributePSVI(attr, attrPSVI)) { + ((ElementImpl) currentElement).setIdAttributeNode (attr, true); + } + } + attr.setSpecified(false); + } + } + } + } + + public void emptyElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + startElement(element, attributes, augs); + endElement(element, augs); + } + + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, String encoding, + Augmentations augs) throws XNIException {} + + public void textDecl(String version, String encoding, Augmentations augs) + throws XNIException {} + + public void endGeneralEntity(String name, Augmentations augs) + throws XNIException {} + + public void characters(XMLString text, Augmentations augs) + throws XNIException { + if (!fIgnoreChars) { + final Element currentElement = (Element) fDOMValidatorHelper.getCurrentElement(); + currentElement.appendChild(fDocument.createTextNode(text.toString())); + } + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) + throws XNIException { + characters(text, augs); + } + + public void endElement(QName element, Augmentations augs) + throws XNIException { + final Node currentElement = fDOMValidatorHelper.getCurrentElement(); + // Write type information to this element + if (augs != null && fDocumentImpl != null) { + ElementPSVI elementPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI); + if (elementPSVI != null) { + if (fStorePSVI) { + ((PSVIElementNSImpl) currentElement).setPSVI(elementPSVI); + } + XSTypeDefinition type = elementPSVI.getMemberTypeDefinition(); + if (type == null) { + type = elementPSVI.getTypeDefinition(); + } + ((ElementNSImpl) currentElement).setType(type); + } + } + } + + public void startCDATA(Augmentations augs) throws XNIException {} + + public void endCDATA(Augmentations augs) throws XNIException {} + + public void endDocument(Augmentations augs) throws XNIException {} + + public void setDocumentSource(XMLDocumentSource source) {} + + public XMLDocumentSource getDocumentSource() { + return null; + } + + /** Returns whether the given attribute is an ID type. **/ + private boolean processAttributePSVI(AttrImpl attr, AttributePSVI attrPSVI) { + if (fStorePSVI) { + ((PSVIAttrNSImpl) attr).setPSVI (attrPSVI); + } + Object type = attrPSVI.getMemberTypeDefinition (); + if (type == null) { + type = attrPSVI.getTypeDefinition (); + if (type != null) { + attr.setType(type); + return ((XSSimpleType) type).isIDType(); + } + } + else { + attr.setType(type); + return ((XSSimpleType) type).isIDType(); + } + return false; + } + +} // DOMResultAugmentor diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMResultBuilder.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMResultBuilder.java new file mode 100644 index 0000000..f2ed6af --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMResultBuilder.java @@ -0,0 +1,370 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.util.ArrayList; + +import javax.xml.transform.dom.DOMResult; + +import org.apache.xerces.dom.AttrImpl; +import org.apache.xerces.dom.CoreDocumentImpl; +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.dom.DocumentTypeImpl; +import org.apache.xerces.dom.ElementImpl; +import org.apache.xerces.dom.ElementNSImpl; +import org.apache.xerces.dom.EntityImpl; +import org.apache.xerces.dom.NotationImpl; +import org.apache.xerces.dom.PSVIAttrNSImpl; +import org.apache.xerces.dom.PSVIDocumentImpl; +import org.apache.xerces.dom.PSVIElementNSImpl; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Entity; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Notation; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + + +/** + *

        DOM result builder.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class DOMResultBuilder implements DOMDocumentHandler { + + /** Table for quick check of child insertion. */ + private final static int[] kidOK; + + static { + kidOK = new int[13]; + kidOK[Node.DOCUMENT_NODE] = + 1 << Node.ELEMENT_NODE | 1 << Node.PROCESSING_INSTRUCTION_NODE | + 1 << Node.COMMENT_NODE | 1 << Node.DOCUMENT_TYPE_NODE; + kidOK[Node.DOCUMENT_FRAGMENT_NODE] = + kidOK[Node.ENTITY_NODE] = + kidOK[Node.ENTITY_REFERENCE_NODE] = + kidOK[Node.ELEMENT_NODE] = + 1 << Node.ELEMENT_NODE | 1 << Node.PROCESSING_INSTRUCTION_NODE | + 1 << Node.COMMENT_NODE | 1 << Node.TEXT_NODE | + 1 << Node.CDATA_SECTION_NODE | 1 << Node.ENTITY_REFERENCE_NODE ; + kidOK[Node.ATTRIBUTE_NODE] = 1 << Node.TEXT_NODE | 1 << Node.ENTITY_REFERENCE_NODE; + kidOK[Node.DOCUMENT_TYPE_NODE] = 0; + kidOK[Node.PROCESSING_INSTRUCTION_NODE] = 0; + kidOK[Node.COMMENT_NODE] = 0; + kidOK[Node.TEXT_NODE] = 0; + kidOK[Node.CDATA_SECTION_NODE] = 0; + kidOK[Node.NOTATION_NODE] = 0; + } // static + + // + // Data + // + + private Document fDocument; + private CoreDocumentImpl fDocumentImpl; + private boolean fStorePSVI; + + private Node fTarget; + private Node fNextSibling; + + private Node fCurrentNode; + private Node fFragmentRoot; + + private final ArrayList fTargetChildren = new ArrayList(); + + private boolean fIgnoreChars; + + private final QName fAttributeQName = new QName(); + + public DOMResultBuilder() {} + + /* + * DOMDocumentHandler methods + */ + + public void setDOMResult(DOMResult result) { + fCurrentNode = null; + fFragmentRoot = null; + fIgnoreChars = false; + fTargetChildren.clear(); + if (result != null) { + fTarget = result.getNode(); + fNextSibling = result.getNextSibling(); + fDocument = (fTarget.getNodeType() == Node.DOCUMENT_NODE) ? (Document) fTarget : fTarget.getOwnerDocument(); + fDocumentImpl = (fDocument instanceof CoreDocumentImpl) ? (CoreDocumentImpl) fDocument : null; + fStorePSVI = (fDocument instanceof PSVIDocumentImpl); + return; + } + fTarget = null; + fNextSibling = null; + fDocument = null; + fDocumentImpl = null; + fStorePSVI = false; + } + + public void doctypeDecl(DocumentType node) throws XNIException { + /** Create new DocumentType node for the target. */ + if (fDocumentImpl != null) { + DocumentType docType = fDocumentImpl.createDocumentType(node.getName(), node.getPublicId(), node.getSystemId()); + final String internalSubset = node.getInternalSubset(); + /** Copy internal subset. */ + if (internalSubset != null) { + ((DocumentTypeImpl) docType).setInternalSubset(internalSubset); + } + /** Copy entities. */ + NamedNodeMap oldMap = node.getEntities(); + NamedNodeMap newMap = docType.getEntities(); + int length = oldMap.getLength(); + for (int i = 0; i < length; ++i) { + Entity oldEntity = (Entity) oldMap.item(i); + EntityImpl newEntity = (EntityImpl) fDocumentImpl.createEntity(oldEntity.getNodeName()); + newEntity.setPublicId(oldEntity.getPublicId()); + newEntity.setSystemId(oldEntity.getSystemId()); + newEntity.setNotationName(oldEntity.getNotationName()); + newMap.setNamedItem(newEntity); + } + /** Copy notations. */ + oldMap = node.getNotations(); + newMap = docType.getNotations(); + length = oldMap.getLength(); + for (int i = 0; i < length; ++i) { + Notation oldNotation = (Notation) oldMap.item(i); + NotationImpl newNotation = (NotationImpl) fDocumentImpl.createNotation(oldNotation.getNodeName()); + newNotation.setPublicId(oldNotation.getPublicId()); + newNotation.setSystemId(oldNotation.getSystemId()); + newMap.setNamedItem(newNotation); + } + append(docType); + } + } + + public void characters(Text node) throws XNIException { + /** Create new Text node for the target. */ + append(fDocument.createTextNode(node.getNodeValue())); + } + + public void cdata(CDATASection node) throws XNIException { + /** Create new CDATASection node for the target. */ + append(fDocument.createCDATASection(node.getNodeValue())); + } + + public void comment(Comment node) throws XNIException { + /** Create new Comment node for the target. */ + append(fDocument.createComment(node.getNodeValue())); + } + + public void processingInstruction(ProcessingInstruction node) + throws XNIException { + /** Create new ProcessingInstruction node for the target. */ + append(fDocument.createProcessingInstruction(node.getTarget(), node.getData())); + } + + public void setIgnoringCharacters(boolean ignore) { + fIgnoreChars = ignore; + } + + /* + * XMLDocumentHandler methods + */ + + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException {} + + public void xmlDecl(String version, String encoding, String standalone, + Augmentations augs) throws XNIException {} + + public void doctypeDecl(String rootElement, String publicId, + String systemId, Augmentations augs) throws XNIException {} + + public void comment(XMLString text, Augmentations augs) throws XNIException {} + + public void processingInstruction(String target, XMLString data, + Augmentations augs) throws XNIException {} + + public void startElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + Element elem; + int attrCount = attributes.getLength(); + if (fDocumentImpl == null) { + elem = fDocument.createElementNS(element.uri, element.rawname); + for (int i = 0; i < attrCount; ++i) { + attributes.getName(i, fAttributeQName); + elem.setAttributeNS(fAttributeQName.uri, fAttributeQName.rawname, attributes.getValue(i)); + } + } + // If it's a Xerces DOM store type information for attributes, set idness, etc.. + else { + elem = fDocumentImpl.createElementNS(element.uri, element.rawname, element.localpart); + for (int i = 0; i < attrCount; ++i) { + attributes.getName(i, fAttributeQName); + AttrImpl attr = (AttrImpl) fDocumentImpl.createAttributeNS(fAttributeQName.uri, + fAttributeQName.rawname, fAttributeQName.localpart); + attr.setValue(attributes.getValue(i)); + elem.setAttributeNodeNS(attr); + + // write type information to this attribute + AttributePSVI attrPSVI = (AttributePSVI) attributes.getAugmentations(i).getItem (Constants.ATTRIBUTE_PSVI); + if (attrPSVI != null) { + if (fStorePSVI) { + ((PSVIAttrNSImpl) attr).setPSVI(attrPSVI); + } + Object type = attrPSVI.getMemberTypeDefinition(); + if (type == null) { + type = attrPSVI.getTypeDefinition(); + if (type != null) { + attr.setType (type); + if (((XSSimpleType) type).isIDType()) { + ((ElementImpl) elem).setIdAttributeNode (attr, true); + } + } + } + else { + attr.setType (type); + if (((XSSimpleType) type).isIDType()) { + ((ElementImpl) elem).setIdAttributeNode (attr, true); + } + } + } + attr.setSpecified(attributes.isSpecified(i)); + } + } + append(elem); + fCurrentNode = elem; + if (fFragmentRoot == null) { + fFragmentRoot = elem; + } + } + + public void emptyElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + startElement(element, attributes, augs); + endElement(element, augs); + } + + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, String encoding, + Augmentations augs) throws XNIException {} + + public void textDecl(String version, String encoding, Augmentations augs) + throws XNIException {} + + public void endGeneralEntity(String name, Augmentations augs) + throws XNIException {} + + public void characters(XMLString text, Augmentations augs) + throws XNIException { + if (!fIgnoreChars) { + append(fDocument.createTextNode(text.toString())); + } + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) + throws XNIException { + characters(text, augs); + } + + public void endElement(QName element, Augmentations augs) + throws XNIException { + // write type information to this element + if (augs != null && fDocumentImpl != null) { + ElementPSVI elementPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI); + if (elementPSVI != null) { + if (fStorePSVI) { + ((PSVIElementNSImpl)fCurrentNode).setPSVI(elementPSVI); + } + XSTypeDefinition type = elementPSVI.getMemberTypeDefinition(); + if (type == null) { + type = elementPSVI.getTypeDefinition(); + } + ((ElementNSImpl)fCurrentNode).setType(type); + } + } + + // adjust current node reference + if (fCurrentNode == fFragmentRoot) { + fCurrentNode = null; + fFragmentRoot = null; + return; + } + fCurrentNode = fCurrentNode.getParentNode(); + } + + public void startCDATA(Augmentations augs) throws XNIException {} + + public void endCDATA(Augmentations augs) throws XNIException {} + + public void endDocument(Augmentations augs) throws XNIException { + final int length = fTargetChildren.size(); + if (fNextSibling == null) { + for (int i = 0; i < length; ++i) { + fTarget.appendChild((Node) fTargetChildren.get(i)); + } + } + else { + for (int i = 0; i < length; ++i) { + fTarget.insertBefore((Node) fTargetChildren.get(i), fNextSibling); + } + } + } + + public void setDocumentSource(XMLDocumentSource source) {} + + public XMLDocumentSource getDocumentSource() { + return null; + } + + /* + * Other methods + */ + + private void append(Node node) throws XNIException { + if (fCurrentNode != null) { + fCurrentNode.appendChild(node); + } + else { + /** Check if this node can be attached to the target. */ + if ((kidOK[fTarget.getNodeType()] & (1 << node.getNodeType())) == 0) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null); + throw new XNIException(msg); + } + fTargetChildren.add(node); + } + } + +} // DOMResultBuilder diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMValidatorHelper.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMValidatorHelper.java new file mode 100644 index 0000000..a4822c0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DOMValidatorHelper.java @@ -0,0 +1,611 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.io.IOException; +import java.util.Enumeration; + +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 org.apache.xerces.dom.NodeImpl; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.validation.EntityState; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.impl.xs.util.SimpleLocator; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLParseException; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Entity; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.xml.sax.SAXException; + +/** + *

        A validator helper for DOMSources.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class DOMValidatorHelper implements ValidatorHelper, EntityState { + + // + // Constants + // + + /** Chunk size (1024). */ + private static final int CHUNK_SIZE = (1 << 10); + + /** Chunk mask (CHUNK_SIZE - 1). */ + private static final int CHUNK_MASK = CHUNK_SIZE - 1; + + // property identifiers + + /** Property identifier: error reporter. */ + private static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: namespace context. */ + private static final String NAMESPACE_CONTEXT = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY; + + /** Property identifier: XML Schema validator. */ + private static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: symbol table. */ + private static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: validation manager. */ + private static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + // + // Data + // + + /** Error reporter. */ + private final XMLErrorReporter fErrorReporter; + + /** The namespace context of this document: stores namespaces in scope. **/ + private final NamespaceSupport fNamespaceContext; + + /** The namespace context of the DOMSource, includes context from ancestor nodes. **/ + private final DOMNamespaceContext fDOMNamespaceContext = new DOMNamespaceContext(); + + /** Schema validator. **/ + private final XMLSchemaValidator fSchemaValidator; + + /** Symbol table **/ + private final SymbolTable fSymbolTable; + + /** Validation manager. **/ + private final ValidationManager fValidationManager; + + /** Component manager. **/ + private final XMLSchemaValidatorComponentManager fComponentManager; + + /** Simple Locator. **/ + private final SimpleLocator fXMLLocator = new SimpleLocator(null, null, -1, -1, -1); + + /** DOM document handler. **/ + private DOMDocumentHandler fDOMValidatorHandler; + + /** DOM result augmentor. **/ + private final DOMResultAugmentor fDOMResultAugmentor = new DOMResultAugmentor(this); + + /** DOM result builder. **/ + private final DOMResultBuilder fDOMResultBuilder = new DOMResultBuilder(); + + /** Map for tracking unparsed entities. **/ + private NamedNodeMap fEntities = null; + + /** Array for holding character data. **/ + private final char [] fCharBuffer = new char[CHUNK_SIZE]; + + /** Root node. **/ + private Node fRoot; + + /** Current element. **/ + private Node fCurrentElement; + + /** Fields for start element, end element and characters. **/ + final QName fElementQName = new QName(); + final QName fAttributeQName = new QName(); + final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); + final XMLString fTempString = new XMLString(); + + public DOMValidatorHelper(XMLSchemaValidatorComponentManager componentManager) { + fComponentManager = componentManager; + fErrorReporter = (XMLErrorReporter) fComponentManager.getProperty(ERROR_REPORTER); + fNamespaceContext = (NamespaceSupport) fComponentManager.getProperty(NAMESPACE_CONTEXT); + fSchemaValidator = (XMLSchemaValidator) fComponentManager.getProperty(SCHEMA_VALIDATOR); + fSymbolTable = (SymbolTable) fComponentManager.getProperty(SYMBOL_TABLE); + fValidationManager = (ValidationManager) fComponentManager.getProperty(VALIDATION_MANAGER); + } + + /* + * ValidatorHelper methods + */ + + public void validate(Source source, Result result) + throws SAXException, IOException { + if (result instanceof DOMResult || result == null) { + final DOMSource domSource = (DOMSource) source; + final DOMResult domResult = (DOMResult) result; + Node node = domSource.getNode(); + fRoot = node; + if (node != null) { + fComponentManager.reset(); + fValidationManager.setEntityState(this); + fDOMNamespaceContext.reset(); + String systemId = domSource.getSystemId(); + fXMLLocator.setLiteralSystemId(systemId); + fXMLLocator.setExpandedSystemId(systemId); + fErrorReporter.setDocumentLocator(fXMLLocator); + try { + // regardless of what type of node this is, fire start and end document events + setupEntityMap((node.getNodeType() == Node.DOCUMENT_NODE) ? (Document) node : node.getOwnerDocument()); + setupDOMResultHandler(domSource, domResult); + fSchemaValidator.startDocument(fXMLLocator, null, fDOMNamespaceContext, null); + validate(node); + fSchemaValidator.endDocument(null); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + finally { + // Release references to application objects + fRoot = null; + fCurrentElement = null; + fEntities = null; + if (fDOMValidatorHandler != null) { + fDOMValidatorHandler.setDOMResult(null); + } + } + } + return; + } + throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "SourceResultMismatch", + new Object [] {source.getClass().getName(), result.getClass().getName()})); + } + + /* + * EntityState methods + */ + + public boolean isEntityDeclared(String name) { + return false; + } + + public boolean isEntityUnparsed(String name) { + if (fEntities != null) { + Entity entity = (Entity) fEntities.getNamedItem(name); + if (entity != null) { + return (entity.getNotationName() != null); + } + } + return false; + } + + /* + * Other methods + */ + + /** Traverse the DOM and fire events to the schema validator. */ + private void validate(Node node) { + final Node top = node; + final boolean useIsSameNode = useIsSameNode(top); + // Performs a non-recursive traversal of the DOM. This + // will avoid a stack overflow for DOMs with high depth. + while (node != null) { + beginNode(node); + Node next = node.getFirstChild(); + while (next == null) { + finishNode(node); + if (top == node) { + break; + } + next = node.getNextSibling(); + if (next == null) { + node = node.getParentNode(); + if (node == null || ((useIsSameNode) ? + top.isSameNode(node) : top == node)) { + if (node != null) { + finishNode(node); + } + next = null; + break; + } + } + } + node = next; + } + } + + /** Do processing for the start of a node. */ + private void beginNode(Node node) { + switch (node.getNodeType()) { + case Node.ELEMENT_NODE: + fCurrentElement = node; + // push namespace context + fNamespaceContext.pushContext(); + // start element + fillQName(fElementQName, node); + processAttributes(node.getAttributes()); + fSchemaValidator.startElement(fElementQName, fAttributes, null); + break; + case Node.TEXT_NODE: + if (fDOMValidatorHandler != null) { + fDOMValidatorHandler.setIgnoringCharacters(true); + sendCharactersToValidator(node.getNodeValue()); + fDOMValidatorHandler.setIgnoringCharacters(false); + fDOMValidatorHandler.characters((Text) node); + } + else { + sendCharactersToValidator(node.getNodeValue()); + } + break; + case Node.CDATA_SECTION_NODE: + if (fDOMValidatorHandler != null) { + fDOMValidatorHandler.setIgnoringCharacters(true); + fSchemaValidator.startCDATA(null); + sendCharactersToValidator(node.getNodeValue()); + fSchemaValidator.endCDATA(null); + fDOMValidatorHandler.setIgnoringCharacters(false); + fDOMValidatorHandler.cdata((CDATASection) node); + } + else { + fSchemaValidator.startCDATA(null); + sendCharactersToValidator(node.getNodeValue()); + fSchemaValidator.endCDATA(null); + } + break; + case Node.PROCESSING_INSTRUCTION_NODE: + /** + * The validator does nothing with processing instructions so bypass it. + * Send the ProcessingInstruction node directly to the result builder. + */ + if (fDOMValidatorHandler != null) { + fDOMValidatorHandler.processingInstruction((ProcessingInstruction) node); + } + break; + case Node.COMMENT_NODE: + /** + * The validator does nothing with comments so bypass it. + * Send the Comment node directly to the result builder. + */ + if (fDOMValidatorHandler != null) { + fDOMValidatorHandler.comment((Comment) node); + } + break; + case Node.DOCUMENT_TYPE_NODE: + /** + * Send the DocumentType node directly to the result builder. + */ + if (fDOMValidatorHandler != null) { + fDOMValidatorHandler.doctypeDecl((DocumentType) node); + } + break; + default: // Ignore other node types. + break; + } + } + + /** Do processing for the end of a node. */ + private void finishNode(Node node) { + if (node.getNodeType() == Node.ELEMENT_NODE) { + fCurrentElement = node; + // end element + fillQName(fElementQName, node); + fSchemaValidator.endElement(fElementQName, null); + // pop namespace context + fNamespaceContext.popContext(); + } + } + + /** + * Extracts NamedNodeMap of entities. We need this to validate + * elements and attributes of type xs:ENTITY, xs:ENTITIES or + * types dervied from them. + */ + private void setupEntityMap(Document doc) { + if (doc != null) { + DocumentType docType = doc.getDoctype(); + if (docType != null) { + fEntities = docType.getEntities(); + return; + } + } + fEntities = null; + } + + /** + * Sets up handler for DOMResult. + */ + private void setupDOMResultHandler(DOMSource source, DOMResult result) throws SAXException { + // If there's no DOMResult, unset the validator handler + if (result == null) { + fDOMValidatorHandler = null; + fSchemaValidator.setDocumentHandler(null); + return; + } + final Node nodeResult = result.getNode(); + // If the source node and result node are the same use the DOMResultAugmentor. + // Otherwise use the DOMResultBuilder. + if (source.getNode() == nodeResult) { + fDOMValidatorHandler = fDOMResultAugmentor; + fDOMResultAugmentor.setDOMResult(result); + fSchemaValidator.setDocumentHandler(fDOMResultAugmentor); + return; + } + if (result.getNode() == null) { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + result.setNode(builder.newDocument()); + } + catch (ParserConfigurationException e) { + throw new SAXException(e); + } + } + fDOMValidatorHandler = fDOMResultBuilder; + fDOMResultBuilder.setDOMResult(result); + fSchemaValidator.setDocumentHandler(fDOMResultBuilder); + } + + private void fillQName(QName toFill, Node node) { + final String prefix = node.getPrefix(); + final String localName = node.getLocalName(); + final String rawName = node.getNodeName(); + final String namespace = node.getNamespaceURI(); + toFill.prefix = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING; + toFill.localpart = (localName != null) ? fSymbolTable.addSymbol(localName) : XMLSymbols.EMPTY_STRING; + toFill.rawname = (rawName != null) ? fSymbolTable.addSymbol(rawName) : XMLSymbols.EMPTY_STRING; + toFill.uri = (namespace != null && namespace.length() > 0) ? fSymbolTable.addSymbol(namespace) : null; + } + + private void processAttributes(NamedNodeMap attrMap) { + final int attrCount = attrMap.getLength(); + fAttributes.removeAllAttributes(); + for (int i = 0; i < attrCount; ++i) { + Attr attr = (Attr) attrMap.item(i); + String value = attr.getValue(); + if (value == null) { + value = XMLSymbols.EMPTY_STRING; + } + fillQName(fAttributeQName, attr); + // REVISIT: Assuming all attributes are of type CDATA. The actual type may not matter. -- mrglavas + fAttributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, value); + fAttributes.setSpecified(i, attr.getSpecified()); + // REVISIT: Should we be looking at non-namespace attributes + // for additional mappings? Should we detect illegal namespace + // declarations and exclude them from the context? -- mrglavas + if (fAttributeQName.uri == NamespaceContext.XMLNS_URI) { + // process namespace attribute + if (fAttributeQName.prefix == XMLSymbols.PREFIX_XMLNS) { + fNamespaceContext.declarePrefix(fAttributeQName.localpart, value.length() != 0 ? fSymbolTable.addSymbol(value) : null); + } + else { + fNamespaceContext.declarePrefix(XMLSymbols.EMPTY_STRING, value.length() != 0 ? fSymbolTable.addSymbol(value) : null); + } + } + } + } + + private void sendCharactersToValidator(String str) { + if (str != null) { + final int length = str.length(); + final int remainder = length & CHUNK_MASK; + if (remainder > 0) { + str.getChars(0, remainder, fCharBuffer, 0); + fTempString.setValues(fCharBuffer, 0, remainder); + fSchemaValidator.characters(fTempString, null); + } + int i = remainder; + while (i < length) { + str.getChars(i, i += CHUNK_SIZE, fCharBuffer, 0); + fTempString.setValues(fCharBuffer, 0, CHUNK_SIZE); + fSchemaValidator.characters(fTempString, null); + } + } + } + + /** + * Use isSameNode() for testing node identity if the DOM implementation + * supports DOM Level 3 core and it isn't the Xerces implementation. + */ + private boolean useIsSameNode(Node node) { + if (node instanceof NodeImpl) { + return false; + } + Document doc = node.getNodeType() == Node.DOCUMENT_NODE + ? (Document) node : node.getOwnerDocument(); + return (doc != null && doc.getImplementation().hasFeature("Core", "3.0")); + } + + /** + * Returns the current element node. + */ + Node getCurrentElement() { + return fCurrentElement; + } + + /** + * NamespaceContext for the DOMSource, includes context for ancestor nodes. + */ + final class DOMNamespaceContext implements NamespaceContext { + + // + // Data + // + + /** + * Namespace binding information. This array is composed of a + * series of tuples containing the namespace binding information: + * <prefix, uri>. + */ + protected String[] fNamespace = new String[16 * 2]; + + /** The size of the namespace information array. */ + protected int fNamespaceSize = 0; + + /** + * Flag indicating whether the namespace context + * has been from the root node's ancestors. + */ + protected boolean fDOMContextBuilt = false; + + // + // Methods + // + + public void pushContext() { + fNamespaceContext.pushContext(); + } + + public void popContext() { + fNamespaceContext.popContext(); + } + + public boolean declarePrefix(String prefix, String uri) { + return fNamespaceContext.declarePrefix(prefix, uri); + } + + public String getURI(String prefix) { + String uri = fNamespaceContext.getURI(prefix); + if (uri == null) { + if (!fDOMContextBuilt) { + fillNamespaceContext(); + fDOMContextBuilt = true; + } + if (fNamespaceSize > 0 && + !fNamespaceContext.containsPrefix(prefix)) { + uri = getURI0(prefix); + } + } + return uri; + } + + public String getPrefix(String uri) { + return fNamespaceContext.getPrefix(uri); + } + + public int getDeclaredPrefixCount() { + return fNamespaceContext.getDeclaredPrefixCount(); + } + + public String getDeclaredPrefixAt(int index) { + return fNamespaceContext.getDeclaredPrefixAt(index); + } + + public Enumeration getAllPrefixes() { + return fNamespaceContext.getAllPrefixes(); + } + + public void reset() { + fDOMContextBuilt = false; + fNamespaceSize = 0; + } + + private void fillNamespaceContext() { + if (fRoot != null) { + Node currentNode = fRoot.getParentNode(); + while (currentNode != null) { + if (Node.ELEMENT_NODE == currentNode.getNodeType()) { + NamedNodeMap attributes = currentNode.getAttributes(); + final int attrCount = attributes.getLength(); + for (int i = 0; i < attrCount; ++i) { + Attr attr = (Attr) attributes.item(i); + String value = attr.getValue(); + if (value == null) { + value = XMLSymbols.EMPTY_STRING; + } + fillQName(fAttributeQName, attr); + // REVISIT: Should we be looking at non-namespace attributes + // for additional mappings? Should we detect illegal namespace + // declarations and exclude them from the context? -- mrglavas + if (fAttributeQName.uri == NamespaceContext.XMLNS_URI) { + // process namespace attribute + if (fAttributeQName.prefix == XMLSymbols.PREFIX_XMLNS) { + declarePrefix0(fAttributeQName.localpart, value.length() != 0 ? fSymbolTable.addSymbol(value) : null); + } + else { + declarePrefix0(XMLSymbols.EMPTY_STRING, value.length() != 0 ? fSymbolTable.addSymbol(value) : null); + } + } + } + + } + currentNode = currentNode.getParentNode(); + } + } + } + + private void declarePrefix0(String prefix, String uri) { + // resize array, if needed + if (fNamespaceSize == fNamespace.length) { + String[] namespacearray = new String[fNamespaceSize * 2]; + System.arraycopy(fNamespace, 0, namespacearray, 0, fNamespaceSize); + fNamespace = namespacearray; + } + + // bind prefix to uri in current context + fNamespace[fNamespaceSize++] = prefix; + fNamespace[fNamespaceSize++] = uri; + } + + private String getURI0(String prefix) { + // find prefix in the DOM context + for (int i = 0; i < fNamespaceSize; i += 2) { + if (fNamespace[i] == prefix) { + return fNamespace[i + 1]; + } + } + // prefix not found + return null; + } + } + +} // DOMValidatorHelper diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DraconianErrorHandler.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DraconianErrorHandler.java new file mode 100644 index 0000000..41777fc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/DraconianErrorHandler.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * {@link ErrorHandler} that throws all errors and fatal errors. + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * @version $Id$ + */ +final class DraconianErrorHandler implements ErrorHandler { + + /** + * Singleton instance. + */ + private static final DraconianErrorHandler ERROR_HANDLER_INSTANCE + = new DraconianErrorHandler(); + + private DraconianErrorHandler() {} + + /** Returns the one and only instance of this error handler. */ + public static DraconianErrorHandler getInstance() { + return ERROR_HANDLER_INSTANCE; + } + + /** Warning: Ignore. */ + public void warning(SAXParseException e) throws SAXException { + // noop + } + + /** Error: Throws back SAXParseException. */ + public void error(SAXParseException e) throws SAXException { + throw e; + } + + /** Fatal Error: Throws back SAXParseException. */ + public void fatalError(SAXParseException e) throws SAXException { + throw e; + } + +} // DraconianErrorHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/EmptyXMLSchema.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/EmptyXMLSchema.java new file mode 100644 index 0000000..896fce7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/EmptyXMLSchema.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; + +/** + *

        Implementation of Schema for W3C XML Schemas + * which contains no schema components.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class EmptyXMLSchema extends AbstractXMLSchema implements XMLGrammarPool { + + /** Zero length grammar array. */ + private static final Grammar [] ZERO_LENGTH_GRAMMAR_ARRAY = new Grammar [0]; + + public EmptyXMLSchema() {} + + /* + * XMLGrammarPool methods + */ + + public Grammar[] retrieveInitialGrammarSet(String grammarType) { + return ZERO_LENGTH_GRAMMAR_ARRAY; + } + + public void cacheGrammars(String grammarType, Grammar[] grammars) {} + + public Grammar retrieveGrammar(XMLGrammarDescription desc) { + return null; + } + + public void lockPool() {} + + public void unlockPool() {} + + public void clear() {} + + /* + * XSGrammarPoolContainer methods + */ + + public XMLGrammarPool getGrammarPool() { + return this; + } + + public boolean isFullyComposed() { + return true; + } + +} // EmptyXMLSchema diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/JAXPValidationMessageFormatter.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/JAXPValidationMessageFormatter.java new file mode 100644 index 0000000..05b4e0c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/JAXPValidationMessageFormatter.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + *

        Used to format JAXP Validation API error messages using a specified locale.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class JAXPValidationMessageFormatter { + + /** + * Formats a message with the specified arguments using the given + * locale information. + * + * @param locale The locale of the message. + * @param key The message key. + * @param arguments The message replacement text arguments. The order + * of the arguments must match that of the placeholders + * in the actual message. + * + * @return the formatted message. + * + * @throws MissingResourceException Thrown if the message with the + * specified key cannot be found. + */ + public static String formatMessage(Locale locale, + String key, Object[] arguments) + throws MissingResourceException { + + if (locale == null) { + locale = Locale.getDefault(); + } + final ResourceBundle resourceBundle = + ResourceBundle.getBundle("org.apache.xerces.impl.msg.JAXPValidationMessages", locale); + + // format message + String msg; + try { + msg = resourceBundle.getString(key); + if (arguments != null) { + try { + msg = java.text.MessageFormat.format(msg, arguments); + } + catch (Exception e) { + msg = resourceBundle.getString("FormatFailed"); + msg += " " + resourceBundle.getString(key); + } + } + } + + // error + catch (MissingResourceException e) { + msg = resourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(key, msg, key); + } + + // no message + if (msg == null) { + msg = key; + if (arguments.length > 0) { + StringBuffer str = new StringBuffer(msg); + str.append('?'); + for (int i = 0; i < arguments.length; i++) { + if (i > 0) { + str.append('&'); + } + str.append(String.valueOf(arguments[i])); + } + } + } + return msg; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ReadOnlyGrammarPool.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ReadOnlyGrammarPool.java new file mode 100644 index 0000000..b3037b7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ReadOnlyGrammarPool.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; + +/** + *

        Filter {@link XMLGrammarPool} that exposes a + * read-only view of the underlying pool.

        + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * @version $Id$ + */ +final class ReadOnlyGrammarPool implements XMLGrammarPool { + + private final XMLGrammarPool core; + + public ReadOnlyGrammarPool( XMLGrammarPool pool ) { + this.core = pool; + } + + public void cacheGrammars(String grammarType, Grammar[] grammars) { + // noop. don't let caching to happen + } + + public void clear() { + // noop. cache is read-only. + } + + public void lockPool() { + // noop. this pool is always read-only + } + + public Grammar retrieveGrammar(XMLGrammarDescription desc) { + return core.retrieveGrammar(desc); + } + + public Grammar[] retrieveInitialGrammarSet(String grammarType) { + return core.retrieveInitialGrammarSet(grammarType); + } + + public void unlockPool() { + // noop. this pool is always read-only. + } + +} // ReadOnlyGrammarPool diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/SimpleXMLSchema.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/SimpleXMLSchema.java new file mode 100644 index 0000000..07ee7e5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/SimpleXMLSchema.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; + +/** + *

        Implementation of Schema for W3C XML Schemas which + * contains schema components from one target namespace.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class SimpleXMLSchema extends AbstractXMLSchema implements XMLGrammarPool { + + /** Zero length grammar array. */ + private static final Grammar [] ZERO_LENGTH_GRAMMAR_ARRAY = new Grammar [0]; + + private final Grammar fGrammar; + private final Grammar[] fGrammars; + private final XMLGrammarDescription fGrammarDescription; + + public SimpleXMLSchema(Grammar grammar) { + fGrammar = grammar; + fGrammars = new Grammar[] {grammar}; + fGrammarDescription = grammar.getGrammarDescription(); + } + + /* + * XMLGrammarPool methods + */ + + public Grammar[] retrieveInitialGrammarSet(String grammarType) { + return XMLGrammarDescription.XML_SCHEMA.equals(grammarType) ? + (Grammar[]) fGrammars.clone() : ZERO_LENGTH_GRAMMAR_ARRAY; + } + + public void cacheGrammars(String grammarType, Grammar[] grammars) {} + + public Grammar retrieveGrammar(XMLGrammarDescription desc) { + return fGrammarDescription.equals(desc) ? fGrammar : null; + } + + public void lockPool() {} + + public void unlockPool() {} + + public void clear() {} + + /* + * XSGrammarPoolContainer methods + */ + + public XMLGrammarPool getGrammarPool() { + return this; + } + + public boolean isFullyComposed() { + return true; + } + +} // SimpleXMLSchema diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/SoftReferenceGrammarPool.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/SoftReferenceGrammarPool.java new file mode 100644 index 0000000..2a88266 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/SoftReferenceGrammarPool.java @@ -0,0 +1,433 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; + +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.grammars.XMLSchemaDescription; + +/** + *

        This grammar pool is a memory sensitive cache. The grammars + * stored in the pool are softly reachable and may be cleared by + * the garbage collector in response to memory demand. Equality + * of XMLSchemaDescriptions is determined using both + * the target namespace for the schema and schema location.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class SoftReferenceGrammarPool implements XMLGrammarPool { + + // + // Constants + // + + /** Default size. */ + protected static final int TABLE_SIZE = 11; + + /** Zero length grammar array. */ + protected static final Grammar [] ZERO_LENGTH_GRAMMAR_ARRAY = new Grammar [0]; + + // + // Data + // + + /** Grammars. */ + protected Entry [] fGrammars = null; + + /** Flag indicating whether this pool is locked */ + protected boolean fPoolIsLocked; + + /** The number of grammars in the pool */ + protected int fGrammarCount = 0; + + /** Reference queue for cleared grammar references */ + protected final ReferenceQueue fReferenceQueue = new ReferenceQueue(); + + // + // Constructors + // + + /** Constructs a grammar pool with a default number of buckets. */ + public SoftReferenceGrammarPool() { + fGrammars = new Entry[TABLE_SIZE]; + fPoolIsLocked = false; + } // () + + /** Constructs a grammar pool with a specified number of buckets. */ + public SoftReferenceGrammarPool(int initialCapacity) { + fGrammars = new Entry[initialCapacity]; + fPoolIsLocked = false; + } + + // + // XMLGrammarPool methods + // + + /*

        Retrieve the initial known set of grammars. This method is + * called by a validator before the validation starts. The application + * can provide an initial set of grammars available to the current + * validation attempt.

        + * + * @param grammarType The type of the grammar, from the + * org.apache.xerces.xni.grammars.XMLGrammarDescription + * interface. + * @return The set of grammars the validator may put in its "bucket" + */ + public Grammar [] retrieveInitialGrammarSet (String grammarType) { + synchronized (fGrammars) { + clean(); + // Return no grammars. This allows the garbage collector to sift + // out grammars which are not in use when memory demand is high. + // It also allows the pool to return the "right" schema grammar + // based on schema locations. + return ZERO_LENGTH_GRAMMAR_ARRAY; + } + } // retrieveInitialGrammarSet (String): Grammar[] + + /*

        Return the final set of grammars that the validator ended up + * with. This method is called after the validation finishes. The + * application may then choose to cache some of the returned grammars.

        + *

        In this implementation, we make our choice based on whether this object + * is "locked"--that is, whether the application has instructed + * us not to accept any new grammars.

        + * + * @param grammarType The type of the grammars being returned; + * @param grammars An array containing the set of grammars being + * returned; order is not significant. + */ + public void cacheGrammars(String grammarType, Grammar[] grammars) { + if (!fPoolIsLocked) { + for (int i = 0; i < grammars.length; ++i) { + putGrammar(grammars[i]); + } + } + } // cacheGrammars(String, Grammar[]); + + /*

        This method requests that the application retrieve a grammar + * corresponding to the given GrammarIdentifier from its cache. + * If it cannot do so it must return null; the parser will then + * call the EntityResolver.

        + * An application must not call its EntityResolver itself + * from this method; this may result in infinite recursions. + * + * This implementation chooses to use the root element name to identify a DTD grammar + * and the target namespace to identify a Schema grammar. + * + * @param desc The description of the Grammar being requested. + * @return The Grammar corresponding to this description or null if + * no such Grammar is known. + */ + public Grammar retrieveGrammar(XMLGrammarDescription desc) { + return getGrammar(desc); + } // retrieveGrammar(XMLGrammarDescription): Grammar + + // + // Public methods + // + + /** + * Puts the specified grammar into the grammar pool and associates it to + * its root element name or its target namespace. + * + * @param grammar The Grammar. + */ + public void putGrammar(Grammar grammar) { + if (!fPoolIsLocked) { + synchronized (fGrammars) { + clean(); + XMLGrammarDescription desc = grammar.getGrammarDescription(); + int hash = hashCode(desc); + int index = (hash & 0x7FFFFFFF) % fGrammars.length; + for (Entry entry = fGrammars[index]; entry != null; entry = entry.next) { + if (entry.hash == hash && equals(entry.desc, desc)) { + if (entry.grammar.get() != grammar) { + entry.grammar = new SoftGrammarReference(entry, grammar, fReferenceQueue); + } + return; + } + } + // create a new entry + Entry entry = new Entry(hash, index, desc, grammar, fGrammars[index], fReferenceQueue); + fGrammars[index] = entry; + fGrammarCount++; + } + } + } // putGrammar(Grammar) + + /** + * Returns the grammar associated to the specified grammar description. + * Currently, the root element name is used as the key for DTD grammars + * and the target namespace is used as the key for Schema grammars. + * + * @param desc The Grammar Description. + */ + public Grammar getGrammar(XMLGrammarDescription desc) { + synchronized (fGrammars) { + clean(); + int hash = hashCode(desc); + int index = (hash & 0x7FFFFFFF) % fGrammars.length; + for (Entry entry = fGrammars[index]; entry != null; entry = entry.next) { + Grammar tempGrammar = (Grammar) entry.grammar.get(); + /** If the soft reference has been cleared, remove this entry from the pool. */ + if (tempGrammar == null) { + removeEntry(entry); + } + else if ((entry.hash == hash) && equals(entry.desc, desc)) { + return tempGrammar; + } + } + return null; + } + } // getGrammar(XMLGrammarDescription):Grammar + + /** + * Removes the grammar associated to the specified grammar description from the + * grammar pool and returns the removed grammar. Currently, the root element name + * is used as the key for DTD grammars and the target namespace is used + * as the key for Schema grammars. + * + * @param desc The Grammar Description. + * @return The removed grammar. + */ + public Grammar removeGrammar(XMLGrammarDescription desc) { + synchronized (fGrammars) { + clean(); + int hash = hashCode(desc); + int index = (hash & 0x7FFFFFFF) % fGrammars.length; + for (Entry entry = fGrammars[index]; entry != null; entry = entry.next) { + if ((entry.hash == hash) && equals(entry.desc, desc)) { + return removeEntry(entry); + } + } + return null; + } + } // removeGrammar(XMLGrammarDescription):Grammar + + /** + * Returns true if the grammar pool contains a grammar associated + * to the specified grammar description. Currently, the root element name + * is used as the key for DTD grammars and the target namespace is used + * as the key for Schema grammars. + * + * @param desc The Grammar Description. + */ + public boolean containsGrammar(XMLGrammarDescription desc) { + synchronized (fGrammars) { + clean(); + int hash = hashCode(desc); + int index = (hash & 0x7FFFFFFF) % fGrammars.length; + for (Entry entry = fGrammars[index]; entry != null ; entry = entry.next) { + Grammar tempGrammar = (Grammar) entry.grammar.get(); + /** If the soft reference has been cleared, remove this entry from the pool. */ + if (tempGrammar == null) { + removeEntry(entry); + } + else if ((entry.hash == hash) && equals(entry.desc, desc)) { + return true; + } + } + return false; + } + } // containsGrammar(XMLGrammarDescription):boolean + + /*

        Sets this grammar pool to a "locked" state--i.e., + * no new grammars will be added until it is "unlocked". + */ + public void lockPool() { + fPoolIsLocked = true; + } // lockPool() + + /*

        Sets this grammar pool to an "unlocked" state--i.e., + * new grammars will be added when putGrammar or cacheGrammars + * are called. + */ + public void unlockPool() { + fPoolIsLocked = false; + } // unlockPool() + + /* + *

        This method clears the pool-i.e., removes references + * to all the grammars in it.

        + */ + public void clear() { + for (int i=0; iAn extension to XMLDocumentHandler for building StAX structures.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +interface StAXDocumentHandler extends XMLDocumentHandler { + + /** + *

        Sets the StAXResult object which will be receiving the output.

        + */ + public void setStAXResult(StAXResult result); + + public void startDocument(XMLStreamReader reader) throws XMLStreamException; + public void endDocument(XMLStreamReader reader) throws XMLStreamException; + public void comment(XMLStreamReader reader) throws XMLStreamException; + public void processingInstruction(XMLStreamReader reader) throws XMLStreamException; + public void entityReference(XMLStreamReader reader) throws XMLStreamException; + + public void startDocument(StartDocument event) throws XMLStreamException; + public void endDocument(EndDocument event) throws XMLStreamException; + public void doctypeDecl(DTD event) throws XMLStreamException; + public void characters(Characters event) throws XMLStreamException; + public void cdata(Characters event) throws XMLStreamException; + public void comment(Comment event) throws XMLStreamException; + public void processingInstruction(ProcessingInstruction event) throws XMLStreamException; + public void entityReference(EntityReference event) throws XMLStreamException; + + public void setIgnoringCharacters(boolean ignore); + +} // StAXDocumentHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXEventResultBuilder.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXEventResultBuilder.java new file mode 100644 index 0000000..d894416 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXEventResultBuilder.java @@ -0,0 +1,376 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.EndDocument; +import javax.xml.stream.events.EntityReference; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.XMLEvent; +import javax.xml.transform.stax.StAXResult; + +import org.apache.xerces.util.JAXPNamespaceContextWrapper; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + *

        StAX event result builder.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class StAXEventResultBuilder implements StAXDocumentHandler { + + // + // Data + // + + private XMLEventWriter fEventWriter; + private final XMLEventFactory fEventFactory; + private final StAXValidatorHelper fStAXValidatorHelper; + private final JAXPNamespaceContextWrapper fNamespaceContext; + private boolean fIgnoreChars; + private boolean fInCDATA; + private final QName fAttrName = new QName(); + + public StAXEventResultBuilder(StAXValidatorHelper helper, JAXPNamespaceContextWrapper context) { + fStAXValidatorHelper = helper; + fNamespaceContext = context; + fEventFactory = XMLEventFactory.newInstance(); + } + + /* + * StAXDocumentHandler methods + */ + + public void setStAXResult(StAXResult result) { + fIgnoreChars = false; + fInCDATA = false; + fEventWriter = (result != null) ? result.getXMLEventWriter() : null; + } + + public void startDocument(XMLStreamReader reader) throws XMLStreamException { + String version = reader.getVersion(); + String encoding = reader.getCharacterEncodingScheme(); + boolean standalone = reader.standaloneSet(); + fEventWriter.add(fEventFactory.createStartDocument(encoding != null ? encoding : "UTF-8", + version != null ? version : "1.0", standalone)); + } + + public void endDocument(XMLStreamReader reader) throws XMLStreamException { + fEventWriter.add(fEventFactory.createEndDocument()); + fEventWriter.flush(); + } + + public void comment(XMLStreamReader reader) throws XMLStreamException { + fEventWriter.add(fEventFactory.createComment(reader.getText())); + } + + public void processingInstruction(XMLStreamReader reader) + throws XMLStreamException { + String data = reader.getPIData(); + fEventWriter.add(fEventFactory.createProcessingInstruction(reader.getPITarget(), + data != null ? data : "")); + } + + public void entityReference(XMLStreamReader reader) + throws XMLStreamException { + String name = reader.getLocalName(); + fEventWriter.add(fEventFactory.createEntityReference(name, + fStAXValidatorHelper.getEntityDeclaration(name))); + } + + public void startDocument(StartDocument event) throws XMLStreamException { + fEventWriter.add(event); + } + + public void endDocument(EndDocument event) throws XMLStreamException { + fEventWriter.add(event); + fEventWriter.flush(); + } + + public void doctypeDecl(DTD event) throws XMLStreamException { + fEventWriter.add(event); + } + + public void characters(Characters event) throws XMLStreamException { + fEventWriter.add(event); + } + + public void cdata(Characters event) throws XMLStreamException { + fEventWriter.add(event); + } + + public void comment(Comment event) throws XMLStreamException { + fEventWriter.add(event); + } + + public void processingInstruction(ProcessingInstruction event) + throws XMLStreamException { + fEventWriter.add(event); + } + + public void entityReference(EntityReference event) + throws XMLStreamException { + fEventWriter.add(event); + } + + public void setIgnoringCharacters(boolean ignore) { + fIgnoreChars = ignore; + } + + /* + * XMLDocumentHandler methods + */ + + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException {} + + public void xmlDecl(String version, String encoding, String standalone, + Augmentations augs) throws XNIException {} + + public void doctypeDecl(String rootElement, String publicId, + String systemId, Augmentations augs) throws XNIException {} + + public void comment(XMLString text, Augmentations augs) throws XNIException {} + + public void processingInstruction(String target, XMLString data, + Augmentations augs) throws XNIException {} + + public void startElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + try { + int length = attributes.getLength(); + if (length == 0) { + /** Avoid creating a new StartElement event object (if possible). */ + XMLEvent start = fStAXValidatorHelper.getCurrentEvent(); + if (start != null) { + fEventWriter.add(start); + return; + } + } + fEventWriter.add(fEventFactory.createStartElement(element.prefix, + element.uri != null ? element.uri : "", element.localpart, + getAttributeIterator(attributes, length), getNamespaceIterator(), + fNamespaceContext.getNamespaceContext())); + } + catch (XMLStreamException e) { + throw new XNIException(e); + } + } + + public void emptyElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + startElement(element, attributes, augs); + endElement(element, augs); + } + + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, String encoding, + Augmentations augs) throws XNIException {} + + public void textDecl(String version, String encoding, Augmentations augs) + throws XNIException {} + + public void endGeneralEntity(String name, Augmentations augs) + throws XNIException {} + + public void characters(XMLString text, Augmentations augs) + throws XNIException { + if (!fIgnoreChars) { + try { + if (!fInCDATA) { + fEventWriter.add(fEventFactory.createCharacters(text.toString())); + } + else { + fEventWriter.add(fEventFactory.createCData(text.toString())); + } + } + catch (XMLStreamException e) { + throw new XNIException(e); + } + } + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) + throws XNIException { + characters(text, augs); + } + + public void endElement(QName element, Augmentations augs) + throws XNIException { + try { + /** Avoid creating a new EndElement event object (if possible). */ + XMLEvent end = fStAXValidatorHelper.getCurrentEvent(); + if (end != null) { + fEventWriter.add(end); + } + else { + fEventWriter.add(fEventFactory.createEndElement(element.prefix, + element.uri, element.localpart, getNamespaceIterator())); + } + } + catch (XMLStreamException e) { + throw new XNIException(e); + } + } + + public void startCDATA(Augmentations augs) throws XNIException { + fInCDATA = true; + } + + public void endCDATA(Augmentations augs) throws XNIException { + fInCDATA = false; + } + + public void endDocument(Augmentations augs) throws XNIException {} + + public void setDocumentSource(XMLDocumentSource source) {} + + public XMLDocumentSource getDocumentSource() { + return null; + } + + /* + * Other methods. + */ + + private Iterator getAttributeIterator(XMLAttributes attributes, int length) { + return (length > 0) ? new AttributeIterator(attributes, length) : EMPTY_COLLECTION_ITERATOR; + } + + private Iterator getNamespaceIterator() { + int length = fNamespaceContext.getDeclaredPrefixCount(); + return (length > 0) ? new NamespaceIterator(length) : EMPTY_COLLECTION_ITERATOR; + } + + /** + * An iterator over XMLAttributes which returns Attribute event objects. + */ + final class AttributeIterator implements Iterator { + + XMLAttributes fAttributes; + int fIndex; + int fEnd; + + AttributeIterator(XMLAttributes attributes, int length) { + fAttributes = attributes; + fIndex = 0; + fEnd = length; + } + + public boolean hasNext() { + if (fIndex < fEnd) { + return true; + } + fAttributes = null; + return false; + } + + public Object next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + fAttributes.getName(fIndex, fAttrName); + return fEventFactory.createAttribute(fAttrName.prefix, + fAttrName.uri != null ? fAttrName.uri : "", + fAttrName.localpart, fAttributes.getValue(fIndex++)); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * An iterator over the current context of a NamespaceContext + * which returns Namespace event objects. + */ + final class NamespaceIterator implements Iterator { + + javax.xml.namespace.NamespaceContext fNC; + int fIndex; + int fEnd; + + NamespaceIterator(int length) { + fNC = fNamespaceContext.getNamespaceContext(); + fIndex = 0; + fEnd = length; + } + + public boolean hasNext() { + if (fIndex < fEnd) { + return true; + } + fNC = null; + return false; + } + + public Object next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + String prefix = fNamespaceContext.getDeclaredPrefixAt(fIndex++); + String uri = fNC.getNamespaceURI(prefix); + if (prefix.length() == 0) { + return fEventFactory.createNamespace(uri != null ? uri : ""); + } + else { + return fEventFactory.createNamespace(prefix, uri != null ? uri : ""); + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * An iterator for an empty collection. + */ + private static final Iterator EMPTY_COLLECTION_ITERATOR = new Iterator () { + public boolean hasNext() { + return false; + } + public Object next() { + throw new NoSuchElementException(); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + +} // StAXEventResultBuilder diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXStreamResultBuilder.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXStreamResultBuilder.java new file mode 100644 index 0000000..e770cb4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXStreamResultBuilder.java @@ -0,0 +1,285 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.EndDocument; +import javax.xml.stream.events.EntityReference; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.transform.stax.StAXResult; + +import org.apache.xerces.util.JAXPNamespaceContextWrapper; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + *

        StAX stream result builder.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class StAXStreamResultBuilder implements StAXDocumentHandler { + + // + // Data + // + + private XMLStreamWriter fStreamWriter; + private final JAXPNamespaceContextWrapper fNamespaceContext; + private boolean fIgnoreChars; + private boolean fInCDATA; + private final QName fAttrName = new QName(); + + public StAXStreamResultBuilder(JAXPNamespaceContextWrapper context) { + fNamespaceContext = context; + } + + /* + * StAXDocumentHandler methods + */ + + public void setStAXResult(StAXResult result) { + fIgnoreChars = false; + fInCDATA = false; + fAttrName.clear(); + fStreamWriter = (result != null) ? result.getXMLStreamWriter() : null; + } + + public void startDocument(XMLStreamReader reader) throws XMLStreamException { + String version = reader.getVersion(); + String encoding = reader.getCharacterEncodingScheme(); + fStreamWriter.writeStartDocument(encoding != null ? encoding : "UTF-8", + version != null ? version : "1.0"); + } + + public void endDocument(XMLStreamReader reader) throws XMLStreamException { + fStreamWriter.writeEndDocument(); + fStreamWriter.flush(); + } + + public void comment(XMLStreamReader reader) throws XMLStreamException { + fStreamWriter.writeComment(reader.getText()); + } + + public void processingInstruction(XMLStreamReader reader) + throws XMLStreamException { + String data = reader.getPIData(); + if (data != null && data.length() > 0) { + fStreamWriter.writeProcessingInstruction(reader.getPITarget(), data); + } + else { + fStreamWriter.writeProcessingInstruction(reader.getPITarget()); + } + } + + public void entityReference(XMLStreamReader reader) throws XMLStreamException { + fStreamWriter.writeEntityRef(reader.getLocalName()); + } + + public void startDocument(StartDocument event) throws XMLStreamException { + String version = event.getVersion(); + String encoding = event.getCharacterEncodingScheme(); + fStreamWriter.writeStartDocument(encoding != null ? encoding : "UTF-8", + version != null ? version : "1.0"); + } + + public void endDocument(EndDocument event) throws XMLStreamException { + fStreamWriter.writeEndDocument(); + fStreamWriter.flush(); + } + + public void doctypeDecl(DTD event) throws XMLStreamException { + fStreamWriter.writeDTD(event.getDocumentTypeDeclaration()); + } + + public void characters(Characters event) throws XMLStreamException { + fStreamWriter.writeCharacters(event.getData()); + } + + public void cdata(Characters event) throws XMLStreamException { + fStreamWriter.writeCData(event.getData()); + } + + public void comment(Comment event) throws XMLStreamException { + fStreamWriter.writeComment(event.getText()); + } + + public void processingInstruction(ProcessingInstruction event) + throws XMLStreamException { + String data = event.getData(); + if (data != null && data.length() > 0) { + fStreamWriter.writeProcessingInstruction(event.getTarget(), data); + } + else { + fStreamWriter.writeProcessingInstruction(event.getTarget()); + } + } + + public void entityReference(EntityReference event) throws XMLStreamException { + fStreamWriter.writeEntityRef(event.getName()); + + } + + public void setIgnoringCharacters(boolean ignore) { + fIgnoreChars = ignore; + } + + /* + * XMLDocumentHandler methods + */ + + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException {} + + public void xmlDecl(String version, String encoding, String standalone, + Augmentations augs) throws XNIException {} + + public void doctypeDecl(String rootElement, String publicId, + String systemId, Augmentations augs) throws XNIException {} + + public void comment(XMLString text, Augmentations augs) throws XNIException {} + + public void processingInstruction(String target, XMLString data, + Augmentations augs) throws XNIException {} + + public void startElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + try { + if (element.prefix.length() > 0) { + fStreamWriter.writeStartElement(element.prefix, + element.localpart, element.uri != null ? element.uri : ""); + } + else if (element.uri != null){ + fStreamWriter.writeStartElement(element.uri, element.localpart); + } + else { + fStreamWriter.writeStartElement(element.localpart); + } + int size = fNamespaceContext.getDeclaredPrefixCount(); + final javax.xml.namespace.NamespaceContext nc = fNamespaceContext.getNamespaceContext(); + for (int i = 0; i < size; ++i) { + String prefix = fNamespaceContext.getDeclaredPrefixAt(i); + String uri = nc.getNamespaceURI(prefix); + if (prefix.length() == 0) { + fStreamWriter.writeDefaultNamespace(uri != null ? uri : ""); + } + else { + fStreamWriter.writeNamespace(prefix, uri != null ? uri : ""); + } + } + size = attributes.getLength(); + for (int i = 0; i < size; ++i) { + attributes.getName(i, fAttrName); + if (fAttrName.prefix.length() > 0) { + fStreamWriter.writeAttribute(fAttrName.prefix, + fAttrName.uri != null ? fAttrName.uri : "", + fAttrName.localpart, attributes.getValue(i)); + } + else if (fAttrName.uri != null) { + fStreamWriter.writeAttribute(fAttrName.uri, + fAttrName.localpart, attributes.getValue(i)); + } + else { + fStreamWriter.writeAttribute(fAttrName.localpart, attributes.getValue(i)); + } + } + } + catch (XMLStreamException e) { + throw new XNIException(e); + } + } + + public void emptyElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + startElement(element, attributes, augs); + endElement(element, augs); + } + + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, String encoding, + Augmentations augs) throws XNIException {} + + public void textDecl(String version, String encoding, Augmentations augs) + throws XNIException {} + + public void endGeneralEntity(String name, Augmentations augs) + throws XNIException {} + + public void characters(XMLString text, Augmentations augs) + throws XNIException { + if (!fIgnoreChars) { + try { + if (!fInCDATA) { + fStreamWriter.writeCharacters(text.ch, text.offset, text.length); + } + else { + fStreamWriter.writeCData(text.toString()); + } + } + catch (XMLStreamException e) { + throw new XNIException(e); + } + } + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) + throws XNIException { + characters(text, augs); + } + + public void endElement(QName element, Augmentations augs) + throws XNIException { + try { + fStreamWriter.writeEndElement(); + } + catch (XMLStreamException e) { + throw new XNIException(e); + } + } + + public void startCDATA(Augmentations augs) throws XNIException { + fInCDATA = true; + } + + public void endCDATA(Augmentations augs) throws XNIException { + fInCDATA = false; + } + + public void endDocument(Augmentations augs) throws XNIException {} + + public void setDocumentSource(XMLDocumentSource source) {} + + public XMLDocumentSource getDocumentSource() { + return null; + } + +} // StAXStreamResultBuilder diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXValidatorHelper.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXValidatorHelper.java new file mode 100644 index 0000000..128b06c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StAXValidatorHelper.java @@ -0,0 +1,702 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.EndDocument; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.stax.StAXResult; +import javax.xml.transform.stax.StAXSource; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.validation.EntityState; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.util.JAXPNamespaceContextWrapper; +import org.apache.xerces.util.StAXLocationWrapper; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLStringBuffer; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLParseException; +import org.xml.sax.SAXException; + +/** + *

        A validator helper for StAXSources.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class StAXValidatorHelper implements ValidatorHelper, EntityState { + + // property identifiers + + /** Property identifier: string interning. */ + private static final String STRING_INTERNING = "javax.xml.stream.isInterning"; + + /** Property identifier: error reporter. */ + private static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: XML Schema validator. */ + private static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: symbol table. */ + private static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: validation manager. */ + private static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + // + // Data + // + + /** Error reporter. */ + private final XMLErrorReporter fErrorReporter; + + /** Schema validator. **/ + private final XMLSchemaValidator fSchemaValidator; + + /** Symbol table **/ + private final SymbolTable fSymbolTable; + + /** Validation manager. **/ + private final ValidationManager fValidationManager; + + /** Component manager. **/ + private final XMLSchemaValidatorComponentManager fComponentManager; + + /** The namespace context of this document: stores namespaces in scope. **/ + private final JAXPNamespaceContextWrapper fNamespaceContext; + + /** XML Locator wrapper for StAX. **/ + private final StAXLocationWrapper fStAXLocationWrapper = new StAXLocationWrapper(); + + /** On demand reader of the Location from an XMLStreamReader. **/ + private final XMLStreamReaderLocation fXMLStreamReaderLocation = new XMLStreamReaderLocation(); + + /** Map for tracking entity declarations. */ + private HashMap fEntities = null; + + /** Flag used to track whether XML names and Namespace URIs have been internalized. */ + private boolean fStringsInternalized = false; + + /** Validator helper for XMLStreamReaders. **/ + private StreamHelper fStreamHelper; + + /** Validator helper for XMLEventReaders. **/ + private EventHelper fEventHelper; + + /** StAX document handler. **/ + private StAXDocumentHandler fStAXValidatorHandler; + + /** StAX stream result builder. **/ + private StAXStreamResultBuilder fStAXStreamResultBuilder; + + /** StAX event result builder. **/ + private StAXEventResultBuilder fStAXEventResultBuilder; + + /** Document depth. **/ + private int fDepth = 0; + + /** Current event. **/ + private XMLEvent fCurrentEvent = null; + + /** Fields for start element, end element and characters. **/ + final QName fElementQName = new QName(); + final QName fAttributeQName = new QName(); + final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); + final ArrayList fDeclaredPrefixes = new ArrayList(); + final XMLString fTempString = new XMLString(); + final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + + public StAXValidatorHelper(XMLSchemaValidatorComponentManager componentManager) { + fComponentManager = componentManager; + fErrorReporter = (XMLErrorReporter) fComponentManager.getProperty(ERROR_REPORTER); + fSchemaValidator = (XMLSchemaValidator) fComponentManager.getProperty(SCHEMA_VALIDATOR); + fSymbolTable = (SymbolTable) fComponentManager.getProperty(SYMBOL_TABLE); + fValidationManager = (ValidationManager) fComponentManager.getProperty(VALIDATION_MANAGER); + fNamespaceContext = new JAXPNamespaceContextWrapper(fSymbolTable); + fNamespaceContext.setDeclaredPrefixes(fDeclaredPrefixes); + } + + /* + * ValidatorHelper methods + */ + + public void validate(Source source, Result result) throws SAXException, + IOException { + if (result instanceof StAXResult || result == null) { + StAXSource staxSource = (StAXSource) source; + StAXResult staxResult = (StAXResult) result; + try { + XMLStreamReader streamReader = staxSource.getXMLStreamReader(); + if (streamReader != null) { + // Hand off to XMLStreamReader helper. + if (fStreamHelper == null) { + fStreamHelper = new StreamHelper(); + } + fStreamHelper.validate(streamReader, staxResult); + } + else { + // Hand off to XMLEventReader helper. + if (fEventHelper == null) { + fEventHelper = new EventHelper(); + } + fEventHelper.validate(staxSource.getXMLEventReader(), staxResult); + } + } + catch (XMLStreamException e) { + throw new SAXException(e); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + finally { + // Release references to application objects + fCurrentEvent = null; + fStAXLocationWrapper.setLocation(null); + fXMLStreamReaderLocation.setXMLStreamReader(null); + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.setStAXResult(null); + } + } + return; + } + throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "SourceResultMismatch", + new Object [] {source.getClass().getName(), result.getClass().getName()})); + } + + /* + * EntityState methods + */ + + public boolean isEntityDeclared(String name) { + if (fEntities != null) { + return fEntities.containsKey(name); + } + return false; + } + + public boolean isEntityUnparsed(String name) { + if (fEntities != null) { + EntityDeclaration entityDecl = (EntityDeclaration) fEntities.get(name); + // If the entity is associated with a notation then it must be an unparsed entity. + if (entityDecl != null) { + return (entityDecl.getNotationName() != null); + } + } + return false; + } + + /* + * Other methods. + */ + + final EntityDeclaration getEntityDeclaration(String name) { + return (fEntities != null) ? (EntityDeclaration) fEntities.get(name) : null; + } + + final XMLEvent getCurrentEvent() { + return fCurrentEvent; + } + + /** Fills in a QName object. */ + final void fillQName(QName toFill, String uri, String localpart, String prefix) { + if (!fStringsInternalized) { + uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; + localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING; + prefix = (prefix != null && prefix.length() > 0) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING; + } + else { + if (uri != null && uri.length() == 0) { + uri = null; + } + if (localpart == null) { + localpart = XMLSymbols.EMPTY_STRING; + } + if (prefix == null) { + prefix = XMLSymbols.EMPTY_STRING; + } + } + String raw = localpart; + if (prefix != XMLSymbols.EMPTY_STRING) { + fStringBuffer.clear(); + fStringBuffer.append(prefix); + fStringBuffer.append(':'); + fStringBuffer.append(localpart); + raw = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); + } + toFill.setValues(prefix, localpart, raw, uri); + } + + /** Setup for validation. **/ + final void setup(Location location, StAXResult result, boolean stringsInternalized) { + fDepth = 0; + fComponentManager.reset(); + setupStAXResultHandler(result); + fValidationManager.setEntityState(this); + if (fEntities != null && !fEntities.isEmpty()) { + // should only clear this if the last document contained unparsed entities + fEntities.clear(); + } + fStAXLocationWrapper.setLocation(location); + fErrorReporter.setDocumentLocator(fStAXLocationWrapper); + fStringsInternalized = stringsInternalized; + } + + /** Copies entity declarations into a hash map. */ + final void processEntityDeclarations(List entityDecls) { + int size = (entityDecls != null) ? entityDecls.size() : 0; + if (size > 0) { + if (fEntities == null) { + fEntities = new HashMap(); + } + for (int i = 0; i < size; ++i) { + EntityDeclaration decl = (EntityDeclaration) entityDecls.get(i); + fEntities.put(decl.getName(), decl); + } + } + } + + /** + * Sets up handler for StAXResult. + */ + private void setupStAXResultHandler(StAXResult result) { + // If there's no StAXResult, unset the validator handler + if (result == null) { + fStAXValidatorHandler = null; + fSchemaValidator.setDocumentHandler(null); + return; + } + XMLStreamWriter writer = result.getXMLStreamWriter(); + if (writer != null) { + if (fStAXStreamResultBuilder == null) { + fStAXStreamResultBuilder = new StAXStreamResultBuilder(fNamespaceContext); + } + fStAXValidatorHandler = fStAXStreamResultBuilder; + fStAXStreamResultBuilder.setStAXResult(result); + } + else { + if (fStAXEventResultBuilder == null) { + fStAXEventResultBuilder = new StAXEventResultBuilder(this, fNamespaceContext); + } + fStAXValidatorHandler = fStAXEventResultBuilder; + fStAXEventResultBuilder.setStAXResult(result); + } + fSchemaValidator.setDocumentHandler(fStAXValidatorHandler); + } + + /** + * Helper for XMLStreamReaders. + */ + final class StreamHelper { + + StreamHelper() {} + + final void validate(XMLStreamReader reader, StAXResult result) + throws SAXException, XMLStreamException { + if (reader.hasNext()) { + int eventType = reader.getEventType(); + if (eventType != XMLStreamConstants.START_DOCUMENT && + eventType != XMLStreamConstants.START_ELEMENT) { + throw new SAXException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "StAXIllegalInitialState", null)); + } + fXMLStreamReaderLocation.setXMLStreamReader(reader); + Object isInterning = Boolean.FALSE; + try { + isInterning = reader.getProperty(STRING_INTERNING); + } + catch (Exception e) {} + setup(fXMLStreamReaderLocation, result, Boolean.TRUE.equals(isInterning)); + fSchemaValidator.startDocument(fStAXLocationWrapper, null, fNamespaceContext, null); + do { + switch (eventType) { + case XMLStreamConstants.START_ELEMENT: + ++fDepth; + fillQName(fElementQName, reader.getNamespaceURI(), + reader.getLocalName(), reader.getPrefix()); + fillXMLAttributes(reader); + fillDeclaredPrefixes(reader); + fNamespaceContext.setNamespaceContext(reader.getNamespaceContext()); + fSchemaValidator.startElement(fElementQName, fAttributes, null); + break; + case XMLStreamConstants.END_ELEMENT: + fillQName(fElementQName, reader.getNamespaceURI(), + reader.getLocalName(), reader.getPrefix()); + fillDeclaredPrefixes(reader); + fNamespaceContext.setNamespaceContext(reader.getNamespaceContext()); + fSchemaValidator.endElement(fElementQName, null); + --fDepth; + break; + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + fTempString.setValues(reader.getTextCharacters(), + reader.getTextStart(), reader.getTextLength()); + fSchemaValidator.characters(fTempString, null); + break; + case XMLStreamConstants.CDATA: + fSchemaValidator.startCDATA(null); + fTempString.setValues(reader.getTextCharacters(), + reader.getTextStart(), reader.getTextLength()); + fSchemaValidator.characters(fTempString, null); + fSchemaValidator.endCDATA(null); + break; + case XMLStreamConstants.START_DOCUMENT: + ++fDepth; + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.startDocument(reader); + } + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.processingInstruction(reader); + } + break; + case XMLStreamConstants.COMMENT: + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.comment(reader); + } + break; + case XMLStreamConstants.ENTITY_REFERENCE: + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.entityReference(reader); + } + break; + case XMLStreamConstants.DTD: + processEntityDeclarations((List) reader.getProperty("javax.xml.stream.entities")); + break; + } + eventType = reader.next(); + } + while (reader.hasNext() && fDepth > 0); + fSchemaValidator.endDocument(null); + if (eventType == XMLStreamConstants.END_DOCUMENT && fStAXValidatorHandler != null) { + fStAXValidatorHandler.endDocument(reader); + } + } + } + + /** Fills in the XMLAttributes object. */ + private void fillXMLAttributes(XMLStreamReader reader) { + fAttributes.removeAllAttributes(); + final int len = reader.getAttributeCount(); + for (int i = 0; i < len; ++i) { + fillQName(fAttributeQName, reader.getAttributeNamespace(i), + reader.getAttributeLocalName(i), reader.getAttributePrefix(i)); + String type = reader.getAttributeType(i); + fAttributes.addAttributeNS(fAttributeQName, + (type != null) ? type : XMLSymbols.fCDATASymbol, reader.getAttributeValue(i)); + fAttributes.setSpecified(i, reader.isAttributeSpecified(i)); + } + } + + /** Fills in the list of declared prefixes. */ + private void fillDeclaredPrefixes(XMLStreamReader reader) { + fDeclaredPrefixes.clear(); + final int len = reader.getNamespaceCount(); + for (int i = 0; i < len; ++i) { + String prefix = reader.getNamespacePrefix(i); + fDeclaredPrefixes.add(prefix != null ? prefix : ""); + } + } + } + + /** + * Helper for XMLEventReaders. + */ + final class EventHelper { + + // + // Constants + // + + /** Chunk size (1024). */ + private static final int CHUNK_SIZE = (1 << 10); + + /** Chunk mask (CHUNK_SIZE - 1). */ + private static final int CHUNK_MASK = CHUNK_SIZE - 1; + + // + // Data + // + + /** Array for holding character data. **/ + private final char [] fCharBuffer = new char[CHUNK_SIZE]; + + EventHelper() {} + + final void validate(XMLEventReader reader, StAXResult result) + throws SAXException, XMLStreamException { + fCurrentEvent = reader.peek(); + if (fCurrentEvent != null) { + int eventType = fCurrentEvent.getEventType(); + if (eventType != XMLStreamConstants.START_DOCUMENT && + eventType != XMLStreamConstants.START_ELEMENT) { + throw new SAXException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "StAXIllegalInitialState", null)); + } + setup(null, result, false); + fSchemaValidator.startDocument(fStAXLocationWrapper, null, fNamespaceContext, null); + loop : while (reader.hasNext()) { + fCurrentEvent = reader.nextEvent(); + eventType = fCurrentEvent.getEventType(); + switch (eventType) { + case XMLStreamConstants.START_ELEMENT: + ++fDepth; + StartElement start = fCurrentEvent.asStartElement(); + fillQName(fElementQName, start.getName()); + fillXMLAttributes(start); + fillDeclaredPrefixes(start); + fNamespaceContext.setNamespaceContext(start.getNamespaceContext()); + fStAXLocationWrapper.setLocation(start.getLocation()); + fSchemaValidator.startElement(fElementQName, fAttributes, null); + break; + case XMLStreamConstants.END_ELEMENT: + EndElement end = fCurrentEvent.asEndElement(); + fillQName(fElementQName, end.getName()); + fillDeclaredPrefixes(end); + fStAXLocationWrapper.setLocation(end.getLocation()); + fSchemaValidator.endElement(fElementQName, null); + if (--fDepth <= 0) { + break loop; + } + break; + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + if (fStAXValidatorHandler != null) { + Characters chars = fCurrentEvent.asCharacters(); + fStAXValidatorHandler.setIgnoringCharacters(true); + sendCharactersToValidator(chars.getData()); + fStAXValidatorHandler.setIgnoringCharacters(false); + fStAXValidatorHandler.characters(chars); + } + else { + sendCharactersToValidator(fCurrentEvent.asCharacters().getData()); + } + break; + case XMLStreamConstants.CDATA: + if (fStAXValidatorHandler != null) { + Characters chars = fCurrentEvent.asCharacters(); + fStAXValidatorHandler.setIgnoringCharacters(true); + fSchemaValidator.startCDATA(null); + sendCharactersToValidator(fCurrentEvent.asCharacters().getData()); + fSchemaValidator.endCDATA(null); + fStAXValidatorHandler.setIgnoringCharacters(false); + fStAXValidatorHandler.cdata(chars); + } + else { + fSchemaValidator.startCDATA(null); + sendCharactersToValidator(fCurrentEvent.asCharacters().getData()); + fSchemaValidator.endCDATA(null); + } + break; + case XMLStreamConstants.START_DOCUMENT: + ++fDepth; + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.startDocument((StartDocument) fCurrentEvent); + } + break; + case XMLStreamConstants.END_DOCUMENT: + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.endDocument((EndDocument) fCurrentEvent); + } + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.processingInstruction((ProcessingInstruction) fCurrentEvent); + } + break; + case XMLStreamConstants.COMMENT: + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.comment((Comment) fCurrentEvent); + } + break; + case XMLStreamConstants.ENTITY_REFERENCE: + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.entityReference((EntityReference) fCurrentEvent); + } + break; + case XMLStreamConstants.DTD: + DTD dtd = (DTD) fCurrentEvent; + processEntityDeclarations(dtd.getEntities()); + if (fStAXValidatorHandler != null) { + fStAXValidatorHandler.doctypeDecl(dtd); + } + break; + } + } + fSchemaValidator.endDocument(null); + } + } + + /** Fills in a QName object. */ + private void fillQName(QName toFill, javax.xml.namespace.QName toCopy) { + StAXValidatorHelper.this.fillQName(toFill, toCopy.getNamespaceURI(), toCopy.getLocalPart(), toCopy.getPrefix()); + } + + /** Fills in the XMLAttributes object. */ + private void fillXMLAttributes(StartElement event) { + fAttributes.removeAllAttributes(); + final Iterator attrs = event.getAttributes(); + while (attrs.hasNext()) { + Attribute attr = (Attribute) attrs.next(); + fillQName(fAttributeQName, attr.getName()); + String type = attr.getDTDType(); + int idx = fAttributes.getLength(); + fAttributes.addAttributeNS(fAttributeQName, + (type != null) ? type : XMLSymbols.fCDATASymbol, attr.getValue()); + fAttributes.setSpecified(idx, attr.isSpecified()); + } + } + + /** Fills in the list of declared prefixes. */ + private void fillDeclaredPrefixes(StartElement event) { + fillDeclaredPrefixes(event.getNamespaces()); + } + + /** Fills in the list of declared prefixes. */ + private void fillDeclaredPrefixes(EndElement event) { + fillDeclaredPrefixes(event.getNamespaces()); + } + + /** Fills in the list of declared prefixes. */ + private void fillDeclaredPrefixes(Iterator namespaces) { + fDeclaredPrefixes.clear(); + while (namespaces.hasNext()) { + Namespace ns = (Namespace) namespaces.next(); + String prefix = ns.getPrefix(); + fDeclaredPrefixes.add(prefix != null ? prefix : ""); + } + } + + /** Send characters to the validator in CHUNK_SIZE character chunks. */ + private void sendCharactersToValidator(String str) { + if (str != null) { + final int length = str.length(); + final int remainder = length & CHUNK_MASK; + if (remainder > 0) { + str.getChars(0, remainder, fCharBuffer, 0); + fTempString.setValues(fCharBuffer, 0, remainder); + fSchemaValidator.characters(fTempString, null); + } + int i = remainder; + while (i < length) { + str.getChars(i, i += CHUNK_SIZE, fCharBuffer, 0); + fTempString.setValues(fCharBuffer, 0, CHUNK_SIZE); + fSchemaValidator.characters(fTempString, null); + } + } + } + } + + /** + * On demand reader of the Location from an XMLStreamReader. + */ + static final class XMLStreamReaderLocation implements Location { + + private XMLStreamReader reader; + + public XMLStreamReaderLocation() {} + + public int getCharacterOffset() { + Location loc = getLocation(); + if (loc != null) { + return loc.getCharacterOffset(); + } + return -1; + } + + public int getColumnNumber() { + Location loc = getLocation(); + if (loc != null) { + return loc.getColumnNumber(); + } + return -1; + } + + public int getLineNumber() { + Location loc = getLocation(); + if (loc != null) { + return loc.getLineNumber(); + } + return -1; + } + + public String getPublicId() { + Location loc = getLocation(); + if (loc != null) { + return loc.getPublicId(); + } + return null; + } + + public String getSystemId() { + Location loc = getLocation(); + if (loc != null) { + return loc.getSystemId(); + } + return null; + } + + public void setXMLStreamReader(XMLStreamReader reader) { + this.reader = reader; + } + + private Location getLocation() { + return reader != null ? reader.getLocation() : null; + } + } + +} // StAXValidatorHelper diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StreamValidatorHelper.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StreamValidatorHelper.java new file mode 100644 index 0000000..11ee2e5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/StreamValidatorHelper.java @@ -0,0 +1,228 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.ref.SoftReference; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.parsers.SAXParser; +import org.apache.xerces.parsers.XML11Configuration; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParseException; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.apache.xml.serialize.Method; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.Serializer; +import org.apache.xml.serialize.SerializerFactory; +import org.xml.sax.SAXException; + +/** + *

        A validator helper for StreamSources.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class StreamValidatorHelper implements ValidatorHelper { + + // feature identifiers + + /** Feature identifier: parser settings. */ + private static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + // property identifiers + + /** Property identifier: entity resolver. */ + private static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: error handler. */ + private static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: error reporter. */ + private static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: XML Schema validator. */ + private static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: symbol table. */ + private static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: validation manager. */ + private static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: security manager. */ + private static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + // + // Data + // + + /** SoftReference to parser configuration. **/ + private SoftReference fConfiguration = new SoftReference(null); + + /** Schema validator. **/ + private final XMLSchemaValidator fSchemaValidator; + + /** Component manager. **/ + private final XMLSchemaValidatorComponentManager fComponentManager; + + /** + * The parser maintains a reference to the configuration, so it must be a SoftReference too. + */ + private SoftReference fParser = new SoftReference(null); + + /** Serializer factory. **/ + private SerializerFactory fSerializerFactory; + + public StreamValidatorHelper(XMLSchemaValidatorComponentManager componentManager) { + fComponentManager = componentManager; + fSchemaValidator = (XMLSchemaValidator) fComponentManager.getProperty(SCHEMA_VALIDATOR); + } + + public void validate(Source source, Result result) + throws SAXException, IOException { + if (result instanceof StreamResult || result == null) { + final StreamSource streamSource = (StreamSource) source; + final StreamResult streamResult = (StreamResult) result; + XMLInputSource input = new XMLInputSource(streamSource.getPublicId(), streamSource.getSystemId(), null); + input.setByteStream(streamSource.getInputStream()); + input.setCharacterStream(streamSource.getReader()); + + // Gets the parser configuration. We'll create and initialize a new one, if we + // haven't created one before or if the previous one was garbage collected. + boolean newConfig = false; + XMLParserConfiguration config = (XMLParserConfiguration) fConfiguration.get(); + if (config == null) { + config = initialize(); + newConfig = true; + } + // If settings have changed on the component manager, refresh the error handler and entity resolver. + else if (fComponentManager.getFeature(PARSER_SETTINGS)) { + config.setProperty(ENTITY_RESOLVER, fComponentManager.getProperty(ENTITY_RESOLVER)); + config.setProperty(ERROR_HANDLER, fComponentManager.getProperty(ERROR_HANDLER)); + config.setProperty(SECURITY_MANAGER, fComponentManager.getProperty(SECURITY_MANAGER)); + } + + // prepare for parse + fComponentManager.reset(); + + if (streamResult != null) { + if (fSerializerFactory == null) { + fSerializerFactory = SerializerFactory.getSerializerFactory(Method.XML); + } + + // there doesn't seem to be a way to reset a serializer, so we need to make + // a new one each time. + Serializer ser; + if (streamResult.getWriter() != null) { + ser = fSerializerFactory.makeSerializer(streamResult.getWriter(), new OutputFormat()); + } + else if (streamResult.getOutputStream() != null) { + ser = fSerializerFactory.makeSerializer(streamResult.getOutputStream(), new OutputFormat()); + } + else if (streamResult.getSystemId() != null) { + String uri = streamResult.getSystemId(); + OutputStream out = XMLEntityManager.createOutputStream(uri); + ser = fSerializerFactory.makeSerializer(out, new OutputFormat()); + } + else { + throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "StreamResultNotInitialized", null)); + } + + // we're using the parser only as an XNI-to-SAX converter, + // so that we can use the SAX-based serializer + SAXParser parser = (SAXParser) fParser.get(); + if (newConfig || parser == null) { + parser = new SAXParser(config); + fParser = new SoftReference(parser); + } + else { + parser.reset(); + } + config.setDocumentHandler(fSchemaValidator); + fSchemaValidator.setDocumentHandler(parser); + parser.setContentHandler(ser.asContentHandler()); + } + else { + fSchemaValidator.setDocumentHandler(null); + } + + try { + config.parse(input); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + finally { + // release the references to the SAXParser and Serializer + fSchemaValidator.setDocumentHandler(null); + } + + return; + } + throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "SourceResultMismatch", + new Object [] {source.getClass().getName(), result.getClass().getName()})); + } + + private XMLParserConfiguration initialize() { + XML11Configuration config = new XML11Configuration(); + config.setProperty(ENTITY_RESOLVER, fComponentManager.getProperty(ENTITY_RESOLVER)); + config.setProperty(ERROR_HANDLER, fComponentManager.getProperty(ERROR_HANDLER)); + XMLErrorReporter errorReporter = (XMLErrorReporter) fComponentManager.getProperty(ERROR_REPORTER); + config.setProperty(ERROR_REPORTER, errorReporter); + // add message formatters + if (errorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + errorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + errorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + config.setProperty(SYMBOL_TABLE, fComponentManager.getProperty(SYMBOL_TABLE)); + config.setProperty(VALIDATION_MANAGER, fComponentManager.getProperty(VALIDATION_MANAGER)); + config.setProperty(SECURITY_MANAGER, fComponentManager.getProperty(SECURITY_MANAGER)); + config.setDocumentHandler(fSchemaValidator); + config.setDTDHandler(null); + config.setDTDContentModelHandler(null); + fConfiguration = new SoftReference(config); + return config; + } + +} // StreamValidatorHelper diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/Util.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/Util.java new file mode 100644 index 0000000..eff97c9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/Util.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import javax.xml.transform.stream.StreamSource; + +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParseException; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + *

        Static utility methods for the Validation API implementation.

        + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * @version $Id$ + */ +final class Util { + + /** + * Creates a proper {@link XMLInputSource} from a {@link StreamSource}. + * + * @return always return non-null valid object. + */ + public static final XMLInputSource toXMLInputSource( StreamSource in ) { + if( in.getReader()!=null ) + return new XMLInputSource( + in.getPublicId(), in.getSystemId(), in.getSystemId(), + in.getReader(), null ); + if( in.getInputStream()!=null ) + return new XMLInputSource( + in.getPublicId(), in.getSystemId(), in.getSystemId(), + in.getInputStream(), null ); + + return new XMLInputSource( + in.getPublicId(), in.getSystemId(), in.getSystemId() ); + } + + /** + * Reconstructs {@link SAXException} from XNIException. + */ + public static SAXException toSAXException(XNIException e) { + if(e instanceof XMLParseException) + return toSAXParseException((XMLParseException)e); + if( e.getException() instanceof SAXException ) + return (SAXException)e.getException(); + return new SAXException(e.getMessage(),e.getException()); + } + + public static SAXParseException toSAXParseException( XMLParseException e ) { + if( e.getException() instanceof SAXParseException ) + return (SAXParseException)e.getException(); + return new SAXParseException( e.getMessage(), + e.getPublicId(), e.getExpandedSystemId(), + e.getLineNumber(), e.getColumnNumber(), + e.getException() ); + } + +} // Util diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorHandlerImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorHandlerImpl.java new file mode 100644 index 0000000..a9ed4f5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorHandlerImpl.java @@ -0,0 +1,1139 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.util.HashMap; + +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.validation.TypeInfoProvider; +import javax.xml.validation.ValidatorHandler; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.impl.validation.EntityState; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.util.AttributesProxy; +import org.apache.xerces.util.SAXLocatorWrapper; +import org.apache.xerces.util.SAXMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.URI; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLParseException; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.ItemPSVI; +import org.apache.xerces.xs.PSVIProvider; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.Attributes2; +import org.xml.sax.ext.EntityResolver2; +import org.xml.sax.ext.LexicalHandler; + +/** + *

        Implementation of ValidatorHandler for W3C XML Schemas and + * also a validator helper for SAXSources.

        + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +final class ValidatorHandlerImpl extends ValidatorHandler implements + DTDHandler, EntityState, PSVIProvider, ValidatorHelper, XMLDocumentHandler { + + // feature identifiers + + /** Feature identifier: namespace prefixes. */ + private static final String NAMESPACE_PREFIXES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE; + + /** Feature identifier: string interning. */ + private static final String STRING_INTERNING = + Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE; + + /** Feature identifier: strings interned. */ + private static final String STRINGS_INTERNED = + Constants.XERCES_FEATURE_PREFIX + Constants.STRINGS_INTERNED_FEATURE; + + // property identifiers + + /** Property identifier: error reporter. */ + private static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: lexical handler. */ + private static final String LEXICAL_HANDLER = + Constants.SAX_PROPERTY_PREFIX + Constants.LEXICAL_HANDLER_PROPERTY; + + /** Property identifier: namespace context. */ + private static final String NAMESPACE_CONTEXT = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY; + + /** Property identifier: XML Schema validator. */ + private static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: security manager. */ + private static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + /** Property identifier: symbol table. */ + private static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: validation manager. */ + private static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + // + // Data + // + + /** Error reporter. */ + private final XMLErrorReporter fErrorReporter; + + /** The namespace context of this document: stores namespaces in scope */ + private final NamespaceContext fNamespaceContext; + + /** Schema validator. **/ + private final XMLSchemaValidator fSchemaValidator; + + /** Symbol table **/ + private final SymbolTable fSymbolTable; + + /** Validation manager. */ + private final ValidationManager fValidationManager; + + /** Component manager. **/ + private final XMLSchemaValidatorComponentManager fComponentManager; + + /** XML Locator wrapper for SAX. **/ + private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper(); + + /** Flag used to track whether the namespace context needs to be pushed. */ + private boolean fNeedPushNSContext = true; + + /** Map for tracking unparsed entities. */ + private HashMap fUnparsedEntities = null; + + /** Flag used to track whether XML names and Namespace URIs have been internalized. */ + private boolean fStringsInternalized = false; + + /** Fields for start element, end element and characters. */ + private final QName fElementQName = new QName(); + private final QName fAttributeQName = new QName(); + private final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); + private final AttributesProxy fAttrAdapter = new AttributesProxy(fAttributes); + private final XMLString fTempString = new XMLString(); + + // + // User Objects + // + + private ContentHandler fContentHandler = null; + + /* + * Constructors + */ + + public ValidatorHandlerImpl(XSGrammarPoolContainer grammarContainer) { + this(new XMLSchemaValidatorComponentManager(grammarContainer)); + fComponentManager.addRecognizedFeatures(new String [] {NAMESPACE_PREFIXES}); + fComponentManager.setFeature(NAMESPACE_PREFIXES, false); + setErrorHandler(null); + setResourceResolver(null); + } + + public ValidatorHandlerImpl(XMLSchemaValidatorComponentManager componentManager) { + fComponentManager = componentManager; + fErrorReporter = (XMLErrorReporter) fComponentManager.getProperty(ERROR_REPORTER); + fNamespaceContext = (NamespaceContext) fComponentManager.getProperty(NAMESPACE_CONTEXT); + fSchemaValidator = (XMLSchemaValidator) fComponentManager.getProperty(SCHEMA_VALIDATOR); + fSymbolTable = (SymbolTable) fComponentManager.getProperty(SYMBOL_TABLE); + fValidationManager = (ValidationManager) fComponentManager.getProperty(VALIDATION_MANAGER); + } + + /* + * ValidatorHandler methods + */ + + public void setContentHandler(ContentHandler receiver) { + fContentHandler = receiver; + } + + public ContentHandler getContentHandler() { + return fContentHandler; + } + + public void setErrorHandler(ErrorHandler errorHandler) { + fComponentManager.setErrorHandler(errorHandler); + } + + public ErrorHandler getErrorHandler() { + return fComponentManager.getErrorHandler(); + } + + public void setResourceResolver(LSResourceResolver resourceResolver) { + fComponentManager.setResourceResolver(resourceResolver); + } + + public LSResourceResolver getResourceResolver() { + return fComponentManager.getResourceResolver(); + } + + public TypeInfoProvider getTypeInfoProvider() { + return fTypeInfoProvider; + } + + public boolean getFeature(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "FeatureNameNull", null)); + } + if (STRINGS_INTERNED.equals(name)) { + return fStringsInternalized; + } + try { + return fComponentManager.getFeature(name); + } + catch (XMLConfigurationException e) { + final String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + } + + public void setFeature(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "FeatureNameNull", null)); + } + if (STRINGS_INTERNED.equals(name)) { + fStringsInternalized = value; + return; + } + try { + fComponentManager.setFeature(name, value); + } + catch (XMLConfigurationException e) { + final String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + } + + public Object getProperty(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "ProperyNameNull", null)); + } + try { + return fComponentManager.getProperty(name); + } + catch (XMLConfigurationException e) { + final String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + } + + public void setProperty(String name, Object object) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "ProperyNameNull", null)); + } + try { + fComponentManager.setProperty(name, object); + } + catch (XMLConfigurationException e) { + final String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + } + + /* + * EntityState methods + */ + + public boolean isEntityDeclared(String name) { + return false; + } + + public boolean isEntityUnparsed(String name) { + if (fUnparsedEntities != null) { + return fUnparsedEntities.containsKey(name); + } + return false; + } + + /* + * XMLDocumentHandler methods + */ + + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException { + if (fContentHandler != null) { + try { + fContentHandler.startDocument(); + } + catch (SAXException e) { + throw new XNIException(e); + } + } + } + + public void xmlDecl(String version, String encoding, String standalone, + Augmentations augs) throws XNIException {} + + public void doctypeDecl(String rootElement, String publicId, + String systemId, Augmentations augs) throws XNIException {} + + public void comment(XMLString text, Augmentations augs) throws XNIException {} + + public void processingInstruction(String target, XMLString data, + Augmentations augs) throws XNIException { + if (fContentHandler != null) { + try { + fContentHandler.processingInstruction(target, data.toString()); + } + catch (SAXException e) { + throw new XNIException(e); + } + } + } + + public void startElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + if (fContentHandler != null) { + try { + fTypeInfoProvider.beginStartElement(augs, attributes); + fContentHandler.startElement((element.uri != null) ? element.uri : XMLSymbols.EMPTY_STRING, + element.localpart, element.rawname, fAttrAdapter); + } + catch (SAXException e) { + throw new XNIException(e); + } + finally { + fTypeInfoProvider.finishStartElement(); + } + } + } + + public void emptyElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + /** Split empty element event. **/ + startElement(element, attributes, augs); + endElement(element, augs); + } + + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, String encoding, + Augmentations augs) throws XNIException {} + + public void textDecl(String version, String encoding, Augmentations augs) + throws XNIException {} + + public void endGeneralEntity(String name, Augmentations augs) + throws XNIException {} + + public void characters(XMLString text, Augmentations augs) + throws XNIException { + if (fContentHandler != null) { + // if the type is union it is possible that we receive + // a character call with empty data + if (text.length == 0) { + return; + } + try { + fContentHandler.characters(text.ch, text.offset, text.length); + } + catch (SAXException e) { + throw new XNIException(e); + } + } + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) + throws XNIException { + if (fContentHandler != null) { + try { + fContentHandler.ignorableWhitespace(text.ch, text.offset, text.length); + } + catch (SAXException e) { + throw new XNIException(e); + } + } + } + + public void endElement(QName element, Augmentations augs) + throws XNIException { + if (fContentHandler != null) { + try { + fTypeInfoProvider.beginEndElement(augs); + fContentHandler.endElement((element.uri != null) ? element.uri : XMLSymbols.EMPTY_STRING, + element.localpart, element.rawname); + } + catch (SAXException e) { + throw new XNIException(e); + } + finally { + fTypeInfoProvider.finishEndElement(); + } + } + } + + public void startCDATA(Augmentations augs) throws XNIException {} + + public void endCDATA(Augmentations augs) throws XNIException {} + + public void endDocument(Augmentations augs) throws XNIException { + if (fContentHandler != null) { + try { + fContentHandler.endDocument(); + } + catch (SAXException e) { + throw new XNIException(e); + } + } + } + + // NO-OP + public void setDocumentSource(XMLDocumentSource source) {} + + public XMLDocumentSource getDocumentSource() { + return fSchemaValidator; + } + + /* + * ContentHandler methods + */ + + public void setDocumentLocator(Locator locator) { + fSAXLocatorWrapper.setLocator(locator); + if (fContentHandler != null) { + fContentHandler.setDocumentLocator(locator); + } + } + + public void startDocument() throws SAXException { + fComponentManager.reset(); + fSchemaValidator.setDocumentHandler(this); + fValidationManager.setEntityState(this); + fTypeInfoProvider.finishStartElement(); // cleans up TypeInfoProvider + fNeedPushNSContext = true; + if (fUnparsedEntities != null && !fUnparsedEntities.isEmpty()) { + // should only clear this if the last document contained unparsed entities + fUnparsedEntities.clear(); + } + fErrorReporter.setDocumentLocator(fSAXLocatorWrapper); + try { + fSchemaValidator.startDocument(fSAXLocatorWrapper, fSAXLocatorWrapper.getEncoding(), fNamespaceContext, null); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + } + + public void endDocument() throws SAXException { + fSAXLocatorWrapper.setLocator(null); + try { + fSchemaValidator.endDocument(null); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + } + + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + String prefixSymbol; + String uriSymbol; + if (!fStringsInternalized) { + prefixSymbol = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING; + uriSymbol = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; + } + else { + prefixSymbol = (prefix != null) ? prefix : XMLSymbols.EMPTY_STRING; + uriSymbol = (uri != null && uri.length() > 0) ? uri : null; + } + if (fNeedPushNSContext) { + fNeedPushNSContext = false; + fNamespaceContext.pushContext(); + } + fNamespaceContext.declarePrefix(prefixSymbol, uriSymbol); + if (fContentHandler != null) { + fContentHandler.startPrefixMapping(prefix, uri); + } + } + + public void endPrefixMapping(String prefix) throws SAXException { + if (fContentHandler != null) { + fContentHandler.endPrefixMapping(prefix); + } + } + + public void startElement(String uri, String localName, String qName, + Attributes atts) throws SAXException { + if (fNeedPushNSContext) { + fNamespaceContext.pushContext(); + } + fNeedPushNSContext = true; + + // Fill element QName + fillQName(fElementQName, uri, localName, qName); + + // Fill XMLAttributes + if (atts instanceof Attributes2) { + fillXMLAttributes2((Attributes2) atts); + } + else { + fillXMLAttributes(atts); + } + + try { + fSchemaValidator.startElement(fElementQName, fAttributes, null); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + } + + public void endElement(String uri, String localName, String qName) + throws SAXException { + fillQName(fElementQName, uri, localName, qName); + try { + fSchemaValidator.endElement(fElementQName, null); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + finally { + fNamespaceContext.popContext(); + } + } + + public void characters(char[] ch, int start, int length) + throws SAXException { + try { + fTempString.setValues(ch, start, length); + fSchemaValidator.characters(fTempString, null); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + } + + public void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException { + try { + fTempString.setValues(ch, start, length); + fSchemaValidator.ignorableWhitespace(fTempString, null); + } + catch (XMLParseException e) { + throw Util.toSAXParseException(e); + } + catch (XNIException e) { + throw Util.toSAXException(e); + } + } + + public void processingInstruction(String target, String data) + throws SAXException { + /** + * Processing instructions do not participate in schema validation, + * so just forward the event to the application's content + * handler. + */ + if (fContentHandler != null) { + fContentHandler.processingInstruction(target, data); + } + } + + public void skippedEntity(String name) throws SAXException { + // there seems to be no corresponding method on XMLDocumentFilter. + // just pass it down to the output, if any. + if (fContentHandler != null) { + fContentHandler.skippedEntity(name); + } + } + + /* + * DTDHandler methods + */ + + public void notationDecl(String name, String publicId, + String systemId) throws SAXException {} + + public void unparsedEntityDecl(String name, String publicId, + String systemId, String notationName) throws SAXException { + if (fUnparsedEntities == null) { + fUnparsedEntities = new HashMap(); + } + fUnparsedEntities.put(name, name); + } + + /* + * ValidatorHelper methods + */ + + public void validate(Source source, Result result) + throws SAXException, IOException { + if (result instanceof SAXResult || result == null) { + final SAXSource saxSource = (SAXSource) source; + final SAXResult saxResult = (SAXResult) result; + + LexicalHandler lh = null; + if (result != null) { + ContentHandler ch = saxResult.getHandler(); + lh = saxResult.getLexicalHandler(); + /** If the lexical handler is not set try casting the ContentHandler. **/ + if (lh == null && ch instanceof LexicalHandler) { + lh = (LexicalHandler) ch; + } + setContentHandler(ch); + } + + XMLReader reader = null; + try { + reader = saxSource.getXMLReader(); + if (reader == null) { + // create one now + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + try { + reader = spf.newSAXParser().getXMLReader(); + // If this is a Xerces SAX parser, set the security manager if there is one + if (reader instanceof org.apache.xerces.parsers.SAXParser) { + Object securityManager = fComponentManager.getProperty(SECURITY_MANAGER); + if (securityManager != null) { + try { + reader.setProperty(SECURITY_MANAGER, securityManager); + } + // Ignore the exception if the security manager cannot be set. + catch (SAXException exc) {} + } + } + } + catch (Exception e) { + // this is impossible, but better safe than sorry + throw new FactoryConfigurationError(e); + } + } + + // If XML names and Namespace URIs are already internalized we + // can avoid running them through the SymbolTable. + try { + fStringsInternalized = reader.getFeature(STRING_INTERNING); + } + catch (SAXException exc) { + // The feature isn't recognized or getting it is not supported. + // In either case, assume that strings are not internalized. + fStringsInternalized = false; + } + + ErrorHandler errorHandler = fComponentManager.getErrorHandler(); + reader.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance()); + reader.setEntityResolver(fResolutionForwarder); + fResolutionForwarder.setEntityResolver(fComponentManager.getResourceResolver()); + reader.setContentHandler(this); + reader.setDTDHandler(this); + try { + reader.setProperty(LEXICAL_HANDLER, lh); + } + // Ignore the exception if the lexical handler cannot be set. + catch (SAXException exc) {} + + InputSource is = saxSource.getInputSource(); + reader.parse(is); + } + finally { + // Release the reference to user's ContentHandler ASAP + setContentHandler(null); + // Disconnect the validator and other objects from the XMLReader + if (reader != null) { + try { + reader.setContentHandler(null); + reader.setDTDHandler(null); + reader.setErrorHandler(null); + reader.setEntityResolver(null); + fResolutionForwarder.setEntityResolver(null); + reader.setProperty(LEXICAL_HANDLER, null); + } + // Ignore the exception if the lexical handler cannot be unset. + catch (Exception exc) {} + } + } + return; + } + throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "SourceResultMismatch", + new Object [] {source.getClass().getName(), result.getClass().getName()})); + } + + /* + * PSVIProvider methods + */ + + public ElementPSVI getElementPSVI() { + return fTypeInfoProvider.getElementPSVI(); + } + + public AttributePSVI getAttributePSVI(int index) { + return fTypeInfoProvider.getAttributePSVI(index); + } + + public AttributePSVI getAttributePSVIByName(String uri, String localname) { + return fTypeInfoProvider.getAttributePSVIByName(uri, localname); + } + + // + // + // helper methods + // + // + + /** Fills in a QName object. */ + private void fillQName(QName toFill, String uri, String localpart, String raw) { + if (!fStringsInternalized) { + uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; + localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING; + raw = (raw != null) ? fSymbolTable.addSymbol(raw) : XMLSymbols.EMPTY_STRING; + } + else { + if (uri != null && uri.length() == 0) { + uri = null; + } + if (localpart == null) { + localpart = XMLSymbols.EMPTY_STRING; + } + if (raw == null) { + raw = XMLSymbols.EMPTY_STRING; + } + } + String prefix = XMLSymbols.EMPTY_STRING; + int prefixIdx = raw.indexOf(':'); + if (prefixIdx != -1) { + prefix = fSymbolTable.addSymbol(raw.substring(0, prefixIdx)); + } + toFill.setValues(prefix, localpart, raw, uri); + } + + /** Fills in the XMLAttributes object. */ + private void fillXMLAttributes(Attributes att) { + fAttributes.removeAllAttributes(); + final int len = att.getLength(); + for (int i = 0; i < len; ++i) { + fillXMLAttribute(att, i); + fAttributes.setSpecified(i, true); + } + } + + /** Fills in the XMLAttributes object. */ + private void fillXMLAttributes2(Attributes2 att) { + fAttributes.removeAllAttributes(); + final int len = att.getLength(); + for (int i = 0; i < len; ++i) { + fillXMLAttribute(att, i); + fAttributes.setSpecified(i, att.isSpecified(i)); + if (att.isDeclared(i)) { + fAttributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE); + } + } + } + + /** Adds an attribute to the XMLAttributes object. */ + private void fillXMLAttribute(Attributes att, int index) { + fillQName(fAttributeQName, att.getURI(index), att.getLocalName(index), att.getQName(index)); + String type = att.getType(index); + fAttributes.addAttributeNS(fAttributeQName, (type != null) ? type : XMLSymbols.fCDATASymbol, att.getValue(index)); + } + + /** + * {@link TypeInfoProvider} implementation. + * + * REVISIT: I'm not sure if this code should belong here. + */ + private final XMLSchemaTypeInfoProvider fTypeInfoProvider = new XMLSchemaTypeInfoProvider(); + private class XMLSchemaTypeInfoProvider extends TypeInfoProvider { + + /** Element augmentations: contains ElementPSVI. **/ + private Augmentations fElementAugs; + + /** Attributes: augmentations for each attribute contain AttributePSVI. **/ + private XMLAttributes fAttributes; + + /** In start element. **/ + private boolean fInStartElement = false; + private boolean fInEndElement = false; + + /** Initializes the TypeInfoProvider with type information for the current element. **/ + void beginStartElement(Augmentations elementAugs, XMLAttributes attributes) { + fInStartElement = true; + fElementAugs = elementAugs; + fAttributes = attributes; + } + + /** Cleanup at the end of start element. **/ + void finishStartElement() { + fInStartElement = false; + fElementAugs = null; + fAttributes = null; + } + + /** Initializes the TypeInfoProvider with type information for the current element. **/ + void beginEndElement(Augmentations elementAugs) { + fInEndElement = true; + fElementAugs = elementAugs; + } + + /** Cleanup at the end of end element. **/ + void finishEndElement() { + fInEndElement = false; + fElementAugs = null; + } + + /** + * Throws a {@link IllegalStateException} if we are not in + * the startElement callback. the JAXP API requires this + * for most of the public methods which access attribute + * type information. + */ + private void checkStateAttribute() { + if (!fInStartElement) { + throw new IllegalStateException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "TypeInfoProviderIllegalStateAttribute", null)); + } + } + + /** + * Throws a {@link IllegalStateException} if we are not in + * the startElement or endElement callbacks. the JAXP API requires + * this for the public methods which access element type information. + */ + private void checkStateElement() { + if (!fInStartElement && !fInEndElement) { + throw new IllegalStateException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "TypeInfoProviderIllegalStateElement", null)); + } + } + + public TypeInfo getAttributeTypeInfo(int index) { + checkStateAttribute(); + return getAttributeType(index); + } + + private TypeInfo getAttributeType( int index ) { + checkStateAttribute(); + if (index < 0 || fAttributes.getLength() <= index) { + throw new IndexOutOfBoundsException(Integer.toString(index)); + } + Augmentations augs = fAttributes.getAugmentations(index); + if (augs == null) { + return null; + } + AttributePSVI psvi = (AttributePSVI)augs.getItem(Constants.ATTRIBUTE_PSVI); + return getTypeInfoFromPSVI(psvi); + } + + public TypeInfo getAttributeTypeInfo(String attributeUri, String attributeLocalName) { + checkStateAttribute(); + return getAttributeTypeInfo(fAttributes.getIndex(attributeUri,attributeLocalName)); + } + + public TypeInfo getAttributeTypeInfo(String attributeQName) { + checkStateAttribute(); + return getAttributeTypeInfo(fAttributes.getIndex(attributeQName)); + } + + public TypeInfo getElementTypeInfo() { + checkStateElement(); + if (fElementAugs == null) { + return null; + } + ElementPSVI psvi = (ElementPSVI)fElementAugs.getItem(Constants.ELEMENT_PSVI); + return getTypeInfoFromPSVI(psvi); + } + + private TypeInfo getTypeInfoFromPSVI(ItemPSVI psvi) { + if (psvi == null) { + return null; + } + // TODO: make sure if this is correct. + // TODO: since the number of types in a schema is quite limited, + // TypeInfoImpl should be pooled. Even better, it should be a part + // of the element decl. + if (psvi.getValidity() == ItemPSVI.VALIDITY_VALID) { + XSTypeDefinition t = psvi.getMemberTypeDefinition(); + if (t != null) { + return (t instanceof TypeInfo) ? (TypeInfo) t : null; + } + } + XSTypeDefinition t = psvi.getTypeDefinition(); + // TODO: can t be null? + if (t != null) { + return (t instanceof TypeInfo) ? (TypeInfo) t : null; + } + return null; + } + + public boolean isIdAttribute(int index) { + checkStateAttribute(); + XSSimpleType type = (XSSimpleType)getAttributeType(index); + if (type == null) { + return false; + } + return type.isIDType(); + } + + public boolean isSpecified(int index) { + checkStateAttribute(); + return fAttributes.isSpecified(index); + } + + /* + * Other methods + */ + + // PSVIProvider support + ElementPSVI getElementPSVI() { + return (fElementAugs != null) ? (ElementPSVI) fElementAugs.getItem(Constants.ELEMENT_PSVI) : null; + } + + AttributePSVI getAttributePSVI(int index) { + if (fAttributes != null) { + Augmentations augs = fAttributes.getAugmentations(index); + if (augs != null) { + return (AttributePSVI) augs.getItem(Constants.ATTRIBUTE_PSVI); + } + } + return null; + } + + AttributePSVI getAttributePSVIByName(String uri, String localname) { + if (fAttributes != null) { + Augmentations augs = fAttributes.getAugmentations(uri, localname); + if (augs != null) { + return (AttributePSVI) augs.getItem(Constants.ATTRIBUTE_PSVI); + } + } + return null; + } + } + + /** SAX adapter for an LSResourceResolver. */ + private final ResolutionForwarder fResolutionForwarder = new ResolutionForwarder(null); + static final class ResolutionForwarder + implements EntityResolver2 { + + // + // Data + // + + /** XML 1.0 type constant according to DOM L3 LS REC spec "http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/" */ + private static final String XML_TYPE = "http://www.w3.org/TR/REC-xml"; + + /** The DOM entity resolver. */ + protected LSResourceResolver fEntityResolver; + + // + // Constructors + // + + /** Default constructor. */ + public ResolutionForwarder() {} + + /** Wraps the specified DOM entity resolver. */ + public ResolutionForwarder(LSResourceResolver entityResolver) { + setEntityResolver(entityResolver); + } + + // + // Public methods + // + + /** Sets the DOM entity resolver. */ + public void setEntityResolver(LSResourceResolver entityResolver) { + fEntityResolver = entityResolver; + } // setEntityResolver(LSResourceResolver) + + /** Returns the DOM entity resolver. */ + public LSResourceResolver getEntityResolver() { + return fEntityResolver; + } // getEntityResolver():LSResourceResolver + + /** + * Always returns null. An LSResourceResolver has no corresponding method. + */ + public InputSource getExternalSubset(String name, String baseURI) + throws SAXException, IOException { + return null; + } + + /** + * Resolves the given resource and adapts the LSInput + * returned into an InputSource. + */ + public InputSource resolveEntity(String name, String publicId, + String baseURI, String systemId) throws SAXException, IOException { + if (fEntityResolver != null) { + LSInput lsInput = fEntityResolver.resolveResource(XML_TYPE, null, publicId, systemId, baseURI); + if (lsInput != null) { + final String pubId = lsInput.getPublicId(); + final String sysId = lsInput.getSystemId(); + final String baseSystemId = lsInput.getBaseURI(); + final Reader charStream = lsInput.getCharacterStream(); + final InputStream byteStream = lsInput.getByteStream(); + final String data = lsInput.getStringData(); + final String encoding = lsInput.getEncoding(); + + /** + * An LSParser looks at inputs specified in LSInput in + * the following order: characterStream, byteStream, + * stringData, systemId, publicId. For consistency + * with the DOM Level 3 Load and Save Recommendation + * use the same lookup order here. + */ + InputSource inputSource = new InputSource(); + inputSource.setPublicId(pubId); + inputSource.setSystemId((baseSystemId != null) ? resolveSystemId(sysId, baseSystemId) : sysId); + + if (charStream != null) { + inputSource.setCharacterStream(charStream); + } + else if (byteStream != null) { + inputSource.setByteStream(byteStream); + } + else if (data != null && data.length() != 0) { + inputSource.setCharacterStream(new StringReader(data)); + } + inputSource.setEncoding(encoding); + return inputSource; + } + } + return null; + } + + /** Delegates to EntityResolver2.resolveEntity(String, String, String, String). */ + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + return resolveEntity(null, publicId, null, systemId); + } + + /** Resolves a system identifier against a base URI. */ + private String resolveSystemId(String systemId, String baseURI) { + try { + return XMLEntityManager.expandSystemId(systemId, baseURI, false); + } + // In the event that resolution failed against the + // base URI, just return the system id as is. There's not + // much else we can do. + catch (URI.MalformedURIException ex) { + return systemId; + } + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorHelper.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorHelper.java new file mode 100644 index 0000000..0f8bb13 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorHelper.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.io.IOException; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; + +import org.xml.sax.SAXException; + +/** + *

        Instances of ValidatorHelper are able to validate + * specific source and result types.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +interface ValidatorHelper { + + public void validate(Source source, Result result) + throws SAXException, IOException; +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorImpl.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorImpl.java new file mode 100644 index 0000000..c7776a3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/ValidatorImpl.java @@ -0,0 +1,334 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.io.IOException; + +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.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXResult; +import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Validator; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.SAXMessageFormatter; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.PSVIProvider; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + *

        Implementation of Validator for W3C XML Schemas.

        + * + * @author Kohsuke Kawaguchi + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +final class ValidatorImpl extends Validator implements PSVIProvider { + + // feature identifiers + + /** JAXP Source/Result feature prefix. */ + private static final String JAXP_SOURCE_RESULT_FEATURE_PREFIX = "http://javax.xml.transform"; + + // property identifiers + + /** Property identifier: Current element node. */ + private static final String CURRENT_ELEMENT_NODE = + Constants.XERCES_PROPERTY_PREFIX + Constants.CURRENT_ELEMENT_NODE_PROPERTY; + + // + // Data + // + + /** Component manager. **/ + private final XMLSchemaValidatorComponentManager fComponentManager; + + /** SAX validator helper. **/ + private ValidatorHandlerImpl fSAXValidatorHelper; + + /** DOM validator helper. **/ + private DOMValidatorHelper fDOMValidatorHelper; + + /** StAX validator helper. **/ + private StAXValidatorHelper fStAXValidatorHelper; + + /** Stream validator helper. **/ + private StreamValidatorHelper fStreamValidatorHelper; + + /** Flag for tracking whether features/properties changed since last reset. */ + private boolean fConfigurationChanged = false; + + /** Flag for tracking whether the error handler changed since last reset. */ + private boolean fErrorHandlerChanged = false; + + /** Flag for tracking whether the resource resolver changed since last reset. */ + private boolean fResourceResolverChanged = false; + + public ValidatorImpl(XSGrammarPoolContainer grammarContainer) { + fComponentManager = new XMLSchemaValidatorComponentManager(grammarContainer); + setErrorHandler(null); + setResourceResolver(null); + } + + public void validate(Source source, Result result) + throws SAXException, IOException { + if (source instanceof SAXSource) { + // Hand off to SAX validator helper. + if (fSAXValidatorHelper == null) { + fSAXValidatorHelper = new ValidatorHandlerImpl(fComponentManager); + } + fSAXValidatorHelper.validate(source, result); + } + else if (source instanceof DOMSource) { + // Hand off to DOM validator helper. + if (fDOMValidatorHelper == null) { + fDOMValidatorHelper = new DOMValidatorHelper(fComponentManager); + } + fDOMValidatorHelper.validate(source, result); + } + else if (source instanceof StAXSource) { + // Hand off to StAX validator helper. + if (fStAXValidatorHelper == null) { + fStAXValidatorHelper = new StAXValidatorHelper(fComponentManager); + } + fStAXValidatorHelper.validate(source, result); + } + else if (source instanceof StreamSource) { + // Hand off to stream validator helper. + if (fStreamValidatorHelper == null) { + fStreamValidatorHelper = new StreamValidatorHelper(fComponentManager); + } + fStreamValidatorHelper.validate(source, result); + } + // Source parameter cannot be null. + else if (source == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "SourceParameterNull", null)); + } + // Source parameter must be a SAXSource, DOMSource or StreamSource + else { + throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "SourceNotAccepted", new Object [] {source.getClass().getName()})); + } + } + + public void setErrorHandler(ErrorHandler errorHandler) { + fErrorHandlerChanged = (errorHandler != null); + fComponentManager.setErrorHandler(errorHandler); + } + + public ErrorHandler getErrorHandler() { + return fComponentManager.getErrorHandler(); + } + + public void setResourceResolver(LSResourceResolver resourceResolver) { + fResourceResolverChanged = (resourceResolver != null); + fComponentManager.setResourceResolver(resourceResolver); + } + + public LSResourceResolver getResourceResolver() { + return fComponentManager.getResourceResolver(); + } + + public boolean getFeature(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "FeatureNameNull", null)); + } + if (name.startsWith(JAXP_SOURCE_RESULT_FEATURE_PREFIX)) { + // Indicates to the caller that this Validator supports a specific JAXP Source or Result. + if (name.equals(StreamSource.FEATURE) || + name.equals(SAXSource.FEATURE) || + name.equals(DOMSource.FEATURE) || + name.equals(StAXSource.FEATURE) || + name.equals(StreamResult.FEATURE) || + name.equals(SAXResult.FEATURE) || + name.equals(DOMResult.FEATURE) || + name.equals(StAXResult.FEATURE)) { + return true; + } + } + try { + return fComponentManager.getFeature(name); + } + catch (XMLConfigurationException e) { + final String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + } + + public void setFeature(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "FeatureNameNull", null)); + } + if (name.startsWith(JAXP_SOURCE_RESULT_FEATURE_PREFIX)) { + if (name.equals(StreamSource.FEATURE) || + name.equals(SAXSource.FEATURE) || + name.equals(DOMSource.FEATURE) || + name.equals(StAXSource.FEATURE) || + name.equals(StreamResult.FEATURE) || + name.equals(SAXResult.FEATURE) || + name.equals(DOMResult.FEATURE) || + name.equals(StAXResult.FEATURE)) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-read-only", new Object [] {name})); + } + } + try { + fComponentManager.setFeature(name, value); + } + catch (XMLConfigurationException e) { + final String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + fConfigurationChanged = true; + } + + public Object getProperty(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "ProperyNameNull", null)); + } + if (CURRENT_ELEMENT_NODE.equals(name)) { + return (fDOMValidatorHelper != null) ? + fDOMValidatorHelper.getCurrentElement() : null; + } + try { + return fComponentManager.getProperty(name); + } + catch (XMLConfigurationException e) { + final String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + } + + public void setProperty(String name, Object object) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), + "ProperyNameNull", null)); + } + if (CURRENT_ELEMENT_NODE.equals(name)) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-read-only", new Object [] {name})); + } + try { + fComponentManager.setProperty(name, object); + } + catch (XMLConfigurationException e) { + final String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + fConfigurationChanged = true; + } + + public void reset() { + // avoid resetting features and properties if the state the validator + // is currently in, is the same as it will be after reset. + if (fConfigurationChanged) { + fComponentManager.restoreInitialState(); + setErrorHandler(null); + setResourceResolver(null); + fConfigurationChanged = false; + fErrorHandlerChanged = false; + fResourceResolverChanged = false; + } + else { + if (fErrorHandlerChanged) { + setErrorHandler(null); + fErrorHandlerChanged = false; + } + if (fResourceResolverChanged) { + setResourceResolver(null); + fResourceResolverChanged = false; + } + } + } + + /* + * PSVIProvider methods + */ + + public ElementPSVI getElementPSVI() { + return (fSAXValidatorHelper != null) ? fSAXValidatorHelper.getElementPSVI() : null; + } + + public AttributePSVI getAttributePSVI(int index) { + return (fSAXValidatorHelper != null) ? fSAXValidatorHelper.getAttributePSVI(index) : null; + } + + public AttributePSVI getAttributePSVIByName(String uri, String localname) { + return (fSAXValidatorHelper != null) ? fSAXValidatorHelper.getAttributePSVIByName(uri, localname) : null; + } + +} // ValidatorImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/WeakReferenceXMLSchema.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/WeakReferenceXMLSchema.java new file mode 100644 index 0000000..705c0ab --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/WeakReferenceXMLSchema.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.lang.ref.WeakReference; + +import org.apache.xerces.xni.grammars.XMLGrammarPool; + +/** + *

        An implementation of Schema for W3C XML Schemas + * that keeps a weak reference to its grammar pool. If + * no validators currently have a reference to the + * grammar pool, the garbage collector is free to reclaim + * its memory.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class WeakReferenceXMLSchema extends AbstractXMLSchema { + + /** Weak reference to grammar pool. */ + private WeakReference fGrammarPool = new WeakReference(null); + + public WeakReferenceXMLSchema() {} + + /* + * XSGrammarPoolContainer methods + */ + + public synchronized XMLGrammarPool getGrammarPool() { + XMLGrammarPool grammarPool = (XMLGrammarPool) fGrammarPool.get(); + // If there's no grammar pool then either we haven't created one + // yet or the garbage collector has already cleaned out the previous one. + if (grammarPool == null) { + grammarPool = new SoftReferenceGrammarPool(); + fGrammarPool = new WeakReference(grammarPool); + } + return grammarPool; + } + + public boolean isFullyComposed() { + return false; + } + +} // WeakReferenceXMLSchema diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchema.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchema.java new file mode 100644 index 0000000..15f673d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchema.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import org.apache.xerces.xni.grammars.XMLGrammarPool; + +/** + *

        Implementation of Schema for W3C XML Schemas.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class XMLSchema extends AbstractXMLSchema { + + /** The grammar pool is immutable */ + private final XMLGrammarPool fGrammarPool; + + /** Whether to consider this schema to be fully composed */ + private final boolean fFullyComposed; + + /** Constructors */ + public XMLSchema(XMLGrammarPool grammarPool) { + this(grammarPool, true); + } + + public XMLSchema(XMLGrammarPool grammarPool, boolean fullyComposed) { + fGrammarPool = grammarPool; + fFullyComposed = fullyComposed; + } + + /* + * XSGrammarPoolContainer methods + */ + + /** + *

        Returns the grammar pool contained inside the container.

        + * + * @return the grammar pool contained inside the container + */ + public XMLGrammarPool getGrammarPool() { + return fGrammarPool; + } + + /** + *

        Returns whether the schema components contained in this object + * can be considered to be a fully composed schema and should be + * used to exclusion of other schema components which may be + * present elsewhere.

        + * + * @return whether the schema components contained in this object + * can be considered to be a fully composed schema + */ + public boolean isFullyComposed() { + return fFullyComposed; + } + +} // XMLSchema diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchemaFactory.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchemaFactory.java new file mode 100644 index 0000000..57b7dad --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchemaFactory.java @@ -0,0 +1,529 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import javax.xml.XMLConstants; +import javax.xml.stream.XMLEventReader; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.xs.XMLSchemaLoader; +import org.apache.xerces.util.DOMEntityResolverWrapper; +import org.apache.xerces.util.DOMInputSource; +import org.apache.xerces.util.ErrorHandlerWrapper; +import org.apache.xerces.util.SAXInputSource; +import org.apache.xerces.util.SAXMessageFormatter; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.util.StAXInputSource; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.w3c.dom.Node; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; + +/** + * {@link SchemaFactory} for XML Schema. + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * @version $Id$ + */ +public final class XMLSchemaFactory extends SchemaFactory { + + // feature identifiers + + /** JAXP Source feature prefix. */ + private static final String JAXP_SOURCE_FEATURE_PREFIX = "http://javax.xml.transform"; + + /** Feature identifier: schema full checking. */ + private static final String SCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + + /** Feature identifier: use grammar pool only. */ + private static final String USE_GRAMMAR_POOL_ONLY = + Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + + // property identifiers + + /** Property identifier: grammar pool. */ + private static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: SecurityManager. */ + private static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + // + // Data + // + + /** The XMLSchemaLoader */ + private final XMLSchemaLoader fXMLSchemaLoader = new XMLSchemaLoader(); + + /** User-specified ErrorHandler; can be null. */ + private ErrorHandler fErrorHandler; + + /** The LSResrouceResolver */ + private LSResourceResolver fLSResourceResolver; + + /** The DOMEntityResolverWrapper */ + private final DOMEntityResolverWrapper fDOMEntityResolverWrapper; + + /** The ErrorHandlerWrapper */ + private final ErrorHandlerWrapper fErrorHandlerWrapper; + + /** The SecurityManager. */ + private SecurityManager fSecurityManager; + + /** The container for the real grammar pool. */ + private final XMLGrammarPoolWrapper fXMLGrammarPoolWrapper; + + /** Whether or not to allow new schemas to be added to the grammar pool */ + private boolean fUseGrammarPoolOnly; + + public XMLSchemaFactory() { + fErrorHandlerWrapper = new ErrorHandlerWrapper(DraconianErrorHandler.getInstance()); + fDOMEntityResolverWrapper = new DOMEntityResolverWrapper(); + fXMLGrammarPoolWrapper = new XMLGrammarPoolWrapper(); + fXMLSchemaLoader.setFeature(SCHEMA_FULL_CHECKING, true); + fXMLSchemaLoader.setProperty(XMLGRAMMAR_POOL, fXMLGrammarPoolWrapper); + fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper); + fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper); + fUseGrammarPoolOnly = true; + } + + /** + *

        Is specified schema supported by this SchemaFactory?

        + * + * @param schemaLanguage Specifies the schema language which the returned SchemaFactory will understand. + * schemaLanguage must specify a valid schema language. + * + * @return true if SchemaFactory supports schemaLanguage, else false. + * + * @throws NullPointerException If schemaLanguage is null. + * @throws IllegalArgumentException If schemaLanguage.length() == 0 + * or schemaLanguage does not specify a valid schema language. + */ + public boolean isSchemaLanguageSupported(String schemaLanguage) { + if (schemaLanguage == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "SchemaLanguageNull", null)); + } + if (schemaLanguage.length() == 0) { + throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "SchemaLanguageLengthZero", null)); + } + // only W3C XML Schema 1.0 is supported + return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI) || + schemaLanguage.equals(Constants.W3C_XML_SCHEMA10_NS_URI); + } + + public LSResourceResolver getResourceResolver() { + return fLSResourceResolver; + } + + public void setResourceResolver(LSResourceResolver resourceResolver) { + fLSResourceResolver = resourceResolver; + fDOMEntityResolverWrapper.setEntityResolver(resourceResolver); + fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper); + } + + public ErrorHandler getErrorHandler() { + return fErrorHandler; + } + + public void setErrorHandler(ErrorHandler errorHandler) { + fErrorHandler = errorHandler; + fErrorHandlerWrapper.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance()); + fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper); + } + + public Schema newSchema( Source[] schemas ) throws SAXException { + + // this will let the loader store parsed Grammars into the pool. + XMLGrammarPoolImplExtension pool = new XMLGrammarPoolImplExtension(); + fXMLGrammarPoolWrapper.setGrammarPool(pool); + + XMLInputSource[] xmlInputSources = new XMLInputSource[schemas.length]; + InputStream inputStream; + Reader reader; + for (int i = 0; i < schemas.length; ++i) { + Source source = schemas[i]; + if (source instanceof StreamSource) { + StreamSource streamSource = (StreamSource) source; + String publicId = streamSource.getPublicId(); + String systemId = streamSource.getSystemId(); + inputStream = streamSource.getInputStream(); + reader = streamSource.getReader(); + XMLInputSource xmlInputSource = new XMLInputSource(publicId, systemId, null); + xmlInputSource.setByteStream(inputStream); + xmlInputSource.setCharacterStream(reader); + xmlInputSources[i] = xmlInputSource; + } + else if (source instanceof SAXSource) { + SAXSource saxSource = (SAXSource) source; + InputSource inputSource = saxSource.getInputSource(); + if (inputSource == null) { + throw new SAXException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "SAXSourceNullInputSource", null)); + } + xmlInputSources[i] = new SAXInputSource(saxSource.getXMLReader(), inputSource); + } + else if (source instanceof DOMSource) { + DOMSource domSource = (DOMSource) source; + Node node = domSource.getNode(); + String systemID = domSource.getSystemId(); + xmlInputSources[i] = new DOMInputSource(node, systemID); + } + else if (source instanceof StAXSource) { + StAXSource staxSource = (StAXSource) source; + XMLEventReader eventReader = staxSource.getXMLEventReader(); + if (eventReader != null) { + xmlInputSources[i] = new StAXInputSource(eventReader); + } + else { + xmlInputSources[i] = new StAXInputSource(staxSource.getXMLStreamReader()); + } + } + else if (source == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "SchemaSourceArrayMemberNull", null)); + } + else { + throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "SchemaFactorySourceUnrecognized", + new Object [] {source.getClass().getName()})); + } + } + + try { + fXMLSchemaLoader.loadGrammar(xmlInputSources); + } + catch (XNIException e) { + // this should have been reported to users already. + throw Util.toSAXException(e); + } + catch (IOException e) { + // this hasn't been reported, so do so now. + SAXParseException se = new SAXParseException(e.getMessage(),null,e); + if (fErrorHandler != null) { + fErrorHandler.error(se); + } + throw se; // and we must throw it. + } + + // Clear reference to grammar pool. + fXMLGrammarPoolWrapper.setGrammarPool(null); + + // Select Schema implementation based on grammar count. + final int grammarCount = pool.getGrammarCount(); + AbstractXMLSchema schema = null; + if (fUseGrammarPoolOnly) { + if (grammarCount > 1) { + schema = new XMLSchema(new ReadOnlyGrammarPool(pool)); + } + else if (grammarCount == 1) { + Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA); + schema = new SimpleXMLSchema(grammars[0]); + } + else { + schema = new EmptyXMLSchema(); + } + } + else { + schema = new XMLSchema(new ReadOnlyGrammarPool(pool), false); + } + propagateFeatures(schema); + return schema; + } + + public Schema newSchema() throws SAXException { + /* + * It would make sense to return an EmptyXMLSchema object here, if + * fUseGrammarPoolOnly is set to true. However, because the default + * value of this feature is true, doing so would change the default + * behaviour of this method. Thus, we return a WeakReferenceXMLSchema + * regardless of the value of fUseGrammarPoolOnly. -PM + */ + + // Use a Schema that uses the system id as the equality source. + AbstractXMLSchema schema = new WeakReferenceXMLSchema(); + propagateFeatures(schema); + return schema; + } + + public Schema newSchema(XMLGrammarPool pool) throws SAXException { + // If the "use-grammar-pool-only" feature is set to true + // prevent the application's grammar pool from being mutated + // by wrapping it in a ReadOnlyGrammarPool. + final AbstractXMLSchema schema = (fUseGrammarPoolOnly) ? + new XMLSchema(new ReadOnlyGrammarPool(pool)) : + new XMLSchema(pool, false); + propagateFeatures(schema); + return schema; + } + + public boolean getFeature(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "FeatureNameNull", null)); + } + if (name.startsWith(JAXP_SOURCE_FEATURE_PREFIX)) { + // Indicates to the caller that this SchemaFactory supports a specific JAXP Source. + if (name.equals(StreamSource.FEATURE) || + name.equals(SAXSource.FEATURE) || + name.equals(DOMSource.FEATURE) || + name.equals(StAXSource.FEATURE)) { + return true; + } + } + if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { + return (fSecurityManager != null); + } + else if (name.equals(USE_GRAMMAR_POOL_ONLY)) { + return fUseGrammarPoolOnly; + } + try { + return fXMLSchemaLoader.getFeature(name); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + } + + public Object getProperty(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "ProperyNameNull", null)); + } + if (name.equals(SECURITY_MANAGER)) { + return fSecurityManager; + } + else if (name.equals(XMLGRAMMAR_POOL)) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "property-not-supported", new Object [] {name})); + } + try { + return fXMLSchemaLoader.getProperty(name); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + } + + public void setFeature(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "FeatureNameNull", null)); + } + if (name.startsWith(JAXP_SOURCE_FEATURE_PREFIX)) { + if (name.equals(StreamSource.FEATURE) || + name.equals(SAXSource.FEATURE) || + name.equals(DOMSource.FEATURE) || + name.equals(StAXSource.FEATURE)) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "feature-read-only", new Object [] {name})); + } + } + if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { + fSecurityManager = value ? new SecurityManager() : null; + fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); + return; + } + else if (name.equals(USE_GRAMMAR_POOL_ONLY)) { + fUseGrammarPoolOnly = value; + return; + } + try { + fXMLSchemaLoader.setFeature(name, value); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + } + + public void setProperty(String name, Object object) + throws SAXNotRecognizedException, SAXNotSupportedException { + if (name == null) { + throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "ProperyNameNull", null)); + } + if (name.equals(SECURITY_MANAGER)) { + fSecurityManager = (SecurityManager) object; + fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); + return; + } + else if (name.equals(XMLGRAMMAR_POOL)) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "property-not-supported", new Object [] {name})); + } + try { + fXMLSchemaLoader.setProperty(name, object); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + } + + private void propagateFeatures(AbstractXMLSchema schema) { + schema.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, fSecurityManager != null); + String[] features = fXMLSchemaLoader.getRecognizedFeatures(); + for (int i = 0; i < features.length; ++i) { + boolean state = fXMLSchemaLoader.getFeature(features[i]); + schema.setFeature(features[i], state); + } + } + + /** + * Extension of XMLGrammarPoolImpl which exposes the number of + * grammars stored in the grammar pool. + */ + static class XMLGrammarPoolImplExtension extends XMLGrammarPoolImpl { + + /** Constructs a grammar pool with a default number of buckets. */ + public XMLGrammarPoolImplExtension() { + super(); + } + + /** Constructs a grammar pool with a specified number of buckets. */ + public XMLGrammarPoolImplExtension(int initialCapacity) { + super(initialCapacity); + } + + /** Returns the number of grammars contained in this pool. */ + int getGrammarCount() { + return fGrammarCount; + } + + } // XMLSchemaFactory.XMLGrammarPoolImplExtension + + /** + * A grammar pool which wraps another. + */ + static class XMLGrammarPoolWrapper implements XMLGrammarPool { + + private XMLGrammarPool fGrammarPool; + + /* + * XMLGrammarPool methods + */ + + public Grammar[] retrieveInitialGrammarSet(String grammarType) { + return fGrammarPool.retrieveInitialGrammarSet(grammarType); + } + + public void cacheGrammars(String grammarType, Grammar[] grammars) { + fGrammarPool.cacheGrammars(grammarType, grammars); + } + + public Grammar retrieveGrammar(XMLGrammarDescription desc) { + return fGrammarPool.retrieveGrammar(desc); + } + + public void lockPool() { + fGrammarPool.lockPool(); + } + + public void unlockPool() { + fGrammarPool.unlockPool(); + } + + public void clear() { + fGrammarPool.clear(); + } + + /* + * Other methods + */ + + void setGrammarPool(XMLGrammarPool grammarPool) { + fGrammarPool = grammarPool; + } + + XMLGrammarPool getGrammarPool() { + return fGrammarPool; + } + + } // XMLSchemaFactory.XMLGrammarPoolWrapper + +} // XMLSchemaFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchemaValidatorComponentManager.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchemaValidatorComponentManager.java new file mode 100644 index 0000000..e02ad35 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XMLSchemaValidatorComponentManager.java @@ -0,0 +1,554 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +import javax.xml.XMLConstants; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.util.DOMEntityResolverWrapper; +import org.apache.xerces.util.ErrorHandlerWrapper; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.ParserConfigurationSettings; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.ErrorHandler; + +/** + *

        An implementation of XMLComponentManager for a schema validator.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +final class XMLSchemaValidatorComponentManager extends ParserConfigurationSettings implements + XMLComponentManager { + + // feature identifiers + + /** Feature identifier: schema validation. */ + private static final String SCHEMA_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** Feature identifier: validation. */ + private static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: use grammar pool only. */ + private static final String USE_GRAMMAR_POOL_ONLY = + Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + + /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */ + private static final String IGNORE_XSI_TYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE; + + /** Feature identifier: whether to ignore ID/IDREF errors */ + private static final String ID_IDREF_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore unparsed entity errors */ + private static final String UNPARSED_ENTITY_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore identity constraint errors */ + private static final String IDENTITY_CONSTRAINT_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE; + + /** Feature identifier: disallow DOCTYPE declaration */ + private static final String DISALLOW_DOCTYPE_DECL_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE; + + /** Feature identifier: expose schema normalized value */ + private static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + + /** Feature identifier: send element default value via characters() */ + private static final String SCHEMA_ELEMENT_DEFAULT = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; + + /** Feature identifier: augment PSVI */ + private static final String SCHEMA_AUGMENT_PSVI = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; + + // property identifiers + + /** Property identifier: entity manager. */ + private static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier: entity resolver. */ + private static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: error handler. */ + private static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: error reporter. */ + private static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: namespace context. */ + private static final String NAMESPACE_CONTEXT = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY; + + /** Property identifier: XML Schema validator. */ + private static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: security manager. */ + private static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + /** Property identifier: symbol table. */ + private static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: validation manager. */ + private static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: grammar pool. */ + private static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: locale. */ + private static final String LOCALE = + Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + + // + // Data + // + + /** + * fConfigUpdated is set to true if there has been any change to the configuration settings, + * i.e a feature or a property was changed. + */ + private boolean fConfigUpdated = true; + + /** + * Tracks whether the validator should use components from + * the grammar pool to the exclusion of all others. + */ + private boolean fUseGrammarPoolOnly; + + /** Lookup map for components required for validation. **/ + private final HashMap fComponents = new HashMap(); + + // + // Components + // + + /** Entity manager. */ + private final XMLEntityManager fEntityManager; + + /** Error reporter. */ + private final XMLErrorReporter fErrorReporter; + + /** Namespace context. */ + private final NamespaceContext fNamespaceContext; + + /** XML Schema validator. */ + private final XMLSchemaValidator fSchemaValidator; + + /** Validation manager. */ + private final ValidationManager fValidationManager; + + // + // Configuration + // + + /** Stores initial feature values for validator reset. */ + private final HashMap fInitFeatures = new HashMap(); + + /** Stores initial property values for validator reset. */ + private final HashMap fInitProperties = new HashMap(); + + /** Stores the initial security manager. */ + private final SecurityManager fInitSecurityManager; + + // + // User Objects + // + + /** Application's ErrorHandler. **/ + private ErrorHandler fErrorHandler = null; + + /** Application's LSResourceResolver. */ + private LSResourceResolver fResourceResolver = null; + + /** Locale chosen by the application. */ + private Locale fLocale = null; + + /** Constructs a component manager suitable for Xerces' schema validator. */ + public XMLSchemaValidatorComponentManager(XSGrammarPoolContainer grammarContainer) { + + // setup components + fEntityManager = new XMLEntityManager(); + fComponents.put(ENTITY_MANAGER, fEntityManager); + + fErrorReporter = new XMLErrorReporter(); + fComponents.put(ERROR_REPORTER, fErrorReporter); + + fNamespaceContext = new NamespaceSupport(); + fComponents.put(NAMESPACE_CONTEXT, fNamespaceContext); + + fSchemaValidator = new XMLSchemaValidator(); + fComponents.put(SCHEMA_VALIDATOR, fSchemaValidator); + + fValidationManager = new ValidationManager(); + fComponents.put(VALIDATION_MANAGER, fValidationManager); + + // setup other properties + fComponents.put(ENTITY_RESOLVER, null); + fComponents.put(ERROR_HANDLER, null); + fComponents.put(SECURITY_MANAGER, null); + fComponents.put(SYMBOL_TABLE, new SymbolTable()); + + // setup grammar pool + fComponents.put(XMLGRAMMAR_POOL, grammarContainer.getGrammarPool()); + fUseGrammarPoolOnly = grammarContainer.isFullyComposed(); + + // add schema message formatter to error reporter + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter()); + + // add all recognized features and properties and apply their defaults + final String [] recognizedFeatures = { + DISALLOW_DOCTYPE_DECL_FEATURE, + NORMALIZE_DATA, + SCHEMA_ELEMENT_DEFAULT, + SCHEMA_AUGMENT_PSVI + }; + addRecognizedFeatures(recognizedFeatures); + fFeatures.put(DISALLOW_DOCTYPE_DECL_FEATURE, Boolean.FALSE); + fFeatures.put(NORMALIZE_DATA, Boolean.FALSE); + fFeatures.put(SCHEMA_ELEMENT_DEFAULT, Boolean.FALSE); + fFeatures.put(SCHEMA_AUGMENT_PSVI, Boolean.TRUE); + + addRecognizedParamsAndSetDefaults(fEntityManager, grammarContainer); + addRecognizedParamsAndSetDefaults(fErrorReporter, grammarContainer); + addRecognizedParamsAndSetDefaults(fSchemaValidator, grammarContainer); + + // if the secure processing feature is set to true, add a security manager to the configuration + Boolean secureProcessing = grammarContainer.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING); + if (Boolean.TRUE.equals(secureProcessing)) { + fInitSecurityManager = new SecurityManager(); + } + else { + fInitSecurityManager = null; + } + fComponents.put(SECURITY_MANAGER, fInitSecurityManager); + + /* TODO: are other XMLSchemaValidator default values never set? + * Initial investigation indicates that they aren't set, but + * that they all have default values of false, so it works out + * anyway -PM + */ + fFeatures.put(IGNORE_XSI_TYPE, Boolean.FALSE); + fFeatures.put(ID_IDREF_CHECKING, Boolean.TRUE); + fFeatures.put(IDENTITY_CONSTRAINT_CHECKING, Boolean.TRUE); + fFeatures.put(UNPARSED_ENTITY_CHECKING, Boolean.TRUE); + } + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * @return true if the feature is supported + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + if (PARSER_SETTINGS.equals(featureId)) { + return fConfigUpdated; + } + else if (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId)) { + return true; + } + else if (USE_GRAMMAR_POOL_ONLY.equals(featureId)) { + return fUseGrammarPoolOnly; + } + else if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(featureId)) { + return getProperty(SECURITY_MANAGER) != null; + } + return super.getFeature(featureId); + } + + /** + * Set the state of a feature. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception XMLConfigurationException If the requested feature is not known. + */ + public void setFeature(String featureId, boolean value) throws XMLConfigurationException { + if (PARSER_SETTINGS.equals(featureId)) { + throw new XMLConfigurationException(XMLConfigurationException.NOT_SUPPORTED, featureId); + } + else if (value == false && (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId))) { + throw new XMLConfigurationException(XMLConfigurationException.NOT_SUPPORTED, featureId); + } + else if (USE_GRAMMAR_POOL_ONLY.equals(featureId) && value != fUseGrammarPoolOnly) { + throw new XMLConfigurationException(XMLConfigurationException.NOT_SUPPORTED, featureId); + } + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(featureId)) { + setProperty(SECURITY_MANAGER, value ? new SecurityManager() : null); + return; + } + fConfigUpdated = true; + fEntityManager.setFeature(featureId, value); + fErrorReporter.setFeature(featureId, value); + fSchemaValidator.setFeature(featureId, value); + if (!fInitFeatures.containsKey(featureId)) { + boolean current = super.getFeature(featureId); + fInitFeatures.put(featureId, current ? Boolean.TRUE : Boolean.FALSE); + } + super.setFeature(featureId, value); + } + + /** + * Returns the value of a property. + * + * @param propertyId The property identifier. + * @return the value of the property + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException { + if (LOCALE.equals(propertyId)) { + return getLocale(); + } + final Object component = fComponents.get(propertyId); + if (component != null) { + return component; + } + else if (fComponents.containsKey(propertyId)) { + return null; + } + return super.getProperty(propertyId); + } + + /** + * Sets the state of a property. + * + * @param propertyId The unique identifier (URI) of the property. + * @param value The requested state of the property. + * + * @exception XMLConfigurationException If the requested property is not known. + */ + public void setProperty(String propertyId, Object value) throws XMLConfigurationException { + if ( ENTITY_MANAGER.equals(propertyId) || ERROR_REPORTER.equals(propertyId) || + NAMESPACE_CONTEXT.equals(propertyId) || SCHEMA_VALIDATOR.equals(propertyId) || + SYMBOL_TABLE.equals(propertyId) || VALIDATION_MANAGER.equals(propertyId) || + XMLGRAMMAR_POOL.equals(propertyId)) { + throw new XMLConfigurationException(XMLConfigurationException.NOT_SUPPORTED, propertyId); + } + fConfigUpdated = true; + fEntityManager.setProperty(propertyId, value); + fErrorReporter.setProperty(propertyId, value); + fSchemaValidator.setProperty(propertyId, value); + if (ENTITY_RESOLVER.equals(propertyId) || ERROR_HANDLER.equals(propertyId) || + SECURITY_MANAGER.equals(propertyId)) { + fComponents.put(propertyId, value); + return; + } + else if (LOCALE.equals(propertyId)) { + setLocale((Locale) value); + fComponents.put(propertyId, value); + return; + } + if (!fInitProperties.containsKey(propertyId)) { + fInitProperties.put(propertyId, super.getProperty(propertyId)); + } + super.setProperty(propertyId, value); + } + + /** + * Adds all of the component's recognized features and properties + * to the list of default recognized features and properties, and + * sets default values on the configuration for features and + * properties which were previously absent from the configuration. + * + * @param component The component whose recognized features + * and properties will be added to the configuration + */ + public void addRecognizedParamsAndSetDefaults(XMLComponent component, XSGrammarPoolContainer grammarContainer) { + + // register component's recognized features + final String[] recognizedFeatures = component.getRecognizedFeatures(); + addRecognizedFeatures(recognizedFeatures); + + // register component's recognized properties + final String[] recognizedProperties = component.getRecognizedProperties(); + addRecognizedProperties(recognizedProperties); + + // set default values + setFeatureDefaults(component, recognizedFeatures, grammarContainer); + setPropertyDefaults(component, recognizedProperties); + } + + /** Calls reset on each of the components owned by this component manager. **/ + public void reset() throws XNIException { + fNamespaceContext.reset(); + fValidationManager.reset(); + fEntityManager.reset(this); + fErrorReporter.reset(this); + fSchemaValidator.reset(this); + // Mark configuration as fixed. + fConfigUpdated = false; + } + + void setErrorHandler(ErrorHandler errorHandler) { + fErrorHandler = errorHandler; + setProperty(ERROR_HANDLER, (errorHandler != null) ? new ErrorHandlerWrapper(errorHandler) : + new ErrorHandlerWrapper(DraconianErrorHandler.getInstance())); + } + + ErrorHandler getErrorHandler() { + return fErrorHandler; + } + + void setResourceResolver(LSResourceResolver resourceResolver) { + fResourceResolver = resourceResolver; + setProperty(ENTITY_RESOLVER, new DOMEntityResolverWrapper(resourceResolver)); + } + + LSResourceResolver getResourceResolver() { + return fResourceResolver; + } + + void setLocale(Locale locale) { + fLocale = locale; + fErrorReporter.setLocale(locale); + } + + Locale getLocale() { + return fLocale; + } + + /** Cleans out configuration, restoring it to its initial state. */ + void restoreInitialState() { + fConfigUpdated = true; + + // Remove error resolver and error handler + fComponents.put(ENTITY_RESOLVER, null); + fComponents.put(ERROR_HANDLER, null); + + // Restore initial security manager + fComponents.put(SECURITY_MANAGER, fInitSecurityManager); + + // Set the Locale back to null. + setLocale(null); + fComponents.put(LOCALE, null); + + // Reset feature and property values to their initial values + if (!fInitFeatures.isEmpty()) { + Iterator iter = fInitFeatures.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String name = (String) entry.getKey(); + boolean value = ((Boolean) entry.getValue()).booleanValue(); + super.setFeature(name, value); + } + fInitFeatures.clear(); + } + if (!fInitProperties.isEmpty()) { + Iterator iter = fInitProperties.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String name = (String) entry.getKey(); + Object value = entry.getValue(); + super.setProperty(name, value); + } + fInitProperties.clear(); + } + } + + /** Sets feature defaults for the given component on this configuration. */ + private void setFeatureDefaults(final XMLComponent component, + final String [] recognizedFeatures, XSGrammarPoolContainer grammarContainer) { + if (recognizedFeatures != null) { + for (int i = 0; i < recognizedFeatures.length; ++i) { + String featureId = recognizedFeatures[i]; + Boolean state = grammarContainer.getFeature(featureId); + if (state == null) { + state = component.getFeatureDefault(featureId); + } + if (state != null) { + // Do not overwrite values already set on the configuration. + if (!fFeatures.containsKey(featureId)) { + fFeatures.put(featureId, state); + // For newly added components who recognize this feature + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + } + + /** Sets property defaults for the given component on this configuration. */ + private void setPropertyDefaults(final XMLComponent component, final String [] recognizedProperties) { + if (recognizedProperties != null) { + for (int i = 0; i < recognizedProperties.length; ++i) { + String propertyId = recognizedProperties[i]; + Object value = component.getPropertyDefault(propertyId); + if (value != null) { + // Do not overwrite values already set on the configuration. + if (!fProperties.containsKey(propertyId)) { + fProperties.put(propertyId, value); + // For newly added components who recognize this property + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + } + +} // XMLSchemaValidatorComponentManager + \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XSGrammarPoolContainer.java b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XSGrammarPoolContainer.java new file mode 100644 index 0000000..55cec85 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/XSGrammarPoolContainer.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.xerces.jaxp.validation; + +import org.apache.xerces.xni.grammars.XMLGrammarPool; + +/** + *

        A container for grammar pools which only contain schema grammars.

        + * + * @author Michael Glavassevich, IBM + * @version $Id$ + */ +public interface XSGrammarPoolContainer { + + /** + *

        Returns the grammar pool contained inside the container.

        + * + * @return the grammar pool contained inside the container + */ + public XMLGrammarPool getGrammarPool(); + + /** + *

        Returns whether the schema components contained in this object + * can be considered to be a fully composed schema and should be + * used to the exclusion of other schema components which may be + * present elsewhere.

        + * + * @return whether the schema components contained in this object + * can be considered to be a fully composed schema + */ + public boolean isFullyComposed(); + + /** + * Returns the initial value of a feature for validators created + * using this grammar pool container or null if the validators + * should use the default value. + */ + public Boolean getFeature(String featureId); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/javax.xml.validation.SchemaFactory b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/javax.xml.validation.SchemaFactory new file mode 100644 index 0000000..ec3f1f4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/jaxp/validation/javax.xml.validation.SchemaFactory @@ -0,0 +1 @@ +org.apache.xerces.jaxp.validation.XMLSchemaFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractDOMParser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractDOMParser.java new file mode 100644 index 0000000..fde2cb9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractDOMParser.java @@ -0,0 +1,2656 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.util.Locale; +import java.util.Stack; + +import org.apache.xerces.dom.AttrImpl; +import org.apache.xerces.dom.CoreDocumentImpl; +import org.apache.xerces.dom.DOMErrorImpl; +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.dom.DeferredDocumentImpl; +import org.apache.xerces.dom.DocumentImpl; +import org.apache.xerces.dom.DocumentTypeImpl; +import org.apache.xerces.dom.ElementDefinitionImpl; +import org.apache.xerces.dom.ElementImpl; +import org.apache.xerces.dom.ElementNSImpl; +import org.apache.xerces.dom.EntityImpl; +import org.apache.xerces.dom.EntityReferenceImpl; +import org.apache.xerces.dom.NodeImpl; +import org.apache.xerces.dom.NotationImpl; +import org.apache.xerces.dom.PSVIAttrNSImpl; +import org.apache.xerces.dom.PSVIDocumentImpl; +import org.apache.xerces.dom.PSVIElementNSImpl; +import org.apache.xerces.dom.TextImpl; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.util.DOMErrorHandlerWrapper; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.XSTypeDefinition; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.DOMError; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.w3c.dom.ls.LSParserFilter; +import org.w3c.dom.traversal.NodeFilter; +import org.xml.sax.SAXException; + +/** + * This is the base class of all DOM parsers. It implements the XNI + * callback methods to create the DOM tree. After a successful parse of + * an XML document, the DOM Document object can be queried using the + * getDocument method. The actual pipeline is defined in + * parser configuration. + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * @author Elena Litani, IBM + * + * @version $Id$ + */ +public class AbstractDOMParser extends AbstractXMLDocumentParser { + + // + // Constants + // + + // feature ids + + /** Feature id: namespace. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX+Constants.NAMESPACES_FEATURE; + + /** Feature id: create entity ref nodes. */ + protected static final String CREATE_ENTITY_REF_NODES = + Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE; + + /** Feature id: include comments. */ + protected static final String INCLUDE_COMMENTS_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE; + + /** Feature id: create cdata nodes. */ + protected static final String CREATE_CDATA_NODES_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE; + + /** Feature id: include ignorable whitespace. */ + protected static final String INCLUDE_IGNORABLE_WHITESPACE = + Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE; + + /** Feature id: defer node expansion. */ + protected static final String DEFER_NODE_EXPANSION = + Constants.XERCES_FEATURE_PREFIX + Constants.DEFER_NODE_EXPANSION_FEATURE; + + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + NAMESPACES, + CREATE_ENTITY_REF_NODES, + INCLUDE_COMMENTS_FEATURE, + CREATE_CDATA_NODES_FEATURE, + INCLUDE_IGNORABLE_WHITESPACE, + DEFER_NODE_EXPANSION + }; + + // property ids + + /** Property id: document class name. */ + protected static final String DOCUMENT_CLASS_NAME = + Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_CLASS_NAME_PROPERTY; + + protected static final String CURRENT_ELEMENT_NODE= + Constants.XERCES_PROPERTY_PREFIX + Constants.CURRENT_ELEMENT_NODE_PROPERTY; + + // protected static final String GRAMMAR_POOL = + // Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + DOCUMENT_CLASS_NAME, + CURRENT_ELEMENT_NODE, + }; + + // other + + /** Default document class name. */ + protected static final String DEFAULT_DOCUMENT_CLASS_NAME = + "org.apache.xerces.dom.DocumentImpl"; + + protected static final String CORE_DOCUMENT_CLASS_NAME = + "org.apache.xerces.dom.CoreDocumentImpl"; + + protected static final String PSVI_DOCUMENT_CLASS_NAME = + "org.apache.xerces.dom.PSVIDocumentImpl"; + + /** + * If the user stops the process, this exception will be thrown. + */ + static final class Abort extends RuntimeException { + private static final long serialVersionUID = 1687848994976808490L; + static final Abort INSTANCE = new Abort(); + private Abort() {} + public Throwable fillInStackTrace() { + return this; + } + } + + // debugging + + private static final boolean DEBUG_EVENTS = false; + private static final boolean DEBUG_BASEURI = false; + + // + // Data + // + + /** DOM L3 error handler */ + protected DOMErrorHandlerWrapper fErrorHandler = null; + + /** True if inside DTD. */ + protected boolean fInDTD; + + // features + + /** Create entity reference nodes. */ + protected boolean fCreateEntityRefNodes; + + /** Include ignorable whitespace. */ + protected boolean fIncludeIgnorableWhitespace; + + /** Include Comments. */ + protected boolean fIncludeComments; + + /** Create cdata nodes. */ + protected boolean fCreateCDATANodes; + + // dom information + + /** The document. */ + protected Document fDocument; + + /** The default Xerces document implementation, if used. */ + protected CoreDocumentImpl fDocumentImpl; + + /** Whether to store PSVI information in DOM tree. */ + protected boolean fStorePSVI; + + /** The document class name to use. */ + protected String fDocumentClassName; + + /** The document type node. */ + protected DocumentType fDocumentType; + + /** Current node. */ + protected Node fCurrentNode; + protected CDATASection fCurrentCDATASection; + protected EntityImpl fCurrentEntityDecl; + protected int fDeferredEntityDecl; + + /** Character buffer */ + protected final StringBuffer fStringBuffer = new StringBuffer (50); + + // internal subset + + /** Internal subset buffer. */ + protected StringBuffer fInternalSubset; + + // deferred expansion data + + protected boolean fDeferNodeExpansion; + protected boolean fNamespaceAware; + protected DeferredDocumentImpl fDeferredDocumentImpl; + protected int fDocumentIndex; + protected int fDocumentTypeIndex; + protected int fCurrentNodeIndex; + protected int fCurrentCDATASectionIndex; + + // state + + /** True if inside DTD external subset. */ + protected boolean fInDTDExternalSubset; + + /** Root element node. */ + protected Node fRoot; + + /** True if inside CDATA section. */ + protected boolean fInCDATASection; + + /** True if saw the first chunk of characters*/ + protected boolean fFirstChunk = false; + + + /** LSParserFilter: specifies that element with given QNAME and all its children + * must be rejected */ + protected boolean fFilterReject = false; + + // data + + /** Base uri stack*/ + protected final Stack fBaseURIStack = new Stack (); + + /** LSParserFilter: tracks the element depth within a rejected subtree. */ + protected int fRejectedElementDepth = 0; + + /** LSParserFilter: store depth of skipped elements */ + protected Stack fSkippedElemStack = null; + + /** LSParserFilter: true if inside entity reference */ + protected boolean fInEntityRef = false; + + /** Attribute QName. */ + private final QName fAttrQName = new QName(); + + /** Document locator. */ + private XMLLocator fLocator; + + // handlers + + protected LSParserFilter fDOMFilter = null; + + // + // Constructors + // + + /** Default constructor. */ + protected AbstractDOMParser (XMLParserConfiguration config) { + + super (config); + + + // add recognized features + fConfiguration.addRecognizedFeatures (RECOGNIZED_FEATURES); + + // set default values + fConfiguration.setFeature (CREATE_ENTITY_REF_NODES, true); + fConfiguration.setFeature (INCLUDE_IGNORABLE_WHITESPACE, true); + fConfiguration.setFeature (DEFER_NODE_EXPANSION, true); + fConfiguration.setFeature (INCLUDE_COMMENTS_FEATURE, true); + fConfiguration.setFeature (CREATE_CDATA_NODES_FEATURE, true); + + // add recognized properties + fConfiguration.addRecognizedProperties (RECOGNIZED_PROPERTIES); + + // set default values + fConfiguration.setProperty (DOCUMENT_CLASS_NAME, + DEFAULT_DOCUMENT_CLASS_NAME); + + } // (XMLParserConfiguration) + + /** + * This method retreives the name of current document class. + */ + protected String getDocumentClassName () { + return fDocumentClassName; + } + + /** + * This method allows the programmer to decide which document + * factory to use when constructing the DOM tree. However, doing + * so will lose the functionality of the default factory. Also, + * a document class other than the default will lose the ability + * to defer node expansion on the DOM tree produced. + * + * @param documentClassName The fully qualified class name of the + * document factory to use when constructing + * the DOM tree. + * + * @see #getDocumentClassName + * @see #DEFAULT_DOCUMENT_CLASS_NAME + */ + protected void setDocumentClassName (String documentClassName) { + + // normalize class name + if (documentClassName == null) { + documentClassName = DEFAULT_DOCUMENT_CLASS_NAME; + } + + if (!documentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME) && + !documentClassName.equals(PSVI_DOCUMENT_CLASS_NAME)) { + // verify that this class exists and is of the right type + try { + Class _class = ObjectFactory.findProviderClass (documentClassName, + ObjectFactory.findClassLoader (), true); + //if (!_class.isAssignableFrom(Document.class)) { + if (!Document.class.isAssignableFrom (_class)) { + throw new IllegalArgumentException ( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "InvalidDocumentClassName", new Object [] {documentClassName})); + } + } + catch (ClassNotFoundException e) { + throw new IllegalArgumentException ( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "MissingDocumentClassName", new Object [] {documentClassName})); + } + } + + // set document class name + fDocumentClassName = documentClassName; + if (!documentClassName.equals (DEFAULT_DOCUMENT_CLASS_NAME)) { + fDeferNodeExpansion = false; + } + + } // setDocumentClassName(String) + + // + // Public methods + // + + /** Returns the DOM document object. */ + public Document getDocument () { + return fDocument; + } // getDocument():Document + + /** + * Drops all references to the last DOM which was built by this parser. + */ + public final void dropDocumentReferences() { + fDocument = null; + fDocumentImpl = null; + fDeferredDocumentImpl = null; + fDocumentType = null; + fCurrentNode = null; + fCurrentCDATASection = null; + fCurrentEntityDecl = null; + fRoot = null; + } // dropDocumentReferences() + + // + // XMLDocumentParser methods + // + + /** + * Resets the parser state. + * + * @throws SAXException Thrown on initialization error. + */ + public void reset () throws XNIException { + super.reset (); + + + // get feature state + fCreateEntityRefNodes = + fConfiguration.getFeature (CREATE_ENTITY_REF_NODES); + + fIncludeIgnorableWhitespace = + fConfiguration.getFeature (INCLUDE_IGNORABLE_WHITESPACE); + + fDeferNodeExpansion = + fConfiguration.getFeature (DEFER_NODE_EXPANSION); + + fNamespaceAware = fConfiguration.getFeature (NAMESPACES); + + fIncludeComments = fConfiguration.getFeature (INCLUDE_COMMENTS_FEATURE); + + fCreateCDATANodes = fConfiguration.getFeature (CREATE_CDATA_NODES_FEATURE); + + // get property + setDocumentClassName ((String) + fConfiguration.getProperty (DOCUMENT_CLASS_NAME)); + + // reset dom information + fDocument = null; + fDocumentImpl = null; + fStorePSVI = false; + fDocumentType = null; + fDocumentTypeIndex = -1; + fDeferredDocumentImpl = null; + fCurrentNode = null; + + // reset string buffer + fStringBuffer.setLength (0); + + // reset state information + fRoot = null; + fInDTD = false; + fInDTDExternalSubset = false; + fInCDATASection = false; + fFirstChunk = false; + fCurrentCDATASection = null; + fCurrentCDATASectionIndex = -1; + + fBaseURIStack.removeAllElements (); + + + } // reset() + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + */ + public void setLocale (Locale locale) { + fConfiguration.setLocale (locale); + + } // setLocale(Locale) + + // + // XMLDocumentHandler methods + // + + /** + * This method notifies the start of a general entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity (String name, + XMLResourceIdentifier identifier, + String encoding, Augmentations augs) + throws XNIException { + if (DEBUG_EVENTS) { + System.out.println ("==>startGeneralEntity ("+name+")"); + if (DEBUG_BASEURI) { + System.out.println (" expandedSystemId( **baseURI): "+identifier.getExpandedSystemId ()); + System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); + } + } + + // Always create entity reference nodes to be able to recreate + // entity as a part of doctype + if (!fDeferNodeExpansion) { + if (fFilterReject) { + return; + } + setCharacterData (true); + EntityReference er = fDocument.createEntityReference (name); + if (fDocumentImpl != null) { + // REVISIT: baseURI/actualEncoding + // remove dependency on our implementation when DOM L3 is REC + // + + EntityReferenceImpl erImpl =(EntityReferenceImpl)er; + + // set base uri + erImpl.setBaseURI (identifier.getExpandedSystemId ()); + if (fDocumentType != null) { + // set actual encoding + NamedNodeMap entities = fDocumentType.getEntities (); + fCurrentEntityDecl = (EntityImpl) entities.getNamedItem (name); + if (fCurrentEntityDecl != null) { + fCurrentEntityDecl.setInputEncoding (encoding); + } + + } + // we don't need synchronization now, because entity ref will be + // expanded anyway. Synch only needed when user creates entityRef node + erImpl.needsSyncChildren (false); + } + fInEntityRef = true; + fCurrentNode.appendChild (er); + fCurrentNode = er; + } + else { + + int er = + fDeferredDocumentImpl.createDeferredEntityReference (name, identifier.getExpandedSystemId ()); + if (fDocumentTypeIndex != -1) { + // find corresponding Entity decl + int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); + while (node != -1) { + short nodeType = fDeferredDocumentImpl.getNodeType (node, false); + if (nodeType == Node.ENTITY_NODE) { + String nodeName = + fDeferredDocumentImpl.getNodeName (node, false); + if (nodeName.equals (name)) { + fDeferredEntityDecl = node; + fDeferredDocumentImpl.setInputEncoding (node, encoding); + break; + } + } + node = fDeferredDocumentImpl.getRealPrevSibling (node, false); + } + } + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, er); + fCurrentNodeIndex = er; + } + + } // startGeneralEntity(String,XMLResourceIdentifier, Augmentations) + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

        + * Note: This method will never be called for the + * document entity; it is only called for external general entities + * referenced in document content. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl (String version, String encoding, Augmentations augs) throws XNIException { + if (fInDTD){ + return; + } + if (!fDeferNodeExpansion) { + if (fCurrentEntityDecl != null && !fFilterReject) { + fCurrentEntityDecl.setXmlEncoding (encoding); + if (version != null) + fCurrentEntityDecl.setXmlVersion (version); + } + } + else { + if (fDeferredEntityDecl !=-1) { + fDeferredDocumentImpl.setEntityInfo (fDeferredEntityDecl, version, encoding); + } + } + } // textDecl(String,String) + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment (XMLString text, Augmentations augs) throws XNIException { + if (fInDTD) { + if (fInternalSubset != null && !fInDTDExternalSubset) { + fInternalSubset.append (""); + } + return; + } + if (!fIncludeComments || fFilterReject) { + return; + } + if (!fDeferNodeExpansion) { + Comment comment = fDocument.createComment (text.toString ()); + + setCharacterData (false); + fCurrentNode.appendChild (comment); + if (fDOMFilter !=null && !fInEntityRef && + (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_COMMENT)!= 0) { + short code = fDOMFilter.acceptNode (comment); + switch (code) { + case LSParserFilter.FILTER_INTERRUPT:{ + throw Abort.INSTANCE; + } + case LSParserFilter.FILTER_REJECT:{ + // REVISIT: the constant FILTER_REJECT should be changed when new + // DOM LS specs gets published + + // fall through to SKIP since comment has no children. + } + case LSParserFilter.FILTER_SKIP: { + // REVISIT: the constant FILTER_SKIP should be changed when new + // DOM LS specs gets published + fCurrentNode.removeChild (comment); + // make sure we don't loose chars if next event is characters() + fFirstChunk = true; + return; + } + + default: { + // accept node + } + } + } + + } + else { + int comment = + fDeferredDocumentImpl.createDeferredComment (text.toString ()); + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, comment); + } + + } // comment(XMLString) + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction (String target, XMLString data, Augmentations augs) + throws XNIException { + + if (fInDTD) { + if (fInternalSubset != null && !fInDTDExternalSubset) { + fInternalSubset.append (" 0) { + fInternalSubset.append (' ').append (data.ch, data.offset, data.length); + } + fInternalSubset.append ("?>"); + } + return; + } + + if (DEBUG_EVENTS) { + System.out.println ("==>processingInstruction ("+target+")"); + } + if (!fDeferNodeExpansion) { + if (fFilterReject) { + return; + } + ProcessingInstruction pi = + fDocument.createProcessingInstruction (target, data.toString ()); + + + setCharacterData (false); + fCurrentNode.appendChild (pi); + if (fDOMFilter !=null && !fInEntityRef && + (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_PROCESSING_INSTRUCTION)!= 0) { + short code = fDOMFilter.acceptNode (pi); + switch (code) { + case LSParserFilter.FILTER_INTERRUPT:{ + throw Abort.INSTANCE; + } + case LSParserFilter.FILTER_REJECT:{ + // fall through to SKIP since PI has no children. + } + case LSParserFilter.FILTER_SKIP: { + fCurrentNode.removeChild (pi); + // fFirstChunk must be set to true so that data + // won't be lost in the case where the child before PI is + // a text node and the next event is characters. + fFirstChunk = true; + return; + } + default: { + } + } + } + } + else { + int pi = fDeferredDocumentImpl. + createDeferredProcessingInstruction (target, data.toString ()); + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, pi); + } + + } // processingInstruction(String,XMLString) + + /** + * The start of the document. + * + * @param locator The system identifier of the entity if the entity + * is external, null otherwise. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param namespaceContext + * The namespace context in effect at the + * start of this document. + * This object represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDocument (XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException { + + fLocator = locator; + if (!fDeferNodeExpansion) { + if (fDocumentClassName.equals (DEFAULT_DOCUMENT_CLASS_NAME)) { + fDocument = new DocumentImpl (); + fDocumentImpl = (CoreDocumentImpl)fDocument; + // REVISIT: when DOM Level 3 is REC rely on Document.support + // instead of specific class + // set DOM error checking off + fDocumentImpl.setStrictErrorChecking (false); + // set actual encoding + fDocumentImpl.setInputEncoding (encoding); + // set documentURI + fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); + } + else if (fDocumentClassName.equals (PSVI_DOCUMENT_CLASS_NAME)) { + fDocument = new PSVIDocumentImpl(); + fDocumentImpl = (CoreDocumentImpl)fDocument; + fStorePSVI = true; + // REVISIT: when DOM Level 3 is REC rely on Document.support + // instead of specific class + // set DOM error checking off + fDocumentImpl.setStrictErrorChecking (false); + // set actual encoding + fDocumentImpl.setInputEncoding (encoding); + // set documentURI + fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); + } + else { + // use specified document class + try { + ClassLoader cl = ObjectFactory.findClassLoader(); + Class documentClass = ObjectFactory.findProviderClass (fDocumentClassName, + cl, true); + fDocument = (Document)documentClass.newInstance (); + + // if subclass of our own class that's cool too + Class defaultDocClass = + ObjectFactory.findProviderClass (CORE_DOCUMENT_CLASS_NAME, + cl, true); + if (defaultDocClass.isAssignableFrom (documentClass)) { + fDocumentImpl = (CoreDocumentImpl)fDocument; + + Class psviDocClass = ObjectFactory.findProviderClass (PSVI_DOCUMENT_CLASS_NAME, + cl, true); + if (psviDocClass.isAssignableFrom (documentClass)) { + fStorePSVI = true; + } + + // REVISIT: when DOM Level 3 is REC rely on + // Document.support instead of specific class + // set DOM error checking off + fDocumentImpl.setStrictErrorChecking (false); + // set actual encoding + fDocumentImpl.setInputEncoding (encoding); + // set documentURI + if (locator != null) { + fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); + } + } + } + catch (ClassNotFoundException e) { + // won't happen we already checked that earlier + } + catch (Exception e) { + throw new RuntimeException ( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "CannotCreateDocumentClass", + new Object [] {fDocumentClassName})); + } + } + fCurrentNode = fDocument; + } + else { + fDeferredDocumentImpl = new DeferredDocumentImpl (fNamespaceAware); + fDocument = fDeferredDocumentImpl; + fDocumentIndex = fDeferredDocumentImpl.createDeferredDocument (); + // REVISIT: strict error checking is not implemented in deferred dom. + // Document.support instead of specific class + + // set actual encoding + fDeferredDocumentImpl.setInputEncoding (encoding); + // set documentURI + fDeferredDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); + fCurrentNodeIndex = fDocumentIndex; + + } + + } // startDocument(String,String) + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void xmlDecl (String version, String encoding, String standalone, + Augmentations augs) + throws XNIException { + if (!fDeferNodeExpansion) { + // REVISIT: when DOM Level 3 is REC rely on Document.support + // instead of specific class + if (fDocumentImpl != null) { + if (version != null) + fDocumentImpl.setXmlVersion (version); + fDocumentImpl.setXmlEncoding (encoding); + fDocumentImpl.setXmlStandalone ("yes".equals (standalone)); + } + } + else { + if (version != null) + fDeferredDocumentImpl.setXmlVersion (version); + fDeferredDocumentImpl.setXmlEncoding (encoding); + fDeferredDocumentImpl.setXmlStandalone ("yes".equals (standalone)); + } + } // xmlDecl(String,String,String) + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * otherwise. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void doctypeDecl (String rootElement, + String publicId, String systemId, Augmentations augs) + throws XNIException { + + if (!fDeferNodeExpansion) { + if (fDocumentImpl != null) { + fDocumentType = fDocumentImpl.createDocumentType ( + rootElement, publicId, systemId); + fCurrentNode.appendChild (fDocumentType); + } + } + else { + fDocumentTypeIndex = fDeferredDocumentImpl. + createDeferredDocumentType (rootElement, publicId, systemId); + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, fDocumentTypeIndex); + } + + } // doctypeDecl(String,String,String) + + /** + * The start of an element. If the document specifies the start element + * by using an empty tag, then the startElement method will immediately + * be followed by the endElement method, with no intervening methods. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startElement (QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + if (DEBUG_EVENTS) { + System.out.println ("==>startElement ("+element.rawname+")"); + } + if (!fDeferNodeExpansion) { + if (fFilterReject) { + ++fRejectedElementDepth; + return; + } + Element el = createElementNode (element); + int attrCount = attributes.getLength (); + boolean seenSchemaDefault = false; + for (int i = 0; i < attrCount; i++) { + attributes.getName (i, fAttrQName); + Attr attr = createAttrNode (fAttrQName); + + String attrValue = attributes.getValue (i); + + AttributePSVI attrPSVI =(AttributePSVI) attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_PSVI); + if (fStorePSVI && attrPSVI != null){ + ((PSVIAttrNSImpl) attr).setPSVI (attrPSVI); + } + + attr.setValue (attrValue); + boolean specified = attributes.isSpecified(i); + // Take special care of schema defaulted attributes. Calling the + // non-namespace aware setAttributeNode() method could overwrite + // another attribute with the same local name. + if (!specified && (seenSchemaDefault || (fAttrQName.uri != null && + fAttrQName.uri != NamespaceContext.XMLNS_URI && fAttrQName.prefix == null))) { + el.setAttributeNodeNS(attr); + seenSchemaDefault = true; + } + else { + el.setAttributeNode(attr); + } + // NOTE: The specified value MUST be set after you set + // the node value because that turns the "specified" + // flag to "true" which may overwrite a "false" + // value from the attribute list. -Ac + if (fDocumentImpl != null) { + AttrImpl attrImpl = (AttrImpl) attr; + Object type = null; + boolean id = false; + + // REVISIT: currently it is possible that someone turns off + // namespaces and turns on xml schema validation + // To avoid classcast exception in AttrImpl check for namespaces + // however the correct solution should probably disallow setting + // namespaces to false when schema processing is turned on. + if (attrPSVI != null && fNamespaceAware) { + // XML Schema + type = attrPSVI.getMemberTypeDefinition (); + if (type == null) { + type = attrPSVI.getTypeDefinition (); + if (type != null) { + id = ((XSSimpleType) type).isIDType (); + attrImpl.setType (type); + } + } + else { + id = ((XSSimpleType) type).isIDType (); + attrImpl.setType (type); + } + } + else { + // DTD + boolean isDeclared = Boolean.TRUE.equals (attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_DECLARED)); + // For DOM Level 3 TypeInfo, the type name must + // be null if this attribute has not been declared + // in the DTD. + if (isDeclared) { + type = attributes.getType (i); + id = "ID".equals (type); + } + attrImpl.setType (type); + } + + if (id) { + ((ElementImpl) el).setIdAttributeNode (attr, true); + } + + attrImpl.setSpecified (specified); + // REVISIT: Handle entities in attribute value. + } + } + setCharacterData (false); + + if (augs != null) { + ElementPSVI elementPSVI = (ElementPSVI)augs.getItem (Constants.ELEMENT_PSVI); + if (elementPSVI != null && fNamespaceAware) { + XSTypeDefinition type = elementPSVI.getMemberTypeDefinition (); + if (type == null) { + type = elementPSVI.getTypeDefinition (); + } + ((ElementNSImpl)el).setType (type); + } + } + + + // filter nodes + if (fDOMFilter != null && !fInEntityRef) { + if (fRoot == null) { + // fill value of the root element + fRoot = el; + } else { + short code = fDOMFilter.startElement(el); + switch (code) { + case LSParserFilter.FILTER_INTERRUPT : + { + throw Abort.INSTANCE; + } + case LSParserFilter.FILTER_REJECT : + { + fFilterReject = true; + fRejectedElementDepth = 0; + return; + } + case LSParserFilter.FILTER_SKIP : + { + // make sure that if any char data is available + // the fFirstChunk is true, so that if the next event + // is characters(), and the last node is text, we will copy + // the value already in the text node to fStringBuffer + // (not to lose it). + fFirstChunk = true; + fSkippedElemStack.push(Boolean.TRUE); + return; + } + default : + { + if (!fSkippedElemStack.isEmpty()) { + fSkippedElemStack.push(Boolean.FALSE); + } + } + } + } + } + fCurrentNode.appendChild (el); + fCurrentNode = el; + } + else { + int el = fDeferredDocumentImpl.createDeferredElement (fNamespaceAware ? + element.uri : null, element.rawname); + Object type = null; + int attrCount = attributes.getLength (); + // Need to loop in reverse order so that the attributes + // are processed in document order when the DOM is expanded. + for (int i = attrCount - 1; i >= 0; --i) { + + // set type information + AttributePSVI attrPSVI = (AttributePSVI)attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_PSVI); + boolean id = false; + + // REVISIT: currently it is possible that someone turns off + // namespaces and turns on xml schema validation + // To avoid classcast exception in AttrImpl check for namespaces + // however the correct solution should probably disallow setting + // namespaces to false when schema processing is turned on. + if (attrPSVI != null && fNamespaceAware) { + // XML Schema + type = attrPSVI.getMemberTypeDefinition (); + if (type == null) { + type = attrPSVI.getTypeDefinition (); + if (type != null){ + id = ((XSSimpleType) type).isIDType (); + } + } + else { + id = ((XSSimpleType) type).isIDType (); + } + } + else { + // DTD + boolean isDeclared = Boolean.TRUE.equals (attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_DECLARED)); + // For DOM Level 3 TypeInfo, the type name must + // be null if this attribute has not been declared + // in the DTD. + if (isDeclared) { + type = attributes.getType (i); + id = "ID".equals (type); + } + } + + // create attribute + fDeferredDocumentImpl.setDeferredAttribute ( + el, + attributes.getQName (i), + attributes.getURI (i), + attributes.getValue (i), + attributes.isSpecified (i), + id, + type); + } + + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, el); + fCurrentNodeIndex = el; + } + } // startElement(QName,XMLAttributes) + + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void emptyElement (QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + startElement (element, attributes, augs); + endElement (element, augs); + + } // emptyElement(QName,XMLAttributes) + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void characters (XMLString text, Augmentations augs) throws XNIException { + + if (DEBUG_EVENTS) { + System.out.println ("==>characters(): "+text.toString ()); + } + + if (!fDeferNodeExpansion) { + + if (fFilterReject) { + return; + } + if (fInCDATASection && fCreateCDATANodes) { + if (fCurrentCDATASection == null) { + fCurrentCDATASection = + fDocument.createCDATASection (text.toString ()); + fCurrentNode.appendChild (fCurrentCDATASection); + fCurrentNode = fCurrentCDATASection; + } + else { + fCurrentCDATASection.appendData (text.toString ()); + } + } + else if (!fInDTD) { + // if type is union (XML Schema) it is possible that we receive + // character call with empty data + if (text.length == 0) { + return; + } + + Node child = fCurrentNode.getLastChild (); + if (child != null && child.getNodeType () == Node.TEXT_NODE) { + // collect all the data into the string buffer. + if (fFirstChunk) { + if (fDocumentImpl != null) { + fStringBuffer.append (((TextImpl)child).removeData ()); + } else { + fStringBuffer.append (((Text)child).getData ()); + ((Text)child).setNodeValue (null); + } + fFirstChunk = false; + } + if (text.length > 0) { + fStringBuffer.append (text.ch, text.offset, text.length); + } + } + else { + fFirstChunk = true; + Text textNode = fDocument.createTextNode (text.toString()); + fCurrentNode.appendChild (textNode); + } + + } + } + else { + // The Text and CDATASection normalization is taken care of within + // the DOM in the deferred case. + if (fInCDATASection && fCreateCDATANodes) { + if (fCurrentCDATASectionIndex == -1) { + int cs = fDeferredDocumentImpl. + createDeferredCDATASection (text.toString ()); + + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, cs); + fCurrentCDATASectionIndex = cs; + fCurrentNodeIndex = cs; + } + else { + int txt = fDeferredDocumentImpl. + createDeferredTextNode (text.toString (), false); + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt); + } + } else if (!fInDTD) { + // if type is union (XML Schema) it is possible that we receive + // character call with empty data + if (text.length == 0) { + return; + } + + String value = text.toString (); + int txt = fDeferredDocumentImpl. + createDeferredTextNode (value, false); + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt); + + } + } + } // characters(XMLString) + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignorableWhitespace (XMLString text, Augmentations augs) throws XNIException { + + if (!fIncludeIgnorableWhitespace || fFilterReject) { + return; + } + if (!fDeferNodeExpansion) { + Node child = fCurrentNode.getLastChild (); + if (child != null && child.getNodeType () == Node.TEXT_NODE) { + Text textNode = (Text)child; + textNode.appendData (text.toString ()); + } + else { + Text textNode = fDocument.createTextNode (text.toString ()); + if (fDocumentImpl != null) { + TextImpl textNodeImpl = (TextImpl)textNode; + textNodeImpl.setIgnorableWhitespace (true); + } + fCurrentNode.appendChild (textNode); + } + } + else { + // The Text normalization is taken care of within the DOM in the + // deferred case. + int txt = fDeferredDocumentImpl. + createDeferredTextNode (text.toString (), true); + fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt); + } + + } // ignorableWhitespace(XMLString) + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endElement (QName element, Augmentations augs) throws XNIException { + if (DEBUG_EVENTS) { + System.out.println ("==>endElement ("+element.rawname+")"); + } + if (!fDeferNodeExpansion) { + + // REVISIT: Should this happen after we call the filter? + if (augs != null && fDocumentImpl != null && (fNamespaceAware || fStorePSVI)) { + ElementPSVI elementPSVI = (ElementPSVI) augs.getItem(Constants.ELEMENT_PSVI); + if (elementPSVI != null) { + // Updating TypeInfo. If the declared type is a union the + // [member type definition] will only be available at the + // end of an element. + if (fNamespaceAware) { + XSTypeDefinition type = elementPSVI.getMemberTypeDefinition(); + if (type == null) { + type = elementPSVI.getTypeDefinition(); + } + ((ElementNSImpl)fCurrentNode).setType(type); + } + if (fStorePSVI) { + ((PSVIElementNSImpl)fCurrentNode).setPSVI (elementPSVI); + } + } + } + + if (fDOMFilter != null) { + if (fFilterReject) { + if (fRejectedElementDepth-- == 0) { + fFilterReject = false; + } + return; + } + if (!fSkippedElemStack.isEmpty()) { + if (fSkippedElemStack.pop() == Boolean.TRUE) { + return; + } + } + setCharacterData (false); + if ((fCurrentNode != fRoot) && !fInEntityRef && (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_ELEMENT)!=0) { + short code = fDOMFilter.acceptNode (fCurrentNode); + switch (code) { + case LSParserFilter.FILTER_INTERRUPT:{ + throw Abort.INSTANCE; + } + case LSParserFilter.FILTER_REJECT:{ + Node parent = fCurrentNode.getParentNode (); + parent.removeChild (fCurrentNode); + fCurrentNode = parent; + return; + } + case LSParserFilter.FILTER_SKIP: { + // make sure that if any char data is available + // the fFirstChunk is true, so that if the next event + // is characters(), and the last node is text, we will copy + // the value already in the text node to fStringBuffer + // (not to lose it). + fFirstChunk = true; + + // replace children + Node parent = fCurrentNode.getParentNode (); + NodeList ls = fCurrentNode.getChildNodes (); + int length = ls.getLength (); + + for (int i=0;i + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endGeneralEntity (String name, Augmentations augs) throws XNIException { + if (DEBUG_EVENTS) { + System.out.println ("==>endGeneralEntity: ("+name+")"); + } + if (!fDeferNodeExpansion) { + + if (fFilterReject) { + return; + } + setCharacterData (true); + + if (fDocumentType != null) { + // get current entity declaration + NamedNodeMap entities = fDocumentType.getEntities (); + fCurrentEntityDecl = (EntityImpl) entities.getNamedItem (name); + if (fCurrentEntityDecl != null) { + if (fCurrentEntityDecl != null && fCurrentEntityDecl.getFirstChild () == null) { + fCurrentEntityDecl.setReadOnly (false, true); + Node child = fCurrentNode.getFirstChild (); + while (child != null) { + Node copy = child.cloneNode (true); + fCurrentEntityDecl.appendChild (copy); + child = child.getNextSibling (); + } + fCurrentEntityDecl.setReadOnly (true, true); + + //entities.setNamedItem(fCurrentEntityDecl); + } + fCurrentEntityDecl = null; + } + + } + fInEntityRef = false; + boolean removeEntityRef = false; + if (fCreateEntityRefNodes) { + if (fDocumentImpl != null) { + // Make entity ref node read only + ((NodeImpl)fCurrentNode).setReadOnly (true, true); + } + + if (fDOMFilter !=null && + (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_ENTITY_REFERENCE)!= 0) { + short code = fDOMFilter.acceptNode (fCurrentNode); + switch (code) { + case LSParserFilter.FILTER_INTERRUPT:{ + throw Abort.INSTANCE; + } + case LSParserFilter.FILTER_REJECT:{ + Node parent = fCurrentNode.getParentNode (); + parent.removeChild (fCurrentNode); + fCurrentNode = parent; + return; + + } + case LSParserFilter.FILTER_SKIP: { + // make sure we don't loose chars if next event is characters() + fFirstChunk = true; + removeEntityRef = true; + break; + } + + default: { + fCurrentNode = fCurrentNode.getParentNode (); + } + } + } else { + fCurrentNode = fCurrentNode.getParentNode (); + } + } + + if (!fCreateEntityRefNodes || removeEntityRef) { + // move entity reference children to the list of + // siblings of its parent and remove entity reference + NodeList children = fCurrentNode.getChildNodes (); + Node parent = fCurrentNode.getParentNode (); + int length = children.getLength (); + if (length > 0) { + + // get previous sibling of the entity reference + Node node = fCurrentNode.getPreviousSibling (); + // normalize text nodes + Node child = children.item (0); + if (node != null && node.getNodeType () == Node.TEXT_NODE && + child.getNodeType () == Node.TEXT_NODE) { + ((Text)node).appendData (child.getNodeValue ()); + fCurrentNode.removeChild (child); + + } else { + node = parent.insertBefore (child, fCurrentNode); + handleBaseURI (node); + } + + for (int i=1;i 0 + parent.removeChild (fCurrentNode); + fCurrentNode = parent; + } + } + else { + + if (fDocumentTypeIndex != -1) { + // find corresponding Entity decl + int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); + while (node != -1) { + short nodeType = fDeferredDocumentImpl.getNodeType (node, false); + if (nodeType == Node.ENTITY_NODE) { + String nodeName = + fDeferredDocumentImpl.getNodeName (node, false); + if (nodeName.equals (name)) { + fDeferredEntityDecl = node; + break; + } + } + node = fDeferredDocumentImpl.getRealPrevSibling (node, false); + } + } + + if (fDeferredEntityDecl != -1 && + fDeferredDocumentImpl.getLastChild (fDeferredEntityDecl, false) == -1) { + // entity definition exists and it does not have any children + int prevIndex = -1; + int childIndex = fDeferredDocumentImpl.getLastChild (fCurrentNodeIndex, false); + while (childIndex != -1) { + int cloneIndex = fDeferredDocumentImpl.cloneNode (childIndex, true); + fDeferredDocumentImpl.insertBefore (fDeferredEntityDecl, cloneIndex, prevIndex); + prevIndex = cloneIndex; + childIndex = fDeferredDocumentImpl.getRealPrevSibling (childIndex, false); + } + } + if (fCreateEntityRefNodes) { + fCurrentNodeIndex = + fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex, + false); + } else { //!fCreateEntityRefNodes + // move children of entity ref before the entity ref. + // remove entity ref. + + // holds a child of entity ref + int childIndex = fDeferredDocumentImpl.getLastChild (fCurrentNodeIndex, false); + int parentIndex = + fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex, + false); + + int prevIndex = fCurrentNodeIndex; + int lastChild = childIndex; + int sibling = -1; + while (childIndex != -1) { + handleBaseURI (childIndex); + sibling = fDeferredDocumentImpl.getRealPrevSibling (childIndex, false); + fDeferredDocumentImpl.insertBefore (parentIndex, childIndex, prevIndex); + prevIndex = childIndex; + childIndex = sibling; + } + if(lastChild != -1) + fDeferredDocumentImpl.setAsLastChild (parentIndex, lastChild); + else{ + sibling = fDeferredDocumentImpl.getRealPrevSibling (prevIndex, false); + fDeferredDocumentImpl.setAsLastChild (parentIndex, sibling); + } + fCurrentNodeIndex = parentIndex; + } + fDeferredEntityDecl = -1; + } + + + } // endGeneralEntity(String, Augmentations) + + + /** + * Record baseURI information for the Element (by adding xml:base attribute) + * or for the ProcessingInstruction (by setting a baseURI field) + * Non deferred DOM. + * + * @param node + */ + protected final void handleBaseURI (Node node){ + if (fDocumentImpl != null) { + // REVISIT: remove dependency on our implementation when + // DOM L3 becomes REC + + String baseURI = null; + short nodeType = node.getNodeType (); + + if (nodeType == Node.ELEMENT_NODE) { + // if an element already has xml:base attribute + // do nothing + if (fNamespaceAware) { + if (((Element)node).getAttributeNodeNS ("http://www.w3.org/XML/1998/namespace","base")!=null) { + return; + } + } else if (((Element)node).getAttributeNode ("xml:base") != null) { + return; + } + // retrive the baseURI from the entity reference + baseURI = ((EntityReferenceImpl)fCurrentNode).getBaseURI (); + if (baseURI !=null && !baseURI.equals (fDocumentImpl.getDocumentURI ())) { + if (fNamespaceAware) { + ((Element)node).setAttributeNS ("http://www.w3.org/XML/1998/namespace", "xml:base", baseURI); + } else { + ((Element)node).setAttribute ("xml:base", baseURI); + } + } + } + else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) { + + baseURI = ((EntityReferenceImpl)fCurrentNode).getBaseURI (); + if (baseURI !=null && fErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl (); + error.fType = "pi-base-uri-not-preserved"; + error.fRelatedData = baseURI; + error.fSeverity = DOMError.SEVERITY_WARNING; + fErrorHandler.getErrorHandler ().handleError (error); + } + } + } + } + + /** + * + * Record baseURI information for the Element (by adding xml:base attribute) + * or for the ProcessingInstruction (by setting a baseURI field) + * Deferred DOM. + * + * @param node + */ + protected final void handleBaseURI (int node){ + short nodeType = fDeferredDocumentImpl.getNodeType (node, false); + + if (nodeType == Node.ELEMENT_NODE) { + String baseURI = fDeferredDocumentImpl.getNodeValueString (fCurrentNodeIndex, false); + if (baseURI == null) { + baseURI = fDeferredDocumentImpl.getDeferredEntityBaseURI (fDeferredEntityDecl); + } + if (baseURI !=null && !baseURI.equals (fDeferredDocumentImpl.getDocumentURI ())) { + fDeferredDocumentImpl.setDeferredAttribute (node, + "xml:base", + "http://www.w3.org/XML/1998/namespace", + baseURI, + true); + } + } + else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) { + + + // retrieve baseURI from the entity reference + String baseURI = fDeferredDocumentImpl.getNodeValueString (fCurrentNodeIndex, false); + + if (baseURI == null) { + // try baseURI of the entity declaration + baseURI = fDeferredDocumentImpl.getDeferredEntityBaseURI (fDeferredEntityDecl); + } + + if (baseURI != null && fErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl (); + error.fType = "pi-base-uri-not-preserved"; + error.fRelatedData = baseURI; + error.fSeverity = DOMError.SEVERITY_WARNING; + fErrorHandler.getErrorHandler ().handleError (error); + } + } + } + + + // + // XMLDTDHandler methods + // + + /** + * The start of the DTD. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing of + * the document DTD. However, it is strongly + * recommended that a locator be supplied that can + * at least report the base system identifier of the + * DTD. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDTD (XMLLocator locator, Augmentations augs) throws XNIException { + if (DEBUG_EVENTS) { + System.out.println ("==>startDTD"); + if (DEBUG_BASEURI) { + System.out.println (" expandedSystemId: "+locator.getExpandedSystemId ()); + System.out.println (" baseURI:"+ locator.getBaseSystemId ()); + } + } + + fInDTD = true; + if (locator != null) { + fBaseURIStack.push (locator.getBaseSystemId ()); + } + if (fDeferNodeExpansion || fDocumentImpl != null) { + fInternalSubset = new StringBuffer (1024); + } + } // startDTD(XMLLocator) + + + /** + * The end of the DTD. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDTD (Augmentations augs) throws XNIException { + if (DEBUG_EVENTS) { + System.out.println ("==>endDTD()"); + } + fInDTD = false; + if (!fBaseURIStack.isEmpty ()) { + fBaseURIStack.pop (); + } + String internalSubset = fInternalSubset != null && fInternalSubset.length () > 0 + ? fInternalSubset.toString () : null; + if (fDeferNodeExpansion) { + if (internalSubset != null) { + fDeferredDocumentImpl.setInternalSubset (fDocumentTypeIndex, internalSubset); + } + } + else if (fDocumentImpl != null) { + if (internalSubset != null) { + ((DocumentTypeImpl)fDocumentType).setInternalSubset (internalSubset); + } + } + } // endDTD() + + /** + * The start of a conditional section. + * + * @param type The type of the conditional section. This value will + * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #CONDITIONAL_INCLUDE + * @see #CONDITIONAL_IGNORE + */ + public void startConditional (short type, Augmentations augs) throws XNIException { + } // startConditional(short) + + /** + * The end of a conditional section. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endConditional (Augmentations augs) throws XNIException { + } // endConditional() + + + /** + * The start of the DTD external subset. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startExternalSubset (XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + if (DEBUG_EVENTS) { + System.out.println ("==>startExternalSubset"); + if (DEBUG_BASEURI) { + System.out.println (" expandedSystemId: "+identifier.getExpandedSystemId ()); + System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); + } + } + fBaseURIStack.push (identifier.getBaseSystemId ()); + fInDTDExternalSubset = true; + } // startExternalSubset(Augmentations) + + /** + * The end of the DTD external subset. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endExternalSubset (Augmentations augs) throws XNIException { + fInDTDExternalSubset = false; + fBaseURIStack.pop (); + } // endExternalSubset(Augmentations) + + /** + * An internal entity declaration. + * + * @param name The name of the entity. Parameter entity names start with + * '%', whereas the name of a general entity is just the + * entity name. + * @param text The value of the entity. + * @param nonNormalizedText The non-normalized value of the entity. This + * value contains the same sequence of characters that was in + * the internal entity declaration, without any entity + * references expanded. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void internalEntityDecl (String name, XMLString text, + XMLString nonNormalizedText, + Augmentations augs) throws XNIException { + + if (DEBUG_EVENTS) { + System.out.println ("==>internalEntityDecl: "+name); + if (DEBUG_BASEURI) { + System.out.println (" baseURI:"+ (String)fBaseURIStack.peek ()); + } + } + // internal subset string + if (fInternalSubset != null && !fInDTDExternalSubset) { + fInternalSubset.append ("\n"); + } + + // NOTE: We only know how to create these nodes for the Xerces + // DOM implementation because DOM Level 2 does not specify + // that functionality. -Ac + + // create full node + // don't add parameter entities! + if(name.startsWith ("%")) + return; + if (fDocumentType != null) { + NamedNodeMap entities = fDocumentType.getEntities (); + EntityImpl entity = (EntityImpl)entities.getNamedItem (name); + if (entity == null) { + entity = (EntityImpl)fDocumentImpl.createEntity (name); + entity.setBaseURI ((String)fBaseURIStack.peek ()); + entities.setNamedItem (entity); + } + } + + // create deferred node + if (fDocumentTypeIndex != -1) { + boolean found = false; + int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); + while (node != -1) { + short nodeType = fDeferredDocumentImpl.getNodeType (node, false); + if (nodeType == Node.ENTITY_NODE) { + String nodeName = fDeferredDocumentImpl.getNodeName (node, false); + if (nodeName.equals (name)) { + found = true; + break; + } + } + node = fDeferredDocumentImpl.getRealPrevSibling (node, false); + } + if (!found) { + int entityIndex = + fDeferredDocumentImpl.createDeferredEntity (name, null, null, null, (String)fBaseURIStack.peek ()); + fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex); + } + } + + } // internalEntityDecl(String,XMLString,XMLString) + + /** + * An external entity declaration. + * + * @param name The name of the entity. Parameter entity names start + * with '%', whereas the name of a general entity is just + * the entity name. + * @param identifier An object containing all location information + * pertinent to this notation. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void externalEntityDecl (String name, XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + + + if (DEBUG_EVENTS) { + System.out.println ("==>externalEntityDecl: "+name); + if (DEBUG_BASEURI) { + System.out.println (" expandedSystemId:"+ identifier.getExpandedSystemId ()); + System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); + } + } + // internal subset string + String publicId = identifier.getPublicId (); + String literalSystemId = identifier.getLiteralSystemId (); + if (fInternalSubset != null && !fInDTDExternalSubset) { + fInternalSubset.append ("\n"); + } + + // NOTE: We only know how to create these nodes for the Xerces + // DOM implementation because DOM Level 2 does not specify + // that functionality. -Ac + + // create full node + // don't add parameter entities! + if(name.startsWith ("%")) + return; + if (fDocumentType != null) { + NamedNodeMap entities = fDocumentType.getEntities (); + EntityImpl entity = (EntityImpl)entities.getNamedItem (name); + if (entity == null) { + entity = (EntityImpl)fDocumentImpl.createEntity (name); + entity.setPublicId (publicId); + entity.setSystemId (literalSystemId); + entity.setBaseURI (identifier.getBaseSystemId ()); + entities.setNamedItem (entity); + } + } + + // create deferred node + if (fDocumentTypeIndex != -1) { + boolean found = false; + int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); + while (nodeIndex != -1) { + short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false); + if (nodeType == Node.ENTITY_NODE) { + String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false); + if (nodeName.equals (name)) { + found = true; + break; + } + } + nodeIndex = fDeferredDocumentImpl.getRealPrevSibling (nodeIndex, false); + } + if (!found) { + int entityIndex = fDeferredDocumentImpl.createDeferredEntity ( + name, publicId, literalSystemId, null, identifier.getBaseSystemId ()); + fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex); + } + } + + } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations) + + + /** + * This method notifies of the start of a parameter entity. The parameter + * entity name start with a '%' character. + * + * @param name The name of the parameter entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal parameter entities). + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startParameterEntity (String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException { + if (DEBUG_EVENTS) { + System.out.println ("==>startParameterEntity: "+name); + if (DEBUG_BASEURI) { + System.out.println (" expandedSystemId: "+identifier.getExpandedSystemId ()); + System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); + } + } + if (augs != null && fInternalSubset != null && + !fInDTDExternalSubset && + Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) { + fInternalSubset.append(name).append(";\n"); + } + fBaseURIStack.push (identifier.getExpandedSystemId ()); + } + + + /** + * This method notifies the end of a parameter entity. Parameter entity + * names begin with a '%' character. + * + * @param name The name of the parameter entity. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endParameterEntity (String name, Augmentations augs) throws XNIException { + + if (DEBUG_EVENTS) { + System.out.println ("==>endParameterEntity: "+name); + } + fBaseURIStack.pop (); + } + + /** + * An unparsed entity declaration. + * + * @param name The name of the entity. + * @param identifier An object containing all location information + * pertinent to this entity. + * @param notation The name of the notation. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void unparsedEntityDecl (String name, XMLResourceIdentifier identifier, + String notation, Augmentations augs) + throws XNIException { + + if (DEBUG_EVENTS) { + System.out.println ("==>unparsedEntityDecl: "+name); + if (DEBUG_BASEURI) { + System.out.println (" expandedSystemId:"+ identifier.getExpandedSystemId ()); + System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); + } + } + // internal subset string + String publicId = identifier.getPublicId (); + String literalSystemId = identifier.getLiteralSystemId (); + if (fInternalSubset != null && !fInDTDExternalSubset) { + fInternalSubset.append ("\n"); + } + + // NOTE: We only know how to create these nodes for the Xerces + // DOM implementation because DOM Level 2 does not specify + // that functionality. -Ac + + // create full node + if (fDocumentType != null) { + NamedNodeMap entities = fDocumentType.getEntities (); + EntityImpl entity = (EntityImpl)entities.getNamedItem (name); + if (entity == null) { + entity = (EntityImpl)fDocumentImpl.createEntity (name); + entity.setPublicId (publicId); + entity.setSystemId (literalSystemId); + entity.setNotationName (notation); + entity.setBaseURI (identifier.getBaseSystemId ()); + entities.setNamedItem (entity); + } + } + + // create deferred node + if (fDocumentTypeIndex != -1) { + boolean found = false; + int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); + while (nodeIndex != -1) { + short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false); + if (nodeType == Node.ENTITY_NODE) { + String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false); + if (nodeName.equals (name)) { + found = true; + break; + } + } + nodeIndex = fDeferredDocumentImpl.getRealPrevSibling (nodeIndex, false); + } + if (!found) { + int entityIndex = fDeferredDocumentImpl.createDeferredEntity ( + name, publicId, literalSystemId, notation, identifier.getBaseSystemId ()); + fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex); + } + } + + } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations) + + /** + * A notation declaration + * + * @param name The name of the notation. + * @param identifier An object containing all location information + * pertinent to this notation. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void notationDecl (String name, XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + + // internal subset string + String publicId = identifier.getPublicId (); + String literalSystemId = identifier.getLiteralSystemId (); + if (fInternalSubset != null && !fInDTDExternalSubset) { + fInternalSubset.append ("\n"); + } + + // NOTE: We only know how to create these nodes for the Xerces + // DOM implementation because DOM Level 2 does not specify + // that functionality. -Ac + + // create full node + if (fDocumentImpl !=null && fDocumentType != null) { + NamedNodeMap notations = fDocumentType.getNotations (); + if (notations.getNamedItem (name) == null) { + NotationImpl notation = (NotationImpl)fDocumentImpl.createNotation (name); + notation.setPublicId (publicId); + notation.setSystemId (literalSystemId); + notation.setBaseURI (identifier.getBaseSystemId ()); + notations.setNamedItem (notation); + } + } + + // create deferred node + if (fDocumentTypeIndex != -1) { + boolean found = false; + int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); + while (nodeIndex != -1) { + short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false); + if (nodeType == Node.NOTATION_NODE) { + String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false); + if (nodeName.equals (name)) { + found = true; + break; + } + } + nodeIndex = fDeferredDocumentImpl.getPrevSibling (nodeIndex, false); + } + if (!found) { + int notationIndex = fDeferredDocumentImpl.createDeferredNotation ( + name, publicId, literalSystemId, identifier.getBaseSystemId ()); + fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, notationIndex); + } + } + + } // notationDecl(String,XMLResourceIdentifier, Augmentations) + + /** + * Characters within an IGNORE conditional section. + * + * @param text The ignored text. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignoredCharacters (XMLString text, Augmentations augs) throws XNIException { + } // ignoredCharacters(XMLString, Augmentations) + + + /** + * An element declaration. + * + * @param name The name of the element. + * @param contentModel The element content model. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void elementDecl (String name, String contentModel, Augmentations augs) + throws XNIException { + + // internal subset string + if (fInternalSubset != null && !fInDTDExternalSubset) { + fInternalSubset.append ("\n"); + } + + } // elementDecl(String,String) + + /** + * An attribute declaration. + * + * @param elementName The name of the element that this attribute + * is associated with. + * @param attributeName The name of the attribute. + * @param type The attribute type. This value will be one of + * the following: "CDATA", "ENTITY", "ENTITIES", + * "ENUMERATION", "ID", "IDREF", "IDREFS", + * "NMTOKEN", "NMTOKENS", or "NOTATION". + * @param enumeration If the type has the value "ENUMERATION" or + * "NOTATION", this array holds the allowed attribute + * values; otherwise, this array is null. + * @param defaultType The attribute default type. This value will be + * one of the following: "#FIXED", "#IMPLIED", + * "#REQUIRED", or null. + * @param defaultValue The attribute default value, or null if no + * default value is specified. + * @param nonNormalizedDefaultValue The attribute default value with no normalization + * performed, or null if no default value is specified. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void attributeDecl (String elementName, String attributeName, + String type, String[] enumeration, + String defaultType, XMLString defaultValue, + XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException { + + // internal subset string + if (fInternalSubset != null && !fInDTDExternalSubset) { + fInternalSubset.append (" 0) { + fInternalSubset.append ('|'); + } + fInternalSubset.append (enumeration[i]); + } + fInternalSubset.append (')'); + } + else { + fInternalSubset.append (type); + } + if (defaultType != null) { + fInternalSubset.append (' '); + fInternalSubset.append (defaultType); + } + if (defaultValue != null) { + fInternalSubset.append (" '"); + for (int i = 0; i < defaultValue.length; i++) { + char c = defaultValue.ch[defaultValue.offset + i]; + if (c == '\'') { + fInternalSubset.append ("'"); + } + else { + fInternalSubset.append (c); + } + } + fInternalSubset.append ('\''); + } + fInternalSubset.append (">\n"); + } + // REVISIT: This code applies to the support of domx/grammar-access + // feature in Xerces 1 + + // deferred expansion + if (fDeferredDocumentImpl != null) { + + // get the default value + if (defaultValue != null) { + + // get element definition + int elementDefIndex = fDeferredDocumentImpl.lookupElementDefinition (elementName); + + // create element definition if not already there + if (elementDefIndex == -1) { + elementDefIndex = fDeferredDocumentImpl.createDeferredElementDefinition (elementName); + fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, elementDefIndex); + } + // add default attribute + boolean nsEnabled = fNamespaceAware; + String namespaceURI = null; + if (nsEnabled) { + // DOM Level 2 wants all namespace declaration attributes + // to be bound to "http://www.w3.org/2000/xmlns/" + // So as long as the XML parser doesn't do it, it needs to + // done here. + if (attributeName.startsWith("xmlns:") || + attributeName.equals("xmlns")) { + namespaceURI = NamespaceContext.XMLNS_URI; + } + else if (attributeName.startsWith("xml:")) { + namespaceURI = NamespaceContext.XML_URI; + } + } + int attrIndex = fDeferredDocumentImpl.createDeferredAttribute ( + attributeName, namespaceURI, defaultValue.toString(), false); + if ("ID".equals (type)) { + fDeferredDocumentImpl.setIdAttribute (attrIndex); + } + // REVISIT: set ID type correctly + fDeferredDocumentImpl.appendChild (elementDefIndex, attrIndex); + } + + } // if deferred + + // full expansion + else if (fDocumentImpl != null) { + + // get the default value + if (defaultValue != null) { + + // get element definition node + NamedNodeMap elements = ((DocumentTypeImpl)fDocumentType).getElements (); + ElementDefinitionImpl elementDef = (ElementDefinitionImpl)elements.getNamedItem (elementName); + if (elementDef == null) { + elementDef = fDocumentImpl.createElementDefinition (elementName); + ((DocumentTypeImpl)fDocumentType).getElements ().setNamedItem (elementDef); + } + + // REVISIT: Check for uniqueness of element name? -Ac + + // create attribute and set properties + boolean nsEnabled = fNamespaceAware; + AttrImpl attr; + if (nsEnabled) { + String namespaceURI = null; + // DOM Level 2 wants all namespace declaration attributes + // to be bound to "http://www.w3.org/2000/xmlns/" + // So as long as the XML parser doesn't do it, it needs to + // done here. + if (attributeName.startsWith("xmlns:") || + attributeName.equals("xmlns")) { + namespaceURI = NamespaceContext.XMLNS_URI; + } + else if (attributeName.startsWith("xml:")) { + namespaceURI = NamespaceContext.XML_URI; + } + attr = (AttrImpl)fDocumentImpl.createAttributeNS (namespaceURI, + attributeName); + } + else { + attr = (AttrImpl)fDocumentImpl.createAttribute (attributeName); + } + attr.setValue (defaultValue.toString ()); + attr.setSpecified (false); + attr.setIdAttribute ("ID".equals (type)); + + // add default attribute to element definition + if (nsEnabled){ + elementDef.getAttributes ().setNamedItemNS (attr); + } + else { + elementDef.getAttributes ().setNamedItem (attr); + } + } + + } // if NOT defer-node-expansion + + } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations) + + + /** + * The start of an attribute list. + * + * @param elementName The name of the element that this attribute + * list is associated with. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startAttlist (String elementName, Augmentations augs) throws XNIException { + } // startAttlist(String) + + + /** + * The end of an attribute list. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endAttlist (Augmentations augs) throws XNIException { + } // endAttlist() + + + // method to create an element node. + // subclasses can override this method to create element nodes in other ways. + protected Element createElementNode (QName element) { + Element el = null; + + if (fNamespaceAware) { + // if we are using xerces DOM implementation, call our + // own constructor to reuse the strings we have here. + if (fDocumentImpl != null) { + el = fDocumentImpl.createElementNS (element.uri, element.rawname, + element.localpart); + } + else { + el = fDocument.createElementNS (element.uri, element.rawname); + } + } + else { + el = fDocument.createElement (element.rawname); + } + + return el; + } + + // method to create an attribute node. + // subclasses can override this method to create attribute nodes in other ways. + protected Attr createAttrNode (QName attrQName) { + Attr attr = null; + + if (fNamespaceAware) { + if (fDocumentImpl != null) { + // if we are using xerces DOM implementation, call our + // own constructor to reuse the strings we have here. + attr = fDocumentImpl.createAttributeNS (attrQName.uri, + attrQName.rawname, + attrQName.localpart); + } + else { + attr = fDocument.createAttributeNS (attrQName.uri, + attrQName.rawname); + } + } + else { + attr = fDocument.createAttribute (attrQName.rawname); + } + + return attr; + } + + /* + * When the first characters() call is received, the data is stored in + * a new Text node. If right after the first characters() we receive another chunk of data, + * the data from the Text node, following the new characters are appended + * to the fStringBuffer and the text node data is set to empty. + * + * This function is called when the state is changed and the + * data must be appended to the current node. + * + * Note: if DOMFilter is set, you must make sure that if Node is skipped, + * or removed fFistChunk must be set to true, otherwise some data can be lost. + * + */ + protected void setCharacterData (boolean sawChars){ + + // handle character data + fFirstChunk = sawChars; + + + // if we have data in the buffer we must have created + // a text node already. + + Node child = fCurrentNode.getLastChild (); + if (child != null) { + if (fStringBuffer.length () > 0) { + // REVISIT: should this check be performed? + if (child.getNodeType () == Node.TEXT_NODE) { + if (fDocumentImpl != null) { + ((TextImpl)child).replaceData (fStringBuffer.toString ()); + } + else { + ((Text)child).setData (fStringBuffer.toString ()); + } + } + // reset string buffer + fStringBuffer.setLength (0); + } + + if (fDOMFilter !=null && !fInEntityRef) { + if ( (child.getNodeType () == Node.TEXT_NODE ) && + ((fDOMFilter.getWhatToShow () & NodeFilter.SHOW_TEXT)!= 0) ) { + short code = fDOMFilter.acceptNode (child); + switch (code) { + case LSParserFilter.FILTER_INTERRUPT:{ + throw Abort.INSTANCE; + } + case LSParserFilter.FILTER_REJECT:{ + // fall through to SKIP since Comment has no children. + } + case LSParserFilter.FILTER_SKIP: { + fCurrentNode.removeChild (child); + return; + } + default: { + // accept node -- do nothing + } + } + } + } // end-if fDOMFilter !=null + + } // end-if child !=null + } + + + /** + * @see org.w3c.dom.ls.LSParser#abort() + */ + public void abort () { + throw Abort.INSTANCE; + } + + +} // class AbstractDOMParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractSAXParser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractSAXParser.java new file mode 100644 index 0000000..75d38cf --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractSAXParser.java @@ -0,0 +1,2401 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.CharConversionException; +import java.io.IOException; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.EntityResolver2Wrapper; +import org.apache.xerces.util.EntityResolverWrapper; +import org.apache.xerces.util.ErrorHandlerWrapper; +import org.apache.xerces.util.SAXMessageFormatter; +import org.apache.xerces.util.SymbolHash; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParseException; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.ElementPSVI; +import org.apache.xerces.xs.PSVIProvider; +import org.xml.sax.AttributeList; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.DocumentHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Parser; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.Attributes2; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.EntityResolver2; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.ext.Locator2; +import org.xml.sax.ext.Locator2Impl; + +/** + * This is the base class of all SAX parsers. It implements both the + * SAX1 and SAX2 parser functionality, while the actual pipeline is + * defined in the parser configuration. + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public abstract class AbstractSAXParser + extends AbstractXMLDocumentParser + implements PSVIProvider, // PSVI + Parser, XMLReader // SAX1, SAX2 +{ + + // + // Constants + // + + // features + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature id: string interning. */ + protected static final String STRING_INTERNING = + Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE; + + /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */ + // this is not meant to be a recognized feature, but we need it here to use + // if it is already a recognized feature for the pipeline + protected static final String ALLOW_UE_AND_NOTATION_EVENTS = + Constants.SAX_FEATURE_PREFIX + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE; + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + NAMESPACES, + STRING_INTERNING, + }; + + // properties + + /** Property id: lexical handler. */ + protected static final String LEXICAL_HANDLER = + Constants.SAX_PROPERTY_PREFIX + Constants.LEXICAL_HANDLER_PROPERTY; + + /** Property id: declaration handler. */ + protected static final String DECLARATION_HANDLER = + Constants.SAX_PROPERTY_PREFIX + Constants.DECLARATION_HANDLER_PROPERTY; + + /** Property id: DOM node. */ + protected static final String DOM_NODE = + Constants.SAX_PROPERTY_PREFIX + Constants.DOM_NODE_PROPERTY; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + LEXICAL_HANDLER, + DECLARATION_HANDLER, + DOM_NODE, + }; + + // + // Data + // + + // features + + /** Namespaces. */ + protected boolean fNamespaces; + + /** Namespace prefixes. */ + protected boolean fNamespacePrefixes = false; + + /** Lexical handler parameter entities. */ + protected boolean fLexicalHandlerParameterEntities = true; + + /** Standalone document declaration. */ + protected boolean fStandalone; + + /** Resolve DTD URIs. */ + protected boolean fResolveDTDURIs = true; + + /** Use EntityResolver2. */ + protected boolean fUseEntityResolver2 = true; + + /** + * XMLNS URIs: Namespace declarations in the + * http://www.w3.org/2000/xmlns/ namespace. + */ + protected boolean fXMLNSURIs = false; + + // parser handlers + + /** Content handler. */ + protected ContentHandler fContentHandler; + + /** Document handler. */ + protected DocumentHandler fDocumentHandler; + + /** Namespace context */ + protected NamespaceContext fNamespaceContext; + + /** DTD handler. */ + protected org.xml.sax.DTDHandler fDTDHandler; + + /** Decl handler. */ + protected DeclHandler fDeclHandler; + + /** Lexical handler. */ + protected LexicalHandler fLexicalHandler; + + protected final QName fQName = new QName(); + + // state + + /** + * True if a parse is in progress. This state is needed because + * some features/properties cannot be set while parsing (e.g. + * validation and namespaces). + */ + protected boolean fParseInProgress = false; + + // track the version of the document being parsed + protected String fVersion; + + // temp vars + private final AttributesProxy fAttributesProxy = new AttributesProxy(); + private Augmentations fAugmentations = null; + + // allows us to keep track of whether an attribute has + // been declared twice, so that we can avoid exposing the + // second declaration to any registered DeclHandler + protected SymbolHash fDeclaredAttrs = null; + + // + // Constructors + // + + /** Default constructor. */ + protected AbstractSAXParser(XMLParserConfiguration config) { + super(config); + + config.addRecognizedFeatures(RECOGNIZED_FEATURES); + config.addRecognizedProperties(RECOGNIZED_PROPERTIES); + + try { + config.setFeature(ALLOW_UE_AND_NOTATION_EVENTS, false); + } + catch (XMLConfigurationException e) { + // it wasn't a recognized feature, so we don't worry about it + } + } // (XMLParserConfiguration) + + // + // XMLDocumentHandler methods + // + + /** + * The start of the document. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing + * of this document. However, it is strongly + * recommended that a locator be supplied that can + * at least report the system identifier of the + * document. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param namespaceContext + * The namespace context in effect at the + * start of this document. + * This object represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException { + + fNamespaceContext = namespaceContext; + + try { + // SAX1 + if (fDocumentHandler != null) { + if (locator != null) { + fDocumentHandler.setDocumentLocator(new LocatorProxy(locator)); + } + // The application may have set the DocumentHandler to null + // within setDocumentLocator() so we need to check again. + if (fDocumentHandler != null) { + fDocumentHandler.startDocument(); + } + } + + // SAX2 + if (fContentHandler != null) { + if (locator != null) { + fContentHandler.setDocumentLocator(new LocatorProxy(locator)); + } + // The application may have set the ContentHandler to null + // within setDocumentLocator() so we need to check again. + if (fContentHandler != null) { + fContentHandler.startDocument(); + } + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // startDocument(locator,encoding,augs) + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) + throws XNIException { + // the version need only be set once; if + // document's XML 1.0|1.1, that's how it'll stay + fVersion = version; + fStandalone = "yes".equals(standalone); + } // xmlDecl(String,String,String) + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * otherwise. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void doctypeDecl(String rootElement, + String publicId, String systemId, Augmentations augs) + throws XNIException { + fInDTD = true; + + try { + // SAX2 extension + if (fLexicalHandler != null) { + fLexicalHandler.startDTD(rootElement, publicId, systemId); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + // is there a DeclHandler? + if (fDeclHandler != null) { + fDeclaredAttrs = new SymbolHash(25); + } + + } // doctypeDecl(String,String,String) + + /** + * This method notifies of the start of an entity. The DTD has the + * pseudo-name of "[dtd]" parameter entity names start with '%'; and + * general entity names are just the entity name. + *

        + * Note: Since the document is an entity, the handler + * will be notified of the start of the document entity by calling the + * startEntity method with the entity name "[xml]" before calling + * the startDocument method. When exposing entity boundaries through the + * SAX API, the document entity is never reported, however. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal parameter entities). + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity(String name, XMLResourceIdentifier identifier, + String encoding, Augmentations augs) + throws XNIException { + + try { + // Only report startEntity if this entity was actually read. + if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) { + // report skipped entity to content handler + if (fContentHandler != null) { + fContentHandler.skippedEntity(name); + } + } + else { + // SAX2 extension + if (fLexicalHandler != null) { + fLexicalHandler.startEntity(name); + } + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // startGeneralEntity(String,String,String,String,String) + + /** + * This method notifies the end of an entity. The DTD has the pseudo-name + * of "[dtd]" parameter entity names start with '%'; and general entity + * names are just the entity name. + *

        + * Note: Since the document is an entity, the handler + * will be notified of the end of the document entity by calling the + * endEntity method with the entity name "[xml]" after calling + * the endDocument method. When exposing entity boundaries through the + * SAX API, the document entity is never reported, however. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augs) throws XNIException { + + try { + // Only report endEntity if this entity was actually read. + if (augs == null || !Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) { + // SAX2 extension + if (fLexicalHandler != null) { + fLexicalHandler.endEntity(name); + } + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // endEntity(String) + + /** + * The start of an element. If the document specifies the start element + * by using an empty tag, then the startElement method will immediately + * be followed by the endElement method, with no intervening methods. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + try { + // SAX1 + if (fDocumentHandler != null) { + // REVISIT: should we support schema-normalized-value for SAX1 events + // + fAttributesProxy.setAttributes(attributes); + fDocumentHandler.startElement(element.rawname, fAttributesProxy); + } + + // SAX2 + if (fContentHandler != null) { + + if (fNamespaces) { + // send prefix mapping events + startNamespaceMapping(); + + // REVISIT: It should not be necessary to iterate over the attribute + // list when the set of [namespace attributes] is empty for this + // element. This should be computable from the NamespaceContext, but + // since we currently don't report the mappings for the xml prefix + // we cannot use the declared prefix count for the current context + // to skip this section. -- mrglavas + int len = attributes.getLength(); + if (!fNamespacePrefixes) { + for (int i = len - 1; i >= 0; --i) { + attributes.getName(i, fQName); + if ((fQName.prefix == XMLSymbols.PREFIX_XMLNS) || + (fQName.rawname == XMLSymbols.PREFIX_XMLNS)) { + // remove namespace declaration attributes + attributes.removeAttributeAt(i); + } + } + } + else if (!fXMLNSURIs) { + for (int i = len - 1; i >= 0; --i) { + attributes.getName(i, fQName); + if ((fQName.prefix == XMLSymbols.PREFIX_XMLNS) || + (fQName.rawname == XMLSymbols.PREFIX_XMLNS)) { + // localpart should be empty string as per SAX documentation: + // http://www.saxproject.org/?selected=namespaces + fQName.prefix = ""; + fQName.uri = ""; + fQName.localpart = ""; + attributes.setName(i, fQName); + } + } + } + } + + fAugmentations = augs; + + String uri = element.uri != null ? element.uri : ""; + String localpart = fNamespaces ? element.localpart : ""; + fAttributesProxy.setAttributes(attributes); + fContentHandler.startElement(uri, localpart, element.rawname, + fAttributesProxy); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // startElement(QName,XMLAttributes) + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException { + + // if type is union (XML Schema) it is possible that we receive + // character call with empty data + if (text.length == 0) { + return; + } + + + try { + // SAX1 + if (fDocumentHandler != null) { + // REVISIT: should we support schema-normalized-value for SAX1 events + // + fDocumentHandler.characters(text.ch, text.offset, text.length); + } + + // SAX2 + if (fContentHandler != null) { + fContentHandler.characters(text.ch, text.offset, text.length); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // characters(XMLString) + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + + try { + // SAX1 + if (fDocumentHandler != null) { + fDocumentHandler.ignorableWhitespace(text.ch, text.offset, text.length); + } + + // SAX2 + if (fContentHandler != null) { + fContentHandler.ignorableWhitespace(text.ch, text.offset, text.length); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // ignorableWhitespace(XMLString) + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException { + + + try { + // SAX1 + if (fDocumentHandler != null) { + fDocumentHandler.endElement(element.rawname); + } + + // SAX2 + if (fContentHandler != null) { + fAugmentations = augs; + String uri = element.uri != null ? element.uri : ""; + String localpart = fNamespaces ? element.localpart : ""; + fContentHandler.endElement(uri, localpart, + element.rawname); + if (fNamespaces) { + endNamespaceMapping(); + } + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // endElement(QName) + + /** + * The start of a CDATA section. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException { + + try { + // SAX2 extension + if (fLexicalHandler != null) { + fLexicalHandler.startCDATA(); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // startCDATA() + + /** + * The end of a CDATA section. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException { + + try { + // SAX2 extension + if (fLexicalHandler != null) { + fLexicalHandler.endCDATA(); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // endCDATA() + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException { + + try { + // SAX2 extension + if (fLexicalHandler != null) { + fLexicalHandler.comment(text.ch, 0, text.length); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // comment(XMLString) + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException { + + // + // REVISIT - I keep running into SAX apps that expect + // null data to be an empty string, which is contrary + // to the comment for this method in the SAX API. + // + + try { + // SAX1 + if (fDocumentHandler != null) { + fDocumentHandler.processingInstruction(target, + data.toString()); + } + + // SAX2 + if (fContentHandler != null) { + fContentHandler.processingInstruction(target, data.toString()); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // processingInstruction(String,XMLString) + + + /** + * The end of the document. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDocument(Augmentations augs) throws XNIException { + + try { + // SAX1 + if (fDocumentHandler != null) { + fDocumentHandler.endDocument(); + } + + // SAX2 + if (fContentHandler != null) { + fContentHandler.endDocument(); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // endDocument() + + // + // XMLDTDHandler methods + // + + /** + * The start of the DTD external subset. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startExternalSubset(XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + startParameterEntity("[dtd]", null, null, augs); + } + + /** + * The end of the DTD external subset. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endExternalSubset(Augmentations augs) throws XNIException { + endParameterEntity("[dtd]", augs); + } + + /** + * This method notifies of the start of parameter entity. The DTD has the + * pseudo-name of "[dtd]" parameter entity names start with '%'; and + * general entity names are just the entity name. + *

        + * Note: Since the document is an entity, the handler + * will be notified of the start of the document entity by calling the + * startEntity method with the entity name "[xml]" before calling + * the startDocument method. When exposing entity boundaries through the + * SAX API, the document entity is never reported, however. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the parameter entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal parameter entities). + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startParameterEntity(String name, + XMLResourceIdentifier identifier, + String encoding, Augmentations augs) + throws XNIException { + + try { + // Only report startEntity if this entity was actually read. + if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) { + // report skipped entity to content handler + if (fContentHandler != null) { + fContentHandler.skippedEntity(name); + } + } + else { + // SAX2 extension + if (fLexicalHandler != null && fLexicalHandlerParameterEntities) { + fLexicalHandler.startEntity(name); + } + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // startParameterEntity(String,identifier,String,Augmentation) + + /** + * This method notifies the end of an entity. The DTD has the pseudo-name + * of "[dtd]" parameter entity names start with '%'; and general entity + * names are just the entity name. + *

        + * Note: Since the document is an entity, the handler + * will be notified of the end of the document entity by calling the + * endEntity method with the entity name "[xml]" after calling + * the endDocument method. When exposing entity boundaries through the + * SAX API, the document entity is never reported, however. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the parameter entity. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endParameterEntity(String name, Augmentations augs) throws XNIException { + + try { + // Only report endEntity if this entity was actually read. + if (augs == null || !Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) { + // SAX2 extension + if (fLexicalHandler != null && fLexicalHandlerParameterEntities) { + fLexicalHandler.endEntity(name); + } + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // endEntity(String) + + /** + * An element declaration. + * + * @param name The name of the element. + * @param contentModel The element content model. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void elementDecl(String name, String contentModel, Augmentations augs) + throws XNIException { + + try { + // SAX2 extension + if (fDeclHandler != null) { + fDeclHandler.elementDecl(name, contentModel); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // elementDecl(String,String, Augmentations) + + /** + * An attribute declaration. + * + * @param elementName The name of the element that this attribute + * is associated with. + * @param attributeName The name of the attribute. + * @param type The attribute type. This value will be one of + * the following: "CDATA", "ENTITY", "ENTITIES", + * "ENUMERATION", "ID", "IDREF", "IDREFS", + * "NMTOKEN", "NMTOKENS", or "NOTATION". + * @param enumeration If the type has the value "ENUMERATION" or + * "NOTATION", this array holds the allowed attribute + * values; otherwise, this array is null. + * @param defaultType The attribute default type. This value will be + * one of the following: "#FIXED", "#IMPLIED", + * "#REQUIRED", or null. + * @param defaultValue The attribute default value, or null if no + * default value is specified. + * + * @param nonNormalizedDefaultValue The attribute default value with no normalization + * performed, or null if no default value is specified. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, + String defaultType, XMLString defaultValue, + XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException { + + try { + // SAX2 extension + if (fDeclHandler != null) { + // used as a key to detect duplicate attribute definitions. + String elemAttr = new StringBuffer(elementName).append('<').append(attributeName).toString(); + if(fDeclaredAttrs.get(elemAttr) != null) { + // we aren't permitted to return duplicate attribute definitions + return; + } + fDeclaredAttrs.put(elemAttr, Boolean.TRUE); + if (type.equals("NOTATION") || + type.equals("ENUMERATION")) { + + StringBuffer str = new StringBuffer(); + if (type.equals("NOTATION")) { + str.append(type); + str.append(" ("); + } + else { + str.append('('); + } + for (int i = 0; i < enumeration.length; i++) { + str.append(enumeration[i]); + if (i < enumeration.length - 1) { + str.append('|'); + } + } + str.append(')'); + type = str.toString(); + } + String value = (defaultValue==null) ? null : defaultValue.toString(); + fDeclHandler.attributeDecl(elementName, attributeName, + type, defaultType, value); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations) + + /** + * An internal entity declaration. + * + * @param name The name of the entity. Parameter entity names start with + * '%', whereas the name of a general entity is just the + * entity name. + * @param text The value of the entity. + * @param nonNormalizedText The non-normalized value of the entity. This + * value contains the same sequence of characters that was in + * the internal entity declaration, without any entity + * references expanded. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void internalEntityDecl(String name, XMLString text, + XMLString nonNormalizedText, + Augmentations augs) throws XNIException { + + try { + // SAX2 extensions + if (fDeclHandler != null) { + fDeclHandler.internalEntityDecl(name, text.toString()); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // internalEntityDecl(String,XMLString,XMLString) + + /** + * An external entity declaration. + * + * @param name The name of the entity. Parameter entity names start + * with '%', whereas the name of a general entity is just + * the entity name. + * @param identifier An object containing all location information + * pertinent to this entity. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void externalEntityDecl(String name, XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + try { + // SAX2 extension + if (fDeclHandler != null) { + String publicId = identifier.getPublicId(); + String systemId = fResolveDTDURIs ? + identifier.getExpandedSystemId() : identifier.getLiteralSystemId(); + fDeclHandler.externalEntityDecl(name, publicId, systemId); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // externalEntityDecl(String,,XMLResourceIdentifier, Augmentations) + + /** + * An unparsed entity declaration. + * + * @param name The name of the entity. + * @param identifier An object containing all location information + * pertinent to this entity. + * @param notation The name of the notation. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier, + String notation, + Augmentations augs) throws XNIException { + try { + // SAX2 extension + if (fDTDHandler != null) { + String publicId = identifier.getPublicId(); + String systemId = fResolveDTDURIs ? + identifier.getExpandedSystemId() : identifier.getLiteralSystemId(); + fDTDHandler.unparsedEntityDecl(name, publicId, systemId, notation); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations) + + /** + * A notation declaration + * + * @param name The name of the notation. + * @param identifier An object containing all location information + * pertinent to this notation. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void notationDecl(String name, XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + try { + // SAX1 and SAX2 + if (fDTDHandler != null) { + String publicId = identifier.getPublicId(); + String systemId = fResolveDTDURIs ? + identifier.getExpandedSystemId() : identifier.getLiteralSystemId(); + fDTDHandler.notationDecl(name, publicId, systemId); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + + } // notationDecl(String,XMLResourceIdentifier, Augmentations) + + /** + * The end of the DTD. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDTD(Augmentations augs) throws XNIException { + fInDTD = false; + + try { + // SAX2 extension + if (fLexicalHandler != null) { + fLexicalHandler.endDTD(); + } + } + catch (SAXException e) { + throw new XNIException(e); + } + if(fDeclaredAttrs != null) { + // help out the GC + fDeclaredAttrs.clear(); + } + + } // endDTD() + + // + // Parser and XMLReader methods + // + + /** + * Parses the input source specified by the given system identifier. + *

        + * This method is equivalent to the following: + *

        +     *     parse(new InputSource(systemId));
        +     * 
        + * + * @param systemId The system identifier (URI). + * + * @exception org.xml.sax.SAXException Throws exception on SAX error. + * @exception java.io.IOException Throws exception on i/o error. + */ + public void parse(String systemId) throws SAXException, IOException { + + // parse document + XMLInputSource source = new XMLInputSource(null, systemId, null); + try { + parse(source); + } + + // wrap XNI exceptions as SAX exceptions + catch (XMLParseException e) { + Exception ex = e.getException(); + if (ex == null || ex instanceof CharConversionException) { + // must be a parser exception; mine it for locator info + // and throw a SAXParseException + Locator2Impl locatorImpl = new Locator2Impl(); + // since XMLParseExceptions know nothing about encoding, + // we cannot return anything meaningful in this context. + // We *could* consult the LocatorProxy, but the + // application can do this itself if it wishes to possibly + // be mislead. + locatorImpl.setXMLVersion(fVersion); + locatorImpl.setPublicId(e.getPublicId()); + locatorImpl.setSystemId(e.getExpandedSystemId()); + locatorImpl.setLineNumber(e.getLineNumber()); + locatorImpl.setColumnNumber(e.getColumnNumber()); + throw (ex == null) ? + new SAXParseException(e.getMessage(), locatorImpl) : + new SAXParseException(e.getMessage(), locatorImpl, ex); + } + if (ex instanceof SAXException) { + // why did we create an XMLParseException? + throw (SAXException)ex; + } + if (ex instanceof IOException) { + throw (IOException)ex; + } + throw new SAXException(ex); + } + catch (XNIException e) { + Exception ex = e.getException(); + if (ex == null) { + throw new SAXException(e.getMessage()); + } + if (ex instanceof SAXException) { + throw (SAXException)ex; + } + if (ex instanceof IOException) { + throw (IOException)ex; + } + throw new SAXException(ex); + } + + } // parse(String) + + /** + * parse + * + * @param inputSource + * + * @exception org.xml.sax.SAXException + * @exception java.io.IOException + */ + public void parse(InputSource inputSource) + throws SAXException, IOException { + + // parse document + try { + XMLInputSource xmlInputSource = + new XMLInputSource(inputSource.getPublicId(), + inputSource.getSystemId(), + null); + xmlInputSource.setByteStream(inputSource.getByteStream()); + xmlInputSource.setCharacterStream(inputSource.getCharacterStream()); + xmlInputSource.setEncoding(inputSource.getEncoding()); + parse(xmlInputSource); + } + + // wrap XNI exceptions as SAX exceptions + catch (XMLParseException e) { + Exception ex = e.getException(); + if (ex == null || ex instanceof CharConversionException) { + // must be a parser exception; mine it for locator info + // and throw a SAXParseException + Locator2Impl locatorImpl = new Locator2Impl(); + // since XMLParseExceptions know nothing about encoding, + // we cannot return anything meaningful in this context. + // We *could* consult the LocatorProxy, but the + // application can do this itself if it wishes to possibly + // be mislead. + locatorImpl.setXMLVersion(fVersion); + locatorImpl.setPublicId(e.getPublicId()); + locatorImpl.setSystemId(e.getExpandedSystemId()); + locatorImpl.setLineNumber(e.getLineNumber()); + locatorImpl.setColumnNumber(e.getColumnNumber()); + throw (ex == null) ? + new SAXParseException(e.getMessage(), locatorImpl) : + new SAXParseException(e.getMessage(), locatorImpl, ex); + } + if (ex instanceof SAXException) { + // why did we create an XMLParseException? + throw (SAXException)ex; + } + if (ex instanceof IOException) { + throw (IOException)ex; + } + throw new SAXException(ex); + } + catch (XNIException e) { + Exception ex = e.getException(); + if (ex == null) { + throw new SAXException(e.getMessage()); + } + if (ex instanceof SAXException) { + throw (SAXException)ex; + } + if (ex instanceof IOException) { + throw (IOException)ex; + } + throw new SAXException(ex); + } + + } // parse(InputSource) + + /** + * Sets the resolver used to resolve external entities. The EntityResolver + * interface supports resolution of public and system identifiers. + * + * @param resolver The new entity resolver. Passing a null value will + * uninstall the currently installed resolver. + */ + public void setEntityResolver(EntityResolver resolver) { + + try { + XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER); + if (fUseEntityResolver2 && resolver instanceof EntityResolver2) { + if (xer instanceof EntityResolver2Wrapper) { + EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer; + er2w.setEntityResolver((EntityResolver2) resolver); + } + else { + fConfiguration.setProperty(ENTITY_RESOLVER, + new EntityResolver2Wrapper((EntityResolver2) resolver)); + } + } + else { + if (xer instanceof EntityResolverWrapper) { + EntityResolverWrapper erw = (EntityResolverWrapper) xer; + erw.setEntityResolver(resolver); + } + else { + fConfiguration.setProperty(ENTITY_RESOLVER, + new EntityResolverWrapper(resolver)); + } + } + } + catch (XMLConfigurationException e) { + // do nothing + } + + } // setEntityResolver(EntityResolver) + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public EntityResolver getEntityResolver() { + + EntityResolver entityResolver = null; + try { + XMLEntityResolver xmlEntityResolver = + (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER); + if (xmlEntityResolver != null) { + if (xmlEntityResolver instanceof EntityResolverWrapper) { + entityResolver = + ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver(); + } + else if (xmlEntityResolver instanceof EntityResolver2Wrapper) { + entityResolver = + ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver(); + } + } + } + catch (XMLConfigurationException e) { + // do nothing + } + return entityResolver; + + } // getEntityResolver():EntityResolver + + /** + * 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 errorHandler The error handler. + * @see #getErrorHandler + */ + public void setErrorHandler(ErrorHandler errorHandler) { + + try { + XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER); + if (xeh instanceof ErrorHandlerWrapper) { + ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh; + ehw.setErrorHandler(errorHandler); + } + else { + fConfiguration.setProperty(ERROR_HANDLER, + new ErrorHandlerWrapper(errorHandler)); + } + } + catch (XMLConfigurationException e) { + // do nothing + } + + } // setErrorHandler(ErrorHandler) + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public ErrorHandler getErrorHandler() { + + ErrorHandler errorHandler = null; + try { + XMLErrorHandler xmlErrorHandler = + (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER); + if (xmlErrorHandler != null && + xmlErrorHandler instanceof ErrorHandlerWrapper) { + errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler(); + } + } + catch (XMLConfigurationException e) { + // do nothing + } + return errorHandler; + + } // getErrorHandler():ErrorHandler + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception SAXException An exception thrown if the parser does not + * support the specified locale. + * + * @see org.xml.sax.Parser + */ + public void setLocale(Locale locale) throws SAXException { + //REVISIT:this methods is not part of SAX2 interfaces, we should throw exception + //if any application uses SAX2 and sets locale also. -nb + fConfiguration.setLocale(locale); + + } // setLocale(Locale) + + /** + * 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 dtdHandler The DTD handler. + * + + * @see #getDTDHandler + */ + public void setDTDHandler(DTDHandler dtdHandler) { + fDTDHandler = dtdHandler; + } // setDTDHandler(DTDHandler) + + // + // Parser methods + // + + /** + * Allow an application to register a document event handler. + *

        + * If the application does not register a document handler, all + * document events reported by the SAX parser will be silently + * ignored (this is the default behaviour implemented by + * HandlerBase). + *

        + * 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 documentHandler The document handler. + */ + public void setDocumentHandler(DocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + } // setDocumentHandler(DocumentHandler) + + // + // XMLReader methods + // + + /** + * Allow an application to register a content event handler. + *

        + * If the application does not register a content handler, all + * content 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 contentHandler The content handler. + * + * @see #getContentHandler + */ + public void setContentHandler(ContentHandler contentHandler) { + fContentHandler = contentHandler; + } // setContentHandler(ContentHandler) + + /** + * Return the current content handler. + * + * @return The current content handler, or null if none + * has been registered. + * + * @see #setContentHandler + */ + public ContentHandler getContentHandler() { + return fContentHandler; + } // getContentHandler():ContentHandler + + /** + * Return the current DTD handler. + * + * @return The current DTD handler, or null if none + * has been registered. + * @see #setDTDHandler + */ + public DTDHandler getDTDHandler() { + return fDTDHandler; + } // getDTDHandler():DTDHandler + + /** + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception SAXNotRecognizedException If the + * requested feature is not known. + * @exception SAXNotSupportedException If the + * requested feature is known, but the requested + * state is not supported. + */ + public void setFeature(String featureId, boolean state) + throws SAXNotRecognizedException, SAXNotSupportedException { + + try { + // + // SAX2 Features + // + + if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length(); + + // http://xml.org/sax/features/namespaces + if (suffixLength == Constants.NAMESPACES_FEATURE.length() && + featureId.endsWith(Constants.NAMESPACES_FEATURE)) { + fConfiguration.setFeature(featureId, state); + fNamespaces = state; + return; + } + + // http://xml.org/sax/features/namespace-prefixes + // controls the reporting of raw prefixed names and Namespace + // declarations (xmlns* attributes): when this feature is false + // (the default), raw prefixed names may optionally be reported, + // and xmlns* attributes must not be reported. + // + if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() && + featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) { + fNamespacePrefixes = state; + return; + } + + // http://xml.org/sax/features/string-interning + // controls the use of java.lang.String#intern() for strings + // passed to SAX handlers. + // + if (suffixLength == Constants.STRING_INTERNING_FEATURE.length() && + featureId.endsWith(Constants.STRING_INTERNING_FEATURE)) { + if (!state) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "false-not-supported", new Object [] {featureId})); + } + return; + } + + // http://xml.org/sax/features/lexical-handler/parameter-entities + // controls whether the beginning and end of parameter entities + // will be reported to the LexicalHandler. + // + if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() && + featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) { + fLexicalHandlerParameterEntities = state; + return; + } + + // http://xml.org/sax/features/resolve-dtd-uris + // controls whether system identifiers will be absolutized relative to + // their base URIs before reporting. + // + if (suffixLength == Constants.RESOLVE_DTD_URIS_FEATURE.length() && + featureId.endsWith(Constants.RESOLVE_DTD_URIS_FEATURE)) { + fResolveDTDURIs = state; + return; + } + + // http://xml.org/sax/features/unicode-normalization-checking + // controls whether Unicode normalization checking is performed + // as per Appendix B of the XML 1.1 specification + // + if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() && + featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) { + // REVISIT: Allow this feature to be set once Unicode normalization + // checking is supported -- mrglavas. + if (state) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "true-not-supported", new Object [] {featureId})); + } + return; + } + + // http://xml.org/sax/features/xmlns-uris + // controls whether the parser reports that namespace declaration + // attributes as being in the namespace: http://www.w3.org/2000/xmlns/ + // + if (suffixLength == Constants.XMLNS_URIS_FEATURE.length() && + featureId.endsWith(Constants.XMLNS_URIS_FEATURE)) { + fXMLNSURIs = state; + return; + } + + // http://xml.org/sax/features/use-entity-resolver2 + // controls whether the methods of an object implementing + // org.xml.sax.ext.EntityResolver2 will be used by the parser. + // + if (suffixLength == Constants.USE_ENTITY_RESOLVER2_FEATURE.length() && + featureId.endsWith(Constants.USE_ENTITY_RESOLVER2_FEATURE)) { + if (state != fUseEntityResolver2) { + fUseEntityResolver2 = state; + // Refresh EntityResolver wrapper. + setEntityResolver(getEntityResolver()); + } + return; + } + + // + // Read only features. + // + + // http://xml.org/sax/features/is-standalone + // reports whether the document specified a standalone document declaration. + // http://xml.org/sax/features/use-attributes2 + // reports whether Attributes objects passed to startElement also implement + // the org.xml.sax.ext.Attributes2 interface. + // http://xml.org/sax/features/use-locator2 + // reports whether Locator objects passed to setDocumentLocator also implement + // the org.xml.sax.ext.Locator2 interface. + // http://xml.org/sax/features/xml-1.1 + // reports whether the parser supports both XML 1.1 and XML 1.0. + if ((suffixLength == Constants.IS_STANDALONE_FEATURE.length() && + featureId.endsWith(Constants.IS_STANDALONE_FEATURE)) || + (suffixLength == Constants.USE_ATTRIBUTES2_FEATURE.length() && + featureId.endsWith(Constants.USE_ATTRIBUTES2_FEATURE)) || + (suffixLength == Constants.USE_LOCATOR2_FEATURE.length() && + featureId.endsWith(Constants.USE_LOCATOR2_FEATURE)) || + (suffixLength == Constants.XML_11_FEATURE.length() && + featureId.endsWith(Constants.XML_11_FEATURE))) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-read-only", new Object [] {featureId})); + } + + + // + // Drop through and perform default processing + // + } + + // + // Xerces Features + // + + /* + else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) { + String feature = featureId.substring(XERCES_FEATURES_PREFIX.length()); + // + // Drop through and perform default processing + // + } + */ + + // + // Default handling + // + + fConfiguration.setFeature(featureId, state); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + + } // setFeature(String,boolean) + + /** + * Query the state of a feature. + * + * Query the current state of any feature in a SAX2 parser. The + * parser might not recognize the feature. + * + * @param featureId The unique identifier (URI) of the feature + * being set. + * @return The current state of the feature. + * @exception org.xml.sax.SAXNotRecognizedException If the + * requested feature is not known. + * @exception SAXNotSupportedException If the + * requested feature is known but not supported. + */ + public boolean getFeature(String featureId) + throws SAXNotRecognizedException, SAXNotSupportedException { + + try { + // + // SAX2 Features + // + + if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length(); + + // http://xml.org/sax/features/namespace-prefixes + // controls the reporting of raw prefixed names and Namespace + // declarations (xmlns* attributes): when this feature is false + // (the default), raw prefixed names may optionally be reported, + // and xmlns* attributes must not be reported. + // + if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() && + featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) { + return fNamespacePrefixes; + } + // http://xml.org/sax/features/string-interning + // controls the use of java.lang.String#intern() for strings + // passed to SAX handlers. + // + if (suffixLength == Constants.STRING_INTERNING_FEATURE.length() && + featureId.endsWith(Constants.STRING_INTERNING_FEATURE)) { + return true; + } + + // http://xml.org/sax/features/is-standalone + // reports whether the document specified a standalone document declaration. + // + if (suffixLength == Constants.IS_STANDALONE_FEATURE.length() && + featureId.endsWith(Constants.IS_STANDALONE_FEATURE)) { + return fStandalone; + } + + // http://xml.org/sax/features/xml-1.1 + // reports whether the parser supports both XML 1.1 and XML 1.0. + // + if (suffixLength == Constants.XML_11_FEATURE.length() && + featureId.endsWith(Constants.XML_11_FEATURE)) { + return (fConfiguration instanceof XML11Configurable); + } + + // http://xml.org/sax/features/lexical-handler/parameter-entities + // controls whether the beginning and end of parameter entities + // will be reported to the LexicalHandler. + // + if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() && + featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) { + return fLexicalHandlerParameterEntities; + } + + // http://xml.org/sax/features/resolve-dtd-uris + // controls whether system identifiers will be absolutized relative to + // their base URIs before reporting. + if (suffixLength == Constants.RESOLVE_DTD_URIS_FEATURE.length() && + featureId.endsWith(Constants.RESOLVE_DTD_URIS_FEATURE)) { + return fResolveDTDURIs; + } + + // http://xml.org/sax/features/xmlns-uris + // controls whether the parser reports that namespace declaration + // attributes as being in the namespace: http://www.w3.org/2000/xmlns/ + // + if (suffixLength == Constants.XMLNS_URIS_FEATURE.length() && + featureId.endsWith(Constants.XMLNS_URIS_FEATURE)) { + return fXMLNSURIs; + } + + // http://xml.org/sax/features/unicode-normalization-checking + // controls whether Unicode normalization checking is performed + // as per Appendix B of the XML 1.1 specification + // + if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() && + featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) { + // REVISIT: Allow this feature to be set once Unicode normalization + // checking is supported -- mrglavas. + return false; + } + + // http://xml.org/sax/features/use-entity-resolver2 + // controls whether the methods of an object implementing + // org.xml.sax.ext.EntityResolver2 will be used by the parser. + // + if (suffixLength == Constants.USE_ENTITY_RESOLVER2_FEATURE.length() && + featureId.endsWith(Constants.USE_ENTITY_RESOLVER2_FEATURE)) { + return fUseEntityResolver2; + } + + // http://xml.org/sax/features/use-attributes2 + // reports whether Attributes objects passed to startElement also implement + // the org.xml.sax.ext.Attributes2 interface. + // http://xml.org/sax/features/use-locator2 + // reports whether Locator objects passed to setDocumentLocator also implement + // the org.xml.sax.ext.Locator2 interface. + // + if ((suffixLength == Constants.USE_ATTRIBUTES2_FEATURE.length() && + featureId.endsWith(Constants.USE_ATTRIBUTES2_FEATURE)) || + (suffixLength == Constants.USE_LOCATOR2_FEATURE.length() && + featureId.endsWith(Constants.USE_LOCATOR2_FEATURE))) { + return true; + } + + + // + // Drop through and perform default processing + // + } + + // + // Xerces Features + // + + /* + else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) { + // + // Drop through and perform default processing + // + } + */ + + return fConfiguration.getFeature(featureId); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + + } // getFeature(String):boolean + + /** + * Set the value of any property in a SAX2 parser. The parser + * might not recognize the property, and if it does recognize + * it, it might not support the requested value. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * @param value The value to which the property is being set. + * + * @exception SAXNotRecognizedException If the + * requested property is not known. + * @exception SAXNotSupportedException If the + * requested property is known, but the requested + * value is not supported. + */ + public void setProperty(String propertyId, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + + try { + // + // SAX2 core properties + // + + if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); + + // + // http://xml.org/sax/properties/lexical-handler + // Value type: org.xml.sax.ext.LexicalHandler + // Access: read/write, pre-parse only + // Set the lexical event handler. + // + if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() && + propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) { + try { + setLexicalHandler((LexicalHandler)value); + } + catch (ClassCastException e) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "incompatible-class", new Object [] {propertyId, "org.xml.sax.ext.LexicalHandler"})); + } + return; + } + // + // http://xml.org/sax/properties/declaration-handler + // Value type: org.xml.sax.ext.DeclHandler + // Access: read/write, pre-parse only + // Set the DTD declaration event handler. + // + if (suffixLength == Constants.DECLARATION_HANDLER_PROPERTY.length() && + propertyId.endsWith(Constants.DECLARATION_HANDLER_PROPERTY)) { + try { + setDeclHandler((DeclHandler)value); + } + catch (ClassCastException e) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "incompatible-class", new Object [] {propertyId, "org.xml.sax.ext.DeclHandler"})); + } + return; + } + // + // http://xml.org/sax/properties/dom-node + // Value type: DOM Node + // Access: read-only + // Get the DOM node currently being visited, if the SAX parser is + // iterating over a DOM tree. If the parser recognises and + // supports this property but is not currently visiting a DOM + // node, it should return null (this is a good way to check for + // availability before the parse begins). + // http://xml.org/sax/properties/document-xml-version + // Value type: java.lang.String + // Access: read-only + // The literal string describing the actual XML version of the document. + // + if ((suffixLength == Constants.DOM_NODE_PROPERTY.length() && + propertyId.endsWith(Constants.DOM_NODE_PROPERTY)) || + (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() && + propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY))) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-read-only", new Object [] {propertyId})); + } + // + // Drop through and perform default processing + // + } + + // + // Xerces Properties + // + + /* + else if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) { + // + // Drop through and perform default processing + // + } + */ + + // + // Perform default processing + // + + fConfiguration.setProperty(propertyId, value); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + + } // setProperty(String,Object) + + /** + * Query the value of a property. + * + * Return the current value of a property in a SAX2 parser. + * The parser might not recognize the property. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * @return The current value of the property. + * @exception org.xml.sax.SAXNotRecognizedException If the + * requested property is not known. + * @exception SAXNotSupportedException If the + * requested property is known but not supported. + */ + public Object getProperty(String propertyId) + throws SAXNotRecognizedException, SAXNotSupportedException { + + try { + // + // SAX2 core properties + // + + if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); + + // + // http://xml.org/sax/properties/document-xml-version + // Value type: java.lang.String + // Access: read-only + // The literal string describing the actual XML version of the document. + // + if (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() && + propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY)) { + return fVersion; + } + + // + // http://xml.org/sax/properties/lexical-handler + // Value type: org.xml.sax.ext.LexicalHandler + // Access: read/write, pre-parse only + // Set the lexical event handler. + // + if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() && + propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) { + return getLexicalHandler(); + } + // + // http://xml.org/sax/properties/declaration-handler + // Value type: org.xml.sax.ext.DeclHandler + // Access: read/write, pre-parse only + // Set the DTD declaration event handler. + // + if (suffixLength == Constants.DECLARATION_HANDLER_PROPERTY.length() && + propertyId.endsWith(Constants.DECLARATION_HANDLER_PROPERTY)) { + return getDeclHandler(); + } + + // + // http://xml.org/sax/properties/dom-node + // Value type: DOM Node + // Access: read-only + // Get the DOM node currently being visited, if the SAX parser is + // iterating over a DOM tree. If the parser recognises and + // supports this property but is not currently visiting a DOM + // node, it should return null (this is a good way to check for + // availability before the parse begins). + // + if (suffixLength == Constants.DOM_NODE_PROPERTY.length() && + propertyId.endsWith(Constants.DOM_NODE_PROPERTY)) { + // we are not iterating a DOM tree + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "dom-node-read-not-supported", null)); + } + + // + // Drop through and perform default processing + // + } + + // + // Xerces properties + // + + /* + else if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) { + // + // Drop through and perform default processing + // + } + */ + + // + // Perform default processing + // + + return fConfiguration.getProperty(propertyId); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + + } // getProperty(String):Object + + // + // Protected methods + // + + // SAX2 core properties + + /** + * Set the DTD declaration event handler. + *

        + * This method is the equivalent to the property: + *

        +     * http://xml.org/sax/properties/declaration-handler
        +     * 
        + * + * @param handler The new handler. + * + * @see #getDeclHandler + * @see #setProperty + */ + protected void setDeclHandler(DeclHandler handler) + throws SAXNotRecognizedException, SAXNotSupportedException { + + if (fParseInProgress) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-parsing-supported", + new Object [] {"http://xml.org/sax/properties/declaration-handler"})); + } + fDeclHandler = handler; + + } // setDeclHandler(DeclHandler) + + /** + * Returns the DTD declaration event handler. + * + * @see #setDeclHandler + */ + protected DeclHandler getDeclHandler() + throws SAXNotRecognizedException, SAXNotSupportedException { + return fDeclHandler; + } // getDeclHandler():DeclHandler + + /** + * Set the lexical event handler. + *

        + * This method is the equivalent to the property: + *

        +     * http://xml.org/sax/properties/lexical-handler
        +     * 
        + * + * @param handler lexical event handler + * + * @see #getLexicalHandler + * @see #setProperty + */ + protected void setLexicalHandler(LexicalHandler handler) + throws SAXNotRecognizedException, SAXNotSupportedException { + + if (fParseInProgress) { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-parsing-supported", + new Object [] {"http://xml.org/sax/properties/lexical-handler"})); + } + fLexicalHandler = handler; + + } // setLexicalHandler(LexicalHandler) + + /** + * Returns the lexical handler. + * + * @see #setLexicalHandler + */ + protected LexicalHandler getLexicalHandler() + throws SAXNotRecognizedException, SAXNotSupportedException { + return fLexicalHandler; + } // getLexicalHandler():LexicalHandler + + /** + * Send startPrefixMapping events + */ + protected final void startNamespaceMapping() throws SAXException{ + int count = fNamespaceContext.getDeclaredPrefixCount(); + if (count > 0) { + String prefix = null; + String uri = null; + for (int i = 0; i < count; i++) { + prefix = fNamespaceContext.getDeclaredPrefixAt(i); + uri = fNamespaceContext.getURI(prefix); + fContentHandler.startPrefixMapping(prefix, + (uri == null) ? "" : uri); + } + } + } + + /** + * Send endPrefixMapping events + */ + protected final void endNamespaceMapping() throws SAXException { + int count = fNamespaceContext.getDeclaredPrefixCount(); + if (count > 0) { + for (int i = 0; i < count; i++) { + fContentHandler.endPrefixMapping(fNamespaceContext.getDeclaredPrefixAt(i)); + } + } + } + + // + // XMLDocumentParser methods + // + + /** + * Reset all components before parsing. + * + * @throws XNIException Thrown if an error occurs during initialization. + */ + public void reset() throws XNIException { + super.reset(); + + // reset state + fInDTD = false; + fVersion = "1.0"; + fStandalone = false; + + // features + fNamespaces = fConfiguration.getFeature(NAMESPACES); + fAugmentations = null; + fDeclaredAttrs = null; + + } // reset() + + // + // Classes + // + + protected static final class LocatorProxy + implements Locator2 { + + // + // Data + // + + /** XML locator. */ + protected XMLLocator fLocator; + + // + // Constructors + // + + /** Constructs an XML locator proxy. */ + public LocatorProxy(XMLLocator locator) { + fLocator = locator; + } + + // + // Locator methods + // + + /** Public identifier. */ + public String getPublicId() { + return fLocator.getPublicId(); + } + + /** System identifier. */ + public String getSystemId() { + return fLocator.getExpandedSystemId(); + } + /** Line number. */ + public int getLineNumber() { + return fLocator.getLineNumber(); + } + + /** Column number. */ + public int getColumnNumber() { + return fLocator.getColumnNumber(); + } + + // Locator2 methods + public String getXMLVersion() { + return fLocator.getXMLVersion(); + } + + public String getEncoding() { + return fLocator.getEncoding(); + } + + } // class LocatorProxy + + protected static final class AttributesProxy + implements AttributeList, Attributes2 { + + // + // Data + // + + /** XML attributes. */ + protected XMLAttributes fAttributes; + + // + // Public methods + // + + /** Sets the XML attributes. */ + public void setAttributes(XMLAttributes attributes) { + fAttributes = attributes; + } // setAttributes(XMLAttributes) + + public int getLength() { + return fAttributes.getLength(); + } + + public String getName(int i) { + return fAttributes.getQName(i); + } + + public String getQName(int index) { + return fAttributes.getQName(index); + } + + public String getURI(int index) { + // REVISIT: this hides the fact that internally we use + // null instead of empty string + // SAX requires URI to be a string or an empty string + String uri= fAttributes.getURI(index); + return uri != null ? uri : ""; + } + + public String getLocalName(int index) { + return fAttributes.getLocalName(index); + } + + public String getType(int i) { + return fAttributes.getType(i); + } + + public String getType(String name) { + return fAttributes.getType(name); + } + + public String getType(String uri, String localName) { + return uri.length() == 0 ? fAttributes.getType(null, localName) : + fAttributes.getType(uri, localName); + } + + public String getValue(int i) { + return fAttributes.getValue(i); + } + + public String getValue(String name) { + return fAttributes.getValue(name); + } + + public String getValue(String uri, String localName) { + return uri.length() == 0 ? fAttributes.getValue(null, localName) : + fAttributes.getValue(uri, localName); + } + + public int getIndex(String qName) { + return fAttributes.getIndex(qName); + } + + public int getIndex(String uri, String localPart) { + return uri.length() == 0 ? fAttributes.getIndex(null, localPart) : + fAttributes.getIndex(uri, localPart); + } + + // Attributes2 methods + // REVISIT: Localize exception messages. -- mrglavas + public boolean isDeclared(int index) { + if (index < 0 || index >= fAttributes.getLength()) { + throw new ArrayIndexOutOfBoundsException(index); + } + return Boolean.TRUE.equals( + fAttributes.getAugmentations(index).getItem( + Constants.ATTRIBUTE_DECLARED)); + } + + public boolean isDeclared(String qName) { + int index = getIndex(qName); + if (index == -1) { + throw new IllegalArgumentException(qName); + } + return Boolean.TRUE.equals( + fAttributes.getAugmentations(index).getItem( + Constants.ATTRIBUTE_DECLARED)); + } + + public boolean isDeclared(String uri, String localName) { + int index = getIndex(uri, localName); + if (index == -1) { + throw new IllegalArgumentException(localName); + } + return Boolean.TRUE.equals( + fAttributes.getAugmentations(index).getItem( + Constants.ATTRIBUTE_DECLARED)); + } + + public boolean isSpecified(int index) { + if (index < 0 || index >= fAttributes.getLength()) { + throw new ArrayIndexOutOfBoundsException(index); + } + return fAttributes.isSpecified(index); + } + + public boolean isSpecified(String qName) { + int index = getIndex(qName); + if (index == -1) { + throw new IllegalArgumentException(qName); + } + return fAttributes.isSpecified(index); + } + + public boolean isSpecified(String uri, String localName) { + int index = getIndex(uri, localName); + if (index == -1) { + throw new IllegalArgumentException(localName); + } + return fAttributes.isSpecified(index); + } + + } // class AttributesProxy + + + // PSVIProvider methods + + public ElementPSVI getElementPSVI(){ + return (fAugmentations != null)?(ElementPSVI)fAugmentations.getItem(Constants.ELEMENT_PSVI):null; + } + + + public AttributePSVI getAttributePSVI(int index){ + + return (AttributePSVI)fAttributesProxy.fAttributes.getAugmentations(index).getItem(Constants.ATTRIBUTE_PSVI); + } + + + public AttributePSVI getAttributePSVIByName(String uri, + String localname){ + return (AttributePSVI)fAttributesProxy.fAttributes.getAugmentations(uri, localname).getItem(Constants.ATTRIBUTE_PSVI); + } + +} // class AbstractSAXParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractXMLDocumentParser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractXMLDocumentParser.java new file mode 100644 index 0000000..079dab6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/AbstractXMLDocumentParser.java @@ -0,0 +1,810 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDTDContentModelSource; +import org.apache.xerces.xni.parser.XMLDTDSource; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLParserConfiguration; + +/** + * This is the base class for all XML document parsers. XMLDocumentParser + * provides a common implementation shared by the various document parsers + * in the Xerces package. While this class is provided for convenience, it + * does not prevent other kinds of parsers to be constructed using the XNI + * interfaces. + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public abstract class AbstractXMLDocumentParser + extends XMLParser + implements XMLDocumentHandler, XMLDTDHandler, XMLDTDContentModelHandler { + + // + // Data + // + + // state + + /** True if inside DTD. */ + protected boolean fInDTD; + + /** Document source*/ + protected XMLDocumentSource fDocumentSource; + + /** DTD source*/ + protected XMLDTDSource fDTDSource; + + /** DTD content model source*/ + protected XMLDTDContentModelSource fDTDContentModelSource; + + // + // Constructors + // + + /** + * Constructs a document parser using the default symbol table + * and grammar pool. + */ + protected AbstractXMLDocumentParser(XMLParserConfiguration config) { + super(config); + + // set handlers + config.setDocumentHandler(this); + config.setDTDHandler(this); + config.setDTDContentModelHandler(this); + + } // (XMLParserConfiguration) + + // + // XMLDocumentHandler methods + // + + /** + * The start of the document. + * + * @param locator The system identifier of the entity if the entity + * is external, null otherwise. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param namespaceContext + * The namespace context in effect at the + * start of this document. + * This object represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, Augmentations augs) + throws XNIException { + } // startDocument(XMLLocator,String) + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) + throws XNIException { + } // xmlDecl(String,String,String) + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * @param augs Additional information that may include infoset augmentations + * otherwise. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) + throws XNIException { + } // doctypeDecl(String,String,String) + + /** + * The start of an element. If the document specifies the start element + * by using an empty tag, then the startElement method will immediately + * be followed by the endElement method, with no intervening methods. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + } // startElement(QName,XMLAttributes) + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException { + + startElement(element, attributes, augs); + endElement(element, augs); + + } // emptyElement(QName,XMLAttributes) + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException { + } // characters(XMLString) + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + } // ignorableWhitespace(XMLString) + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException { + } // endElement(QName) + + /** + * The start of a CDATA section. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException { + } // startCDATA() + + /** + * The end of a CDATA section. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException { + } // endCDATA() + + /** + * The end of the document. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDocument(Augmentations augs) throws XNIException { + } // endDocument() + + + /** + * This method notifies the start of an entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException { + } // startGeneralEntity(String,XMLResourceIdentifier,String,Augmentations) + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

        + * Note: This method will never be called for the + * document entity; it is only called for external general entities + * referenced in document content. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { + } // textDecl(String, String, Augmentations) + + /** + * This method notifies the end of an entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augs) + throws XNIException { + } // endGeneralEntity(String,Augmentations) + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException { + } // comment (XMLString, Augmentations) + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException { + } // processingInstruction(String, XMLString, Augmentations) + + + /** Sets the document source */ + public void setDocumentSource(XMLDocumentSource source){ + fDocumentSource = source; + } // setDocumentSource + + /** Returns the document source */ + public XMLDocumentSource getDocumentSource (){ + return fDocumentSource; + } // getDocumentSource + // + // XMLDTDHandler methods + // + + /** + * The start of the DTD. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing of + * the document DTD. However, it is strongly + * recommended that a locator be supplied that can + * at least report the base system identifier of the + * DTD. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException { + fInDTD = true; + } // startDTD(XMLLocator) + + + /** + * The start of the DTD external subset. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startExternalSubset(XMLResourceIdentifier identifier, Augmentations augmentations) + throws XNIException { + } // startExternalSubset(Augmentations) + + /** + * The end of the DTD external subset. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endExternalSubset(Augmentations augmentations) + throws XNIException { + } // endExternalSubset(Augmentations) + + /** + * This method notifies the start of an entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startParameterEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException { + } // startParameterEntity(String,XMLResourceIdentifier,String,Augmentations) + + /** + * This method notifies the end of an entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endParameterEntity(String name, Augmentations augs) + throws XNIException { + } // endParameterEntity(String,Augmentations) + + /** + * Characters within an IGNORE conditional section. + * + * @param text The ignored text. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignoredCharacters(XMLString text, Augmentations augs) throws XNIException { + } // ignoredCharacters(XMLString, Augmentations) + + /** + * An element declaration. + * + * @param name The name of the element. + * @param contentModel The element content model. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void elementDecl(String name, String contentModel, Augmentations augs) + throws XNIException { + } // elementDecl(String,String) + + /** + * The start of an attribute list. + * + * @param elementName The name of the element that this attribute + * list is associated with. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startAttlist(String elementName, Augmentations augs) throws XNIException { + } // startAttlist(String) + + /** + * An attribute declaration. + * + * @param elementName The name of the element that this attribute + * is associated with. + * @param attributeName The name of the attribute. + * @param type The attribute type. This value will be one of + * the following: "CDATA", "ENTITY", "ENTITIES", + * "ENUMERATION", "ID", "IDREF", "IDREFS", + * "NMTOKEN", "NMTOKENS", or "NOTATION". + * @param enumeration If the type has the value "ENUMERATION" or + * "NOTATION", this array holds the allowed attribute + * values; otherwise, this array is null. + * @param defaultType The attribute default type. This value will be + * one of the following: "#FIXED", "#IMPLIED", + * "#REQUIRED", or null. + * @param defaultValue The attribute default value, or null if no + * default value is specified. + * @param nonNormalizedDefaultValue The attribute default value with no normalization + * performed, or null if no default value is specified. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, + String defaultType, XMLString defaultValue, + XMLString nonNormalizedDefaultValue, Augmentations augs) + throws XNIException { + } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations) + + /** + * The end of an attribute list. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endAttlist(Augmentations augs) throws XNIException { + } // endAttlist() + + /** + * An internal entity declaration. + * + * @param name The name of the entity. Parameter entity names start with + * '%', whereas the name of a general entity is just the + * entity name. + * @param text The value of the entity. + * @param nonNormalizedText The non-normalized value of the entity. This + * value contains the same sequence of characters that was in + * the internal entity declaration, without any entity + * references expanded. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void internalEntityDecl(String name, XMLString text, + XMLString nonNormalizedText, Augmentations augs) + throws XNIException { + } // internalEntityDecl(String,XMLString,XMLString) + + /** + * An external entity declaration. + * + * @param name The name of the entity. Parameter entity names start + * with '%', whereas the name of a general entity is just + * the entity name. + * @param identifier An object containing all location information + * pertinent to this entity. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void externalEntityDecl(String name, XMLResourceIdentifier identifier, + Augmentations augs) throws XNIException { + } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations) + + /** + * An unparsed entity declaration. + * + * @param name The name of the entity. + * @param identifier An object containing all location information + * pertinent to this entity. + * @param notation The name of the notation. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier, + String notation, Augmentations augs) throws XNIException { + } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations) + + /** + * A notation declaration + * + * @param name The name of the notation. + * @param identifier An object containing all location information + * pertinent to this notation. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void notationDecl(String name, XMLResourceIdentifier identifier, + Augmentations augs) + throws XNIException { + } // notationDecl(String,XMLResourceIdentifier, Augmentations) + + /** + * The start of a conditional section. + * + * @param type The type of the conditional section. This value will + * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #CONDITIONAL_INCLUDE + * @see #CONDITIONAL_IGNORE + */ + public void startConditional(short type, Augmentations augs) throws XNIException { + } // startConditional(short) + + /** + * The end of a conditional section. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endConditional(Augmentations augs) throws XNIException { + } // endConditional() + + /** + * The end of the DTD. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDTD(Augmentations augs) throws XNIException { + fInDTD = false; + } // endDTD() + + // set the source of this handler + public void setDTDSource(XMLDTDSource source) { + fDTDSource = source; + } + + // return the source from which this handler derives its events + public XMLDTDSource getDTDSource() { + return fDTDSource; + } + + // + // XMLDTDContentModelHandler methods + // + + /** + * The start of a content model. Depending on the type of the content + * model, specific methods may be called between the call to the + * startContentModel method and the call to the endContentModel method. + * + * @param elementName The name of the element. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startContentModel(String elementName, Augmentations augs) throws XNIException { + } // startContentModel(String, Augmentations) + + /** + * A content model of ANY. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #empty + * @see #startGroup + */ + public void any(Augmentations augs) throws XNIException { + } // any(Augmentations) + + /** + * A content model of EMPTY. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #any + * @see #startGroup + */ + public void empty(Augmentations augs) throws XNIException { + } // empty(Augmentations) + + /** + * A start of either a mixed or children content model. A mixed + * content model will immediately be followed by a call to the + * pcdata() method. A children content model will + * contain additional groups and/or elements. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #any + * @see #empty + */ + public void startGroup(Augmentations augs) throws XNIException { + } // stargGroup(Augmentations) + + /** + * The appearance of "#PCDATA" within a group signifying a + * mixed content model. This method will be the first called + * following the content model's startGroup(). + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #startGroup + */ + public void pcdata(Augmentations augs) throws XNIException { + } // pcdata(Augmentations) + + /** + * A referenced element in a mixed or children content model. + * + * @param elementName The name of the referenced element. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void element(String elementName, Augmentations augs) throws XNIException { + } // element(String, Augmentations) + + /** + * The separator between choices or sequences of a mixed or children + * content model. + * + * @param separator The type of children separator. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #SEPARATOR_CHOICE + * @see #SEPARATOR_SEQUENCE + */ + public void separator(short separator, Augmentations augs) throws XNIException { + } // separator(short, Augmentations) + + /** + * The occurrence count for a child in a children content model or + * for the mixed content model group. + * + * @param occurrence The occurrence count for the last element + * or group. + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #OCCURS_ZERO_OR_ONE + * @see #OCCURS_ZERO_OR_MORE + * @see #OCCURS_ONE_OR_MORE + */ + public void occurrence(short occurrence, Augmentations augs) throws XNIException { + } // occurence(short, Augmentations) + + /** + * The end of a group for mixed or children content models. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endGroup(Augmentations augs) throws XNIException { + } // endGroup(Augmentations) + + /** + * The end of a content model. + * + * @param augs Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endContentModel(Augmentations augs) throws XNIException { + } // endContentModel(Augmentations) + + // set content model source + public void setDTDContentModelSource(XMLDTDContentModelSource source) { + fDTDContentModelSource = source; + } + + // get content model source + public XMLDTDContentModelSource getDTDContentModelSource() { + return fDTDContentModelSource; + } + + // + // Protected methods + // + + /** + * reset all components before parsing + */ + protected void reset() throws XNIException { + super.reset(); + fInDTD = false; + } // reset() + +} // class AbstractXMLDocumentParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/BasicParserConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/BasicParserConfiguration.java new file mode 100644 index 0000000..60936e4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/BasicParserConfiguration.java @@ -0,0 +1,587 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.ParserConfigurationSettings; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParserConfiguration; + +/** + * A very basic parser configuration. This configuration class can + * be used as a base class for custom parser configurations. The + * basic parser configuration creates the symbol table (if not + * specified at construction time) and manages all of the recognized + * features and properties. + *

        + * The basic parser configuration does not mandate + * any particular pipeline configuration or the use of specific + * components except for the symbol table. If even this is too much + * for a basic parser configuration, the programmer can create a new + * configuration class that implements the + * XMLParserConfiguration interface. + *

        + * Subclasses of the basic parser configuration can add their own + * recognized features and properties by calling the + * addRecognizedFeature and + * addRecognizedProperty methods, respectively. + *

        + * The basic parser configuration assumes that the configuration + * will be made up of various parser components that implement the + * XMLComponent interface. If subclasses of this + * configuration create their own components for use in the + * parser configuration, then each component should be added to + * the list of components by calling the addComponent + * method. The basic parser configuration will make sure to call + * the reset method of each registered component + * before parsing an instance document. + *

        + * This class recognizes the following features and properties: + *

          + *
        • Features + *
            + *
          • http://xml.org/sax/features/validation
          • + *
          • http://xml.org/sax/features/namespaces
          • + *
          • http://xml.org/sax/features/external-general-entities
          • + *
          • http://xml.org/sax/features/external-parameter-entities
          • + *
          + *
        • Properties + *
            + *
          • http://xml.org/sax/properties/xml-string
          • + *
          • http://apache.org/xml/properties/internal/symbol-table
          • + *
          • http://apache.org/xml/properties/internal/error-handler
          • + *
          • http://apache.org/xml/properties/internal/entity-resolver
          • + *
          + *
        + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public abstract class BasicParserConfiguration + extends ParserConfigurationSettings + implements XMLParserConfiguration { + + // + // Constants + // + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: external general entities. */ + protected static final String EXTERNAL_GENERAL_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE; + + /** Feature identifier: external parameter entities. */ + protected static final String EXTERNAL_PARAMETER_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE; + + // property identifiers + + /** Property identifier: xml string. */ + protected static final String XML_STRING = + Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY; + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + // + // Data + // + + // components (non-configurable) + + /** Symbol table. */ + protected SymbolTable fSymbolTable; + + + // data + + /** Locale. */ + protected Locale fLocale; + + /** Components. */ + protected ArrayList fComponents; + + // handlers + + /** The document handler. */ + protected XMLDocumentHandler fDocumentHandler; + + /** The DTD handler. */ + protected XMLDTDHandler fDTDHandler; + + /** The DTD content model handler. */ + protected XMLDTDContentModelHandler fDTDContentModelHandler; + + /** Last component in the document pipeline */ + protected XMLDocumentSource fLastComponent; + + // + // Constructors + // + + /** Default Constructor. */ + protected BasicParserConfiguration() { + this(null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + protected BasicParserConfiguration(SymbolTable symbolTable) { + this(symbolTable, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table + * and parent settings. + * + * @param symbolTable The symbol table to use. + * @param parentSettings The parent settings. + */ + protected BasicParserConfiguration(SymbolTable symbolTable, + XMLComponentManager parentSettings) { + super(parentSettings); + + // create a vector to hold all the components in use + fComponents = new ArrayList(); + + // create storage for recognized features and properties + fRecognizedFeatures = new ArrayList(); + fRecognizedProperties = new ArrayList(); + + // create table for features and properties + fFeatures = new HashMap(); + fProperties = new HashMap(); + + // add default recognized features + final String[] recognizedFeatures = { + PARSER_SETTINGS, + VALIDATION, + NAMESPACES, + EXTERNAL_GENERAL_ENTITIES, + EXTERNAL_PARAMETER_ENTITIES, + }; + addRecognizedFeatures(recognizedFeatures); + fFeatures.put(PARSER_SETTINGS, Boolean.TRUE); + // set state for default features + fFeatures.put(VALIDATION, Boolean.FALSE); + fFeatures.put(NAMESPACES, Boolean.TRUE); + fFeatures.put(EXTERNAL_GENERAL_ENTITIES, Boolean.TRUE); + fFeatures.put(EXTERNAL_PARAMETER_ENTITIES, Boolean.TRUE); + + // add default recognized properties + final String[] recognizedProperties = { + XML_STRING, + SYMBOL_TABLE, + ERROR_HANDLER, + ENTITY_RESOLVER, + }; + addRecognizedProperties(recognizedProperties); + + if (symbolTable == null) { + symbolTable = new SymbolTable(); + } + fSymbolTable = symbolTable; + fProperties.put(SYMBOL_TABLE, fSymbolTable); + + } // (SymbolTable) + + /** + * Adds a component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addComponent(XMLComponent component) { + + // don't add a component more than once + if (fComponents.contains(component)) { + return; + } + fComponents.add(component); + + // register component's recognized features + String[] recognizedFeatures = component.getRecognizedFeatures(); + addRecognizedFeatures(recognizedFeatures); + + // register component's recognized properties + String[] recognizedProperties = component.getRecognizedProperties(); + addRecognizedProperties(recognizedProperties); + + // set default values + if (recognizedFeatures != null) { + for (int i = 0; i < recognizedFeatures.length; i++) { + String featureId = recognizedFeatures[i]; + Boolean state = component.getFeatureDefault(featureId); + if (state != null) { + super.setFeature(featureId, state.booleanValue()); + } + } + } + if (recognizedProperties != null) { + for (int i = 0; i < recognizedProperties.length; i++) { + String propertyId = recognizedProperties[i]; + Object value = component.getPropertyDefault(propertyId); + if (value != null) { + super.setProperty(propertyId, value); + } + } + } + + } // addComponent(XMLComponent) + + // + // XMLParserConfiguration methods + // + + /** + * Parse an XML document. + *

        + * The parser can use this method to instruct this configuration + * to begin parsing an XML document from any valid input source + * (a character stream, a byte stream, or a URI). + *

        + * Parsers may not invoke this method while a parse is in progress. + * Once a parse is complete, the parser may then parse another XML + * document. + *

        + * This method is synchronous: it will not return until parsing + * has ended. If a client application wants to terminate + * parsing early, it should throw an exception. + * + * @param inputSource The input source for the top-level of the + * XML document. + * + * @exception XNIException Any XNI exception, possibly wrapping + * another exception. + * @exception IOException An IO exception from the parser, possibly + * from a byte stream or character stream + * supplied by the parser. + */ + public abstract void parse(XMLInputSource inputSource) + throws XNIException, IOException; + + /** + * Sets the document handler on the last component in the pipeline + * to receive information about the document. + * + * @param documentHandler The document handler. + */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + if (fLastComponent != null) { + fLastComponent.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler !=null){ + fDocumentHandler.setDocumentSource(fLastComponent); + } + } + } // setDocumentHandler(XMLDocumentHandler) + + /** Returns the registered document handler. */ + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } // getDocumentHandler():XMLDocumentHandler + + /** + * Sets the DTD handler. + * + * @param dtdHandler The DTD handler. + */ + public void setDTDHandler(XMLDTDHandler dtdHandler) { + fDTDHandler = dtdHandler; + } // setDTDHandler(XMLDTDHandler) + + /** Returns the registered DTD handler. */ + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } // getDTDHandler():XMLDTDHandler + + /** + * Sets the DTD content model handler. + * + * @param handler The DTD content model handler. + */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) { + fDTDContentModelHandler = handler; + } // setDTDContentModelHandler(XMLDTDContentModelHandler) + + /** Returns the registered DTD content model handler. */ + public XMLDTDContentModelHandler getDTDContentModelHandler() { + return fDTDContentModelHandler; + } // getDTDContentModelHandler():XMLDTDContentModelHandler + + /** + * Sets the resolver used to resolve external entities. The EntityResolver + * interface supports resolution of public and system identifiers. + * + * @param resolver The new entity resolver. Passing a null value will + * uninstall the currently installed resolver. + */ + public void setEntityResolver(XMLEntityResolver resolver) { + // REVISIT: Should this be a property? + fProperties.put(ENTITY_RESOLVER, resolver); + } // setEntityResolver(XMLEntityResolver) + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public XMLEntityResolver getEntityResolver() { + // REVISIT: Should this be a property? + return (XMLEntityResolver)fProperties.get(ENTITY_RESOLVER); + } // getEntityResolver():XMLEntityResolver + + /** + * 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 errorHandler The error handler. + * @exception java.lang.NullPointerException If the handler + * argument is null. + * @see #getErrorHandler + */ + public void setErrorHandler(XMLErrorHandler errorHandler) { + // REVISIT: Should this be a property? + fProperties.put(ERROR_HANDLER, errorHandler); + } // setErrorHandler(XMLErrorHandler) + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public XMLErrorHandler getErrorHandler() { + // REVISIT: Should this be a property? + return (XMLErrorHandler)fProperties.get(ERROR_HANDLER); + } // getErrorHandler():XMLErrorHandler + + /** + * Set the state of a feature. + * + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + + // forward to every component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.setFeature(featureId, state); + } + // save state if noone "objects" + super.setFeature(featureId, state); + + } // setFeature(String,boolean) + + /** + * setProperty + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // forward to every component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.setProperty(propertyId, value); + } + + // store value if noone "objects" + super.setProperty(propertyId, value); + + } // setProperty(String,Object) + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException { + fLocale = locale; + } // setLocale(Locale) + + /** Returns the locale. */ + public Locale getLocale() { + return fLocale; + } // getLocale():Locale + + // + // Protected methods + // + + /** + * reset all components before parsing and namespace context + */ + protected void reset() throws XNIException { + + // reset every component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.reset(this); + } + + } // reset() + + /** + * Check a property. If the property is known and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known or supported. + */ + protected void checkProperty(String propertyId) + throws XMLConfigurationException { + + // special cases + if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); + + // + // http://xml.org/sax/properties/xml-string + // Value type: String + // Access: read-only + // Get the literal string of characters associated with the + // current event. If the parser recognises and supports this + // property but is not currently parsing text, it should return + // null (this is a good way to check for availability before the + // parse begins). + // + if (suffixLength == Constants.XML_STRING_PROPERTY.length() && + propertyId.endsWith(Constants.XML_STRING_PROPERTY)) { + // REVISIT - we should probably ask xml-dev for a precise + // definition of what this is actually supposed to return, and + // in exactly which circumstances. + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, propertyId); + } + } + + // check property + super.checkProperty(propertyId); + + } // checkProperty(String) + + + /** + * Check a feature. If feature is know and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) + throws XMLConfigurationException { + + // + // Xerces Features + // + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // special performance feature: no one by component manager is allowed to set it + // + if (suffixLength == Constants.PARSER_SETTINGS.length() && + featureId.endsWith(Constants.PARSER_SETTINGS)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + } + + super.checkFeature(featureId); + + } // checkFeature(String) + + +} // class BasicParserConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/CachingParserPool.java b/resources/xerces2-j-src/org/apache/xerces/parsers/CachingParserPool.java new file mode 100644 index 0000000..4f4f4d5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/CachingParserPool.java @@ -0,0 +1,427 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.util.ShadowedSymbolTable; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.SynchronizedSymbolTable; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; + +/** + * A parser pool that enables caching of grammars. The caching parser + * pool is constructed with a specific symbol table and grammar pool + * that has already been populated with the grammars used by the + * application. + *

        + * Once the caching parser pool is constructed, specific parser + * instances are created by calling the appropriate factory method + * on the parser pool. + *

        + * Note: There is a performance penalty for using + * a caching parser pool due to thread safety. Access to the symbol + * table and grammar pool must be synchronized to ensure the safe + * operation of the symbol table and grammar pool. + *

        + * Note: If performance is critical, then another + * mechanism needs to be used instead of the caching parser pool. + * One approach would be to create parser instances that do not + * share these structures. Instead, each instance would get its + * own copy to use while parsing. This avoids the synchronization + * overhead at the expense of more memory and the time required + * to copy the structures for each new parser instance. And even + * when a parser instance is re-used, there is a potential for a + * memory leak due to new symbols being added to the symbol table + * over time. In other words, always take caution to make sure + * that your application is thread-safe and avoids leaking memory. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class CachingParserPool { + + // + // Constants + // + + /** Default shadow symbol table (false). */ + public static final boolean DEFAULT_SHADOW_SYMBOL_TABLE = false; + + /** Default shadow grammar pool (false). */ + public static final boolean DEFAULT_SHADOW_GRAMMAR_POOL = false; + + // + // Data + // + + /** + * Symbol table. The symbol table that the caching parser pool is + * constructed with is automatically wrapped in a synchronized + * version for thread-safety. + */ + protected SymbolTable fSynchronizedSymbolTable; + + /** + * Grammar pool. The grammar pool that the caching parser pool is + * constructed with is automatically wrapped in a synchronized + * version for thread-safety. + */ + protected XMLGrammarPool fSynchronizedGrammarPool; + + /** + * Shadow the symbol table for new parser instances. If true, + * new parser instances use shadow copies of the main symbol + * table and are not allowed to add new symbols to the main + * symbol table. New symbols are added to the shadow symbol + * table and are local to the parser instance. + */ + protected boolean fShadowSymbolTable = DEFAULT_SHADOW_SYMBOL_TABLE; + + /** + * Shadow the grammar pool for new parser instances. If true, + * new parser instances use shadow copies of the main grammar + * pool and are not allowed to add new grammars to the main + * grammar pool. New grammars are added to the shadow grammar + * pool and are local to the parser instance. + */ + protected boolean fShadowGrammarPool = DEFAULT_SHADOW_GRAMMAR_POOL; + + // + // Constructors + // + + /** Default constructor. */ + public CachingParserPool() { + this(new SymbolTable(), new XMLGrammarPoolImpl()); + } // () + + /** + * Constructs a caching parser pool with the specified symbol table + * and grammar pool. + * + * @param symbolTable The symbol table. + * @param grammarPool The grammar pool. + */ + public CachingParserPool(SymbolTable symbolTable, XMLGrammarPool grammarPool) { + fSynchronizedSymbolTable = new SynchronizedSymbolTable(symbolTable); + fSynchronizedGrammarPool = new SynchronizedGrammarPool(grammarPool); + } // (SymbolTable,XMLGrammarPool) + + // + // Public methods + // + + /** Returns the symbol table. */ + public SymbolTable getSymbolTable() { + return fSynchronizedSymbolTable; + } // getSymbolTable():SymbolTable + + /** Returns the grammar pool. */ + public XMLGrammarPool getXMLGrammarPool() { + return fSynchronizedGrammarPool; + } // getXMLGrammarPool():XMLGrammarPool + + // setters and getters + + /** + * Sets whether new parser instance receive shadow copies of the + * main symbol table. + * + * @param shadow If true, new parser instances use shadow copies + * of the main symbol table and are not allowed to + * add new symbols to the main symbol table. New + * symbols are added to the shadow symbol table and + * are local to the parser instance. If false, new + * parser instances are allowed to add new symbols + * to the main symbol table. + */ + public void setShadowSymbolTable(boolean shadow) { + fShadowSymbolTable = shadow; + } // setShadowSymbolTable(boolean) + + // factory methods + + /** Creates a new DOM parser. */ + public DOMParser createDOMParser() { + SymbolTable symbolTable = fShadowSymbolTable + ? new ShadowedSymbolTable(fSynchronizedSymbolTable) + : fSynchronizedSymbolTable; + XMLGrammarPool grammarPool = fShadowGrammarPool + ? new ShadowedGrammarPool(fSynchronizedGrammarPool) + : fSynchronizedGrammarPool; + return new DOMParser(symbolTable, grammarPool); + } // createDOMParser():DOMParser + + /** Creates a new SAX parser. */ + public SAXParser createSAXParser() { + SymbolTable symbolTable = fShadowSymbolTable + ? new ShadowedSymbolTable(fSynchronizedSymbolTable) + : fSynchronizedSymbolTable; + XMLGrammarPool grammarPool = fShadowGrammarPool + ? new ShadowedGrammarPool(fSynchronizedGrammarPool) + : fSynchronizedGrammarPool; + return new SAXParser(symbolTable, grammarPool); + } // createSAXParser():SAXParser + + // + // Classes + // + + /** + * Synchronized grammar pool. + * + * @author Andy Clark, IBM + */ + public static final class SynchronizedGrammarPool + implements XMLGrammarPool { + + // + // Data + // + + /** Main grammar pool. */ + private XMLGrammarPool fGrammarPool; + + // + // Constructors + // + + /** Constructs a synchronized grammar pool. */ + public SynchronizedGrammarPool(XMLGrammarPool grammarPool) { + fGrammarPool = grammarPool; + } // (XMLGrammarPool) + + // + // GrammarPool methods + // + + // retrieve the initial set of grammars for the validator + // to work with. + // REVISIT: does this need to be synchronized since it's just reading? + // @param grammarType type of the grammars to be retrieved. + // @return the initial grammar set the validator may place in its "bucket" + public Grammar [] retrieveInitialGrammarSet(String grammarType ) { + synchronized (fGrammarPool) { + return fGrammarPool.retrieveInitialGrammarSet(grammarType); + } + } // retrieveInitialGrammarSet(String): Grammar[] + + // retrieve a particular grammar. + // REVISIT: does this need to be synchronized since it's just reading? + // @param gDesc description of the grammar to be retrieved + // @return Grammar corresponding to gDesc, or null if none exists. + public Grammar retrieveGrammar(XMLGrammarDescription gDesc) { + synchronized (fGrammarPool) { + return fGrammarPool.retrieveGrammar(gDesc); + } + } // retrieveGrammar(XMLGrammarDesc): Grammar + + // give the grammarPool the option of caching these grammars. + // This certainly must be synchronized. + // @param grammarType The type of the grammars to be cached. + // @param grammars the Grammars that may be cached (unordered, Grammars previously + // given to the validator may be included). + public void cacheGrammars(String grammarType, Grammar[] grammars) { + synchronized (fGrammarPool) { + fGrammarPool.cacheGrammars(grammarType, grammars); + } + } // cacheGrammars(String, Grammar[]); + + /** lock the grammar pool */ + public void lockPool() { + synchronized (fGrammarPool) { + fGrammarPool.lockPool(); + } + } // lockPool() + + /** clear the grammar pool */ + public void clear() { + synchronized (fGrammarPool) { + fGrammarPool.clear(); + } + } // lockPool() + + /** unlock the grammar pool */ + public void unlockPool() { + synchronized (fGrammarPool) { + fGrammarPool.unlockPool(); + } + } // unlockPool() + + /*** + * Methods corresponding to original (pre Xerces2.0.0final) + * grammarPool have been commented out. + */ + /** + * Puts the specified grammar into the grammar pool. + * + * @param key Key to associate with grammar. + * @param grammar Grammar object. + */ + /****** + public void putGrammar(String key, Grammar grammar) { + synchronized (fGrammarPool) { + fGrammarPool.putGrammar(key, grammar); + } + } // putGrammar(String,Grammar) + *******/ + + /** + * Returns the grammar associated to the specified key. + * + * @param key The key of the grammar. + */ + /********** + public Grammar getGrammar(String key) { + synchronized (fGrammarPool) { + return fGrammarPool.getGrammar(key); + } + } // getGrammar(String):Grammar + ***********/ + + /** + * Removes the grammar associated to the specified key from the + * grammar pool and returns the removed grammar. + * + * @param key The key of the grammar. + */ + /********** + public Grammar removeGrammar(String key) { + synchronized (fGrammarPool) { + return fGrammarPool.removeGrammar(key); + } + } // removeGrammar(String):Grammar + ******/ + + /** + * Returns true if the grammar pool contains a grammar associated + * to the specified key. + * + * @param key The key of the grammar. + */ + /********** + public boolean containsGrammar(String key) { + synchronized (fGrammarPool) { + return fGrammarPool.containsGrammar(key); + } + } // containsGrammar(String):boolean + ********/ + + } // class SynchronizedGrammarPool + + /** + * Shadowed grammar pool. + * This class is predicated on the existence of a concrete implementation; + * so using our own doesn't seem to bad an idea. + * + * @author Andy Clark, IBM + * @author Neil Graham, IBM + */ + public static final class ShadowedGrammarPool + extends XMLGrammarPoolImpl { + + // + // Data + // + + /** Main grammar pool. */ + private XMLGrammarPool fGrammarPool; + + // + // Constructors + // + + /** Constructs a shadowed grammar pool. */ + public ShadowedGrammarPool(XMLGrammarPool grammarPool) { + fGrammarPool = grammarPool; + } // (GrammarPool) + + // + // GrammarPool methods + // + + /** + * Retrieve the initial set of grammars for the validator to work with. + * REVISIT: does this need to be synchronized since it's just reading? + * + * @param grammarType Type of the grammars to be retrieved. + * @return The initial grammar set the validator may place in its "bucket" + */ + public Grammar [] retrieveInitialGrammarSet(String grammarType ) { + Grammar [] grammars = super.retrieveInitialGrammarSet(grammarType); + if (grammars != null) return grammars; + return fGrammarPool.retrieveInitialGrammarSet(grammarType); + } // retrieveInitialGrammarSet(String): Grammar[] + + /** + * Retrieve a particular grammar. + * REVISIT: does this need to be synchronized since it's just reading? + * + * @param gDesc Description of the grammar to be retrieved + * @return Grammar corresponding to gDesc, or null if none exists. + */ + public Grammar retrieveGrammar(XMLGrammarDescription gDesc) { + Grammar g = super.retrieveGrammar(gDesc); + if(g != null) return g; + return fGrammarPool.retrieveGrammar(gDesc); + } // retrieveGrammar(XMLGrammarDesc): Grammar + + /** + * Give the grammarPool the option of caching these grammars. + * This certainly must be synchronized. + * + * @param grammarType The type of the grammars to be cached. + * @param grammars The Grammars that may be cached (unordered, Grammars previously + * given to the validator may be included). + */ + public void cacheGrammars(String grammarType, Grammar[] grammars) { + // better give both grammars a shot... + super.cacheGrammars(grammarType, grammars); + fGrammarPool.cacheGrammars(grammarType, grammars); + } // cacheGrammars(grammarType, Grammar[]); + + /** + * Returns the grammar associated to the specified description. + * + * @param desc The description of the grammar. + */ + public Grammar getGrammar(XMLGrammarDescription desc) { + + if (super.containsGrammar(desc)) { + return super.getGrammar(desc); + } + return null; + + } // getGrammar(XMLGrammarDescription):Grammar + + /** + * Returns true if the grammar pool contains a grammar associated + * to the specified description. + * + * @param desc The description of the grammar. + */ + public boolean containsGrammar(XMLGrammarDescription desc) { + return super.containsGrammar(desc); + } // containsGrammar(XMLGrammarDescription):boolean + + } // class ShadowedGrammarPool + +} // class CachingParserPool diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/DOMASBuilderImpl.java b/resources/xerces2-j-src/org/apache/xerces/parsers/DOMASBuilderImpl.java new file mode 100644 index 0000000..a31bbfa --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/DOMASBuilderImpl.java @@ -0,0 +1,295 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.util.Vector; + +import org.apache.xerces.dom.ASModelImpl; +import org.apache.xerces.dom3.as.ASModel; +import org.apache.xerces.dom3.as.DOMASBuilder; +import org.apache.xerces.dom3.as.DOMASException; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.XSGrammarBucket; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.w3c.dom.ls.LSInput; + +/** + * This is Abstract Schema DOM Builder class. It extends the DOMParserImpl + * class. Provides support for preparsing schemas. + * + * @deprecated + * @author Pavani Mukthipudi, Sun Microsystems Inc. + * @author Neil Graham, IBM + * @version $Id$ + * + */ + +public class DOMASBuilderImpl + extends DOMParserImpl implements DOMASBuilder { + + // + // Constants + // + + // Feature ids + + protected static final String SCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + + // Property ids + + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + + // + // Data + // + + protected XSGrammarBucket fGrammarBucket; + + protected ASModelImpl fAbstractSchema; + + // + // Constructors + // + + /** + * Constructs a DOM Builder using the dtd/xml schema parser configuration. + */ + public DOMASBuilderImpl() { + super(new XMLGrammarCachingConfiguration()); + } // + + /** + * Constructs a DOM Builder using the specified parser configuration. + * We must demand that the configuration extend XMLGrammarCachingConfiguration to make + * sure all relevant methods/features are available. + */ + public DOMASBuilderImpl(XMLGrammarCachingConfiguration config) { + super(config); + } // (XMLParserConfiguration) + + /** + * Constructs a DOM Builder using the specified symbol table. + */ + public DOMASBuilderImpl(SymbolTable symbolTable) { + super(new XMLGrammarCachingConfiguration(symbolTable)); + } // (SymbolTable) + + + /** + * Constructs a DOM Builder using the specified symbol table and + * grammar pool. + * The grammarPool implementation should extent the default + * implementation; otherwise, correct functioning of this class may + * not occur. + */ + public DOMASBuilderImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool) { + super(new XMLGrammarCachingConfiguration(symbolTable, grammarPool)); + } + + // + // DOMASBuilder methods + // + + /** + * Associate an ASModel with a document instance. This + * ASModel will be used by the " + * validate-if-schema" and " + * datatype-normalization" options during the load of a new + * Document. + */ + public ASModel getAbstractSchema() { + return fAbstractSchema; + } + + /** + * Associate an ASModel with a document instance. This + * ASModel will be used by the " + * validate-if-schema" and " + * datatype-normalization" options during the load of a new + * Document. + */ + public void setAbstractSchema(ASModel abstractSchema) { + + // since the ASModel associated with this object is an attribute + // according to the DOM IDL, we must obliterate anything + // that was set before, rather than adding to it. + // REVISIT: so shouldn't we attempt to clear the + // grammarPool before adding stuff to it? - NG + fAbstractSchema = (ASModelImpl)abstractSchema; + + // make sure the GrammarPool is properly initialized. + XMLGrammarPool grammarPool = (XMLGrammarPool)fConfiguration.getProperty(StandardParserConfiguration.XMLGRAMMAR_POOL); + // if there is no grammar pool, create one + // REVISIT: ASBuilder should always create one. + if (grammarPool == null) { + // something's not right in this situation... + grammarPool = new XMLGrammarPoolImpl(); + fConfiguration.setProperty(StandardParserConfiguration.XMLGRAMMAR_POOL, + grammarPool); + } + if (fAbstractSchema != null) { + initGrammarPool(fAbstractSchema, grammarPool); + } + } + + /** + * Parse a Abstract Schema from a location identified by an URI. + * + * @param uri The location of the Abstract Schema to be read. + * @return The newly created Abstract Schema. + * @exception DOMASException + * Exceptions raised by parseASURI() originate with the + * installed ErrorHandler, and thus depend on the implementation of + * the DOMErrorHandler interfaces. The default error + * handlers will raise a DOMASException if any form of + * Abstract Schema inconsistencies or warning occurs during the parse, + * but application defined errorHandlers are not required to do so. + *
        WRONG_MIME_TYPE_ERR: Raised when mimeTypeCheck is + * true and the inputsource has an incorrect MIME Type. + * See attribute mimeTypeCheck. + * @exception DOMSystemException + * Exceptions raised by parseURI() originate with the + * installed ErrorHandler, and thus depend on the implementation of + * the DOMErrorHandler interfaces. The default error + * handlers will raise a DOMSystemException if any form I/O or other + * system error occurs during the parse, but application defined error + * handlers are not required to do so. + */ + public ASModel parseASURI(String uri) + throws DOMASException, Exception { + XMLInputSource source = new XMLInputSource(null, uri, null); + return parseASInputSource(source); + } + + /** + * Parse a Abstract Schema from a location identified by an + * LSInput. + * + * @param is The LSInput from which the source + * Abstract Schema is to be read. + * @return The newly created ASModel. + * @exception DOMASException + * Exceptions raised by parseASURI() originate with the + * installed ErrorHandler, and thus depend on the implementation of + * the DOMErrorHandler interfaces. The default error + * handlers will raise a DOMASException if any form of + * Abstract Schema inconsistencies or warning occurs during the parse, + * but application defined errorHandlers are not required to do so. + *
        WRONG_MIME_TYPE_ERR: Raised when mimeTypeCheck is + * true and the inputsource has an incorrect MIME Type. See attribute + * mimeTypeCheck. + * @exception DOMSystemException + * Exceptions raised by parseURI() originate with the + * installed ErrorHandler, and thus depend on the implementation of + * the DOMErrorHandler interfaces. The default error + * handlers will raise a DOMSystemException if any form I/O or other + * system error occurs during the parse, but application defined error + * handlers are not required to do so. + */ + public ASModel parseASInputSource(LSInput is) + throws DOMASException, Exception { + + // need to wrap the LSInput with an XMLInputSource + XMLInputSource xis = this.dom2xmlInputSource(is); + try { + return parseASInputSource(xis); + } + catch (XNIException e) { + Exception ex = e.getException(); + throw ex; + } + } + + ASModel parseASInputSource(XMLInputSource is) throws Exception { + + if (fGrammarBucket == null) { + fGrammarBucket = new XSGrammarBucket(); + } + + initGrammarBucket(); + + // actually do the parse: + // save some casting + XMLGrammarCachingConfiguration gramConfig = (XMLGrammarCachingConfiguration)fConfiguration; + // ensure grammarPool doesn't absorb grammars while it's parsing + gramConfig.lockGrammarPool(); + SchemaGrammar grammar = gramConfig.parseXMLSchema(is); + gramConfig.unlockGrammarPool(); + + ASModelImpl newAsModel = null; + if (grammar != null) { + newAsModel = new ASModelImpl(); + fGrammarBucket.putGrammar (grammar, true); + addGrammars(newAsModel, fGrammarBucket); + } + return newAsModel; + } + + // put all the grammars we have access to in the GrammarBucket + private void initGrammarBucket() { + fGrammarBucket.reset(); + if (fAbstractSchema != null) + initGrammarBucketRecurse(fAbstractSchema); + } + private void initGrammarBucketRecurse(ASModelImpl currModel) { + if(currModel.getGrammar() != null) { + fGrammarBucket.putGrammar(currModel.getGrammar()); + } + for(int i = 0; i < currModel.getInternalASModels().size(); i++) { + ASModelImpl nextModel = (ASModelImpl)(currModel.getInternalASModels().elementAt(i)); + initGrammarBucketRecurse(nextModel); + } + } + + private void addGrammars(ASModelImpl model, XSGrammarBucket grammarBucket) { + SchemaGrammar [] grammarList = grammarBucket.getGrammars(); + for(int i=0; i(XMLParserConfiguration) + + /** + * Constructs a DOM parser using the dtd/xml schema parser configuration. + */ + public DOMParser() { + this(null, null); + } // () + + /** + * Constructs a DOM parser using the specified symbol table. + */ + public DOMParser(SymbolTable symbolTable) { + this(symbolTable, null); + } // (SymbolTable) + + + /** + * Constructs a DOM parser using the specified symbol table and + * grammar pool. + */ + public DOMParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) { + super((XMLParserConfiguration)ObjectFactory.createObject( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration" + )); + + // set properties + fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES); + if (symbolTable != null) { + fConfiguration.setProperty(SYMBOL_TABLE, symbolTable); + } + if (grammarPool != null) { + fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool); + } + + } // (SymbolTable,XMLGrammarPool) + + // + // XMLReader methods + // + + /** + * Parses the input source specified by the given system identifier. + *

        + * This method is equivalent to the following: + *

        +     *     parse(new InputSource(systemId));
        +     * 
        + * + * @param systemId The system identifier (URI). + * + * @exception org.xml.sax.SAXException Throws exception on SAX error. + * @exception java.io.IOException Throws exception on i/o error. + */ + public void parse(String systemId) throws SAXException, IOException { + + // parse document + XMLInputSource source = new XMLInputSource(null, systemId, null); + try { + parse(source); + } + + // wrap XNI exceptions as SAX exceptions + catch (XMLParseException e) { + Exception ex = e.getException(); + if (ex == null || ex instanceof CharConversionException) { + // must be a parser exception; mine it for locator info and throw + // a SAXParseException + LocatorImpl locatorImpl = new LocatorImpl(); + locatorImpl.setPublicId(e.getPublicId()); + locatorImpl.setSystemId(e.getExpandedSystemId()); + locatorImpl.setLineNumber(e.getLineNumber()); + locatorImpl.setColumnNumber(e.getColumnNumber()); + throw (ex == null) ? + new SAXParseException(e.getMessage(), locatorImpl) : + new SAXParseException(e.getMessage(), locatorImpl, ex); + } + if (ex instanceof SAXException) { + // why did we create an XMLParseException? + throw (SAXException)ex; + } + if (ex instanceof IOException) { + throw (IOException)ex; + } + throw new SAXException(ex); + } + catch (XNIException e) { + e.printStackTrace(); + Exception ex = e.getException(); + if (ex == null) { + throw new SAXException(e.getMessage()); + } + if (ex instanceof SAXException) { + throw (SAXException)ex; + } + if (ex instanceof IOException) { + throw (IOException)ex; + } + throw new SAXException(ex); + } + + } // parse(String) + + /** + * parse + * + * @param inputSource + * + * @exception org.xml.sax.SAXException + * @exception java.io.IOException + */ + public void parse(InputSource inputSource) + throws SAXException, IOException { + + // parse document + try { + XMLInputSource xmlInputSource = + new XMLInputSource(inputSource.getPublicId(), + inputSource.getSystemId(), + null); + xmlInputSource.setByteStream(inputSource.getByteStream()); + xmlInputSource.setCharacterStream(inputSource.getCharacterStream()); + xmlInputSource.setEncoding(inputSource.getEncoding()); + parse(xmlInputSource); + } + + // wrap XNI exceptions as SAX exceptions + catch (XMLParseException e) { + Exception ex = e.getException(); + if (ex == null || ex instanceof CharConversionException) { + // must be a parser exception; mine it for locator info and throw + // a SAXParseException + LocatorImpl locatorImpl = new LocatorImpl(); + locatorImpl.setPublicId(e.getPublicId()); + locatorImpl.setSystemId(e.getExpandedSystemId()); + locatorImpl.setLineNumber(e.getLineNumber()); + locatorImpl.setColumnNumber(e.getColumnNumber()); + throw (ex == null) ? + new SAXParseException(e.getMessage(), locatorImpl) : + new SAXParseException(e.getMessage(), locatorImpl, ex); + } + if (ex instanceof SAXException) { + // why did we create an XMLParseException? + throw (SAXException)ex; + } + if (ex instanceof IOException) { + throw (IOException)ex; + } + throw new SAXException(ex); + } + catch (XNIException e) { + Exception ex = e.getException(); + if (ex == null) { + throw new SAXException(e.getMessage()); + } + if (ex instanceof SAXException) { + throw (SAXException)ex; + } + if (ex instanceof IOException) { + throw (IOException)ex; + } + throw new SAXException(ex); + } + + } // parse(InputSource) + + /** + * Sets the resolver used to resolve external entities. The EntityResolver + * interface supports resolution of public and system identifiers. + * + * @param resolver The new entity resolver. Passing a null value will + * uninstall the currently installed resolver. + */ + public void setEntityResolver(EntityResolver resolver) { + + try { + XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER); + if (fUseEntityResolver2 && resolver instanceof EntityResolver2) { + if (xer instanceof EntityResolver2Wrapper) { + EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer; + er2w.setEntityResolver((EntityResolver2) resolver); + } + else { + fConfiguration.setProperty(ENTITY_RESOLVER, + new EntityResolver2Wrapper((EntityResolver2) resolver)); + } + } + else { + if (xer instanceof EntityResolverWrapper) { + EntityResolverWrapper erw = (EntityResolverWrapper) xer; + erw.setEntityResolver(resolver); + } + else { + fConfiguration.setProperty(ENTITY_RESOLVER, + new EntityResolverWrapper(resolver)); + } + } + } + catch (XMLConfigurationException e) { + // do nothing + } + + } // setEntityResolver(EntityResolver) + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public EntityResolver getEntityResolver() { + + EntityResolver entityResolver = null; + try { + XMLEntityResolver xmlEntityResolver = + (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER); + if (xmlEntityResolver != null) { + if (xmlEntityResolver instanceof EntityResolverWrapper) { + entityResolver = + ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver(); + } + else if (xmlEntityResolver instanceof EntityResolver2Wrapper) { + entityResolver = + ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver(); + } + } + } + catch (XMLConfigurationException e) { + // do nothing + } + return entityResolver; + + } // getEntityResolver():EntityResolver + + /** + * 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 errorHandler The error handler. + * @exception java.lang.NullPointerException If the handler + * argument is null. + * @see #getErrorHandler + */ + public void setErrorHandler(ErrorHandler errorHandler) { + + try { + XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER); + if (xeh instanceof ErrorHandlerWrapper) { + ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh; + ehw.setErrorHandler(errorHandler); + } + else { + fConfiguration.setProperty(ERROR_HANDLER, + new ErrorHandlerWrapper(errorHandler)); + } + } + catch (XMLConfigurationException e) { + // do nothing + } + + } // setErrorHandler(ErrorHandler) + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public ErrorHandler getErrorHandler() { + + ErrorHandler errorHandler = null; + try { + XMLErrorHandler xmlErrorHandler = + (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER); + if (xmlErrorHandler != null && + xmlErrorHandler instanceof ErrorHandlerWrapper) { + errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler(); + } + } + catch (XMLConfigurationException e) { + // do nothing + } + return errorHandler; + + } // getErrorHandler():ErrorHandler + + /** + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception SAXNotRecognizedException If the + * requested feature is not known. + * @exception SAXNotSupportedException If the + * requested feature is known, but the requested + * state is not supported. + */ + public void setFeature(String featureId, boolean state) + throws SAXNotRecognizedException, SAXNotSupportedException { + + try { + + // http://xml.org/sax/features/use-entity-resolver2 + // controls whether the methods of an object implementing + // org.xml.sax.ext.EntityResolver2 will be used by the parser. + // + if (featureId.equals(USE_ENTITY_RESOLVER2)) { + if (state != fUseEntityResolver2) { + fUseEntityResolver2 = state; + // Refresh EntityResolver wrapper. + setEntityResolver(getEntityResolver()); + } + return; + } + + // + // Default handling + // + + fConfiguration.setFeature(featureId, state); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + + } // setFeature(String,boolean) + + /** + * Query the state of a feature. + * + * Query the current state of any feature in a SAX2 parser. The + * parser might not recognize the feature. + * + * @param featureId The unique identifier (URI) of the feature + * being set. + * @return The current state of the feature. + * @exception org.xml.sax.SAXNotRecognizedException If the + * requested feature is not known. + * @exception SAXNotSupportedException If the + * requested feature is known but not supported. + */ + public boolean getFeature(String featureId) + throws SAXNotRecognizedException, SAXNotSupportedException { + + try { + + // http://xml.org/sax/features/use-entity-resolver2 + // controls whether the methods of an object implementing + // org.xml.sax.ext.EntityResolver2 will be used by the parser. + // + if (featureId.equals(USE_ENTITY_RESOLVER2)) { + return fUseEntityResolver2; + } + + // + // Default handling + // + + return fConfiguration.getFeature(featureId); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "feature-not-supported", new Object [] {identifier})); + } + } + + } // getFeature(String):boolean + + /** + * Set the value of any property in a SAX2 parser. The parser + * might not recognize the property, and if it does recognize + * it, it might not support the requested value. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * @param value The value to which the property is being set. + * + * @exception SAXNotRecognizedException If the + * requested property is not known. + * @exception SAXNotSupportedException If the + * requested property is known, but the requested + * value is not supported. + */ + public void setProperty(String propertyId, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + + try { + fConfiguration.setProperty(propertyId, value); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + + } // setProperty(String,Object) + + /** + * Query the value of a property. + * + * Return the current value of a property in a SAX2 parser. + * The parser might not recognize the property. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * @return The current value of the property. + * @exception org.xml.sax.SAXNotRecognizedException If the + * requested property is not known. + * @exception SAXNotSupportedException If the + * requested property is known but not supported. + */ + public Object getProperty(String propertyId) + throws SAXNotRecognizedException, SAXNotSupportedException { + + if (propertyId.equals(CURRENT_ELEMENT_NODE)) { + boolean deferred = false; + try { + deferred = getFeature(DEFER_NODE_EXPANSION); + } + catch (XMLConfigurationException e){ + // ignore + } + if (deferred) { + throw new SAXNotSupportedException( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "CannotQueryDeferredNode", null)); + } + return (fCurrentNode!=null && + fCurrentNode.getNodeType() == Node.ELEMENT_NODE)? fCurrentNode:null; + } + + try { + return fConfiguration.getProperty(propertyId); + } + catch (XMLConfigurationException e) { + String identifier = e.getIdentifier(); + if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { + throw new SAXNotRecognizedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-recognized", new Object [] {identifier})); + } + else { + throw new SAXNotSupportedException( + SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), + "property-not-supported", new Object [] {identifier})); + } + } + + } // getProperty(String):Object + + /** + * Returns this parser's XMLParserConfiguration. + */ + public XMLParserConfiguration getXMLParserConfiguration() { + return fConfiguration; + } // getXMLParserConfiguration():XMLParserConfiguration + +} // class DOMParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/DOMParserImpl.java b/resources/xerces2-j-src/org/apache/xerces/parsers/DOMParserImpl.java new file mode 100644 index 0000000..8ecd3b0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/DOMParserImpl.java @@ -0,0 +1,1420 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Stack; +import java.util.StringTokenizer; + +import org.apache.xerces.dom.DOMErrorImpl; +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.dom.DOMStringListImpl; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.DOMEntityResolverWrapper; +import org.apache.xerces.util.DOMErrorHandlerWrapper; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDContentModelSource; +import org.apache.xerces.xni.parser.XMLDTDSource; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParseException; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSParserFilter; +import org.w3c.dom.ls.LSResourceResolver; +import org.w3c.dom.traversal.NodeFilter; + +/** + * This is Xerces DOM Builder class. It uses the abstract DOM + * parser with a document scanner, a dtd scanner, and a validator, as + * well as a grammar pool. + * + * @author Pavani Mukthipudi, Sun Microsystems Inc. + * @author Elena Litani, IBM + * @author Rahul Srivastava, Sun Microsystems Inc. + * @version $Id$ + */ +public class DOMParserImpl + extends AbstractDOMParser implements LSParser, DOMConfiguration { + + // SAX & Xerces feature ids + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature id: validation. */ + protected static final String VALIDATION_FEATURE = + Constants.SAX_FEATURE_PREFIX+Constants.VALIDATION_FEATURE; + + /** XML Schema validation */ + protected static final String XMLSCHEMA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** XML Schema full checking */ + protected static final String XMLSCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + + /** Dynamic validation */ + protected static final String DYNAMIC_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; + + /** Feature identifier: expose schema normalized value */ + protected static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + + /** Feature identifier: disallow docType Decls. */ + protected static final String DISALLOW_DOCTYPE_DECL_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE; + + /** Feature identifier: honour all schemaLocations */ + protected static final String HONOUR_ALL_SCHEMALOCATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; + + /** Feature identifier: namespace growth */ + protected static final String NAMESPACE_GROWTH = + Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; + + /** Feature identifier: tolerate duplicates */ + protected static final String TOLERATE_DUPLICATES = + Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; + + // internal properties + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + protected static final String PSVI_AUGMENT = + Constants.XERCES_FEATURE_PREFIX +Constants.SCHEMA_AUGMENT_PSVI; + + // + // Data + // + + /** Include namespace declaration attributes in the document. **/ + protected boolean fNamespaceDeclarations = true; + + // REVISIT: this value should be null by default and should be set during creation of + // LSParser + protected String fSchemaType = null; + + protected boolean fBusy = false; + + private boolean abortNow = false; + + private Thread currentThread; + + protected final static boolean DEBUG = false; + + private String fSchemaLocation = null; + private DOMStringList fRecognizedParameters; + + private boolean fNullFilterInUse = false; + private AbortHandler abortHandler = null; + + // + // Constructors + // + + /** + * Constructs a DOM Builder using the standard parser configuration. + */ + public DOMParserImpl (String configuration, String schemaType) { + this ( + (XMLParserConfiguration) ObjectFactory.createObject ( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + configuration)); + if (schemaType != null) { + if (schemaType.equals (Constants.NS_DTD)) { + //Schema validation is false by default and hence there is no + //need to set it to false here. Also, schema validation is + //not a recognized feature for DTDConfiguration's and so + //setting this feature here would result in a Configuration + //Exception. + fConfiguration.setProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, + Constants.NS_DTD); + fSchemaType = Constants.NS_DTD; + } + else if (schemaType.equals (Constants.NS_XMLSCHEMA)) { + // XML Schem validation + fConfiguration.setProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, + Constants.NS_XMLSCHEMA); + } + } + + } + + /** + * Constructs a DOM Builder using the specified parser configuration. + */ + public DOMParserImpl (XMLParserConfiguration config) { + super (config); + + // add recognized features + final String[] domRecognizedFeatures = { + Constants.DOM_CANONICAL_FORM, + Constants.DOM_CDATA_SECTIONS, + Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING, + Constants.DOM_INFOSET, + Constants.DOM_NAMESPACE_DECLARATIONS, + Constants.DOM_SPLIT_CDATA, + Constants.DOM_SUPPORTED_MEDIATYPES_ONLY, + Constants.DOM_CERTIFIED, + Constants.DOM_WELLFORMED, + Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS, + }; + + fConfiguration.addRecognizedFeatures (domRecognizedFeatures); + + // turn off deferred DOM + fConfiguration.setFeature (DEFER_NODE_EXPANSION, false); + + // Set values so that the value of the + // infoset parameter is true (its default value). + // + // true: namespace-declarations, well-formed, + // element-content-whitespace, comments, namespaces + // + // false: validate-if-schema, entities, + // datatype-normalization, cdata-sections + + fConfiguration.setFeature(Constants.DOM_NAMESPACE_DECLARATIONS, true); + fConfiguration.setFeature(Constants.DOM_WELLFORMED, true); + fConfiguration.setFeature(INCLUDE_COMMENTS_FEATURE, true); + fConfiguration.setFeature(INCLUDE_IGNORABLE_WHITESPACE, true); + fConfiguration.setFeature(NAMESPACES, true); + + fConfiguration.setFeature(DYNAMIC_VALIDATION, false); + fConfiguration.setFeature(CREATE_ENTITY_REF_NODES, false); + fConfiguration.setFeature(CREATE_CDATA_NODES_FEATURE, false); + + // set other default values + fConfiguration.setFeature (Constants.DOM_CANONICAL_FORM, false); + fConfiguration.setFeature (Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING, true); + fConfiguration.setFeature (Constants.DOM_SPLIT_CDATA, true); + fConfiguration.setFeature (Constants.DOM_SUPPORTED_MEDIATYPES_ONLY, false); + fConfiguration.setFeature (Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS, true); + + // REVISIT: by default Xerces assumes that input is certified. + // default is different from the one specified in the DOM spec + fConfiguration.setFeature (Constants.DOM_CERTIFIED, true); + + // Xerces datatype-normalization feature is on by default + // This is a recognized feature only for XML Schemas. If the + // configuration doesn't support this feature, ignore it. + try { + fConfiguration.setFeature ( NORMALIZE_DATA, false ); + } + catch (XMLConfigurationException exc) {} + + } // (XMLParserConfiguration) + + /** + * Constructs a DOM Builder using the specified symbol table. + */ + public DOMParserImpl (SymbolTable symbolTable) { + this ( + (XMLParserConfiguration) ObjectFactory.createObject ( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration")); + fConfiguration.setProperty ( + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY, + symbolTable); + } // (SymbolTable) + + + /** + * Constructs a DOM Builder using the specified symbol table and + * grammar pool. + */ + public DOMParserImpl (SymbolTable symbolTable, XMLGrammarPool grammarPool) { + this ( + (XMLParserConfiguration) ObjectFactory.createObject ( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration")); + fConfiguration.setProperty ( + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY, + symbolTable); + fConfiguration.setProperty ( + Constants.XERCES_PROPERTY_PREFIX + + Constants.XMLGRAMMAR_POOL_PROPERTY, + grammarPool); + } + + /** + * Resets the parser state. + * + * @throws SAXException Thrown on initialization error. + */ + public void reset () { + super.reset(); + + // get state of namespace-declarations parameter. + fNamespaceDeclarations = + fConfiguration.getFeature(Constants.DOM_NAMESPACE_DECLARATIONS); + + // DOM Filter + if (fNullFilterInUse) { + fDOMFilter = null; + fNullFilterInUse = false; + } + if (fSkippedElemStack != null) { + fSkippedElemStack.removeAllElements(); + } + fRejectedElementDepth = 0; + fFilterReject = false; + fSchemaType = null; + + } // reset() + + // + // DOMParser methods + // + + public DOMConfiguration getDomConfig (){ + return this; + } + + /** + * When a filter is provided, the implementation will call out to the + * filter as it is constructing the DOM tree structure. The filter can + * choose to remove elements from the document being constructed, or to + * terminate the parsing early. + *
        The filter is invoked after the operations requested by the + * DOMConfiguration parameters have been applied. For + * example, if " + * validate" is set to true, the validation is done before invoking the + * filter. + */ + public LSParserFilter getFilter () { + return !fNullFilterInUse ? fDOMFilter : null; + } + + /** + * When a filter is provided, the implementation will call out to the + * filter as it is constructing the DOM tree structure. The filter can + * choose to remove elements from the document being constructed, or to + * terminate the parsing early. + *
        The filter is invoked after the operations requested by the + * DOMConfiguration parameters have been applied. For + * example, if " + * validate" is set to true, the validation is done before invoking the + * filter. + */ + public void setFilter (LSParserFilter filter) { + if (fBusy && filter == null && fDOMFilter != null) { + fNullFilterInUse = true; + fDOMFilter = NullLSParserFilter.INSTANCE; + } + else { + fDOMFilter = filter; + } + if (fSkippedElemStack == null) { + fSkippedElemStack = new Stack(); + } + } + + /** + * Set parameters and properties + */ + public void setParameter (String name, Object value) throws DOMException { + // set features + + if (value instanceof Boolean) { + boolean state = ((Boolean)value).booleanValue(); + try { + if (name.equalsIgnoreCase (Constants.DOM_COMMENTS)) { + fConfiguration.setFeature (INCLUDE_COMMENTS_FEATURE, state); + } + else if (name.equalsIgnoreCase (Constants.DOM_DATATYPE_NORMALIZATION)) { + fConfiguration.setFeature (NORMALIZE_DATA, state); + } + else if (name.equalsIgnoreCase (Constants.DOM_ENTITIES)) { + fConfiguration.setFeature (CREATE_ENTITY_REF_NODES, state); + } + else if (name.equalsIgnoreCase (Constants.DOM_DISALLOW_DOCTYPE)) { + fConfiguration.setFeature (DISALLOW_DOCTYPE_DECL_FEATURE, state); + } + else if (name.equalsIgnoreCase (Constants.DOM_SUPPORTED_MEDIATYPES_ONLY) + || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS) + || name.equalsIgnoreCase (Constants.DOM_CHECK_CHAR_NORMALIZATION) + || name.equalsIgnoreCase (Constants.DOM_CANONICAL_FORM)) { + if (state) { // true is not supported + throw newFeatureNotSupportedError(name); + } + // setting those features to false is no-op + } + else if (name.equalsIgnoreCase (Constants.DOM_NAMESPACES)) { + fConfiguration.setFeature (NAMESPACES, state); + } + else if (name.equalsIgnoreCase (Constants.DOM_INFOSET)) { + // Setting false has no effect. + if (state) { + // true: namespaces, namespace-declarations, + // comments, element-content-whitespace + fConfiguration.setFeature(NAMESPACES, true); + fConfiguration.setFeature(Constants.DOM_NAMESPACE_DECLARATIONS, true); + fConfiguration.setFeature(INCLUDE_COMMENTS_FEATURE, true); + fConfiguration.setFeature(INCLUDE_IGNORABLE_WHITESPACE, true); + + // false: validate-if-schema, entities, + // datatype-normalization, cdata-sections + fConfiguration.setFeature(DYNAMIC_VALIDATION, false); + fConfiguration.setFeature(CREATE_ENTITY_REF_NODES, false); + fConfiguration.setFeature(NORMALIZE_DATA, false); + fConfiguration.setFeature(CREATE_CDATA_NODES_FEATURE, false); + } + } + else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) { + fConfiguration.setFeature(CREATE_CDATA_NODES_FEATURE, state); + } + else if (name.equalsIgnoreCase (Constants.DOM_NAMESPACE_DECLARATIONS)) { + fConfiguration.setFeature(Constants.DOM_NAMESPACE_DECLARATIONS, state); + } + else if (name.equalsIgnoreCase (Constants.DOM_WELLFORMED) + || name.equalsIgnoreCase (Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { + if (!state) { // false is not supported + throw newFeatureNotSupportedError(name); + } + // setting these features to true is no-op + // REVISIT: implement "namespace-declaration" feature + } + else if (name.equalsIgnoreCase (Constants.DOM_VALIDATE)) { + fConfiguration.setFeature (VALIDATION_FEATURE, state); + if (fSchemaType != Constants.NS_DTD) { + fConfiguration.setFeature (XMLSCHEMA, state); + fConfiguration.setFeature (XMLSCHEMA_FULL_CHECKING, state); + } + if (state){ + fConfiguration.setFeature (DYNAMIC_VALIDATION, false); + } + } + else if (name.equalsIgnoreCase (Constants.DOM_VALIDATE_IF_SCHEMA)) { + fConfiguration.setFeature (DYNAMIC_VALIDATION, state); + // Note: validation and dynamic validation are mutually exclusive + if (state){ + fConfiguration.setFeature (VALIDATION_FEATURE, false); + } + } + else if (name.equalsIgnoreCase (Constants.DOM_ELEMENT_CONTENT_WHITESPACE)) { + fConfiguration.setFeature (INCLUDE_IGNORABLE_WHITESPACE, state); + } + else if (name.equalsIgnoreCase (Constants.DOM_PSVI)){ + //XSModel - turn on PSVI augmentation + fConfiguration.setFeature (PSVI_AUGMENT, true); + fConfiguration.setProperty (DOCUMENT_CLASS_NAME, + "org.apache.xerces.dom.PSVIDocumentImpl"); + } + else { + // Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING feature, + // Constants.DOM_SPLIT_CDATA feature, + // or any Xerces feature + String normalizedName; + // The honour-all-schemaLocations feature is + // mixed case so requires special treatment. + if (name.equalsIgnoreCase(HONOUR_ALL_SCHEMALOCATIONS)) { + normalizedName = HONOUR_ALL_SCHEMALOCATIONS; + } + else if (name.equals(NAMESPACE_GROWTH)) { + normalizedName = NAMESPACE_GROWTH; + } + else if (name.equals(TOLERATE_DUPLICATES)) { + normalizedName = TOLERATE_DUPLICATES; + } + else { + normalizedName = name.toLowerCase(Locale.ENGLISH); + } + fConfiguration.setFeature(normalizedName, state); + } + + } + catch (XMLConfigurationException e) { + throw newFeatureNotFoundError(name); + } + } + else { // set properties + if (name.equalsIgnoreCase (Constants.DOM_ERROR_HANDLER)) { + if (value instanceof DOMErrorHandler || value == null) { + try { + fErrorHandler = new DOMErrorHandlerWrapper ((DOMErrorHandler) value); + fConfiguration.setProperty (ERROR_HANDLER, fErrorHandler); + } + catch (XMLConfigurationException e) {} + } + else { + throw newTypeMismatchError(name); + } + + } + else if (name.equalsIgnoreCase (Constants.DOM_RESOURCE_RESOLVER)) { + if (value instanceof LSResourceResolver || value == null) { + try { + fConfiguration.setProperty (ENTITY_RESOLVER, new DOMEntityResolverWrapper ((LSResourceResolver) value)); + } + catch (XMLConfigurationException e) {} + } + else { + throw newTypeMismatchError(name); + } + + } + else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_LOCATION)) { + if (value instanceof String || value == null) { + try { + if (value == null) { + fSchemaLocation = null; + fConfiguration.setProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE, + null); + } + else { + fSchemaLocation = (String)value; + // map DOM schema-location to JAXP schemaSource property + // tokenize location string + StringTokenizer t = new StringTokenizer (fSchemaLocation, " \n\t\r"); + if (t.hasMoreTokens()) { + ArrayList locations = new ArrayList(); + locations.add (t.nextToken()); + while (t.hasMoreTokens()) { + locations.add (t.nextToken()); + } + fConfiguration.setProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE, + locations.toArray ()); + } + else { + fConfiguration.setProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE, + value); + } + } + } + catch (XMLConfigurationException e) {} + } + else { + throw newTypeMismatchError(name); + } + + } + else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_TYPE)) { + if (value instanceof String || value == null) { + try { + if (value == null) { + // turn off schema features + fConfiguration.setFeature (XMLSCHEMA, false); + fConfiguration.setFeature (XMLSCHEMA_FULL_CHECKING, false); + // map to JAXP schemaLanguage + fConfiguration.setProperty ( Constants.JAXP_PROPERTY_PREFIX + + Constants.SCHEMA_LANGUAGE, + null); + fSchemaType = null; + } + else if (value.equals (Constants.NS_XMLSCHEMA)) { + // turn on schema features + fConfiguration.setFeature (XMLSCHEMA, true); + fConfiguration.setFeature (XMLSCHEMA_FULL_CHECKING, true); + // map to JAXP schemaLanguage + fConfiguration.setProperty ( Constants.JAXP_PROPERTY_PREFIX + + Constants.SCHEMA_LANGUAGE, + Constants.NS_XMLSCHEMA); + fSchemaType = Constants.NS_XMLSCHEMA; + } + else if (value.equals (Constants.NS_DTD)) { + // turn off schema features + fConfiguration.setFeature (XMLSCHEMA, false); + fConfiguration.setFeature (XMLSCHEMA_FULL_CHECKING, false); + // map to JAXP schemaLanguage + fConfiguration.setProperty ( Constants.JAXP_PROPERTY_PREFIX + + Constants.SCHEMA_LANGUAGE, + Constants.NS_DTD); + fSchemaType = Constants.NS_DTD; + } + } + catch (XMLConfigurationException e) {} + } + else { + throw newTypeMismatchError(name); + } + + } + else if (name.equalsIgnoreCase (DOCUMENT_CLASS_NAME)) { + fConfiguration.setProperty (DOCUMENT_CLASS_NAME, value); + } + else { + // Try to set the property. + String normalizedName = name.toLowerCase(Locale.ENGLISH); + try { + fConfiguration.setProperty(normalizedName, value); + return; + } + catch (XMLConfigurationException e) {} + + // If this is a boolean parameter a type mismatch should be thrown. + try { + // The honour-all-schemaLocations feature is + // mixed case so requires special treatment. + if (name.equalsIgnoreCase(HONOUR_ALL_SCHEMALOCATIONS)) { + normalizedName = HONOUR_ALL_SCHEMALOCATIONS; + } + else if (name.equals(NAMESPACE_GROWTH)) { + normalizedName = NAMESPACE_GROWTH; + } + else if (name.equals(TOLERATE_DUPLICATES)) { + normalizedName = TOLERATE_DUPLICATES; + } + fConfiguration.getFeature(normalizedName); + throw newTypeMismatchError(name); + + } + catch (XMLConfigurationException e) {} + + // Parameter is not recognized + throw newFeatureNotFoundError(name); + } + } + } + + /** + * Look up the value of a feature or a property. + */ + public Object getParameter (String name) throws DOMException { + if (name.equalsIgnoreCase (Constants.DOM_COMMENTS)) { + return (fConfiguration.getFeature (INCLUDE_COMMENTS_FEATURE)) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_DATATYPE_NORMALIZATION)) { + return (fConfiguration.getFeature (NORMALIZE_DATA)) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_ENTITIES)) { + return (fConfiguration.getFeature (CREATE_ENTITY_REF_NODES)) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_NAMESPACES)) { + return (fConfiguration.getFeature (NAMESPACES)) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_VALIDATE)) { + return (fConfiguration.getFeature (VALIDATION_FEATURE)) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_VALIDATE_IF_SCHEMA)) { + return (fConfiguration.getFeature (DYNAMIC_VALIDATION)) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_ELEMENT_CONTENT_WHITESPACE)) { + return (fConfiguration.getFeature (INCLUDE_IGNORABLE_WHITESPACE)) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_DISALLOW_DOCTYPE)) { + return (fConfiguration.getFeature (DISALLOW_DOCTYPE_DECL_FEATURE)) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_INFOSET)) { + // REVISIT: This is somewhat expensive to compute + // but it's possible that the user has a reference + // to the configuration and is changing the values + // of these features directly on it. + boolean infoset = fConfiguration.getFeature(NAMESPACES) && + fConfiguration.getFeature(Constants.DOM_NAMESPACE_DECLARATIONS) && + fConfiguration.getFeature(INCLUDE_COMMENTS_FEATURE) && + fConfiguration.getFeature(INCLUDE_IGNORABLE_WHITESPACE) && + !fConfiguration.getFeature(DYNAMIC_VALIDATION) && + !fConfiguration.getFeature(CREATE_ENTITY_REF_NODES) && + !fConfiguration.getFeature(NORMALIZE_DATA) && + !fConfiguration.getFeature(CREATE_CDATA_NODES_FEATURE); + return (infoset) ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) { + return (fConfiguration.getFeature(CREATE_CDATA_NODES_FEATURE)) + ? Boolean.TRUE : Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION ) || + name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) { + return Boolean.FALSE; + } + else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS) + || name.equalsIgnoreCase (Constants.DOM_WELLFORMED) + || name.equalsIgnoreCase (Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS) + || name.equalsIgnoreCase (Constants.DOM_CANONICAL_FORM) + || name.equalsIgnoreCase (Constants.DOM_SUPPORTED_MEDIATYPES_ONLY) + || name.equalsIgnoreCase (Constants.DOM_SPLIT_CDATA) + || name.equalsIgnoreCase (Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING)) { + return (fConfiguration.getFeature (name.toLowerCase(Locale.ENGLISH))) + ? Boolean.TRUE + : Boolean.FALSE; + } + else if (name.equalsIgnoreCase (Constants.DOM_ERROR_HANDLER)) { + if (fErrorHandler != null) { + return fErrorHandler.getErrorHandler (); + } + return null; + } + else if (name.equalsIgnoreCase (Constants.DOM_RESOURCE_RESOLVER)) { + try { + XMLEntityResolver entityResolver = + (XMLEntityResolver) fConfiguration.getProperty (ENTITY_RESOLVER); + if (entityResolver != null + && entityResolver instanceof DOMEntityResolverWrapper) { + return ((DOMEntityResolverWrapper) entityResolver).getEntityResolver(); + } + } + catch (XMLConfigurationException e) {} + return null; + } + else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_TYPE)) { + return fConfiguration.getProperty ( + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE); + } + else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_LOCATION)) { + return fSchemaLocation; + } + else if (name.equalsIgnoreCase (SYMBOL_TABLE)) { + return fConfiguration.getProperty (SYMBOL_TABLE); + } + else if (name.equalsIgnoreCase (DOCUMENT_CLASS_NAME)) { + return fConfiguration.getProperty (DOCUMENT_CLASS_NAME); + } + else { + // This could be a recognized feature or property. + String normalizedName; + + // The honour-all-schemaLocations feature is + // mixed case so requires special treatment. + if (name.equalsIgnoreCase(HONOUR_ALL_SCHEMALOCATIONS)) { + normalizedName = HONOUR_ALL_SCHEMALOCATIONS; + } + else if (name.equals(NAMESPACE_GROWTH)) { + normalizedName = NAMESPACE_GROWTH; + } + else if (name.equals(TOLERATE_DUPLICATES)) { + normalizedName = TOLERATE_DUPLICATES; + } + else { + normalizedName = name.toLowerCase(Locale.ENGLISH); + } + try { + return fConfiguration.getFeature(normalizedName) + ? Boolean.TRUE : Boolean.FALSE; + } + catch (XMLConfigurationException e) {} + + // This isn't a feature; perhaps it's a property + try { + return fConfiguration.getProperty(normalizedName); + } + catch (XMLConfigurationException e) {} + + throw newFeatureNotFoundError(name); + } + } + + public boolean canSetParameter (String name, Object value) { + if (value == null) { + return true; + } + + if (value instanceof Boolean) { + boolean state = ((Boolean)value).booleanValue(); + if ( name.equalsIgnoreCase (Constants.DOM_SUPPORTED_MEDIATYPES_ONLY) + || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS) + || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION ) + || name.equalsIgnoreCase (Constants.DOM_CANONICAL_FORM) ) { + // true is not supported + return (state) ? false : true; + } + else if (name.equalsIgnoreCase (Constants.DOM_WELLFORMED) + || name.equalsIgnoreCase (Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { + // false is not supported + return (state) ? true : false; + } + else if (name.equalsIgnoreCase (Constants.DOM_CDATA_SECTIONS) + || name.equalsIgnoreCase (Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING) + || name.equalsIgnoreCase (Constants.DOM_COMMENTS) + || name.equalsIgnoreCase (Constants.DOM_DATATYPE_NORMALIZATION) + || name.equalsIgnoreCase (Constants.DOM_DISALLOW_DOCTYPE) + || name.equalsIgnoreCase (Constants.DOM_ENTITIES) + || name.equalsIgnoreCase (Constants.DOM_INFOSET) + || name.equalsIgnoreCase (Constants.DOM_NAMESPACES) + || name.equalsIgnoreCase (Constants.DOM_NAMESPACE_DECLARATIONS) + || name.equalsIgnoreCase (Constants.DOM_VALIDATE) + || name.equalsIgnoreCase (Constants.DOM_VALIDATE_IF_SCHEMA) + || name.equalsIgnoreCase (Constants.DOM_ELEMENT_CONTENT_WHITESPACE) + || name.equalsIgnoreCase (Constants.DOM_XMLDECL)) { + return true; + } + + // Recognize Xerces features. + try { + String normalizedName; + // The honour-all-schemaLocations feature is + // mixed case so requires special treatment. + if (name.equalsIgnoreCase(HONOUR_ALL_SCHEMALOCATIONS)) { + normalizedName = HONOUR_ALL_SCHEMALOCATIONS; + } + else if (name.equalsIgnoreCase(NAMESPACE_GROWTH)) { + normalizedName = NAMESPACE_GROWTH; + } + else if (name.equalsIgnoreCase(TOLERATE_DUPLICATES)) { + normalizedName = TOLERATE_DUPLICATES; + } + else { + normalizedName = name.toLowerCase(Locale.ENGLISH); + } + fConfiguration.getFeature(normalizedName); + return true; + } + catch (XMLConfigurationException e) { + return false; + } + } + else { // check properties + if (name.equalsIgnoreCase (Constants.DOM_ERROR_HANDLER)) { + if (value instanceof DOMErrorHandler || value == null) { + return true; + } + return false; + } + else if (name.equalsIgnoreCase (Constants.DOM_RESOURCE_RESOLVER)) { + if (value instanceof LSResourceResolver || value == null) { + return true; + } + return false; + } + else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_TYPE)) { + if ((value instanceof String + && (value.equals (Constants.NS_XMLSCHEMA) + || value.equals (Constants.NS_DTD))) || value == null) { + return true; + } + return false; + } + else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_LOCATION)) { + if (value instanceof String || value == null) + return true; + return false; + } + else if (name.equalsIgnoreCase (DOCUMENT_CLASS_NAME)) { + return true; + } + + // Recognize Xerces properties. + try { + fConfiguration.getProperty(name.toLowerCase(Locale.ENGLISH)); + return true; + } + catch (XMLConfigurationException e) { + return false; + } + } + } + + /** + * DOM Level 3 CR - Experimental. + * + * The list of the parameters supported by this + * DOMConfiguration object and for which at least one value + * can be set by the application. Note that this list can also contain + * parameter names defined outside this specification. + */ + public DOMStringList getParameterNames () { + if (fRecognizedParameters == null){ + ArrayList parameters = new ArrayList(); + + // REVISIT: add Xerces recognized properties/features + parameters.add(Constants.DOM_NAMESPACES); + parameters.add(Constants.DOM_CDATA_SECTIONS); + parameters.add(Constants.DOM_CANONICAL_FORM); + parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS); + parameters.add(Constants.DOM_SPLIT_CDATA); + + parameters.add(Constants.DOM_ENTITIES); + parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA); + parameters.add(Constants.DOM_VALIDATE); + parameters.add(Constants.DOM_DATATYPE_NORMALIZATION); + + parameters.add(Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING); + parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION); + parameters.add(Constants.DOM_SUPPORTED_MEDIATYPES_ONLY); + parameters.add(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS); + + parameters.add(Constants.DOM_NORMALIZE_CHARACTERS); + parameters.add(Constants.DOM_WELLFORMED); + parameters.add(Constants.DOM_INFOSET); + parameters.add(Constants.DOM_DISALLOW_DOCTYPE); + parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE); + parameters.add(Constants.DOM_COMMENTS); + + parameters.add(Constants.DOM_ERROR_HANDLER); + parameters.add(Constants.DOM_RESOURCE_RESOLVER); + parameters.add(Constants.DOM_SCHEMA_LOCATION); + parameters.add(Constants.DOM_SCHEMA_TYPE); + + fRecognizedParameters = new DOMStringListImpl(parameters); + + } + + return fRecognizedParameters; + } + + /** + * Parse an XML document from a location identified by an URI reference. + * If the URI contains a fragment identifier (see section 4.1 in ), the + * behavior is not defined by this specification. + * + */ + public Document parseURI (String uri) throws LSException { + + //If DOMParser insstance is already busy parsing another document when this + // method is called, then raise INVALID_STATE_ERR according to DOM L3 LS spec + if ( fBusy ) { + throw newInvalidStateError(); + } + + XMLInputSource source = new XMLInputSource (null, uri, null); + try { + currentThread = Thread.currentThread(); + fBusy = true; + parse (source); + fBusy = false; + if (abortNow && currentThread.isInterrupted()) { + //reset interrupt state + abortNow = false; + Thread.interrupted(); + } + } catch (Exception e){ + fBusy = false; + if (abortNow && currentThread.isInterrupted()) { + Thread.interrupted(); + } + if (abortNow) { + abortNow = false; + restoreHandlers(); + return null; + } + // Consume this exception if the user + // issued an interrupt or an abort. + if (e != Abort.INSTANCE) { + if (!(e instanceof XMLParseException) && fErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl (); + error.fException = e; + error.fMessage = e.getMessage (); + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + fErrorHandler.getErrorHandler ().handleError (error); + } + if (DEBUG) { + e.printStackTrace (); + } + throw (LSException) DOMUtil.createLSException(LSException.PARSE_ERR, e).fillInStackTrace(); + } + } + Document doc = getDocument(); + dropDocumentReferences(); + return doc; + } + + /** + * Parse an XML document from a resource identified by an + * LSInput. + * + */ + public Document parse (LSInput is) throws LSException { + + // need to wrap the LSInput with an XMLInputSource + XMLInputSource xmlInputSource = dom2xmlInputSource (is); + if ( fBusy ) { + throw newInvalidStateError(); + } + + try { + currentThread = Thread.currentThread(); + fBusy = true; + parse (xmlInputSource); + fBusy = false; + if (abortNow && currentThread.isInterrupted()) { + //reset interrupt state + abortNow = false; + Thread.interrupted(); + } + } catch (Exception e) { + fBusy = false; + if (abortNow && currentThread.isInterrupted()) { + Thread.interrupted(); + } + if (abortNow) { + abortNow = false; + restoreHandlers(); + return null; + } + // Consume this exception if the user + // issued an interrupt or an abort. + if (e != Abort.INSTANCE) { + if (!(e instanceof XMLParseException) && fErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl (); + error.fException = e; + error.fMessage = e.getMessage (); + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + fErrorHandler.getErrorHandler().handleError (error); + } + if (DEBUG) { + e.printStackTrace (); + } + throw (LSException) DOMUtil.createLSException(LSException.PARSE_ERR, e).fillInStackTrace(); + } + } + Document doc = getDocument(); + dropDocumentReferences(); + return doc; + } + + + private void restoreHandlers() { + fConfiguration.setDocumentHandler(this); + fConfiguration.setDTDHandler(this); + fConfiguration.setDTDContentModelHandler(this); + } + + /** + * Parse an XML document or fragment from a resource identified by an + * LSInput and insert the content into an existing + * document at the position epcified with the contextNode + * and action arguments. When parsing the input stream the + * context node is used for resolving unbound namespace prefixes. + * + * @param is The LSInput from which the source + * document is to be read. + * @param cnode The Node that is used as the context for + * the data that is being parsed. + * @param action This parameter describes which action should be taken + * between the new set of node being inserted and the existing + * children of the context node. The set of possible actions is + * defined above. + * @exception DOMException + * HIERARCHY_REQUEST_ERR: Thrown if this action results in an invalid + * hierarchy (i.e. a Document with more than one document element). + */ + public Node parseWithContext (LSInput is, Node cnode, + short action) throws DOMException, LSException { + // REVISIT: need to implement. + throw new DOMException (DOMException.NOT_SUPPORTED_ERR, "Not supported"); + } + + + /** + * NON-DOM: convert LSInput to XNIInputSource + * + * @param is + * @return + */ + XMLInputSource dom2xmlInputSource (LSInput is) { + // need to wrap the LSInput with an XMLInputSource + XMLInputSource xis = null; + // check whether there is a Reader + // according to DOM, we need to treat such reader as "UTF-16". + if (is.getCharacterStream () != null) { + xis = new XMLInputSource (is.getPublicId (), is.getSystemId (), + is.getBaseURI (), is.getCharacterStream (), + "UTF-16"); + } + // check whether there is an InputStream + else if (is.getByteStream () != null) { + xis = new XMLInputSource (is.getPublicId (), is.getSystemId (), + is.getBaseURI (), is.getByteStream (), + is.getEncoding ()); + } + // if there is a string data, use a StringReader + // according to DOM, we need to treat such data as "UTF-16". + else if (is.getStringData () != null && is.getStringData().length() > 0) { + xis = new XMLInputSource (is.getPublicId (), is.getSystemId (), + is.getBaseURI (), new StringReader (is.getStringData ()), + "UTF-16"); + } + // otherwise, just use the public/system/base Ids + else if ((is.getSystemId() != null && is.getSystemId().length() > 0) || + (is.getPublicId() != null && is.getPublicId().length() > 0)) { + xis = new XMLInputSource (is.getPublicId (), is.getSystemId (), + is.getBaseURI ()); + } + else { + // all inputs are null + if (fErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl(); + error.fType = "no-input-specified"; + error.fMessage = "no-input-specified"; + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + fErrorHandler.getErrorHandler().handleError(error); + } + throw new LSException(LSException.PARSE_ERR, "no-input-specified"); + } + return xis; + } + + /** + * @see org.w3c.dom.ls.LSParser#getAsync() + */ + public boolean getAsync () { + return false; + } + + /** + * @see org.w3c.dom.ls.LSParser#getBusy() + */ + public boolean getBusy () { + return fBusy; + } + + /** + * @see org.w3c.dom.ls.LSParser#abort() + */ + public void abort () { + // If parse operation is in progress then reset it + if (fBusy) { + fBusy = false; + if (currentThread != null) { + abortNow = true; + if (abortHandler == null) { + abortHandler = new AbortHandler(); + } + fConfiguration.setDocumentHandler(abortHandler); + fConfiguration.setDTDHandler(abortHandler); + fConfiguration.setDTDContentModelHandler(abortHandler); + if (currentThread == Thread.currentThread()) { + throw Abort.INSTANCE; + } + currentThread.interrupt(); + } + } + return; // If not busy then this is noop + } + + /** + * The start of an element. If the document specifies the start element + * by using an empty tag, then the startElement method will immediately + * be followed by the endElement method, with no intervening methods. + * Overriding the parent to handle DOM_NAMESPACE_DECLARATIONS=false. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startElement (QName element, XMLAttributes attributes, Augmentations augs) { + // namespace declarations parameter has no effect if namespaces is false. + if (!fNamespaceDeclarations && fNamespaceAware) { + int len = attributes.getLength(); + for (int i = len - 1; i >= 0; --i) { + if (XMLSymbols.PREFIX_XMLNS == attributes.getPrefix(i) || + XMLSymbols.PREFIX_XMLNS == attributes.getQName(i)) { + attributes.removeAttributeAt(i); + } + } + } + super.startElement(element, attributes, augs); + } + + static final class NullLSParserFilter implements LSParserFilter { + static final NullLSParserFilter INSTANCE = new NullLSParserFilter(); + private NullLSParserFilter() {} + public short acceptNode(Node nodeArg) { + return LSParserFilter.FILTER_ACCEPT; + } + public int getWhatToShow() { + return NodeFilter.SHOW_ALL; + } + public short startElement(Element elementArg) { + return LSParserFilter.FILTER_ACCEPT; + } + } + + private static final class AbortHandler implements XMLDocumentHandler, XMLDTDHandler, XMLDTDContentModelHandler { + + private XMLDocumentSource documentSource; + private XMLDTDContentModelSource dtdContentSource; + private XMLDTDSource dtdSource; + + public void startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void comment(XMLString text, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void processingInstruction(String target, XMLString data, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void startGeneralEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void endGeneralEntity(String name, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void characters(XMLString text, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void endElement(QName element, Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void startCDATA(Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void endCDATA(Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void endDocument(Augmentations augs) throws XNIException { + throw Abort.INSTANCE; + } + + public void setDocumentSource(XMLDocumentSource source) { + documentSource = source; + } + + public XMLDocumentSource getDocumentSource() { + return documentSource; + } + + public void startDTD(XMLLocator locator, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void startParameterEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void endParameterEntity(String name, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void startExternalSubset(XMLResourceIdentifier identifier, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void endExternalSubset(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void elementDecl(String name, String contentModel, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void startAttlist(String elementName, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void attributeDecl(String elementName, String attributeName, String type, String[] enumeration, String defaultType, XMLString defaultValue, XMLString nonNormalizedDefaultValue, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void endAttlist(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void internalEntityDecl(String name, XMLString text, XMLString nonNormalizedText, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void externalEntityDecl(String name, XMLResourceIdentifier identifier, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier, String notation, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void notationDecl(String name, XMLResourceIdentifier identifier, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void startConditional(short type, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void ignoredCharacters(XMLString text, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void endConditional(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void endDTD(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void setDTDSource(XMLDTDSource source) { + dtdSource = source; + } + + public XMLDTDSource getDTDSource() { + return dtdSource; + } + + public void startContentModel(String elementName, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void any(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void empty(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void startGroup(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void pcdata(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void element(String elementName, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void separator(short separator, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void occurrence(short occurrence, Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void endGroup(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void endContentModel(Augmentations augmentations) throws XNIException { + throw Abort.INSTANCE; + } + + public void setDTDContentModelSource(XMLDTDContentModelSource source) { + dtdContentSource = source; + } + + public XMLDTDContentModelSource getDTDContentModelSource() { + return dtdContentSource; + } + } + + private static DOMException newInvalidStateError() { + String msg = + DOMMessageFormatter.formatMessage ( + DOMMessageFormatter.DOM_DOMAIN, + "INVALID_STATE_ERR", null); + throw new DOMException ( DOMException.INVALID_STATE_ERR, msg); + } + + private static DOMException newFeatureNotSupportedError(String name) { + String msg = + DOMMessageFormatter.formatMessage ( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + return new DOMException (DOMException.NOT_SUPPORTED_ERR, msg); + } + + private static DOMException newFeatureNotFoundError(String name) { + String msg = + DOMMessageFormatter.formatMessage ( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[] { name }); + return new DOMException (DOMException.NOT_FOUND_ERR, msg); + } + + private static DOMException newTypeMismatchError(String name) { + String msg = + DOMMessageFormatter.formatMessage ( + DOMMessageFormatter.DOM_DOMAIN, + "TYPE_MISMATCH_ERR", + new Object[] { name }); + return new DOMException (DOMException.TYPE_MISMATCH_ERR, msg); + } + +} // class DOMParserImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/DTDConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/DTDConfiguration.java new file mode 100644 index 0000000..7667051 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/DTDConfiguration.java @@ -0,0 +1,867 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLDTDScannerImpl; +import org.apache.xerces.impl.XMLDocumentScannerImpl; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.XMLNamespaceBinder; +import org.apache.xerces.impl.dtd.XMLDTDProcessor; +import org.apache.xerces.impl.dtd.XMLDTDValidator; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDScanner; +import org.apache.xerces.xni.parser.XMLDocumentScanner; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLPullParserConfiguration; + +/** + * This is the DTD-only parser configuration. It extends the basic + * configuration with a standard set of parser components appropriate + * to DTD-centric validation. Since + * the Xerces2 reference implementation document and DTD scanner + * implementations are capable of acting as pull parsers, this + * configuration implements the + * XMLPullParserConfiguration interface. + *

        + * In addition to the features and properties recognized by the base + * parser configuration, this class recognizes these additional + * features and properties: + *

          + *
        • Features + *
            + *
          • http://apache.org/xml/features/validation/warn-on-duplicate-attdef
          • + *
          • http://apache.org/xml/features/validation/warn-on-undeclared-elemdef
          • + *
          • http://apache.org/xml/features/allow-java-encodings
          • + *
          • http://apache.org/xml/features/continue-after-fatal-error
          • + *
          • http://apache.org/xml/features/load-external-dtd
          • + *
          + *
        • Properties + *
            + *
          • http://apache.org/xml/properties/internal/error-reporter
          • + *
          • http://apache.org/xml/properties/internal/entity-manager
          • + *
          • http://apache.org/xml/properties/internal/document-scanner
          • + *
          • http://apache.org/xml/properties/internal/dtd-scanner
          • + *
          • http://apache.org/xml/properties/internal/grammar-pool
          • + *
          • http://apache.org/xml/properties/internal/validator/dtd
          • + *
          • http://apache.org/xml/properties/internal/datatype-validator-factory
          • + *
          + *
        + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class DTDConfiguration + extends BasicParserConfiguration + implements XMLPullParserConfiguration { + + // + // Constants + // + + // feature identifiers + + /** Feature identifier: warn on duplicate attribute definition. */ + protected static final String WARN_ON_DUPLICATE_ATTDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; + + /** Feature identifier: warn on duplicate entity definition. */ + protected static final String WARN_ON_DUPLICATE_ENTITYDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ENTITYDEF_FEATURE; + + /** Feature identifier: warn on undeclared element definition. */ + protected static final String WARN_ON_UNDECLARED_ELEMDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE; + + /** Feature identifier: allow Java encodings. */ + protected static final String ALLOW_JAVA_ENCODINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; + + /** Feature identifier: continue after fatal error. */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + /** Feature identifier: load external DTD. */ + protected static final String LOAD_EXTERNAL_DTD = + Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE; + + /** Feature identifier: notify built-in refereces. */ + protected static final String NOTIFY_BUILTIN_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE; + + /** Feature identifier: notify character refereces. */ + protected static final String NOTIFY_CHAR_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE; + + + // property identifiers + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier document scanner: */ + protected static final String DOCUMENT_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_SCANNER_PROPERTY; + + /** Property identifier: DTD scanner. */ + protected static final String DTD_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY; + + /** Property identifier: grammar pool. */ + protected static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: DTD loader. */ + protected static final String DTD_PROCESSOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_PROCESSOR_PROPERTY; + + /** Property identifier: DTD validator. */ + protected static final String DTD_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; + + /** Property identifier: namespace binder. */ + protected static final String NAMESPACE_BINDER = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_BINDER_PROPERTY; + + /** Property identifier: datatype validator factory. */ + protected static final String DATATYPE_VALIDATOR_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; + + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: JAXP schema language / DOM schema-type. */ + protected static final String JAXP_SCHEMA_LANGUAGE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE; + + /** Property identifier: JAXP schema source/ DOM schema-location. */ + protected static final String JAXP_SCHEMA_SOURCE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; + + /** Property identifier: locale. */ + protected static final String LOCALE = + Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + + // debugging + + /** Set to true and recompile to print exception stack trace. */ + protected static final boolean PRINT_EXCEPTION_STACK_TRACE = false; + + // + // Data + // + + // components (non-configurable) + + /** Grammar pool. */ + protected XMLGrammarPool fGrammarPool; + + /** Datatype validator factory. */ + protected DTDDVFactory fDatatypeValidatorFactory; + + // components (configurable) + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + /** Entity manager. */ + protected XMLEntityManager fEntityManager; + + /** Document scanner. */ + protected XMLDocumentScanner fScanner; + + /** Input Source */ + protected XMLInputSource fInputSource; + + /** DTD scanner. */ + protected XMLDTDScanner fDTDScanner; + + /** DTD Processor . */ + protected XMLDTDProcessor fDTDProcessor; + + /** DTD Validator. */ + protected XMLDTDValidator fDTDValidator; + + /** Namespace binder. */ + protected XMLNamespaceBinder fNamespaceBinder; + + protected ValidationManager fValidationManager; + // state + + /** Locator */ + protected XMLLocator fLocator; + + /** + * True if a parse is in progress. This state is needed because + * some features/properties cannot be set while parsing (e.g. + * validation and namespaces). + */ + protected boolean fParseInProgress = false; + + // + // Constructors + // + + /** Default constructor. */ + public DTDConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public DTDConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public DTDConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public DTDConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, parentSettings); + + // add default recognized features + final String[] recognizedFeatures = { + //WARN_ON_DUPLICATE_ATTDEF, // from XMLDTDScannerImpl + //WARN_ON_UNDECLARED_ELEMDEF, // from XMLDTDScannerImpl + //ALLOW_JAVA_ENCODINGS, // from XMLEntityManager + CONTINUE_AFTER_FATAL_ERROR, + LOAD_EXTERNAL_DTD, // from XMLDTDScannerImpl + //NOTIFY_BUILTIN_REFS, // from XMLDocumentFragmentScannerImpl + //NOTIFY_CHAR_REFS, // from XMLDocumentFragmentScannerImpl + //WARN_ON_DUPLICATE_ENTITYDEF, // from XMLEntityManager + }; + addRecognizedFeatures(recognizedFeatures); + + // set state for default features + //setFeature(WARN_ON_DUPLICATE_ATTDEF, false); // from XMLDTDScannerImpl + //setFeature(WARN_ON_UNDECLARED_ELEMDEF, false); // from XMLDTDScannerImpl + //setFeature(ALLOW_JAVA_ENCODINGS, false); // from XMLEntityManager + setFeature(CONTINUE_AFTER_FATAL_ERROR, false); + setFeature(LOAD_EXTERNAL_DTD, true); // from XMLDTDScannerImpl + //setFeature(NOTIFY_BUILTIN_REFS, false); // from XMLDocumentFragmentScannerImpl + //setFeature(NOTIFY_CHAR_REFS, false); // from XMLDocumentFragmentScannerImpl + //setFeature(WARN_ON_DUPLICATE_ENTITYDEF, false); // from XMLEntityManager + + // add default recognized properties + final String[] recognizedProperties = { + ERROR_REPORTER, + ENTITY_MANAGER, + DOCUMENT_SCANNER, + DTD_SCANNER, + DTD_PROCESSOR, + DTD_VALIDATOR, + NAMESPACE_BINDER, + XMLGRAMMAR_POOL, + DATATYPE_VALIDATOR_FACTORY, + VALIDATION_MANAGER, + JAXP_SCHEMA_SOURCE, + JAXP_SCHEMA_LANGUAGE, + LOCALE + }; + addRecognizedProperties(recognizedProperties); + + fGrammarPool = grammarPool; + if(fGrammarPool != null){ + setProperty(XMLGRAMMAR_POOL, fGrammarPool); + } + + fEntityManager = createEntityManager(); + setProperty(ENTITY_MANAGER, fEntityManager); + addComponent(fEntityManager); + + fErrorReporter = createErrorReporter(); + fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner()); + setProperty(ERROR_REPORTER, fErrorReporter); + addComponent(fErrorReporter); + + fScanner = createDocumentScanner(); + setProperty(DOCUMENT_SCANNER, fScanner); + if (fScanner instanceof XMLComponent) { + addComponent((XMLComponent)fScanner); + } + + fDTDScanner = createDTDScanner(); + if (fDTDScanner != null) { + setProperty(DTD_SCANNER, fDTDScanner); + if (fDTDScanner instanceof XMLComponent) { + addComponent((XMLComponent)fDTDScanner); + } + } + + fDTDProcessor = createDTDProcessor(); + if (fDTDProcessor != null) { + setProperty(DTD_PROCESSOR, fDTDProcessor); + addComponent(fDTDProcessor); + } + + fDTDValidator = createDTDValidator(); + if (fDTDValidator != null) { + setProperty(DTD_VALIDATOR, fDTDValidator); + addComponent(fDTDValidator); + } + + fNamespaceBinder = createNamespaceBinder(); + if (fNamespaceBinder != null) { + setProperty(NAMESPACE_BINDER, fNamespaceBinder); + addComponent(fNamespaceBinder); + } + + fDatatypeValidatorFactory = createDatatypeValidatorFactory(); + if (fDatatypeValidatorFactory != null) { + setProperty(DATATYPE_VALIDATOR_FACTORY, + fDatatypeValidatorFactory); + } + fValidationManager = createValidationManager(); + + if (fValidationManager != null) { + setProperty (VALIDATION_MANAGER, fValidationManager); + } + // add message formatters + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + + // set locale + try { + setLocale(Locale.getDefault()); + } + catch (XNIException e) { + // do nothing + // REVISIT: What is the right thing to do? -Ac + } + + } // (SymbolTable,XMLGrammarPool) + + // + // Public methods + // + + public Object getProperty(String propertyId) + throws XMLConfigurationException { + if (LOCALE.equals(propertyId)) { + return getLocale(); + } + return super.getProperty(propertyId); + } + + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + if (LOCALE.equals(propertyId)) { + setLocale((Locale) value); + } + super.setProperty(propertyId, value); + } + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException { + super.setLocale(locale); + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + + // + // XMLPullParserConfiguration methods + // + + // parsing + + /** + * Sets the input source for the document to parse. + * + * @param inputSource The document's input source. + * + * @exception XMLConfigurationException Thrown if there is a + * configuration error when initializing the + * parser. + * @exception IOException Thrown on I/O error. + * + * @see #parse(boolean) + */ + public void setInputSource(XMLInputSource inputSource) + throws XMLConfigurationException, IOException { + + // REVISIT: this method used to reset all the components and + // construct the pipeline. Now reset() is called + // in parse (boolean) just before we parse the document + // Should this method still throw exceptions..? + + fInputSource = inputSource; + + } // setInputSource(XMLInputSource) + + /** + * Parses the document in a pull parsing fashion. + * + * @param complete True if the pull parser should parse the + * remaining document completely. + * + * @return True if there is more document to parse. + * + * @exception XNIException Any XNI exception, possibly wrapping + * another exception. + * @exception IOException An IO exception from the parser, possibly + * from a byte stream or character stream + * supplied by the parser. + * + * @see #setInputSource + */ + public boolean parse(boolean complete) throws XNIException, IOException { + // + // reset and configure pipeline and set InputSource. + if (fInputSource !=null) { + try { + // resets and sets the pipeline. + reset(); + fScanner.setInputSource(fInputSource); + fInputSource = null; + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + } + + try { + return fScanner.scanDocument(complete); + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + + } // parse(boolean):boolean + + /** + * If the application decides to terminate parsing before the xml document + * is fully parsed, the application should call this method to free any + * resource allocated during parsing. For example, close all opened streams. + */ + public void cleanup() { + fEntityManager.closeReaders(); + } + + // + // XMLParserConfiguration methods + // + + /** + * Parses the specified input source. + * + * @param source The input source. + * + * @exception XNIException Throws exception on XNI error. + * @exception java.io.IOException Throws exception on i/o error. + */ + public void parse(XMLInputSource source) throws XNIException, IOException { + + if (fParseInProgress) { + // REVISIT - need to add new error message + throw new XNIException("FWK005 parse may not be called while parsing."); + } + fParseInProgress = true; + + try { + setInputSource(source); + parse(true); + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + finally { + fParseInProgress = false; + // close all streams opened by xerces + this.cleanup(); + } + + } // parse(InputSource) + + // + // Protected methods + // + + /** + * Reset all components before parsing. + * + * @throws XNIException Thrown if an error occurs during initialization. + */ + protected void reset() throws XNIException { + + if (fValidationManager != null) + fValidationManager.reset(); + // configure the pipeline and initialize the components + configurePipeline(); + super.reset(); + } // reset() + + /** Configures the pipeline. */ + protected void configurePipeline() { + + // REVISIT: This should be better designed. In other words, we + // need to figure out what is the best way for people to + // re-use *most* of the standard configuration but do + // things common things such as remove a component (e.g. + // the validator), insert a new component (e.g. XInclude), + // etc... -Ac + + // setup document pipeline + if (fDTDValidator != null) { + fScanner.setDocumentHandler(fDTDValidator); + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + + // filters + fDTDValidator.setDocumentHandler(fNamespaceBinder); + fDTDValidator.setDocumentSource(fScanner); + fNamespaceBinder.setDocumentHandler(fDocumentHandler); + fNamespaceBinder.setDocumentSource(fDTDValidator); + fLastComponent = fNamespaceBinder; + } + else { + fDTDValidator.setDocumentHandler(fDocumentHandler); + fDTDValidator.setDocumentSource(fScanner); + fLastComponent = fDTDValidator; + } + } + else { + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + fScanner.setDocumentHandler(fNamespaceBinder); + fNamespaceBinder.setDocumentHandler(fDocumentHandler); + fNamespaceBinder.setDocumentSource(fScanner); + fLastComponent = fNamespaceBinder; + } + else { + fScanner.setDocumentHandler(fDocumentHandler); + fLastComponent = fScanner; + } + } + + configureDTDPipeline(); + } // configurePipeline() + + protected void configureDTDPipeline (){ + + // setup dtd pipeline + if (fDTDScanner != null) { + fProperties.put(DTD_SCANNER, fDTDScanner); + if (fDTDProcessor != null) { + fProperties.put(DTD_PROCESSOR, fDTDProcessor); + fDTDScanner.setDTDHandler(fDTDProcessor); + fDTDProcessor.setDTDSource(fDTDScanner); + fDTDProcessor.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fDTDProcessor); + } + + fDTDScanner.setDTDContentModelHandler(fDTDProcessor); + fDTDProcessor.setDTDContentModelSource(fDTDScanner); + fDTDProcessor.setDTDContentModelHandler(fDTDContentModelHandler); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.setDTDContentModelSource(fDTDProcessor); + } + } + else { + fDTDScanner.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fDTDScanner); + } + fDTDScanner.setDTDContentModelHandler(fDTDContentModelHandler); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.setDTDContentModelSource(fDTDScanner); + } + } + } + + + } + + // features and properties + + /** + * Check a feature. If feature is know and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) + throws XMLConfigurationException { + + // + // Xerces Features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/validation/dynamic + // Allows the parser to validate a document only when it + // contains a grammar. Validation is turned on/off based + // on each document instance, automatically. + // + if (suffixLength == Constants.DYNAMIC_VALIDATION_FEATURE.length() && + featureId.endsWith(Constants.DYNAMIC_VALIDATION_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE.length() && + featureId.endsWith(Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_CONTENT_MODELS_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_CONTENT_MODELS_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-dtd-grammar + // + if (suffixLength == Constants.LOAD_DTD_GRAMMAR_FEATURE.length() && + featureId.endsWith(Constants.LOAD_DTD_GRAMMAR_FEATURE)) { + return; + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-external-dtd + // + if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() && + featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_DATATYPES_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_DATATYPES_FEATURE)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + } + + // + // Not recognized + // + + super.checkFeature(featureId); + + } // checkFeature(String) + + /** + * Check a property. If the property is know and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkProperty(String propertyId) + throws XMLConfigurationException { + + // + // Xerces Properties + // + + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() && + propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) { + return; + } + } + + // + // Not recognized + // + + super.checkProperty(propertyId); + + } // checkProperty(String) + + // factory methods + + /** Creates an entity manager. */ + protected XMLEntityManager createEntityManager() { + return new XMLEntityManager(); + } // createEntityManager():XMLEntityManager + + /** Creates an error reporter. */ + protected XMLErrorReporter createErrorReporter() { + return new XMLErrorReporter(); + } // createErrorReporter():XMLErrorReporter + + /** Create a document scanner. */ + protected XMLDocumentScanner createDocumentScanner() { + return new XMLDocumentScannerImpl(); + } // createDocumentScanner():XMLDocumentScanner + + /** Create a DTD scanner. */ + protected XMLDTDScanner createDTDScanner() { + return new XMLDTDScannerImpl(); + } // createDTDScanner():XMLDTDScanner + + /** Create a DTD loader . */ + protected XMLDTDProcessor createDTDProcessor() { + return new XMLDTDProcessor(); + } // createDTDProcessor():XMLDTDProcessor + + /** Create a DTD validator. */ + protected XMLDTDValidator createDTDValidator() { + return new XMLDTDValidator(); + } // createDTDValidator():XMLDTDValidator + + /** Create a namespace binder. */ + protected XMLNamespaceBinder createNamespaceBinder() { + return new XMLNamespaceBinder(); + } // createNamespaceBinder():XMLNamespaceBinder + + /** Create a datatype validator factory. */ + protected DTDDVFactory createDatatypeValidatorFactory() { + return DTDDVFactory.getInstance(); + } // createDatatypeValidatorFactory():DatatypeValidatorFactory + protected ValidationManager createValidationManager(){ + return new ValidationManager(); + } + +} // class DTDConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/DTDParser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/DTDParser.java new file mode 100644 index 0000000..8efc320 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/DTDParser.java @@ -0,0 +1,478 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.dtd.DTDGrammar; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDTDScanner; + +/** + * @version $Id$ + */ +public abstract class DTDParser + extends XMLGrammarParser + implements XMLDTDHandler, XMLDTDContentModelHandler { + + // + // Data + // + + /** fDTDScanner */ + protected XMLDTDScanner fDTDScanner; + + // + // Constructors + // + + /** + * + * + * @param symbolTable + */ + public DTDParser(SymbolTable symbolTable) { + super(symbolTable); + } + + // + // Methods + // + + /** + * getDTDGrammar + * + * @return the grammar created by this parser + */ + public DTDGrammar getDTDGrammar() { + return null; + } // getDTDGrammar + + // + // XMLDTDHandler methods + // + + /** + * This method notifies of the start of an entity. The DTD has the + * pseudo-name of "[dtd]" and parameter entity names start with '%'. + *

        + * Note: Since the DTD is an entity, the handler + * will be notified of the start of the DTD entity by calling the + * startEntity method with the entity name "[dtd]" before calling + * the startDTD method. + * + * @param name The name of the entity. + * @param publicId The public identifier of the entity if the entity + * is external, null otherwise. + * @param systemId The system identifier of the entity if the entity + * is external, null otherwise. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal parameter entities). + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startEntity(String name, String publicId, String systemId, + String encoding) throws XNIException { + } + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

        + * Note: This method is only called for external + * parameter entities referenced in the DTD. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding) throws XNIException { + } + + /** + * The start of the DTD. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDTD(XMLLocator locator, Augmentations augmentations) + throws XNIException { + } + + /** + * A comment. + * + * @param text The text in the comment. + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augmentations) throws XNIException { + } // comment + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, + Augmentations augmentations) + throws XNIException { + } // processingInstruction + + /** + * The start of the external subset. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startExternalSubset(XMLResourceIdentifier identifier, + Augmentations augmentations) throws XNIException { + } // startExternalSubset + + /** + * The end of the external subset. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endExternalSubset(Augmentations augmentations) throws XNIException { + } // endExternalSubset + + /** + * An element declaration. + * + * @param name The name of the element. + * @param contentModel The element content model. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void elementDecl(String name, String contentModel, + Augmentations augmentations) + throws XNIException { + } // elementDecl + + /** + * The start of an attribute list. + * + * @param elementName The name of the element that this attribute + * list is associated with. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startAttlist(String elementName, + Augmentations augmentations) throws XNIException { + } // startAttlist + + /** + * An attribute declaration. + * + * @param elementName The name of the element that this attribute + * is associated with. + * @param attributeName The name of the attribute. + * @param type The attribute type. This value will be one of + * the following: "CDATA", "ENTITY", "ENTITIES", + * "ENUMERATION", "ID", "IDREF", "IDREFS", + * "NMTOKEN", "NMTOKENS", or "NOTATION". + * @param enumeration If the type has the value "ENUMERATION", this + * array holds the allowed attribute values; + * otherwise, this array is null. + * @param defaultType The attribute default type. This value will be + * one of the following: "#FIXED", "#IMPLIED", + * "#REQUIRED", or null. + * @param defaultValue The attribute default value, or null if no + * default value is specified. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, + String defaultType, XMLString defaultValue, + XMLString nonNormalizedDefaultValue, Augmentations augmentations) + throws XNIException { + } // attributeDecl + + /** + * The end of an attribute list. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endAttlist(Augmentations augmentations) throws XNIException { + } // endAttlist + + /** + * An internal entity declaration. + * + * @param name The name of the entity. Parameter entity names start with + * '%', whereas the name of a general entity is just the + * entity name. + * @param text The value of the entity. + * @param nonNormalizedText The non-normalized value of the entity. This + * value contains the same sequence of characters that was in + * the internal entity declaration, without any entity + * references expanded. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void internalEntityDecl(String name, XMLString text, + XMLString nonNormalizedText, + Augmentations augmentations) + throws XNIException { + } // internalEntityDecl(String,XMLString,XMLString) + + /** + * An external entity declaration. + * + * @param name The name of the entity. Parameter entity names start + * with '%', whereas the name of a general entity is just + * the entity name. + * @param identifier An object containing all location information + * pertinent to this entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void externalEntityDecl(String name, + XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException { + } // externalEntityDecl + + /** + * An unparsed entity declaration. + * + * @param name The name of the entity. + * @param identifier An object containing all location information + * pertinent to this entity. + * @param notation The name of the notation. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void unparsedEntityDecl(String name, + XMLResourceIdentifier identifier, + String notation, Augmentations augmentations) + throws XNIException { + } // unparsedEntityDecl + + /** + * A notation declaration + * + * @param name The name of the notation. + * @param identifier An object containing all location information + * pertinent to this notation. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void notationDecl(String name, XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException { + } // notationDecl + + /** + * The start of a conditional section. + * + * @param type The type of the conditional section. This value will + * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see XMLDTDHandler#CONDITIONAL_INCLUDE + * @see XMLDTDHandler#CONDITIONAL_IGNORE + */ + public void startConditional(short type, Augmentations augmentations) throws XNIException { + } // startConditional + + /** + * The end of a conditional section. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endConditional(Augmentations augmentations) throws XNIException { + } // endConditional + + /** + * The end of the DTD. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDTD(Augmentations augmentations) throws XNIException { + } // endDTD + + /** + * This method notifies the end of an entity. The DTD has the pseudo-name + * of "[dtd]" and parameter entity names start with '%'. + *

        + * Note: Since the DTD is an entity, the handler + * will be notified of the end of the DTD entity by calling the + * endEntity method with the entity name "[dtd]" after calling + * the endDTD method. + * + * @param name The name of the entity. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endEntity(String name, Augmentations augmentations) throws XNIException { + } + + // + // XMLDTDContentModelHandler methods + // + + /** + * The start of a content model. Depending on the type of the content + * model, specific methods may be called between the call to the + * startContentModel method and the call to the endContentModel method. + * + * @param elementName The name of the element. + * @param type The content model type. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_EMPTY + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_ANY + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_MIXED + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_CHILDREN + */ + public void startContentModel(String elementName, short type) + throws XNIException { + } // startContentModel + + /** + * A referenced element in a mixed content model. If the mixed content + * model only allows text content, then this method will not be called + * for that model. However, if this method is called for a mixed + * content model, then the zero or more occurrence count is implied. + *

        + * Note: This method is only called after a call to + * the startContentModel method where the type is TYPE_MIXED. + * + * @param elementName The name of the referenced element. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_MIXED + */ + public void mixedElement(String elementName) throws XNIException { + } // mixedElement + + /** + * The start of a children group. + *

        + * Note: This method is only called after a call to + * the startContentModel method where the type is TYPE_CHILDREN. + *

        + * Note: Children groups can be nested and have + * associated occurrence counts. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_CHILDREN + */ + public void childrenStartGroup() throws XNIException { + } // childrenStartGroup + + /** + * A referenced element in a children content model. + * + * @param elementName The name of the referenced element. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_CHILDREN + */ + public void childrenElement(String elementName) throws XNIException { + } // childrenElement + + /** + * The separator between choices or sequences of a children content + * model. + *

        + * Note: This method is only called after a call to + * the startContentModel method where the type is TYPE_CHILDREN. + * + * @param separator The type of children separator. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see XMLDTDContentModelHandler#SEPARATOR_CHOICE + * @see XMLDTDContentModelHandler#SEPARATOR_SEQUENCE + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_CHILDREN + */ + public void childrenSeparator(short separator) throws XNIException { + } // childrenSeparator + + /** + * The occurrence count for a child in a children content model. + *

        + * Note: This method is only called after a call to + * the startContentModel method where the type is TYPE_CHILDREN. + * + * @param occurrence The occurrence count for the last children element + * or children group. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see XMLDTDContentModelHandler#OCCURS_ZERO_OR_ONE + * @see XMLDTDContentModelHandler#OCCURS_ZERO_OR_MORE + * @see XMLDTDContentModelHandler#OCCURS_ONE_OR_MORE + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_CHILDREN + */ + public void childrenOccurrence(short occurrence) throws XNIException { + } // childrenOccurrence + + /** + * The end of a children group. + *

        + * Note: This method is only called after a call to + * the startContentModel method where the type is TYPE_CHILDREN. + * + * @see org.apache.xerces.impl.dtd.XMLElementDecl#TYPE_CHILDREN + */ + public void childrenEndGroup() throws XNIException { + } // childrenEndGroup + + /** + * The end of a content model. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endContentModel() throws XNIException { + } // endContentModel + +} // class DTDParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/IntegratedParserConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/IntegratedParserConfiguration.java new file mode 100644 index 0000000..a40ba11 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/IntegratedParserConfiguration.java @@ -0,0 +1,250 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.XMLDocumentScannerImpl; +import org.apache.xerces.impl.XMLNSDocumentScannerImpl; +import org.apache.xerces.impl.dtd.XMLDTDValidator; +import org.apache.xerces.impl.dtd.XMLNSDTDValidator; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLDocumentScanner; + +/** + * This is configuration uses a scanner that integrates both scanning of the document + * and binding namespaces. + * + * If namespace feature is turned on, the pipeline is constructured with the + * following components: + * XMLNSDocumentScannerImpl -> XMLNSDTDValidator -> (optional) XMLSchemaValidator + * + * If the namespace feature is turned off the default document scanner implementation + * is used (XMLDocumentScannerImpl). + *

        + * In addition to the features and properties recognized by the base + * parser configuration, this class recognizes these additional + * features and properties: + *

          + *
        • Features + *
            + *
          • http://apache.org/xml/features/validation/schema
          • + *
          • http://apache.org/xml/features/validation/schema-full-checking
          • + *
          • http://apache.org/xml/features/validation/schema/normalized-value
          • + *
          • http://apache.org/xml/features/validation/schema/element-default
          • + *
          + *
        • Properties + *
            + *
          • http://apache.org/xml/properties/internal/error-reporter
          • + *
          • http://apache.org/xml/properties/internal/entity-manager
          • + *
          • http://apache.org/xml/properties/internal/document-scanner
          • + *
          • http://apache.org/xml/properties/internal/dtd-scanner
          • + *
          • http://apache.org/xml/properties/internal/grammar-pool
          • + *
          • http://apache.org/xml/properties/internal/validator/dtd
          • + *
          • http://apache.org/xml/properties/internal/datatype-validator-factory
          • + *
          + *
        + * + * @author Elena Litani, IBM + * + * @version $Id$ + */ +public class IntegratedParserConfiguration +extends StandardParserConfiguration { + + + // + // REVISIT: should this configuration depend on the others + // like DTD/Standard one? + // + + /** Document scanner that does namespace binding. */ + protected XMLNSDocumentScannerImpl fNamespaceScanner; + + /** Default Xerces implementation of scanner */ + protected XMLDocumentScannerImpl fNonNSScanner; + + /** DTD Validator that does not bind namespaces */ + protected XMLDTDValidator fNonNSDTDValidator; + + // + // Constructors + // + + /** Default constructor. */ + public IntegratedParserConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public IntegratedParserConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public IntegratedParserConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public IntegratedParserConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + + // create components + fNonNSScanner = new XMLDocumentScannerImpl(); + fNonNSDTDValidator = new XMLDTDValidator(); + + // add components + addComponent((XMLComponent)fNonNSScanner); + addComponent((XMLComponent)fNonNSDTDValidator); + + } // (SymbolTable,XMLGrammarPool) + + + /** Configures the pipeline. */ + protected void configurePipeline() { + + // use XML 1.0 datatype library + setProperty(DATATYPE_VALIDATOR_FACTORY, fDatatypeValidatorFactory); + + // setup DTD pipeline + configureDTDPipeline(); + + // setup document pipeline + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + fProperties.put(NAMESPACE_BINDER, fNamespaceBinder); + fScanner = fNamespaceScanner; + fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner); + if (fDTDValidator != null) { + fProperties.put(DTD_VALIDATOR, fDTDValidator); + fNamespaceScanner.setDTDValidator(fDTDValidator); + fNamespaceScanner.setDocumentHandler(fDTDValidator); + fDTDValidator.setDocumentSource(fNamespaceScanner); + fDTDValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fDTDValidator); + } + fLastComponent = fDTDValidator; + } + else { + fNamespaceScanner.setDocumentHandler(fDocumentHandler); + fNamespaceScanner.setDTDValidator(null); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fNamespaceScanner); + } + fLastComponent = fNamespaceScanner; + } + } + else { + fScanner = fNonNSScanner; + fProperties.put(DOCUMENT_SCANNER, fNonNSScanner); + if (fNonNSDTDValidator != null) { + fProperties.put(DTD_VALIDATOR, fNonNSDTDValidator); + fNonNSScanner.setDocumentHandler(fNonNSDTDValidator); + fNonNSDTDValidator.setDocumentSource(fNonNSScanner); + fNonNSDTDValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fNonNSDTDValidator); + } + fLastComponent = fNonNSDTDValidator; + } + else { + fScanner.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fScanner); + } + fLastComponent = fScanner; + } + } + + // setup document pipeline + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // If schema validator was not in the pipeline insert it. + if (fSchemaValidator == null) { + fSchemaValidator = new XMLSchemaValidator(); + + // add schema component + fProperties.put(SCHEMA_VALIDATOR, fSchemaValidator); + addComponent(fSchemaValidator); + // add schema message formatter + if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { + XSMessageFormatter xmft = new XSMessageFormatter(); + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, xmft); + } + + } + + fLastComponent.setDocumentHandler(fSchemaValidator); + fSchemaValidator.setDocumentSource(fLastComponent); + fSchemaValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fSchemaValidator); + } + fLastComponent = fSchemaValidator; + } + } // configurePipeline() + + + + /** Create a document scanner: this scanner performs namespace binding + */ + protected XMLDocumentScanner createDocumentScanner() { + fNamespaceScanner = new XMLNSDocumentScannerImpl(); + return fNamespaceScanner; + } // createDocumentScanner():XMLDocumentScanner + + + /** Create a DTD validator: this validator performs namespace binding. + */ + protected XMLDTDValidator createDTDValidator() { + return new XMLNSDTDValidator(); + } // createDTDValidator():XMLDTDValidator + +} // class IntegratedParserConfiguration + diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/NonValidatingConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/NonValidatingConfiguration.java new file mode 100644 index 0000000..85620e2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/NonValidatingConfiguration.java @@ -0,0 +1,793 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLDTDScannerImpl; +import org.apache.xerces.impl.XMLDocumentScannerImpl; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.XMLNSDocumentScannerImpl; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDScanner; +import org.apache.xerces.xni.parser.XMLDocumentScanner; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLPullParserConfiguration; + +/** + * This is the non validating parser configuration. It extends the basic + * configuration with the set of following parser components: + * Document scanner, DTD scanner, namespace binder, document handler. + *

        + * Xerces parser that uses this configuration is not conformant + * non-validating XML processor, since conformant non-validating processor is required + * to process "all the declarations they read in the internal DTD subset ... must use the information in those declarations to normalize attribute values, + * include the replacement text of internal entities, and supply default attribute values". + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public class NonValidatingConfiguration + extends BasicParserConfiguration + implements XMLPullParserConfiguration { + + // + // Constants + // + + // feature identifiers + + /** Feature identifier: warn on duplicate attribute definition. */ + protected static final String WARN_ON_DUPLICATE_ATTDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; + + /** Feature identifier: warn on duplicate entity definition. */ + protected static final String WARN_ON_DUPLICATE_ENTITYDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ENTITYDEF_FEATURE; + + /** Feature identifier: warn on undeclared element definition. */ + protected static final String WARN_ON_UNDECLARED_ELEMDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE; + + /** Feature identifier: allow Java encodings. */ + protected static final String ALLOW_JAVA_ENCODINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; + + /** Feature identifier: continue after fatal error. */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + /** Feature identifier: load external DTD. */ + protected static final String LOAD_EXTERNAL_DTD = + Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE; + + /** Feature identifier: notify built-in refereces. */ + protected static final String NOTIFY_BUILTIN_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE; + + /** Feature identifier: notify character refereces. */ + protected static final String NOTIFY_CHAR_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE; + + + /** Feature identifier: expose schema normalized value */ + protected static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + + + /** Feature identifier: send element default value via characters() */ + protected static final String SCHEMA_ELEMENT_DEFAULT = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; + + // property identifiers + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier document scanner: */ + protected static final String DOCUMENT_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_SCANNER_PROPERTY; + + /** Property identifier: DTD scanner. */ + protected static final String DTD_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY; + + /** Property identifier: grammar pool. */ + protected static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: DTD validator. */ + protected static final String DTD_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; + + /** Property identifier: namespace binder. */ + protected static final String NAMESPACE_BINDER = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_BINDER_PROPERTY; + + /** Property identifier: datatype validator factory. */ + protected static final String DATATYPE_VALIDATOR_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; + + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: XML Schema validator. */ + protected static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: locale. */ + protected static final String LOCALE = + Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + + + // debugging + + /** Set to true and recompile to print exception stack trace. */ + private static final boolean PRINT_EXCEPTION_STACK_TRACE = false; + + // + // Data + // + + // components (non-configurable) + + /** Grammar pool. */ + protected XMLGrammarPool fGrammarPool; + + /** Datatype validator factory. */ + protected DTDDVFactory fDatatypeValidatorFactory; + + // components (configurable) + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + /** Entity manager. */ + protected XMLEntityManager fEntityManager; + + /** Document scanner. */ + protected XMLDocumentScanner fScanner; + + /** Input Source */ + protected XMLInputSource fInputSource; + + /** DTD scanner. */ + protected XMLDTDScanner fDTDScanner; + + + protected ValidationManager fValidationManager; + + // private data + + /** Document scanner that does namespace binding. */ + private XMLNSDocumentScannerImpl fNamespaceScanner; + + /** Default Xerces implementation of scanner*/ + private XMLDocumentScannerImpl fNonNSScanner; + + + /** fConfigUpdated is set to true if there has been any change to the configuration settings, + * i.e a feature or a property was changed. + */ + protected boolean fConfigUpdated = false; + + + // state + + /** Locator */ + protected XMLLocator fLocator; + + /** + * True if a parse is in progress. This state is needed because + * some features/properties cannot be set while parsing (e.g. + * validation and namespaces). + */ + protected boolean fParseInProgress = false; + + // + // Constructors + // + + /** Default constructor. */ + public NonValidatingConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public NonValidatingConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public NonValidatingConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public NonValidatingConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, parentSettings); + + // add default recognized features + final String[] recognizedFeatures = { + PARSER_SETTINGS, + NAMESPACES, + //WARN_ON_DUPLICATE_ATTDEF, // from XMLDTDScannerImpl + //WARN_ON_UNDECLARED_ELEMDEF, // from XMLDTDScannerImpl + //ALLOW_JAVA_ENCODINGS, // from XMLEntityManager + CONTINUE_AFTER_FATAL_ERROR, + //LOAD_EXTERNAL_DTD, // from XMLDTDScannerImpl + //NOTIFY_BUILTIN_REFS, // from XMLDocumentFragmentScannerImpl + //NOTIFY_CHAR_REFS, // from XMLDocumentFragmentScannerImpl + //WARN_ON_DUPLICATE_ENTITYDEF // from XMLEntityManager + }; + addRecognizedFeatures(recognizedFeatures); + + // set state for default features + //setFeature(WARN_ON_DUPLICATE_ATTDEF, false); // from XMLDTDScannerImpl + //setFeature(WARN_ON_UNDECLARED_ELEMDEF, false); // from XMLDTDScannerImpl + //setFeature(ALLOW_JAVA_ENCODINGS, false); // from XMLEntityManager + fFeatures.put(CONTINUE_AFTER_FATAL_ERROR, Boolean.FALSE); + fFeatures.put(PARSER_SETTINGS, Boolean.TRUE); + fFeatures.put(NAMESPACES, Boolean.TRUE); + //setFeature(LOAD_EXTERNAL_DTD, true); // from XMLDTDScannerImpl + //setFeature(NOTIFY_BUILTIN_REFS, false); // from XMLDocumentFragmentScannerImpl + //setFeature(NOTIFY_CHAR_REFS, false); // from XMLDocumentFragmentScannerImpl + //setFeature(WARN_ON_DUPLICATE_ENTITYDEF, false); // from XMLEntityManager + + // add default recognized properties + final String[] recognizedProperties = { + ERROR_REPORTER, + ENTITY_MANAGER, + DOCUMENT_SCANNER, + DTD_SCANNER, + DTD_VALIDATOR, + NAMESPACE_BINDER, + XMLGRAMMAR_POOL, + DATATYPE_VALIDATOR_FACTORY, + VALIDATION_MANAGER, + LOCALE + }; + addRecognizedProperties(recognizedProperties); + + fGrammarPool = grammarPool; + if(fGrammarPool != null){ + fProperties.put(XMLGRAMMAR_POOL, fGrammarPool); + } + + fEntityManager = createEntityManager(); + fProperties.put(ENTITY_MANAGER, fEntityManager); + addComponent(fEntityManager); + + fErrorReporter = createErrorReporter(); + fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner()); + fProperties.put(ERROR_REPORTER, fErrorReporter); + addComponent(fErrorReporter); + + // this configuration delays creation of the scanner + // till it is known if namespace processing should be performed + + fDTDScanner = createDTDScanner(); + if (fDTDScanner != null) { + fProperties.put(DTD_SCANNER, fDTDScanner); + if (fDTDScanner instanceof XMLComponent) { + addComponent((XMLComponent)fDTDScanner); + } + } + + fDatatypeValidatorFactory = createDatatypeValidatorFactory(); + if (fDatatypeValidatorFactory != null) { + fProperties.put(DATATYPE_VALIDATOR_FACTORY, + fDatatypeValidatorFactory); + } + fValidationManager = createValidationManager(); + + if (fValidationManager != null) { + fProperties.put(VALIDATION_MANAGER, fValidationManager); + } + // add message formatters + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + + fConfigUpdated = false; + + // set locale + try { + setLocale(Locale.getDefault()); + } + catch (XNIException e) { + // do nothing + // REVISIT: What is the right thing to do? -Ac + } + + } // (SymbolTable,XMLGrammarPool) + + // + // Public methods + // + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + fConfigUpdated = true; + super.setFeature(featureId, state); + } + + public Object getProperty(String propertyId) + throws XMLConfigurationException { + if (LOCALE.equals(propertyId)) { + return getLocale(); + } + return super.getProperty(propertyId); + } + + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + fConfigUpdated = true; + if (LOCALE.equals(propertyId)) { + setLocale((Locale) value); + } + super.setProperty(propertyId, value); + } + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException { + super.setLocale(locale); + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + + public boolean getFeature(String featureId) + throws XMLConfigurationException { + // make this feature special + if (featureId.equals(PARSER_SETTINGS)){ + return fConfigUpdated; + } + return super.getFeature(featureId); + + } // getFeature(String):boolean + // + // XMLPullParserConfiguration methods + // + + // parsing + + /** + * Sets the input source for the document to parse. + * + * @param inputSource The document's input source. + * + * @exception XMLConfigurationException Thrown if there is a + * configuration error when initializing the + * parser. + * @exception IOException Thrown on I/O error. + * + * @see #parse(boolean) + */ + public void setInputSource(XMLInputSource inputSource) + throws XMLConfigurationException, IOException { + + // REVISIT: this method used to reset all the components and + // construct the pipeline. Now reset() is called + // in parse (boolean) just before we parse the document + // Should this method still throw exceptions..? + + fInputSource = inputSource; + + } // setInputSource(XMLInputSource) + + /** + * Parses the document in a pull parsing fashion. + * + * @param complete True if the pull parser should parse the + * remaining document completely. + * + * @return True if there is more document to parse. + * + * @exception XNIException Any XNI exception, possibly wrapping + * another exception. + * @exception IOException An IO exception from the parser, possibly + * from a byte stream or character stream + * supplied by the parser. + * + * @see #setInputSource + */ + public boolean parse(boolean complete) throws XNIException, IOException { + // + // reset and configure pipeline and set InputSource. + if (fInputSource !=null) { + try { + // resets and sets the pipeline. + reset(); + fScanner.setInputSource(fInputSource); + fInputSource = null; + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + } + + try { + return fScanner.scanDocument(complete); + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + + } // parse(boolean):boolean + + /** + * If the application decides to terminate parsing before the xml document + * is fully parsed, the application should call this method to free any + * resource allocated during parsing. For example, close all opened streams. + */ + public void cleanup() { + fEntityManager.closeReaders(); + } + + // + // XMLParserConfiguration methods + // + + /** + * Parses the specified input source. + * + * @param source The input source. + * + * @exception XNIException Throws exception on XNI error. + * @exception java.io.IOException Throws exception on i/o error. + */ + public void parse(XMLInputSource source) throws XNIException, IOException { + + if (fParseInProgress) { + // REVISIT - need to add new error message + throw new XNIException("FWK005 parse may not be called while parsing."); + } + fParseInProgress = true; + + try { + setInputSource(source); + parse(true); + } + catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } + catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + finally { + fParseInProgress = false; + // close all streams opened by xerces + this.cleanup(); + } + + } // parse(InputSource) + + // + // Protected methods + // + + /** + * Reset all components before parsing. + * + * @throws XNIException Thrown if an error occurs during initialization. + */ + protected void reset() throws XNIException { + + if (fValidationManager != null) + fValidationManager.reset(); + // configure the pipeline and initialize the components + configurePipeline(); + super.reset(); + + } // reset() + + /** Configures the pipeline. */ + protected void configurePipeline() { + // create appropriate scanner + // and register it as one of the components. + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + if (fNamespaceScanner == null) { + fNamespaceScanner = new XMLNSDocumentScannerImpl(); + addComponent((XMLComponent)fNamespaceScanner); + } + fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner); + fNamespaceScanner.setDTDValidator(null); + fScanner = fNamespaceScanner; + } + else { + if (fNonNSScanner == null) { + fNonNSScanner = new XMLDocumentScannerImpl(); + addComponent((XMLComponent)fNonNSScanner); + } + fProperties.put(DOCUMENT_SCANNER, fNonNSScanner); + fScanner = fNonNSScanner; + } + + fScanner.setDocumentHandler(fDocumentHandler); + fLastComponent = fScanner; + // setup dtd pipeline + if (fDTDScanner != null) { + fDTDScanner.setDTDHandler(fDTDHandler); + fDTDScanner.setDTDContentModelHandler(fDTDContentModelHandler); + } + + + } // configurePipeline() + + // features and properties + + /** + * Check a feature. If feature is know and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) + throws XMLConfigurationException { + + // + // Xerces Features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/validation/dynamic + // Allows the parser to validate a document only when it + // contains a grammar. Validation is turned on/off based + // on each document instance, automatically. + // + if (suffixLength == Constants.DYNAMIC_VALIDATION_FEATURE.length() && + featureId.endsWith(Constants.DYNAMIC_VALIDATION_FEATURE)) { + return; + } + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE.length() && + featureId.endsWith(Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_CONTENT_MODELS_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_CONTENT_MODELS_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-dtd-grammar + // + if (suffixLength == Constants.LOAD_DTD_GRAMMAR_FEATURE.length() && + featureId.endsWith(Constants.LOAD_DTD_GRAMMAR_FEATURE)) { + return; + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-external-dtd + // + if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() && + featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_DATATYPES_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_DATATYPES_FEATURE)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + } + + // + // Not recognized + // + + super.checkFeature(featureId); + + } // checkFeature(String) + + /** + * Check a property. If the property is know and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkProperty(String propertyId) + throws XMLConfigurationException { + + // + // Xerces Properties + // + + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() && + propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) { + return; + } + } + + if (propertyId.startsWith(Constants.JAXP_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.JAXP_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SCHEMA_SOURCE.length() && + propertyId.endsWith(Constants.SCHEMA_SOURCE)) { + return; + } + } + + // + // Not recognized + // + + super.checkProperty(propertyId); + + } // checkProperty(String) + + // factory methods + + /** Creates an entity manager. */ + protected XMLEntityManager createEntityManager() { + return new XMLEntityManager(); + } // createEntityManager():XMLEntityManager + + /** Creates an error reporter. */ + protected XMLErrorReporter createErrorReporter() { + return new XMLErrorReporter(); + } // createErrorReporter():XMLErrorReporter + + /** Create a document scanner. */ + protected XMLDocumentScanner createDocumentScanner() { + return null; + } // createDocumentScanner():XMLDocumentScanner + + /** Create a DTD scanner. */ + protected XMLDTDScanner createDTDScanner() { + return new XMLDTDScannerImpl(); + } // createDTDScanner():XMLDTDScanner + + /** Create a datatype validator factory. */ + protected DTDDVFactory createDatatypeValidatorFactory() { + return DTDDVFactory.getInstance(); + } // createDatatypeValidatorFactory():DatatypeValidatorFactory + protected ValidationManager createValidationManager(){ + return new ValidationManager(); + } + +} // class NonValidatingConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/ObjectFactory.java b/resources/xerces2-j-src/org/apache/xerces/parsers/ObjectFactory.java new file mode 100644 index 0000000..3dfd235 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/ObjectFactory.java @@ -0,0 +1,543 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; + +/** + * This class is duplicated for each JAXP subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of the JAXP + * API. + *

        + * This code is designed to implement the JAXP 1.1 spec pluggability + * feature and is designed to run on JDK version 1.1 and + * later, and to compile on JDK 1.2 and onward. + * The code also runs both as part of an unbundled jar file and + * when bundled as part of the JDK. + *

        + * + * @version $Id$ + */ +final class ObjectFactory { + + // + // Constants + // + + // name of default properties file to look for in JDK's jre/lib directory + private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties"; + + /** Set to true for debugging */ + private static final boolean DEBUG = isDebugEnabled(); + + /** + * Default columns per line. + */ + private static final int DEFAULT_LINE_LENGTH = 80; + + /** cache the contents of the xerces.properties file. + * Until an attempt has been made to read this file, this will + * be null; if the file does not exist or we encounter some other error + * during the read, this will be empty. + */ + private static Properties fXercesProperties = null; + + /*** + * Cache the time stamp of the xerces.properties file so + * that we know if it's been modified and can invalidate + * the cache when necessary. + */ + private static long fLastModified = -1; + + // + // static methods + // + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *

          + *
        1. query the system property using System.getProperty + *
        2. read META-INF/services/factoryId file + *
        3. use fallback classname + *
        + * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, String fallbackClassName) + throws ConfigurationError { + return createObject(factoryId, null, fallbackClassName); + } // createObject(String,String):Object + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *
          + *
        1. query the system property using System.getProperty + *
        2. read $java.home/lib/propertiesFilename file + *
        3. read META-INF/services/factoryId file + *
        4. use fallback classname + *
        + * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param propertiesFilename The filename in the $java.home/lib directory + * of the properties file. If none specified, + * ${java.home}/lib/xerces.properties will be used. + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, + String propertiesFilename, + String fallbackClassName) + throws ConfigurationError + { + if (DEBUG) debugPrintln("debug is on"); + + ClassLoader cl = findClassLoader(); + + // Use the system property first + try { + String systemProp = SecuritySupport.getSystemProperty(factoryId); + if (systemProp != null && systemProp.length() > 0) { + if (DEBUG) debugPrintln("found system property, value=" + systemProp); + return newInstance(systemProp, cl, true); + } + } catch (SecurityException se) { + // Ignore and continue w/ next location + } + + // Try to read from propertiesFilename, or $java.home/lib/xerces.properties + String factoryClassName = null; + // no properties file name specified; use $JAVA_HOME/lib/xerces.properties: + if (propertiesFilename == null) { + File propertiesFile = null; + boolean propertiesFileExists = false; + try { + String javah = SecuritySupport.getSystemProperty("java.home"); + propertiesFilename = javah + File.separator + + "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME; + propertiesFile = new File(propertiesFilename); + propertiesFileExists = SecuritySupport.getFileExists(propertiesFile); + } catch (SecurityException e) { + // try again... + fLastModified = -1; + fXercesProperties = null; + } + + synchronized (ObjectFactory.class) { + boolean loadProperties = false; + FileInputStream fis = null; + try { + // file existed last time + if(fLastModified >= 0) { + if(propertiesFileExists && + (fLastModified < (fLastModified = SecuritySupport.getLastModified(propertiesFile)))) { + loadProperties = true; + } else { + // file has stopped existing... + if(!propertiesFileExists) { + fLastModified = -1; + fXercesProperties = null; + } // else, file wasn't modified! + } + } else { + // file has started to exist: + if(propertiesFileExists) { + loadProperties = true; + fLastModified = SecuritySupport.getLastModified(propertiesFile); + } // else, nothing's changed + } + if(loadProperties) { + // must never have attempted to read xerces.properties before (or it's outdeated) + fXercesProperties = new Properties(); + fis = SecuritySupport.getFileInputStream(propertiesFile); + fXercesProperties.load(fis); + } + } catch (Exception x) { + fXercesProperties = null; + fLastModified = -1; + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if(fXercesProperties != null) { + factoryClassName = fXercesProperties.getProperty(factoryId); + } + } else { + FileInputStream fis = null; + try { + fis = SecuritySupport.getFileInputStream(new File(propertiesFilename)); + Properties props = new Properties(); + props.load(fis); + factoryClassName = props.getProperty(factoryId); + } catch (Exception x) { + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if (factoryClassName != null) { + if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName); + return newInstance(factoryClassName, cl, true); + } + + // Try Jar Service Provider Mechanism + Object provider = findJarServiceProvider(factoryId); + if (provider != null) { + return provider; + } + + if (fallbackClassName == null) { + throw new ConfigurationError( + "Provider for " + factoryId + " cannot be found", null); + } + + if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); + return newInstance(fallbackClassName, cl, true); + } // createObject(String,String,String):Object + + // + // Private static methods + // + + /** Returns true if debug has been enabled. */ + private static boolean isDebugEnabled() { + try { + String val = SecuritySupport.getSystemProperty("xerces.debug"); + // Allow simply setting the prop to turn on debug + return (val != null && (!"false".equals(val))); + } + catch (SecurityException se) {} + return false; + } // isDebugEnabled() + + /** Prints a message to standard error if debugging is enabled. */ + private static void debugPrintln(String msg) { + if (DEBUG) { + System.err.println("XERCES: " + msg); + } + } // debugPrintln(String) + + /** + * Figure out which ClassLoader to use. For JDK 1.2 and later use + * the context ClassLoader. + */ + static ClassLoader findClassLoader() + throws ConfigurationError + { + // Figure out which ClassLoader to use for loading the provider + // class. If there is a Context ClassLoader then use it. + ClassLoader context = SecuritySupport.getContextClassLoader(); + ClassLoader system = SecuritySupport.getSystemClassLoader(); + + ClassLoader chain = system; + while (true) { + if (context == chain) { + // Assert: we are on JDK 1.1 or we have no Context ClassLoader + // or any Context ClassLoader in chain of system classloader + // (including extension ClassLoader) so extend to widest + // ClassLoader (always look in system ClassLoader if Xerces + // is in boot/extension/system classpath and in current + // ClassLoader otherwise); normal classloaders delegate + // back to system ClassLoader first so this widening doesn't + // change the fact that context ClassLoader will be consulted + ClassLoader current = ObjectFactory.class.getClassLoader(); + + chain = system; + while (true) { + if (current == chain) { + // Assert: Current ClassLoader in chain of + // boot/extension/system ClassLoaders + return system; + } + if (chain == null) { + break; + } + chain = SecuritySupport.getParentClassLoader(chain); + } + + // Assert: Current ClassLoader not in chain of + // boot/extension/system ClassLoaders + return current; + } + + if (chain == null) { + // boot ClassLoader reached + break; + } + + // Check for any extension ClassLoaders in chain up to + // boot ClassLoader + chain = SecuritySupport.getParentClassLoader(chain); + }; + + // Assert: Context ClassLoader not in chain of + // boot/extension/system ClassLoaders + return context; + } // findClassLoader():ClassLoader + + /** + * Create an instance of a class using the specified ClassLoader + */ + static Object newInstance(String className, ClassLoader cl, + boolean doFallback) + throws ConfigurationError + { + // assert(className != null); + try{ + Class providerClass = findProviderClass(className, cl, doFallback); + Object instance = providerClass.newInstance(); + if (DEBUG) debugPrintln("created new instance of " + providerClass + + " using ClassLoader: " + cl); + return instance; + } catch (ClassNotFoundException x) { + throw new ConfigurationError( + "Provider " + className + " not found", x); + } catch (Exception x) { + throw new ConfigurationError( + "Provider " + className + " could not be instantiated: " + x, + x); + } + } + + /** + * Find a Class using the specified ClassLoader + */ + static Class findProviderClass(String className, ClassLoader cl, + boolean doFallback) + throws ClassNotFoundException, ConfigurationError + { + //throw security exception if the calling thread is not allowed to access the package + //restrict the access to package as specified in java.security policy + SecurityManager security = System.getSecurityManager(); + if (security != null) { + final int lastDot = className.lastIndexOf('.'); + String packageName = className; + if (lastDot != -1) packageName = className.substring(0, lastDot); + security.checkPackageAccess(packageName); + } + Class providerClass; + if (cl == null) { + // XXX Use the bootstrap ClassLoader. There is no way to + // load a class using the bootstrap ClassLoader that works + // in both JDK 1.1 and Java 2. However, this should still + // work b/c the following should be true: + // + // (cl == null) iff current ClassLoader == null + // + // Thus Class.forName(String) will use the current + // ClassLoader which will be the bootstrap ClassLoader. + providerClass = Class.forName(className); + } else { + try { + providerClass = cl.loadClass(className); + } catch (ClassNotFoundException x) { + if (doFallback) { + // Fall back to current classloader + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (current == null) { + providerClass = Class.forName(className); + } else if (cl != current) { + cl = current; + providerClass = cl.loadClass(className); + } else { + throw x; + } + } else { + throw x; + } + } + } + + return providerClass; + } + + /* + * Try to find provider using Jar Service Provider Mechanism + * + * @return instance of provider class if found or null + */ + private static Object findJarServiceProvider(String factoryId) + throws ConfigurationError + { + String serviceId = "META-INF/services/" + factoryId; + InputStream is = null; + + // First try the Context ClassLoader + ClassLoader cl = findClassLoader(); + + is = SecuritySupport.getResourceAsStream(cl, serviceId); + + // If no provider found then try the current ClassLoader + if (is == null) { + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (cl != current) { + cl = current; + is = SecuritySupport.getResourceAsStream(cl, serviceId); + } + } + + if (is == null) { + // No provider found + return null; + } + + if (DEBUG) debugPrintln("found jar resource=" + serviceId + + " using ClassLoader: " + cl); + + // Read the service provider name in UTF-8 as specified in + // the jar spec. Unfortunately this fails in Microsoft + // VJ++, which does not implement the UTF-8 + // encoding. Theoretically, we should simply let it fail in + // that case, since the JVM is obviously broken if it + // doesn't support such a basic standard. But since there + // are still some users attempting to use VJ++ for + // development, we have dropped in a fallback which makes a + // second attempt using the platform's default encoding. In + // VJ++ this is apparently ASCII, which is a subset of + // UTF-8... and since the strings we'll be reading here are + // also primarily limited to the 7-bit ASCII range (at + // least, in English versions), this should work well + // enough to keep us on the air until we're ready to + // officially decommit from VJ++. [Edited comment from + // jkesselm] + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); + } catch (java.io.UnsupportedEncodingException e) { + rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); + } + + String factoryClassName = null; + try { + // XXX Does not handle all possible input as specified by the + // Jar Service Provider specification + factoryClassName = rd.readLine(); + } catch (IOException x) { + // No provider found + return null; + } + finally { + try { + // try to close the reader. + rd.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + + if (factoryClassName != null && + ! "".equals(factoryClassName)) { + if (DEBUG) debugPrintln("found in resource, value=" + + factoryClassName); + + // Note: here we do not want to fall back to the current + // ClassLoader because we want to avoid the case where the + // resource file was found using one ClassLoader and the + // provider class was instantiated using a different one. + return newInstance(factoryClassName, cl, false); + } + + // No provider found + return null; + } + + // + // Classes + // + + /** + * A configuration error. + */ + static final class ConfigurationError + extends Error { + + /** Serialization version. */ + static final long serialVersionUID = -7285495612271660427L; + + // + // Data + // + + /** Exception. */ + private Exception exception; + + // + // Constructors + // + + /** + * Construct a new instance with the specified detail string and + * exception. + */ + ConfigurationError(String msg, Exception x) { + super(msg); + this.exception = x; + } // (String,Exception) + + // + // methods + // + + /** Returns the exception associated to this error. */ + Exception getException() { + return exception; + } // getException():Exception + + } // class ConfigurationError + +} // class ObjectFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/SAXParser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/SAXParser.java new file mode 100644 index 0000000..a408cdf --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/SAXParser.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLParserConfiguration; + +/** + * This is the main Xerces SAX parser class. It uses the abstract SAX + * parser with a document scanner, a dtd scanner, and a validator, as + * well as a grammar pool. + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class SAXParser + extends AbstractSAXParser { + + // + // Constants + // + + // features + + /** Feature identifier: notify built-in refereces. */ + protected static final String NOTIFY_BUILTIN_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE; + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = { + NOTIFY_BUILTIN_REFS, + }; + + // properties + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: XML grammar pool. */ + protected static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX+Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + XMLGRAMMAR_POOL, + }; + + // + // Constructors + // + + /** + * Constructs a SAX parser using the specified parser configuration. + */ + public SAXParser(XMLParserConfiguration config) { + super(config); + } // (XMLParserConfiguration) + + /** + * Constructs a SAX parser using the dtd/xml schema parser configuration. + */ + public SAXParser() { + this(null, null); + } // () + + /** + * Constructs a SAX parser using the specified symbol table. + */ + public SAXParser(SymbolTable symbolTable) { + this(symbolTable, null); + } // (SymbolTable) + + /** + * Constructs a SAX parser using the specified symbol table and + * grammar pool. + */ + public SAXParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) { + super((XMLParserConfiguration)ObjectFactory.createObject( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration" + )); + + // set features + fConfiguration.addRecognizedFeatures(RECOGNIZED_FEATURES); + fConfiguration.setFeature(NOTIFY_BUILTIN_REFS, true); + + // set properties + fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES); + if (symbolTable != null) { + fConfiguration.setProperty(SYMBOL_TABLE, symbolTable); + } + if (grammarPool != null) { + fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool); + } + + } // (SymbolTable,XMLGrammarPool) + +} // class SAXParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/SecureProcessingConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/SecureProcessingConfiguration.java new file mode 100644 index 0000000..cf908bb --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/SecureProcessingConfiguration.java @@ -0,0 +1,921 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilterInputStream; +import java.io.FilterReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URL; +import java.util.Properties; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityDescription; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.dtd.XMLDTDProcessor; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDFilter; +import org.apache.xerces.xni.parser.XMLDTDScanner; +import org.apache.xerces.xni.parser.XMLDTDSource; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * This configuration enhances Xerces support for the JAXP secure processing feature. + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class SecureProcessingConfiguration extends + XIncludeAwareParserConfiguration { + + // + // Constants + // + + /** Property identifier: security manager. */ + private static final String SECURITY_MANAGER_PROPERTY = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + /** Property identifier: entity resolver. */ + private static final String ENTITY_RESOLVER_PROPERTY = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Feature identifier: external general entities. */ + private static final String EXTERNAL_GENERAL_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE; + + /** Feature identifier: external parameter entities. */ + private static final String EXTERNAL_PARAMETER_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE; + + /** Feature identifier: load external DTD. */ + private static final String LOAD_EXTERNAL_DTD = + Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE; + + /** Set to true for debugging */ + private static final boolean DEBUG = isDebugEnabled(); + + /** Cache the contents of the jaxp.properties file, if used. */ + private static Properties jaxpProperties = null; + + /** Cache the timestamp of the jaxp.properties file, if used. */ + private static long lastModified = -1; + + /** Xerces SecurityManager default value for entity expansion limit. **/ + private static final int SECURITY_MANAGER_DEFAULT_ENTITY_EXPANSION_LIMIT = 100000; + + /** Xerces SecurityManager default value of number of nodes created. **/ + private static final int SECURITY_MANAGER_DEFAULT_MAX_OCCUR_NODE_LIMIT = 3000; + + private static final String ENTITY_EXPANSION_LIMIT_PROPERTY_NAME = "jdk.xml.entityExpansionLimit"; + private static final String MAX_OCCUR_LIMIT_PROPERTY_NAME = "jdk.xml.maxOccur"; + private static final String TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME = "jdk.xml.totalEntitySizeLimit"; + private static final String MAX_GENERAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME = "jdk.xml.maxGeneralEntitySizeLimit"; + private static final String MAX_PARAMETER_ENTITY_SIZE_LIMIT_PROPERTY_NAME = "jdk.xml.maxParameterEntitySizeLimit"; + private static final String RESOLVE_EXTERNAL_ENTITIES_PROPERTY_NAME = "jdk.xml.resolveExternalEntities"; + + private static final int ENTITY_EXPANSION_LIMIT_DEFAULT_VALUE = 64000; + private static final int MAX_OCCUR_LIMIT_DEFAULT_VALUE = 5000; + private static final int TOTAL_ENTITY_SIZE_LIMIT_DEFAULT_VALUE = 50000000; + private static final int MAX_GENERAL_ENTITY_SIZE_LIMIT_DEFAULT_VALUE = Integer.MAX_VALUE; + private static final int MAX_PARAMETER_ENTITY_SIZE_LIMIT_DEFAULT_VALUE = Integer.MAX_VALUE; + private static final boolean RESOLVE_EXTERNAL_ENTITIES_DEFAULT_VALUE = true; + + protected final int ENTITY_EXPANSION_LIMIT_SYSTEM_VALUE; + protected final int MAX_OCCUR_LIMIT_SYSTEM_VALUE; + protected final int TOTAL_ENTITY_SIZE_LIMIT_SYSTEM_VALUE; + protected final int MAX_GENERAL_ENTITY_SIZE_LIMIT_SYSTEM_VALUE; + protected final int MAX_PARAMETER_ENTITY_SIZE_LIMIT_SYSTEM_VALUE; + protected final boolean RESOLVE_EXTERNAL_ENTITIES_SYSTEM_VALUE; + + // + // Fields + // + + private final boolean fJavaSecurityManagerEnabled; + private boolean fLimitSpecified; + private SecurityManager fSecurityManager; + private InternalEntityMonitor fInternalEntityMonitor; + private final ExternalEntityMonitor fExternalEntityMonitor; + private int fTotalEntitySize = 0; + + /** Default constructor. */ + public SecureProcessingConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public SecureProcessingConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public SecureProcessingConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public SecureProcessingConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + fJavaSecurityManagerEnabled = (System.getSecurityManager() != null); + ENTITY_EXPANSION_LIMIT_SYSTEM_VALUE = getPropertyValue(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, ENTITY_EXPANSION_LIMIT_DEFAULT_VALUE); + MAX_OCCUR_LIMIT_SYSTEM_VALUE = getPropertyValue(MAX_OCCUR_LIMIT_PROPERTY_NAME, MAX_OCCUR_LIMIT_DEFAULT_VALUE); + TOTAL_ENTITY_SIZE_LIMIT_SYSTEM_VALUE = getPropertyValue(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, TOTAL_ENTITY_SIZE_LIMIT_DEFAULT_VALUE); + MAX_GENERAL_ENTITY_SIZE_LIMIT_SYSTEM_VALUE = getPropertyValue(MAX_GENERAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, MAX_GENERAL_ENTITY_SIZE_LIMIT_DEFAULT_VALUE); + MAX_PARAMETER_ENTITY_SIZE_LIMIT_SYSTEM_VALUE = getPropertyValue(MAX_PARAMETER_ENTITY_SIZE_LIMIT_PROPERTY_NAME, MAX_PARAMETER_ENTITY_SIZE_LIMIT_DEFAULT_VALUE); + RESOLVE_EXTERNAL_ENTITIES_SYSTEM_VALUE = getPropertyValue(RESOLVE_EXTERNAL_ENTITIES_PROPERTY_NAME, RESOLVE_EXTERNAL_ENTITIES_DEFAULT_VALUE); + if (fJavaSecurityManagerEnabled || fLimitSpecified) { + if (!RESOLVE_EXTERNAL_ENTITIES_SYSTEM_VALUE) { + super.setFeature(EXTERNAL_GENERAL_ENTITIES, false); + super.setFeature(EXTERNAL_PARAMETER_ENTITIES, false); + super.setFeature(LOAD_EXTERNAL_DTD, false); + } + fSecurityManager = new org.apache.xerces.util.SecurityManager(); + fSecurityManager.setEntityExpansionLimit(ENTITY_EXPANSION_LIMIT_SYSTEM_VALUE); + fSecurityManager.setMaxOccurNodeLimit(MAX_OCCUR_LIMIT_SYSTEM_VALUE); + super.setProperty(SECURITY_MANAGER_PROPERTY, fSecurityManager); + } + fExternalEntityMonitor = new ExternalEntityMonitor(); + super.setProperty(ENTITY_RESOLVER_PROPERTY, fExternalEntityMonitor); + } + + protected void checkEntitySizeLimits(int sizeOfEntity, int delta, boolean isPE) { + fTotalEntitySize += delta; + if (fTotalEntitySize > TOTAL_ENTITY_SIZE_LIMIT_SYSTEM_VALUE) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "TotalEntitySizeLimitExceeded", + new Object[] {new Integer(TOTAL_ENTITY_SIZE_LIMIT_SYSTEM_VALUE)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + if (isPE) { + if (sizeOfEntity > MAX_PARAMETER_ENTITY_SIZE_LIMIT_SYSTEM_VALUE) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MaxParameterEntitySizeLimitExceeded", + new Object[] {new Integer(MAX_PARAMETER_ENTITY_SIZE_LIMIT_SYSTEM_VALUE)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + else if (sizeOfEntity > MAX_GENERAL_ENTITY_SIZE_LIMIT_SYSTEM_VALUE) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "MaxGeneralEntitySizeLimitExceeded", + new Object[] {new Integer(MAX_GENERAL_ENTITY_SIZE_LIMIT_SYSTEM_VALUE)}, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + + /** + * Returns the value of a property. + * + * @param propertyId The property identifier. + * @return the value of the property + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException { + if (SECURITY_MANAGER_PROPERTY.equals(propertyId)) { + return fSecurityManager; + } + else if (ENTITY_RESOLVER_PROPERTY.equals(propertyId)) { + return fExternalEntityMonitor; + } + return super.getProperty(propertyId); + } + + /** + * setProperty + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + if (SECURITY_MANAGER_PROPERTY.equals(propertyId)) { + // Do not allow the Xerces SecurityManager to be + // removed if the Java SecurityManager has been installed. + if (value == null && fJavaSecurityManagerEnabled) { + return; + } + fSecurityManager = (SecurityManager) value; + if (fSecurityManager != null) { + // Override SecurityManager default values with the system property / jaxp.properties / config default determined values. + if (fSecurityManager.getEntityExpansionLimit() == SECURITY_MANAGER_DEFAULT_ENTITY_EXPANSION_LIMIT) { + fSecurityManager.setEntityExpansionLimit(ENTITY_EXPANSION_LIMIT_SYSTEM_VALUE); + } + if (fSecurityManager.getMaxOccurNodeLimit() == SECURITY_MANAGER_DEFAULT_MAX_OCCUR_NODE_LIMIT) { + fSecurityManager.setMaxOccurNodeLimit(MAX_OCCUR_LIMIT_SYSTEM_VALUE); + } + } + } + else if (ENTITY_RESOLVER_PROPERTY.equals(propertyId)) { + fExternalEntityMonitor.setEntityResolver((XMLEntityResolver) value); + return; + } + super.setProperty(propertyId, value); + } + + /** Configures the XML 1.0 pipeline. */ + protected void configurePipeline() { + super.configurePipeline(); + configurePipelineCommon(true); + } + + /** Configures the XML 1.1 pipeline. */ + protected void configureXML11Pipeline() { + super.configureXML11Pipeline(); + configurePipelineCommon(false); + } + + private void configurePipelineCommon(boolean isXML10) { + if (fSecurityManager != null) { + fTotalEntitySize = 0; + if (fInternalEntityMonitor == null) { + fInternalEntityMonitor = new InternalEntityMonitor(); + } + // Reconfigure DTD pipeline. Insert internal entity decl monitor. + final XMLDTDScanner dtdScanner; + final XMLDTDProcessor dtdProcessor; + if (isXML10) { + dtdScanner = fDTDScanner; + dtdProcessor = fDTDProcessor; + } + else { + dtdScanner = fXML11DTDScanner; + dtdProcessor = fXML11DTDProcessor; + } + dtdScanner.setDTDHandler(fInternalEntityMonitor); + fInternalEntityMonitor.setDTDSource(dtdScanner); + fInternalEntityMonitor.setDTDHandler(dtdProcessor); + dtdProcessor.setDTDSource(fInternalEntityMonitor); + } + } + + private int getPropertyValue(String propertyName, int defaultValue) { + + // Step #1: Use the system property first + try { + String propertyValue = SecuritySupport.getSystemProperty(propertyName); + if (propertyValue != null && propertyValue.length() > 0) { + if (DEBUG) { + debugPrintln("found system property \"" + propertyName + "\", value=" + propertyValue); + } + final int intValue = Integer.parseInt(propertyValue); + fLimitSpecified = true; + if (intValue > 0) { + return intValue; + } + // Treat 0 and negative numbers as no limit (i.e. max integer). + return Integer.MAX_VALUE; + } + } + // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } + // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } + catch (Throwable e) { + // Ignore all other exceptions/errors and continue w/ next location + if (DEBUG) { + debugPrintln(e.getClass().getName() + ": " + e.getMessage()); + e.printStackTrace(); + } + } + + // Step #2: Use $java.home/lib/jaxp.properties + try { + boolean fExists = false; + File f = null; + try { + String javah = SecuritySupport.getSystemProperty("java.home"); + String configFile = javah + File.separator + + "lib" + File.separator + "jaxp.properties"; + + f = new File(configFile); + fExists = SecuritySupport.getFileExists(f); + + } + catch (SecurityException se) { + // If there is a security exception, move on to next location. + lastModified = -1; + jaxpProperties = null; + } + + synchronized (SecureProcessingConfiguration.class) { + + boolean runBlock = false; + FileInputStream fis = null; + + try { + if (lastModified >= 0) { + // File has been modified, or didn't previously exist. + // Need to reload properties + if ((fExists) && + (lastModified < (lastModified = SecuritySupport.getLastModified(f)))) { + runBlock = true; + } + else { + if (!fExists) { + // file existed, but it's been deleted. + lastModified = -1; + jaxpProperties = null; + } + } + } + else { + if (fExists) { + // File didn't exist, but it does now. + runBlock = true; + lastModified = SecuritySupport.getLastModified(f); + } + } + + if (runBlock == true) { + // Try to read from $java.home/lib/jaxp.properties + jaxpProperties = new Properties(); + + fis = SecuritySupport.getFileInputStream(f); + jaxpProperties.load(fis); + } + + } + catch (Exception x) { + lastModified = -1; + jaxpProperties = null; + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and return the default value + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + + if (jaxpProperties != null) { + String propertyValue = jaxpProperties.getProperty(propertyName); + if (propertyValue != null && propertyValue.length() > 0) { + if (DEBUG) { + debugPrintln("found \"" + propertyName + "\" in jaxp.properties, value=" + propertyValue); + } + final int intValue = Integer.parseInt(propertyValue); + fLimitSpecified = true; + if (intValue > 0) { + return intValue; + } + // Treat 0 and negative numbers as no limit (i.e. max integer). + return Integer.MAX_VALUE; + } + } + } + // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } + // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } + catch (Throwable e) { + // Ignore all other exceptions/errors and return the default value. + if (DEBUG) { + debugPrintln(e.getClass().getName() + ": " + e.getMessage()); + e.printStackTrace(); + } + } + + // Step #3: Return the default value. + return defaultValue; + } + + private boolean getPropertyValue(String propertyName, boolean defaultValue) { + + // Step #1: Use the system property first + try { + String propertyValue = SecuritySupport.getSystemProperty(propertyName); + if (propertyValue != null && propertyValue.length() > 0) { + if (DEBUG) { + debugPrintln("found system property \"" + propertyName + "\", value=" + propertyValue); + } + final boolean booleanValue = Boolean.valueOf(propertyValue).booleanValue(); + fLimitSpecified = true; + return booleanValue; + } + } + // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } + // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } + catch (Throwable e) { + // Ignore all other exceptions/errors and continue w/ next location + if (DEBUG) { + debugPrintln(e.getClass().getName() + ": " + e.getMessage()); + e.printStackTrace(); + } + } + + // Step #2: Use $java.home/lib/jaxp.properties + try { + boolean fExists = false; + File f = null; + try { + String javah = SecuritySupport.getSystemProperty("java.home"); + String configFile = javah + File.separator + + "lib" + File.separator + "jaxp.properties"; + + f = new File(configFile); + fExists = SecuritySupport.getFileExists(f); + + } + catch (SecurityException se) { + // If there is a security exception, move on to next location. + lastModified = -1; + jaxpProperties = null; + } + + synchronized (SecureProcessingConfiguration.class) { + + boolean runBlock = false; + FileInputStream fis = null; + + try { + if (lastModified >= 0) { + // File has been modified, or didn't previously exist. + // Need to reload properties + if ((fExists) && + (lastModified < (lastModified = SecuritySupport.getLastModified(f)))) { + runBlock = true; + } + else { + if (!fExists) { + // file existed, but it's been deleted. + lastModified = -1; + jaxpProperties = null; + } + } + } + else { + if (fExists) { + // File didn't exist, but it does now. + runBlock = true; + lastModified = SecuritySupport.getLastModified(f); + } + } + + if (runBlock == true) { + // Try to read from $java.home/lib/jaxp.properties + jaxpProperties = new Properties(); + + fis = SecuritySupport.getFileInputStream(f); + jaxpProperties.load(fis); + } + + } + catch (Exception x) { + lastModified = -1; + jaxpProperties = null; + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and return the default value + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + + if (jaxpProperties != null) { + String propertyValue = jaxpProperties.getProperty(propertyName); + if (propertyValue != null && propertyValue.length() > 0) { + if (DEBUG) { + debugPrintln("found \"" + propertyName + "\" in jaxp.properties, value=" + propertyValue); + } + final boolean booleanValue = Boolean.valueOf(propertyValue).booleanValue(); + fLimitSpecified = true; + return booleanValue; + } + } + } + // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } + // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } + catch (Throwable e) { + // Ignore all other exceptions/errors and return the default value. + if (DEBUG) { + debugPrintln(e.getClass().getName() + ": " + e.getMessage()); + e.printStackTrace(); + } + } + + // Step #3: Return the default value. + return defaultValue; + } + + // + // Private static methods + // + + /** Returns true if debug has been enabled. */ + private static boolean isDebugEnabled() { + try { + String val = SecuritySupport.getSystemProperty("xerces.debug"); + // Allow simply setting the prop to turn on debug + return (val != null && (!"false".equals(val))); + } + catch (SecurityException se) {} + return false; + } // isDebugEnabled() + + /** Prints a message to standard error if debugging is enabled. */ + private static void debugPrintln(String msg) { + if (DEBUG) { + System.err.println("XERCES: " + msg); + } + } // debugPrintln(String) + + /** + * XMLDTDFilter which checks limits imposed by the application + * on the sizes of general and parameter entities. + */ + final class InternalEntityMonitor implements XMLDTDFilter { + + /** DTD source and handler. **/ + private XMLDTDSource fDTDSource; + private XMLDTDHandler fDTDHandler; + + public InternalEntityMonitor() {} + + /* + * XMLDTDHandler methods + */ + + public void startDTD(XMLLocator locator, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startDTD(locator, augmentations); + } + } + + public void startParameterEntity(String name, + XMLResourceIdentifier identifier, String encoding, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startParameterEntity(name, identifier, encoding, augmentations); + } + } + + public void textDecl(String version, String encoding, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.textDecl(version, encoding, augmentations); + } + } + + public void endParameterEntity(String name, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endParameterEntity(name, augmentations); + } + } + + public void startExternalSubset(XMLResourceIdentifier identifier, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startExternalSubset(identifier, augmentations); + } + } + + public void endExternalSubset(Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endExternalSubset(augmentations); + } + } + + public void comment(XMLString text, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.comment(text, augmentations); + } + } + + public void processingInstruction(String target, XMLString data, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.processingInstruction(target, data, augmentations); + } + } + + public void elementDecl(String name, String contentModel, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.elementDecl(name, contentModel, augmentations); + } + } + + public void startAttlist(String elementName, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startAttlist(elementName, augmentations); + } + } + + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, String defaultType, + XMLString defaultValue, XMLString nonNormalizedDefaultValue, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.attributeDecl(elementName, attributeName, + type, enumeration, defaultType, + defaultValue, nonNormalizedDefaultValue, + augmentations); + } + } + + public void endAttlist(Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endAttlist(augmentations); + } + } + + public void internalEntityDecl(String name, XMLString text, + XMLString nonNormalizedText, Augmentations augmentations) + throws XNIException { + checkEntitySizeLimits(text.length, text.length, name != null && name.startsWith("%")); + if (fDTDHandler != null) { + fDTDHandler.internalEntityDecl(name, text, + nonNormalizedText, augmentations); + } + } + + public void externalEntityDecl(String name, + XMLResourceIdentifier identifier, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.externalEntityDecl(name, identifier, augmentations); + } + } + + public void unparsedEntityDecl(String name, + XMLResourceIdentifier identifier, String notation, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.unparsedEntityDecl(name, identifier, notation, augmentations); + } + } + + public void notationDecl(String name, XMLResourceIdentifier identifier, + Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.notationDecl(name, identifier, augmentations); + } + } + + public void startConditional(short type, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startConditional(type, augmentations); + } + } + + public void ignoredCharacters(XMLString text, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.ignoredCharacters(text, augmentations); + } + + } + + public void endConditional(Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endConditional(augmentations); + } + } + + public void endDTD(Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endDTD(augmentations); + } + } + + public void setDTDSource(XMLDTDSource source) { + fDTDSource = source; + } + + public XMLDTDSource getDTDSource() { + return fDTDSource; + } + + /* + * XMLDTDSource methods + */ + + public void setDTDHandler(XMLDTDHandler handler) { + fDTDHandler = handler; + } + + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } + } + + /** + * XMLEntityResolver which checks limits imposed by the application + * on the sizes of general and parameter entities. + */ + final class ExternalEntityMonitor implements XMLEntityResolver { + + /** + * java.io.InputStream wrapper which check entity size limits. + */ + final class InputStreamMonitor extends FilterInputStream { + + private final boolean isPE; + private int size = 0; + + protected InputStreamMonitor(InputStream in, boolean isPE) { + super(in); + this.isPE = isPE; + } + + public int read() throws IOException { + int i = super.read(); + if (i != -1) { + ++size; + checkEntitySizeLimits(size, 1, isPE); + } + return i; + } + + public int read(byte[] b, int off, int len) throws IOException { + int i = super.read(b, off, len); + if (i > 0) { + size += i; + checkEntitySizeLimits(size, i, isPE); + } + return i; + } + } + + /** + * java.io.Reader wrapper which check entity size limits. + */ + final class ReaderMonitor extends FilterReader { + + private final boolean isPE; + private int size = 0; + + protected ReaderMonitor(Reader in, boolean isPE) { + super(in); + this.isPE = isPE; + } + + public int read() throws IOException { + int i = super.read(); + if (i != -1) { + ++size; + checkEntitySizeLimits(size, 1, isPE); + } + return i; + } + + public int read(char[] cbuf, int off, int len) throws IOException { + int i = super.read(cbuf, off, len); + if (i > 0) { + size += i; + checkEntitySizeLimits(size, i, isPE); + } + return i; + } + } + + private XMLEntityResolver fEntityResolver; + + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) throws XNIException, + IOException { + XMLInputSource source = null; + if (fEntityResolver != null) { + source = fEntityResolver.resolveEntity(resourceIdentifier); + } + if (fSecurityManager != null && resourceIdentifier instanceof XMLEntityDescription) { + String name = ((XMLEntityDescription) resourceIdentifier).getEntityName(); + boolean isPE = name != null && name.startsWith("%"); + if (source == null) { + String publicId = resourceIdentifier.getPublicId(); + String systemId = resourceIdentifier.getExpandedSystemId(); + String baseSystemId = resourceIdentifier.getBaseSystemId(); + source = new XMLInputSource(publicId, systemId, baseSystemId); + } + Reader reader = source.getCharacterStream(); + if (reader != null) { + source.setCharacterStream(new ReaderMonitor(reader, isPE)); + } + else { + InputStream stream = source.getByteStream(); + if (stream != null) { + source.setByteStream(new InputStreamMonitor(stream, isPE)); + } + else { + String systemId = resourceIdentifier.getExpandedSystemId(); + URL url = new URL(systemId); + stream = url.openStream(); + source.setByteStream(new InputStreamMonitor(stream, isPE)); + } + } + } + return source; + } + + /** Sets the XNI entity resolver. */ + public void setEntityResolver(XMLEntityResolver entityResolver) { + fEntityResolver = entityResolver; + } // setEntityResolver(XMLEntityResolver) + + /** Returns the XNI entity resolver. */ + public XMLEntityResolver getEntityResolver() { + return fEntityResolver; + } // getEntityResolver():XMLEntityResolver + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/SecurityConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/SecurityConfiguration.java new file mode 100644 index 0000000..94a1844 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/SecurityConfiguration.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; + +/** + * This configuration allows Xerces to behave in a security-conscious manner; that is, + * it permits applications to instruct Xerces to limit certain + * operations that could be exploited by malicious document authors to cause a denail-of-service + * attack when the document is parsed. + * + * In addition to the features and properties recognized by the base + * parser configuration, this class recognizes these additional + * features and properties: + *

          + *
        • Properties + *
            + *
          • http://apache.org/xml/properties/security-manager
          • + *
          + *
        + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class SecurityConfiguration extends XIncludeAwareParserConfiguration +{ + + // + // Constants + // + + protected static final String SECURITY_MANAGER_PROPERTY = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + // + // Constructors + // + + /** Default constructor. */ + public SecurityConfiguration () { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public SecurityConfiguration (SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public SecurityConfiguration (SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public SecurityConfiguration (SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + + // create the SecurityManager property: + setProperty(SECURITY_MANAGER_PROPERTY, new SecurityManager()); + } // (SymbolTable,XMLGrammarPool) + +} // class SecurityConfiguration + diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/SecuritySupport.java b/resources/xerces2-j-src/org/apache/xerces/parsers/SecuritySupport.java new file mode 100644 index 0000000..87a8d87 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/SecuritySupport.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * This class is duplicated for each subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of any API. + * + * @xerces.internal + * + * @version $Id$ + */ +final class SecuritySupport { + + static ClassLoader getContextClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (SecurityException ex) { } + return cl; + } + }); + } + + static ClassLoader getSystemClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (SecurityException ex) {} + return cl; + } + }); + } + + static ClassLoader getParentClassLoader(final ClassLoader cl) { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader parent = null; + try { + parent = cl.getParent(); + } catch (SecurityException ex) {} + + // eliminate loops in case of the boot + // ClassLoader returning itself as a parent + return (parent == cl) ? null : parent; + } + }); + } + + static String getSystemProperty(final String propName) { + return (String) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(propName); + } + }); + } + + static FileInputStream getFileInputStream(final File file) + throws FileNotFoundException + { + try { + return (FileInputStream) + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws FileNotFoundException { + return new FileInputStream(file); + } + }); + } catch (PrivilegedActionException e) { + throw (FileNotFoundException)e.getException(); + } + } + + static InputStream getResourceAsStream(final ClassLoader cl, + final String name) + { + return (InputStream) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + InputStream ris; + if (cl == null) { + ris = ClassLoader.getSystemResourceAsStream(name); + } else { + ris = cl.getResourceAsStream(name); + } + return ris; + } + }); + } + + static boolean getFileExists(final File f) { + return ((Boolean) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return f.exists() ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + } + + static long getLastModified(final File f) { + return ((Long) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return new Long(f.lastModified()); + } + })).longValue(); + } + + private SecuritySupport () {} +} diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/SoftReferenceSymbolTableConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/SoftReferenceSymbolTableConfiguration.java new file mode 100644 index 0000000..b6f7f4d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/SoftReferenceSymbolTableConfiguration.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.util.SoftReferenceSymbolTable; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; + +/** + * This parser configuration extends the default configuration allowing Xerces to + * handle usage scenarios where the names in the XML documents being parsed are mostly + * unique by installing a memory sensitive SymbolTable. The internalized + * strings stored in this SymbolTable are softly reachable and may be + * cleared by the garbage collector in response to memory demand. + * + * @see org.apache.xerces.util.SoftReferenceSymbolTable + * + * @author Peter McCracken, IBM + * + * @version $Id$ + */ +public class SoftReferenceSymbolTableConfiguration extends + XIncludeAwareParserConfiguration { + + /** Default constructor. */ + public SoftReferenceSymbolTableConfiguration() { + this(new SoftReferenceSymbolTable(), null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public SoftReferenceSymbolTableConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public SoftReferenceSymbolTableConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public SoftReferenceSymbolTableConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/StandardParserConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/StandardParserConfiguration.java new file mode 100644 index 0000000..7819094 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/StandardParserConfiguration.java @@ -0,0 +1,413 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; + +/** + * This is the "standard" parser configuration. It extends the DTD + * configuration with the standard set of parser components. + * The standard set of parser components include those needed + * to parse and validate with DTD's, and those needed for XML + * Schema.

        + *

        + * In addition to the features and properties recognized by the base + * parser configuration, this class recognizes these additional + * features and properties: + *

          + *
        • Features + *
            + *
          • http://apache.org/xml/features/validation/schema
          • + *
          • http://apache.org/xml/features/validation/schema-full-checking
          • + *
          • http://apache.org/xml/features/validation/schema/normalized-value
          • + *
          • http://apache.org/xml/features/validation/schema/element-default
          • + *
          + *
        • Properties + *
            + *
          • http://apache.org/xml/properties/internal/error-reporter
          • + *
          • http://apache.org/xml/properties/internal/entity-manager
          • + *
          • http://apache.org/xml/properties/internal/document-scanner
          • + *
          • http://apache.org/xml/properties/internal/dtd-scanner
          • + *
          • http://apache.org/xml/properties/internal/grammar-pool
          • + *
          • http://apache.org/xml/properties/internal/validator/dtd
          • + *
          • http://apache.org/xml/properties/internal/datatype-validator-factory
          • + *
          + *
        + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class StandardParserConfiguration + extends DTDConfiguration { + + // + // Constants + // + + // feature identifiers + + /** Feature identifier: expose schema normalized value */ + protected static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + + + /** Feature identifier: send element default value via characters() */ + protected static final String SCHEMA_ELEMENT_DEFAULT = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; + + + /** Feature identifier: augment PSVI */ + protected static final String SCHEMA_AUGMENT_PSVI = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; + + + /** feature identifier: XML Schema validation */ + protected static final String XMLSCHEMA_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** feature identifier: XML Schema validation -- full checking */ + protected static final String XMLSCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + + /** Feature: generate synthetic annotations */ + protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE; + + /** Feature identifier: validate annotations */ + protected static final String VALIDATE_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE; + + /** Feature identifier: honour all schemaLocations */ + protected static final String HONOUR_ALL_SCHEMALOCATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; + + /** Feature identifier: namespace growth */ + protected static final String NAMESPACE_GROWTH = + Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; + + /** Feature identifier: tolerate duplicates */ + protected static final String TOLERATE_DUPLICATES = + Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; + + /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */ + protected static final String IGNORE_XSI_TYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE; + + /** Feature identifier: whether to ignore ID/IDREF errors */ + protected static final String ID_IDREF_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore unparsed entity errors */ + protected static final String UNPARSED_ENTITY_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore identity constraint errors */ + protected static final String IDENTITY_CONSTRAINT_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE; + + // property identifiers + + /** Property identifier: XML Schema validator. */ + protected static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: schema location. */ + protected static final String SCHEMA_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION; + + /** Property identifier: no namespace schema location. */ + protected static final String SCHEMA_NONS_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION; + + /** Property identifier: root type definition. */ + protected static final String ROOT_TYPE_DEF = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY; + + /** Property identifier: root element declaration. */ + protected static final String ROOT_ELEMENT_DECL = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_ELEMENT_DECLARATION_PROPERTY; + + /** Property identifier: Schema DV Factory */ + protected static final String SCHEMA_DV_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY; + + // + // Data + // + + // components (non-configurable) + + /** XML Schema Validator. */ + protected XMLSchemaValidator fSchemaValidator; + + // + // Constructors + // + + /** Default constructor. */ + public StandardParserConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public StandardParserConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public StandardParserConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public StandardParserConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + + // add default recognized features + final String[] recognizedFeatures = { + NORMALIZE_DATA, + SCHEMA_ELEMENT_DEFAULT, + SCHEMA_AUGMENT_PSVI, + GENERATE_SYNTHETIC_ANNOTATIONS, + VALIDATE_ANNOTATIONS, + HONOUR_ALL_SCHEMALOCATIONS, + NAMESPACE_GROWTH, + TOLERATE_DUPLICATES, + // NOTE: These shouldn't really be here but since the XML Schema + // validator is constructed dynamically, its recognized + // features might not have been set and it would cause a + // not-recognized exception to be thrown. -Ac + XMLSCHEMA_VALIDATION, + XMLSCHEMA_FULL_CHECKING, + IGNORE_XSI_TYPE, + ID_IDREF_CHECKING, + IDENTITY_CONSTRAINT_CHECKING, + UNPARSED_ENTITY_CHECKING, + }; + addRecognizedFeatures(recognizedFeatures); + + // set state for default features + setFeature(SCHEMA_ELEMENT_DEFAULT, true); + setFeature(NORMALIZE_DATA, true); + setFeature(SCHEMA_AUGMENT_PSVI, true); + setFeature(GENERATE_SYNTHETIC_ANNOTATIONS, false); + setFeature(VALIDATE_ANNOTATIONS, false); + setFeature(HONOUR_ALL_SCHEMALOCATIONS, false); + setFeature(NAMESPACE_GROWTH, false); + setFeature(TOLERATE_DUPLICATES, false); + + setFeature(IGNORE_XSI_TYPE, false); + setFeature(ID_IDREF_CHECKING, true); + setFeature(IDENTITY_CONSTRAINT_CHECKING, true); + setFeature(UNPARSED_ENTITY_CHECKING, true); + + // add default recognized properties + + final String[] recognizedProperties = { + // NOTE: These shouldn't really be here but since the XML Schema + // validator is constructed dynamically, its recognized + // properties might not have been set and it would cause a + // not-recognized exception to be thrown. -Ac + SCHEMA_LOCATION, + SCHEMA_NONS_LOCATION, + ROOT_TYPE_DEF, + ROOT_ELEMENT_DECL, + SCHEMA_DV_FACTORY, + }; + + addRecognizedProperties(recognizedProperties); + } // (SymbolTable,XMLGrammarPool) + + // + // Public methods + // + + /** Configures the pipeline. */ + protected void configurePipeline() { + super.configurePipeline(); + if ( getFeature(XMLSCHEMA_VALIDATION )) { + // If schema validator was not in the pipeline insert it. + if (fSchemaValidator == null) { + fSchemaValidator = new XMLSchemaValidator(); + + // add schema component + fProperties.put(SCHEMA_VALIDATOR, fSchemaValidator); + addComponent(fSchemaValidator); + // add schema message formatter + if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { + XSMessageFormatter xmft = new XSMessageFormatter(); + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, xmft); + } + + } + fLastComponent = fSchemaValidator; + fNamespaceBinder.setDocumentHandler(fSchemaValidator); + + fSchemaValidator.setDocumentHandler(fDocumentHandler); + fSchemaValidator.setDocumentSource(fNamespaceBinder); + } + + + } // configurePipeline() + + // features and properties + + /** + * Check a feature. If feature is know and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) + throws XMLConfigurationException { + + // + // Xerces Features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/validation/schema + // Lets the user turn Schema validation support on/off. + // + if (suffixLength == Constants.SCHEMA_VALIDATION_FEATURE.length() && + featureId.endsWith(Constants.SCHEMA_VALIDATION_FEATURE)) { + return; + } + // activate full schema checking + if (suffixLength == Constants.SCHEMA_FULL_CHECKING.length() && + featureId.endsWith(Constants.SCHEMA_FULL_CHECKING)) { + return; + } + // Feature identifier: expose schema normalized value + // http://apache.org/xml/features/validation/schema/normalized-value + if (suffixLength == Constants.SCHEMA_NORMALIZED_VALUE.length() && + featureId.endsWith(Constants.SCHEMA_NORMALIZED_VALUE)) { + return; + } + // Feature identifier: send element default value via characters() + // http://apache.org/xml/features/validation/schema/element-default + if (suffixLength == Constants.SCHEMA_ELEMENT_DEFAULT.length() && + featureId.endsWith(Constants.SCHEMA_ELEMENT_DEFAULT)) { + return; + } + } + + // + // Not recognized + // + + super.checkFeature(featureId); + + } // checkFeature(String) + + /** + * Check a property. If the property is know and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkProperty(String propertyId) + throws XMLConfigurationException { + + // + // Xerces Properties + // + + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SCHEMA_LOCATION.length() && + propertyId.endsWith(Constants.SCHEMA_LOCATION)) { + return; + } + if (suffixLength == Constants.SCHEMA_NONS_LOCATION.length() && + propertyId.endsWith(Constants.SCHEMA_NONS_LOCATION)) { + return; + } + } + + if (propertyId.startsWith(Constants.JAXP_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.JAXP_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SCHEMA_SOURCE.length() && + propertyId.endsWith(Constants.SCHEMA_SOURCE)) { + return; + } + } + + // + // Not recognized + // + + super.checkProperty(propertyId); + + } // checkProperty(String) + +} // class StandardParserConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XIncludeAwareParserConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XIncludeAwareParserConfiguration.java new file mode 100644 index 0000000..04815ca --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XIncludeAwareParserConfiguration.java @@ -0,0 +1,293 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xinclude.XIncludeHandler; +import org.apache.xerces.xinclude.XIncludeNamespaceSupport; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + * This class is the configuration used to parse XML 1.0 and XML 1.1 documents + * and provides support for XInclude. This is the default Xerces configuration. + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XIncludeAwareParserConfiguration extends XML11Configuration { + + /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */ + protected static final String ALLOW_UE_AND_NOTATION_EVENTS = + Constants.SAX_FEATURE_PREFIX + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE; + + /** Feature identifier: fixup base URIs. */ + protected static final String XINCLUDE_FIXUP_BASE_URIS = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE; + + /** Feature identifier: fixup language. */ + protected static final String XINCLUDE_FIXUP_LANGUAGE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE; + + /** Feature identifier: XInclude processing */ + protected static final String XINCLUDE_FEATURE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE; + + /** Property identifier: XInclude handler. */ + protected static final String XINCLUDE_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.XINCLUDE_HANDLER_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String NAMESPACE_CONTEXT = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY; + + // + // Components + // + + /** XInclude handler. */ + protected XIncludeHandler fXIncludeHandler; + + /** Non-XInclude NamespaceContext. */ + protected NamespaceSupport fNonXIncludeNSContext; + + /** XInclude NamespaceContext. */ + protected XIncludeNamespaceSupport fXIncludeNSContext; + + /** Current NamespaceContext. */ + protected NamespaceContext fCurrentNSContext; + + /** Flag indicating whether XInclude processsing is enabled. */ + protected boolean fXIncludeEnabled = false; + + /** Default constructor. */ + public XIncludeAwareParserConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public XIncludeAwareParserConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public XIncludeAwareParserConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public XIncludeAwareParserConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + + final String[] recognizedFeatures = { + ALLOW_UE_AND_NOTATION_EVENTS, + XINCLUDE_FIXUP_BASE_URIS, + XINCLUDE_FIXUP_LANGUAGE + }; + addRecognizedFeatures(recognizedFeatures); + + // add default recognized properties + final String[] recognizedProperties = + { XINCLUDE_HANDLER, NAMESPACE_CONTEXT }; + addRecognizedProperties(recognizedProperties); + + setFeature(ALLOW_UE_AND_NOTATION_EVENTS, true); + setFeature(XINCLUDE_FIXUP_BASE_URIS, true); + setFeature(XINCLUDE_FIXUP_LANGUAGE, true); + + fNonXIncludeNSContext = new NamespaceSupport(); + fCurrentNSContext = fNonXIncludeNSContext; + setProperty(NAMESPACE_CONTEXT, fNonXIncludeNSContext); + } + + + /** Configures the pipeline. */ + protected void configurePipeline() { + super.configurePipeline(); + if (fXIncludeEnabled) { + // If the XInclude handler was not in the pipeline insert it. + if (fXIncludeHandler == null) { + fXIncludeHandler = new XIncludeHandler(); + // add XInclude component + setProperty(XINCLUDE_HANDLER, fXIncludeHandler); + addCommonComponent(fXIncludeHandler); + fXIncludeHandler.reset(this); + } + // Setup NamespaceContext + if (fCurrentNSContext != fXIncludeNSContext) { + if (fXIncludeNSContext == null) { + fXIncludeNSContext = new XIncludeNamespaceSupport(); + } + fCurrentNSContext = fXIncludeNSContext; + setProperty(NAMESPACE_CONTEXT, fXIncludeNSContext); + } + //configure DTD pipeline + fDTDScanner.setDTDHandler(fDTDProcessor); + fDTDProcessor.setDTDSource(fDTDScanner); + fDTDProcessor.setDTDHandler(fXIncludeHandler); + fXIncludeHandler.setDTDSource(fDTDProcessor); + fXIncludeHandler.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXIncludeHandler); + } + + // configure XML document pipeline: insert after DTDValidator and + // before XML Schema validator + XMLDocumentSource prev = null; + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // we don't have to worry about fSchemaValidator being null, since + // super.configurePipeline() instantiated it if the feature was set + prev = fSchemaValidator.getDocumentSource(); + } + // Otherwise, insert after the last component in the pipeline + else { + prev = fLastComponent; + fLastComponent = fXIncludeHandler; + } + + XMLDocumentHandler next = prev.getDocumentHandler(); + prev.setDocumentHandler(fXIncludeHandler); + fXIncludeHandler.setDocumentSource(prev); + if (next != null) { + fXIncludeHandler.setDocumentHandler(next); + next.setDocumentSource(fXIncludeHandler); + } + } + else { + // Setup NamespaceContext + if (fCurrentNSContext != fNonXIncludeNSContext) { + fCurrentNSContext = fNonXIncludeNSContext; + setProperty(NAMESPACE_CONTEXT, fNonXIncludeNSContext); + } + } + } // configurePipeline() + + protected void configureXML11Pipeline() { + super.configureXML11Pipeline(); + if (fXIncludeEnabled) { + // If the XInclude handler was not in the pipeline insert it. + if (fXIncludeHandler == null) { + fXIncludeHandler = new XIncludeHandler(); + // add XInclude component + setProperty(XINCLUDE_HANDLER, fXIncludeHandler); + addCommonComponent(fXIncludeHandler); + fXIncludeHandler.reset(this); + } + // Setup NamespaceContext + if (fCurrentNSContext != fXIncludeNSContext) { + if (fXIncludeNSContext == null) { + fXIncludeNSContext = new XIncludeNamespaceSupport(); + } + fCurrentNSContext = fXIncludeNSContext; + setProperty(NAMESPACE_CONTEXT, fXIncludeNSContext); + } + // configure XML 1.1. DTD pipeline + fXML11DTDScanner.setDTDHandler(fXML11DTDProcessor); + fXML11DTDProcessor.setDTDSource(fXML11DTDScanner); + fXML11DTDProcessor.setDTDHandler(fXIncludeHandler); + fXIncludeHandler.setDTDSource(fXML11DTDProcessor); + fXIncludeHandler.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXIncludeHandler); + } + + // configure XML document pipeline: insert after DTDValidator and + // before XML Schema validator + XMLDocumentSource prev = null; + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // we don't have to worry about fSchemaValidator being null, since + // super.configurePipeline() instantiated it if the feature was set + prev = fSchemaValidator.getDocumentSource(); + } + // Otherwise, insert after the last component in the pipeline + else { + prev = fLastComponent; + fLastComponent = fXIncludeHandler; + } + + XMLDocumentHandler next = prev.getDocumentHandler(); + prev.setDocumentHandler(fXIncludeHandler); + fXIncludeHandler.setDocumentSource(prev); + if (next != null) { + fXIncludeHandler.setDocumentHandler(next); + next.setDocumentSource(fXIncludeHandler); + } + } + else { + // Setup NamespaceContext + if (fCurrentNSContext != fNonXIncludeNSContext) { + fCurrentNSContext = fNonXIncludeNSContext; + setProperty(NAMESPACE_CONTEXT, fNonXIncludeNSContext); + } + } + } // configureXML11Pipeline() + + public boolean getFeature(String featureId) + throws XMLConfigurationException { + if (featureId.equals(PARSER_SETTINGS)) { + return fConfigUpdated; + } + else if (featureId.equals(XINCLUDE_FEATURE)) { + return fXIncludeEnabled; + } + return super.getFeature0(featureId); + + } // getFeature(String):boolean + + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + if (featureId.equals(XINCLUDE_FEATURE)) { + fXIncludeEnabled = state; + fConfigUpdated = true; + return; + } + super.setFeature(featureId,state); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XIncludeParserConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XIncludeParserConfiguration.java new file mode 100644 index 0000000..8c09df6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XIncludeParserConfiguration.java @@ -0,0 +1,213 @@ +/* + * 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. + */ +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xinclude.XIncludeHandler; +import org.apache.xerces.xinclude.XIncludeNamespaceSupport; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + * This parser configuration includes an XIncludeHandler in the pipeline + * before the schema validator, or as the last component in the pipeline if there is + * no schema validator. Using this pipeline will enable processing according to the + * XML Inclusions specification, to the conformance level described in + * XIncludeHandler. + * + * @author Peter McCracken, IBM + * @see org.apache.xerces.xinclude.XIncludeHandler + */ +public class XIncludeParserConfiguration extends XML11Configuration { + + private XIncludeHandler fXIncludeHandler; + + /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */ + protected static final String ALLOW_UE_AND_NOTATION_EVENTS = + Constants.SAX_FEATURE_PREFIX + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE; + + /** Feature identifier: fixup base URIs. */ + protected static final String XINCLUDE_FIXUP_BASE_URIS = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE; + + /** Feature identifier: fixup language. */ + protected static final String XINCLUDE_FIXUP_LANGUAGE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE; + + /** Property identifier: error reporter. */ + protected static final String XINCLUDE_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.XINCLUDE_HANDLER_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String NAMESPACE_CONTEXT = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY; + + /** Default constructor. */ + public XIncludeParserConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public XIncludeParserConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public XIncludeParserConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public XIncludeParserConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + + fXIncludeHandler = new XIncludeHandler(); + addCommonComponent(fXIncludeHandler); + + final String[] recognizedFeatures = { + ALLOW_UE_AND_NOTATION_EVENTS, + XINCLUDE_FIXUP_BASE_URIS, + XINCLUDE_FIXUP_LANGUAGE + }; + addRecognizedFeatures(recognizedFeatures); + + // add default recognized properties + final String[] recognizedProperties = + { XINCLUDE_HANDLER, NAMESPACE_CONTEXT }; + addRecognizedProperties(recognizedProperties); + + setFeature(ALLOW_UE_AND_NOTATION_EVENTS, true); + setFeature(XINCLUDE_FIXUP_BASE_URIS, true); + setFeature(XINCLUDE_FIXUP_LANGUAGE, true); + + setProperty(XINCLUDE_HANDLER, fXIncludeHandler); + setProperty(NAMESPACE_CONTEXT, new XIncludeNamespaceSupport()); + } // (SymbolTable,XMLGrammarPool)} + + + /** Configures the pipeline. */ + protected void configurePipeline() { + super.configurePipeline(); + + //configure DTD pipeline + fDTDScanner.setDTDHandler(fDTDProcessor); + fDTDProcessor.setDTDSource(fDTDScanner); + fDTDProcessor.setDTDHandler(fXIncludeHandler); + fXIncludeHandler.setDTDSource(fDTDProcessor); + fXIncludeHandler.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXIncludeHandler); + } + + // configure XML document pipeline: insert after DTDValidator and + // before XML Schema validator + XMLDocumentSource prev = null; + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // we don't have to worry about fSchemaValidator being null, since + // super.configurePipeline() instantiated it if the feature was set + prev = fSchemaValidator.getDocumentSource(); + } + // Otherwise, insert after the last component in the pipeline + else { + prev = fLastComponent; + fLastComponent = fXIncludeHandler; + } + + XMLDocumentHandler next = prev.getDocumentHandler(); + prev.setDocumentHandler(fXIncludeHandler); + fXIncludeHandler.setDocumentSource(prev); + if (next != null) { + fXIncludeHandler.setDocumentHandler(next); + next.setDocumentSource(fXIncludeHandler); + } + + } // configurePipeline() + + protected void configureXML11Pipeline() { + super.configureXML11Pipeline(); + + // configure XML 1.1. DTD pipeline + fXML11DTDScanner.setDTDHandler(fXML11DTDProcessor); + fXML11DTDProcessor.setDTDSource(fXML11DTDScanner); + fXML11DTDProcessor.setDTDHandler(fXIncludeHandler); + fXIncludeHandler.setDTDSource(fXML11DTDProcessor); + fXIncludeHandler.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXIncludeHandler); + } + + // configure XML document pipeline: insert after DTDValidator and + // before XML Schema validator + XMLDocumentSource prev = null; + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // we don't have to worry about fSchemaValidator being null, since + // super.configurePipeline() instantiated it if the feature was set + prev = fSchemaValidator.getDocumentSource(); + } + // Otherwise, insert after the last component in the pipeline + else { + prev = fLastComponent; + fLastComponent = fXIncludeHandler; + } + + XMLDocumentHandler next = prev.getDocumentHandler(); + prev.setDocumentHandler(fXIncludeHandler); + fXIncludeHandler.setDocumentSource(prev); + if (next != null) { + fXIncludeHandler.setDocumentHandler(next); + next.setDocumentSource(fXIncludeHandler); + } + + } // configureXML11Pipeline() + + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + if (propertyId.equals(XINCLUDE_HANDLER)) { + } + + super.setProperty(propertyId, value); + } // setProperty(String,Object) +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XML11Configurable.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XML11Configurable.java new file mode 100644 index 0000000..a22c950 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XML11Configurable.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +/** + *

        An XMLParserConfiguration implements this interface + * in order to indicate that it provides support for XML 1.1.

        + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public interface XML11Configurable {} + diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XML11Configuration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XML11Configuration.java new file mode 100644 index 0000000..40c7bc5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XML11Configuration.java @@ -0,0 +1,1601 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XML11DTDScannerImpl; +import org.apache.xerces.impl.XML11DocumentScannerImpl; +import org.apache.xerces.impl.XML11NSDocumentScannerImpl; +import org.apache.xerces.impl.XMLDTDScannerImpl; +import org.apache.xerces.impl.XMLDocumentScannerImpl; +import org.apache.xerces.impl.XMLEntityHandler; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.XMLNSDocumentScannerImpl; +import org.apache.xerces.impl.XMLVersionDetector; +import org.apache.xerces.impl.dtd.XML11DTDProcessor; +import org.apache.xerces.impl.dtd.XML11DTDValidator; +import org.apache.xerces.impl.dtd.XML11NSDTDValidator; +import org.apache.xerces.impl.dtd.XMLDTDProcessor; +import org.apache.xerces.impl.dtd.XMLDTDValidator; +import org.apache.xerces.impl.dtd.XMLNSDTDValidator; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.impl.xs.XMLSchemaValidator; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.util.ParserConfigurationSettings; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDScanner; +import org.apache.xerces.xni.parser.XMLDocumentScanner; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLPullParserConfiguration; + +/** + * This class is the configuration used to parse XML 1.0 and XML 1.1 documents. + * + * @author Elena Litani, IBM + * @author Neil Graham, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XML11Configuration extends ParserConfigurationSettings + implements XMLPullParserConfiguration, XML11Configurable { + + // + // Constants + // + protected final static String XML11_DATATYPE_VALIDATOR_FACTORY = + "org.apache.xerces.impl.dv.dtd.XML11DTDDVFactoryImpl"; + + // feature identifiers + + /** Feature identifier: warn on duplicate attribute definition. */ + protected static final String WARN_ON_DUPLICATE_ATTDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; + + /** Feature identifier: warn on duplicate entity definition. */ + protected static final String WARN_ON_DUPLICATE_ENTITYDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ENTITYDEF_FEATURE; + + /** Feature identifier: warn on undeclared element definition. */ + protected static final String WARN_ON_UNDECLARED_ELEMDEF = + Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE; + + /** Feature identifier: allow Java encodings. */ + protected static final String ALLOW_JAVA_ENCODINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE; + + /** Feature identifier: continue after fatal error. */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + /** Feature identifier: load external DTD. */ + protected static final String LOAD_EXTERNAL_DTD = + Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE; + + /** Feature identifier: notify built-in refereces. */ + protected static final String NOTIFY_BUILTIN_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE; + + /** Feature identifier: notify character refereces. */ + protected static final String NOTIFY_CHAR_REFS = + Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE; + + /** Feature identifier: expose schema normalized value */ + protected static final String NORMALIZE_DATA = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE; + + /** Feature identifier: send element default value via characters() */ + protected static final String SCHEMA_ELEMENT_DEFAULT = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT; + + /** Feature identifier: augment PSVI */ + protected static final String SCHEMA_AUGMENT_PSVI = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; + + /** feature identifier: XML Schema validation */ + protected static final String XMLSCHEMA_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** feature identifier: XML Schema validation -- full checking */ + protected static final String XMLSCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; + + /** Feature: generate synthetic annotations */ + protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE; + + /** Feature identifier: validate annotations */ + protected static final String VALIDATE_ANNOTATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE; + + /** Feature identifier: honour all schemaLocations */ + protected static final String HONOUR_ALL_SCHEMALOCATIONS = + Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE; + + /** Feature identifier: namespace growth */ + protected static final String NAMESPACE_GROWTH = + Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE; + + /** Feature identifier: tolerate duplicates */ + protected static final String TOLERATE_DUPLICATES = + Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE; + + /** Feature identifier: use grammar pool only */ + protected static final String USE_GRAMMAR_POOL_ONLY = + Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE; + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: external general entities. */ + protected static final String EXTERNAL_GENERAL_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE; + + /** Feature identifier: external parameter entities. */ + protected static final String EXTERNAL_PARAMETER_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE; + + /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */ + protected static final String IGNORE_XSI_TYPE = + Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE; + + /** Feature identifier: whether to ignore ID/IDREF errors */ + protected static final String ID_IDREF_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore unparsed entity errors */ + protected static final String UNPARSED_ENTITY_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE; + + /** Feature identifier: whether to ignore identity constraint errors */ + protected static final String IDENTITY_CONSTRAINT_CHECKING = + Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE; + + + + // property identifiers + + + /** Property identifier: xml string. */ + protected static final String XML_STRING = + Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY; + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + + /** Property identifier: XML Schema validator. */ + protected static final String SCHEMA_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; + + /** Property identifier: schema location. */ + protected static final String SCHEMA_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION; + + /** Property identifier: no namespace schema location. */ + protected static final String SCHEMA_NONS_LOCATION = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION; + + // property identifiers + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier document scanner: */ + protected static final String DOCUMENT_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_SCANNER_PROPERTY; + + /** Property identifier: DTD scanner. */ + protected static final String DTD_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY; + + /** Property identifier: grammar pool. */ + protected static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: DTD loader. */ + protected static final String DTD_PROCESSOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_PROCESSOR_PROPERTY; + + /** Property identifier: DTD validator. */ + protected static final String DTD_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; + + /** Property identifier: namespace binder. */ + protected static final String NAMESPACE_BINDER = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_BINDER_PROPERTY; + + /** Property identifier: datatype validator factory. */ + protected static final String DATATYPE_VALIDATOR_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; + + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: JAXP schema language / DOM schema-type. */ + protected static final String JAXP_SCHEMA_LANGUAGE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE; + + /** Property identifier: JAXP schema source/ DOM schema-location. */ + protected static final String JAXP_SCHEMA_SOURCE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; + + /** Property identifier: locale. */ + protected static final String LOCALE = + Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + + /** Property identifier: root type definition. */ + protected static final String ROOT_TYPE_DEF = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY; + + /** Property identifier: root element declaration. */ + protected static final String ROOT_ELEMENT_DECL = + Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_ELEMENT_DECLARATION_PROPERTY; + + /** Property identifier: Schema DV Factory */ + protected static final String SCHEMA_DV_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY; + + // debugging + + /** Set to true and recompile to print exception stack trace. */ + protected static final boolean PRINT_EXCEPTION_STACK_TRACE = false; + + // + // Data + // + + protected SymbolTable fSymbolTable; + protected XMLInputSource fInputSource; + protected final ValidationManager fValidationManager; + protected final XMLVersionDetector fVersionDetector; + protected Locale fLocale; + + /** XML 1.0 Components. */ + protected final ArrayList fComponents; + + /** XML 1.1. Components. */ + protected final ArrayList fXML11Components; + + /** Common components: XMLEntityManager, XMLErrorReporter, XMLSchemaValidator */ + protected final ArrayList fCommonComponents; + + /** The document handler. */ + protected XMLDocumentHandler fDocumentHandler; + + /** The DTD handler. */ + protected XMLDTDHandler fDTDHandler; + + /** The DTD content model handler. */ + protected XMLDTDContentModelHandler fDTDContentModelHandler; + + /** Last component in the document pipeline */ + protected XMLDocumentSource fLastComponent; + + /** + * True if a parse is in progress. This state is needed because + * some features/properties cannot be set while parsing (e.g. + * validation and namespaces). + */ + protected boolean fParseInProgress = false; + + /** fConfigUpdated is set to true if there has been any change to the configuration settings, + * i.e a feature or a property was changed. + */ + protected boolean fConfigUpdated = false; + + // + // XML 1.0 components + // + + /** The XML 1.0 Datatype validator factory. */ + protected final DTDDVFactory fDatatypeValidatorFactory; + + /** The XML 1.0 Document scanner that does namespace binding. */ + protected final XMLNSDocumentScannerImpl fNamespaceScanner; + + /** The XML 1.0 Non-namespace implementation of scanner */ + protected XMLDocumentScannerImpl fNonNSScanner; + + /** The XML 1.0 DTD Validator: binds namespaces */ + protected final XMLDTDValidator fDTDValidator; + + /** The XML 1.0 DTD Validator that does not bind namespaces */ + protected XMLDTDValidator fNonNSDTDValidator; + + /** The XML 1.0 DTD scanner. */ + protected final XMLDTDScanner fDTDScanner; + + /** The XML 1.0 DTD Processor . */ + protected final XMLDTDProcessor fDTDProcessor; + + // + // XML 1.1 components + // + + /** The XML 1.1 datatype factory. **/ + protected DTDDVFactory fXML11DatatypeFactory = null; + + /** The XML 1.1 document scanner that does namespace binding. **/ + protected XML11NSDocumentScannerImpl fXML11NSDocScanner = null; + + /** The XML 1.1 document scanner that does not do namespace binding. **/ + protected XML11DocumentScannerImpl fXML11DocScanner = null; + + /** The XML 1.1 DTD validator that does namespace binding. **/ + protected XML11NSDTDValidator fXML11NSDTDValidator = null; + + /** The XML 1.1 DTD validator that does not do namespace binding. **/ + protected XML11DTDValidator fXML11DTDValidator = null; + + /** The XML 1.1 DTD scanner. **/ + protected XML11DTDScannerImpl fXML11DTDScanner = null; + + /** The XML 1.1 DTD processor. **/ + protected XML11DTDProcessor fXML11DTDProcessor = null; + + // + // Common components + // + + /** Grammar pool. */ + protected XMLGrammarPool fGrammarPool; + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + /** Entity manager. */ + protected XMLEntityManager fEntityManager; + + /** XML Schema Validator. */ + protected XMLSchemaValidator fSchemaValidator; + + /** Current scanner */ + protected XMLDocumentScanner fCurrentScanner; + /** Current Datatype validator factory. */ + protected DTDDVFactory fCurrentDVFactory; + /** Current DTD scanner. */ + protected XMLDTDScanner fCurrentDTDScanner; + + /** Flag indiciating whether XML11 components have been initialized. */ + private boolean f11Initialized = false; + + // + // Constructors + // + + /** Default constructor. */ + public XML11Configuration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public XML11Configuration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public XML11Configuration(SymbolTable symbolTable, XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public XML11Configuration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + + super(parentSettings); + + // create a vector to hold all the components in use + // XML 1.0 specialized components + fComponents = new ArrayList(); + // XML 1.1 specialized components + fXML11Components = new ArrayList(); + // Common components for XML 1.1. and XML 1.0 + fCommonComponents = new ArrayList(); + + // create storage for recognized features and properties + fRecognizedFeatures = new ArrayList(); + fRecognizedProperties = new ArrayList(); + + // create table for features and properties + fFeatures = new HashMap(); + fProperties = new HashMap(); + + // add default recognized features + final String[] recognizedFeatures = + { + CONTINUE_AFTER_FATAL_ERROR, LOAD_EXTERNAL_DTD, // from XMLDTDScannerImpl + VALIDATION, + NAMESPACES, + NORMALIZE_DATA, SCHEMA_ELEMENT_DEFAULT, SCHEMA_AUGMENT_PSVI, + GENERATE_SYNTHETIC_ANNOTATIONS, VALIDATE_ANNOTATIONS, + HONOUR_ALL_SCHEMALOCATIONS, NAMESPACE_GROWTH, + TOLERATE_DUPLICATES, IGNORE_XSI_TYPE, + ID_IDREF_CHECKING, IDENTITY_CONSTRAINT_CHECKING, + UNPARSED_ENTITY_CHECKING, USE_GRAMMAR_POOL_ONLY, + // NOTE: These shouldn't really be here but since the XML Schema + // validator is constructed dynamically, its recognized + // features might not have been set and it would cause a + // not-recognized exception to be thrown. -Ac + XMLSCHEMA_VALIDATION, XMLSCHEMA_FULL_CHECKING, + EXTERNAL_GENERAL_ENTITIES, + EXTERNAL_PARAMETER_ENTITIES, + PARSER_SETTINGS, + + }; + addRecognizedFeatures(recognizedFeatures); + // set state for default features + fFeatures.put(VALIDATION, Boolean.FALSE); + fFeatures.put(NAMESPACES, Boolean.TRUE); + fFeatures.put(EXTERNAL_GENERAL_ENTITIES, Boolean.TRUE); + fFeatures.put(EXTERNAL_PARAMETER_ENTITIES, Boolean.TRUE); + fFeatures.put(CONTINUE_AFTER_FATAL_ERROR, Boolean.FALSE); + fFeatures.put(LOAD_EXTERNAL_DTD, Boolean.TRUE); + fFeatures.put(SCHEMA_ELEMENT_DEFAULT, Boolean.TRUE); + fFeatures.put(NORMALIZE_DATA, Boolean.TRUE); + fFeatures.put(SCHEMA_AUGMENT_PSVI, Boolean.TRUE); + fFeatures.put(GENERATE_SYNTHETIC_ANNOTATIONS, Boolean.FALSE); + fFeatures.put(VALIDATE_ANNOTATIONS, Boolean.FALSE); + fFeatures.put(HONOUR_ALL_SCHEMALOCATIONS, Boolean.FALSE); + fFeatures.put(NAMESPACE_GROWTH, Boolean.FALSE); + fFeatures.put(TOLERATE_DUPLICATES, Boolean.FALSE); + fFeatures.put(IGNORE_XSI_TYPE, Boolean.FALSE); + fFeatures.put(ID_IDREF_CHECKING, Boolean.TRUE); + fFeatures.put(IDENTITY_CONSTRAINT_CHECKING, Boolean.TRUE); + fFeatures.put(UNPARSED_ENTITY_CHECKING, Boolean.TRUE); + fFeatures.put(USE_GRAMMAR_POOL_ONLY, Boolean.FALSE); + fFeatures.put(PARSER_SETTINGS, Boolean.TRUE); + + // add default recognized properties + final String[] recognizedProperties = + { + SYMBOL_TABLE, + ERROR_HANDLER, + ENTITY_RESOLVER, + ERROR_REPORTER, + ENTITY_MANAGER, + DOCUMENT_SCANNER, + DTD_SCANNER, + DTD_PROCESSOR, + DTD_VALIDATOR, + DATATYPE_VALIDATOR_FACTORY, + VALIDATION_MANAGER, + SCHEMA_VALIDATOR, + XML_STRING, + XMLGRAMMAR_POOL, + JAXP_SCHEMA_SOURCE, + JAXP_SCHEMA_LANGUAGE, + // NOTE: These shouldn't really be here but since the XML Schema + // validator is constructed dynamically, its recognized + // properties might not have been set and it would cause a + // not-recognized exception to be thrown. -Ac + SCHEMA_LOCATION, + SCHEMA_NONS_LOCATION, + LOCALE, + ROOT_TYPE_DEF, + ROOT_ELEMENT_DECL, + SCHEMA_DV_FACTORY, + }; + addRecognizedProperties(recognizedProperties); + + if (symbolTable == null) { + symbolTable = new SymbolTable(); + } + fSymbolTable = symbolTable; + fProperties.put(SYMBOL_TABLE, fSymbolTable); + + fGrammarPool = grammarPool; + if (fGrammarPool != null) { + fProperties.put(XMLGRAMMAR_POOL, fGrammarPool); + } + + fEntityManager = new XMLEntityManager(); + fProperties.put(ENTITY_MANAGER, fEntityManager); + addCommonComponent(fEntityManager); + + fErrorReporter = new XMLErrorReporter(); + fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner()); + fProperties.put(ERROR_REPORTER, fErrorReporter); + addCommonComponent(fErrorReporter); + + fNamespaceScanner = new XMLNSDocumentScannerImpl(); + fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner); + addComponent((XMLComponent) fNamespaceScanner); + + fDTDScanner = new XMLDTDScannerImpl(); + fProperties.put(DTD_SCANNER, fDTDScanner); + addComponent((XMLComponent) fDTDScanner); + + fDTDProcessor = new XMLDTDProcessor(); + fProperties.put(DTD_PROCESSOR, fDTDProcessor); + addComponent(fDTDProcessor); + + fDTDValidator = new XMLNSDTDValidator(); + fProperties.put(DTD_VALIDATOR, fDTDValidator); + addComponent(fDTDValidator); + + fDatatypeValidatorFactory = DTDDVFactory.getInstance(); + fProperties.put(DATATYPE_VALIDATOR_FACTORY, fDatatypeValidatorFactory); + + fValidationManager = new ValidationManager(); + fProperties.put(VALIDATION_MANAGER, fValidationManager); + + fVersionDetector = new XMLVersionDetector(); + + // add message formatters + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + + // set locale + try { + setLocale(Locale.getDefault()); + } catch (XNIException e) { + // do nothing + // REVISIT: What is the right thing to do? -Ac + } + + fConfigUpdated = false; + + } // (SymbolTable,XMLGrammarPool) + + // + // Public methods + // + /** + * Sets the input source for the document to parse. + * + * @param inputSource The document's input source. + * + * @exception XMLConfigurationException Thrown if there is a + * configuration error when initializing the + * parser. + * @exception IOException Thrown on I/O error. + * + * @see #parse(boolean) + */ + public void setInputSource(XMLInputSource inputSource) + throws XMLConfigurationException, IOException { + + // REVISIT: this method used to reset all the components and + // construct the pipeline. Now reset() is called + // in parse (boolean) just before we parse the document + // Should this method still throw exceptions..? + + fInputSource = inputSource; + + } // setInputSource(XMLInputSource) + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException { + fLocale = locale; + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + /** + * Sets the document handler on the last component in the pipeline + * to receive information about the document. + * + * @param documentHandler The document handler. + */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + if (fLastComponent != null) { + fLastComponent.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler !=null){ + fDocumentHandler.setDocumentSource(fLastComponent); + } + } + } // setDocumentHandler(XMLDocumentHandler) + + /** Returns the registered document handler. */ + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } // getDocumentHandler():XMLDocumentHandler + + /** + * Sets the DTD handler. + * + * @param dtdHandler The DTD handler. + */ + public void setDTDHandler(XMLDTDHandler dtdHandler) { + fDTDHandler = dtdHandler; + } // setDTDHandler(XMLDTDHandler) + + /** Returns the registered DTD handler. */ + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } // getDTDHandler():XMLDTDHandler + + /** + * Sets the DTD content model handler. + * + * @param handler The DTD content model handler. + */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) { + fDTDContentModelHandler = handler; + } // setDTDContentModelHandler(XMLDTDContentModelHandler) + + /** Returns the registered DTD content model handler. */ + public XMLDTDContentModelHandler getDTDContentModelHandler() { + return fDTDContentModelHandler; + } // getDTDContentModelHandler():XMLDTDContentModelHandler + + /** + * Sets the resolver used to resolve external entities. The EntityResolver + * interface supports resolution of public and system identifiers. + * + * @param resolver The new entity resolver. Passing a null value will + * uninstall the currently installed resolver. + */ + public void setEntityResolver(XMLEntityResolver resolver) { + fProperties.put(ENTITY_RESOLVER, resolver); + } // setEntityResolver(XMLEntityResolver) + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public XMLEntityResolver getEntityResolver() { + return (XMLEntityResolver)fProperties.get(ENTITY_RESOLVER); + } // getEntityResolver():XMLEntityResolver + + /** + * 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 errorHandler The error handler. + * @exception java.lang.NullPointerException If the handler + * argument is null. + * @see #getErrorHandler + */ + public void setErrorHandler(XMLErrorHandler errorHandler) { + fProperties.put(ERROR_HANDLER, errorHandler); + } // setErrorHandler(XMLErrorHandler) + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public XMLErrorHandler getErrorHandler() { + // REVISIT: Should this be a property? + return (XMLErrorHandler)fProperties.get(ERROR_HANDLER); + } // getErrorHandler():XMLErrorHandler + + + /** + * If the application decides to terminate parsing before the xml document + * is fully parsed, the application should call this method to free any + * resource allocated during parsing. For example, close all opened streams. + */ + public void cleanup() { + fEntityManager.closeReaders(); + } + + /** + * Parses the specified input source. + * + * @param source The input source. + * + * @exception XNIException Throws exception on XNI error. + * @exception java.io.IOException Throws exception on i/o error. + */ + public void parse(XMLInputSource source) throws XNIException, IOException { + + if (fParseInProgress) { + // REVISIT - need to add new error message + throw new XNIException("FWK005 parse may not be called while parsing."); + } + fParseInProgress = true; + + try { + setInputSource(source); + parse(true); + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } finally { + fParseInProgress = false; + // close all streams opened by xerces + this.cleanup(); + } + + } // parse(InputSource) + + public boolean parse(boolean complete) throws XNIException, IOException { + // + // reset and configure pipeline and set InputSource. + if (fInputSource != null) { + try { + fValidationManager.reset(); + fVersionDetector.reset(this); + resetCommon(); + + short version = fVersionDetector.determineDocVersion(fInputSource); + // XML 1.0 + if (version == Constants.XML_VERSION_1_0) { + configurePipeline(); + reset(); + } + // XML 1.1 + else if (version == Constants.XML_VERSION_1_1) { + initXML11Components(); + configureXML11Pipeline(); + resetXML11(); + } + // Unrecoverable error reported during version detection + else { + return false; + } + + // mark configuration as fixed + fConfigUpdated = false; + + // resets and sets the pipeline. + fVersionDetector.startDocumentParsing((XMLEntityHandler) fCurrentScanner, version); + fInputSource = null; + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + } + + try { + return fCurrentScanner.scanDocument(complete); + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + + } // parse(boolean):boolean + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * @return true if the feature is supported + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + // make this feature special + if (featureId.equals(PARSER_SETTINGS)){ + return fConfigUpdated; + } + return super.getFeature(featureId); + + } // getFeature(String):boolean + + /** + * Set the state of a feature. + * + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + fConfigUpdated = true; + // forward to every XML 1.0 component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.setFeature(featureId, state); + } + // forward it to common components + count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.setFeature(featureId, state); + } + + // forward to every XML 1.1 component + count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + try{ + c.setFeature(featureId, state); + } + catch (Exception e){ + // no op + } + } + // save state if noone "objects" + super.setFeature(featureId, state); + + } // setFeature(String,boolean) + + /** + * Returns the value of a property. + * + * @param propertyId The property identifier. + * @return the value of the property + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException { + if (LOCALE.equals(propertyId)) { + return getLocale(); + } + return super.getProperty(propertyId); + } + + /** + * setProperty + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + fConfigUpdated = true; + if (LOCALE.equals(propertyId)) { + setLocale((Locale) value); + } + // forward to every XML 1.0 component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.setProperty(propertyId, value); + } + // forward it to every common Component + count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.setProperty(propertyId, value); + } + // forward it to every XML 1.1 component + count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + try{ + c.setProperty(propertyId, value); + } + catch (Exception e){ + // ignore it + } + } + + // store value if noone "objects" + super.setProperty(propertyId, value); + + } // setProperty(String,Object) + + + /** Returns the locale. */ + public Locale getLocale() { + return fLocale; + } // getLocale():Locale + + /** + * reset all XML 1.0 components before parsing and namespace context + */ + protected void reset() throws XNIException { + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.reset(this); + } + + } // reset() + + /** + * reset all common components before parsing + */ + protected void resetCommon() throws XNIException { + // reset common components + int count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.reset(this); + } + + } // resetCommon() + + + /** + * reset all components before parsing and namespace context + */ + protected void resetXML11() throws XNIException { + // reset every component + int count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + c.reset(this); + } + + } // resetXML11() + + + /** + * Configures the XML 1.1 pipeline. + * Note: this method also resets the new XML11 components. + */ + protected void configureXML11Pipeline() { + if (fCurrentDVFactory != fXML11DatatypeFactory) { + fCurrentDVFactory = fXML11DatatypeFactory; + setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); + } + if (fCurrentDTDScanner != fXML11DTDScanner) { + fCurrentDTDScanner = fXML11DTDScanner; + setProperty(DTD_SCANNER, fCurrentDTDScanner); + setProperty(DTD_PROCESSOR, fXML11DTDProcessor); + } + + fXML11DTDScanner.setDTDHandler(fXML11DTDProcessor); + fXML11DTDProcessor.setDTDSource(fXML11DTDScanner); + fXML11DTDProcessor.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXML11DTDProcessor); + } + + fXML11DTDScanner.setDTDContentModelHandler(fXML11DTDProcessor); + fXML11DTDProcessor.setDTDContentModelSource(fXML11DTDScanner); + fXML11DTDProcessor.setDTDContentModelHandler(fDTDContentModelHandler); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.setDTDContentModelSource(fXML11DTDProcessor); + } + + // setup XML 1.1 document pipeline + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + if (fCurrentScanner != fXML11NSDocScanner) { + fCurrentScanner = fXML11NSDocScanner; + setProperty(DOCUMENT_SCANNER, fXML11NSDocScanner); + setProperty(DTD_VALIDATOR, fXML11NSDTDValidator); + } + + fXML11NSDocScanner.setDTDValidator(fXML11NSDTDValidator); + fXML11NSDocScanner.setDocumentHandler(fXML11NSDTDValidator); + fXML11NSDTDValidator.setDocumentSource(fXML11NSDocScanner); + fXML11NSDTDValidator.setDocumentHandler(fDocumentHandler); + + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fXML11NSDTDValidator); + } + fLastComponent = fXML11NSDTDValidator; + + } else { + // create components + if (fXML11DocScanner == null) { + // non namespace document pipeline + fXML11DocScanner = new XML11DocumentScannerImpl(); + addXML11Component(fXML11DocScanner); + fXML11DTDValidator = new XML11DTDValidator(); + addXML11Component(fXML11DTDValidator); + } + if (fCurrentScanner != fXML11DocScanner) { + fCurrentScanner = fXML11DocScanner; + setProperty(DOCUMENT_SCANNER, fXML11DocScanner); + setProperty(DTD_VALIDATOR, fXML11DTDValidator); + } + fXML11DocScanner.setDocumentHandler(fXML11DTDValidator); + fXML11DTDValidator.setDocumentSource(fXML11DocScanner); + fXML11DTDValidator.setDocumentHandler(fDocumentHandler); + + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fXML11DTDValidator); + } + fLastComponent = fXML11DTDValidator; + } + + // setup document pipeline + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // If schema validator was not in the pipeline insert it. + if (fSchemaValidator == null) { + fSchemaValidator = new XMLSchemaValidator(); + // add schema component + setProperty(SCHEMA_VALIDATOR, fSchemaValidator); + addCommonComponent(fSchemaValidator); + fSchemaValidator.reset(this); + // add schema message formatter + if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { + XSMessageFormatter xmft = new XSMessageFormatter(); + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, xmft); + } + } + + fLastComponent.setDocumentHandler(fSchemaValidator); + fSchemaValidator.setDocumentSource(fLastComponent); + fSchemaValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fSchemaValidator); + } + fLastComponent = fSchemaValidator; + } + + } // configureXML11Pipeline() + + /** Configures the pipeline. */ + protected void configurePipeline() { + if (fCurrentDVFactory != fDatatypeValidatorFactory) { + fCurrentDVFactory = fDatatypeValidatorFactory; + // use XML 1.0 datatype library + setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); + } + + // setup DTD pipeline + if (fCurrentDTDScanner != fDTDScanner) { + fCurrentDTDScanner = fDTDScanner; + setProperty(DTD_SCANNER, fCurrentDTDScanner); + setProperty(DTD_PROCESSOR, fDTDProcessor); + } + fDTDScanner.setDTDHandler(fDTDProcessor); + fDTDProcessor.setDTDSource(fDTDScanner); + fDTDProcessor.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fDTDProcessor); + } + + fDTDScanner.setDTDContentModelHandler(fDTDProcessor); + fDTDProcessor.setDTDContentModelSource(fDTDScanner); + fDTDProcessor.setDTDContentModelHandler(fDTDContentModelHandler); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.setDTDContentModelSource(fDTDProcessor); + } + + // setup document pipeline + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + if (fCurrentScanner != fNamespaceScanner) { + fCurrentScanner = fNamespaceScanner; + setProperty(DOCUMENT_SCANNER, fNamespaceScanner); + setProperty(DTD_VALIDATOR, fDTDValidator); + } + fNamespaceScanner.setDTDValidator(fDTDValidator); + fNamespaceScanner.setDocumentHandler(fDTDValidator); + fDTDValidator.setDocumentSource(fNamespaceScanner); + fDTDValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fDTDValidator); + } + fLastComponent = fDTDValidator; + } else { + // create components + if (fNonNSScanner == null) { + fNonNSScanner = new XMLDocumentScannerImpl(); + fNonNSDTDValidator = new XMLDTDValidator(); + // add components + addComponent((XMLComponent) fNonNSScanner); + addComponent((XMLComponent) fNonNSDTDValidator); + } + if (fCurrentScanner != fNonNSScanner) { + fCurrentScanner = fNonNSScanner; + setProperty(DOCUMENT_SCANNER, fNonNSScanner); + setProperty(DTD_VALIDATOR, fNonNSDTDValidator); + } + + fNonNSScanner.setDocumentHandler(fNonNSDTDValidator); + fNonNSDTDValidator.setDocumentSource(fNonNSScanner); + fNonNSDTDValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fNonNSDTDValidator); + } + fLastComponent = fNonNSDTDValidator; + } + + // add XML Schema validator if needed + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // If schema validator was not in the pipeline insert it. + if (fSchemaValidator == null) { + fSchemaValidator = new XMLSchemaValidator(); + // add schema component + setProperty(SCHEMA_VALIDATOR, fSchemaValidator); + addCommonComponent(fSchemaValidator); + fSchemaValidator.reset(this); + // add schema message formatter + if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { + XSMessageFormatter xmft = new XSMessageFormatter(); + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, xmft); + } + + } + fLastComponent.setDocumentHandler(fSchemaValidator); + fSchemaValidator.setDocumentSource(fLastComponent); + fSchemaValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fSchemaValidator); + } + fLastComponent = fSchemaValidator; + } + } // configurePipeline() + + + // features and properties + + /** + * Check a feature. If feature is know and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) throws XMLConfigurationException { + + // + // Xerces Features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/validation/dynamic + // Allows the parser to validate a document only when it + // contains a grammar. Validation is turned on/off based + // on each document instance, automatically. + // + if (suffixLength == Constants.DYNAMIC_VALIDATION_FEATURE.length() && + featureId.endsWith(Constants.DYNAMIC_VALIDATION_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE.length() && + featureId.endsWith(Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_CONTENT_MODELS_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_CONTENT_MODELS_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-dtd-grammar + // + if (suffixLength == Constants.LOAD_DTD_GRAMMAR_FEATURE.length() && + featureId.endsWith(Constants.LOAD_DTD_GRAMMAR_FEATURE)) { + return; + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-external-dtd + // + if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() && + featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_DATATYPES_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_DATATYPES_FEATURE)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + + // + // http://apache.org/xml/features/validation/schema + // Lets the user turn Schema validation support on/off. + // + if (suffixLength == Constants.SCHEMA_VALIDATION_FEATURE.length() && + featureId.endsWith(Constants.SCHEMA_VALIDATION_FEATURE)) { + return; + } + // activate full schema checking + if (suffixLength == Constants.SCHEMA_FULL_CHECKING.length() && + featureId.endsWith(Constants.SCHEMA_FULL_CHECKING)) { + return; + } + // Feature identifier: expose schema normalized value + // http://apache.org/xml/features/validation/schema/normalized-value + if (suffixLength == Constants.SCHEMA_NORMALIZED_VALUE.length() && + featureId.endsWith(Constants.SCHEMA_NORMALIZED_VALUE)) { + return; + } + // Feature identifier: send element default value via characters() + // http://apache.org/xml/features/validation/schema/element-default + if (suffixLength == Constants.SCHEMA_ELEMENT_DEFAULT.length() && + featureId.endsWith(Constants.SCHEMA_ELEMENT_DEFAULT)) { + return; + } + + // special performance feature: only component manager is allowed to set it. + if (suffixLength == Constants.PARSER_SETTINGS.length() && + featureId.endsWith(Constants.PARSER_SETTINGS)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + + } + + // + // Not recognized + // + + super.checkFeature(featureId); + + } // checkFeature(String) + + /** + * Check a property. If the property is know and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkProperty(String propertyId) throws XMLConfigurationException { + + // + // Xerces Properties + // + + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() && + propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) { + return; + } + if (suffixLength == Constants.SCHEMA_LOCATION.length() && + propertyId.endsWith(Constants.SCHEMA_LOCATION)) { + return; + } + if (suffixLength == Constants.SCHEMA_NONS_LOCATION.length() && + propertyId.endsWith(Constants.SCHEMA_NONS_LOCATION)) { + return; + } + } + + if (propertyId.startsWith(Constants.JAXP_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.JAXP_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SCHEMA_SOURCE.length() && + propertyId.endsWith(Constants.SCHEMA_SOURCE)) { + return; + } + } + + // special cases + if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); + + // + // http://xml.org/sax/properties/xml-string + // Value type: String + // Access: read-only + // Get the literal string of characters associated with the + // current event. If the parser recognises and supports this + // property but is not currently parsing text, it should return + // null (this is a good way to check for availability before the + // parse begins). + // + if (suffixLength == Constants.XML_STRING_PROPERTY.length() && + propertyId.endsWith(Constants.XML_STRING_PROPERTY)) { + // REVISIT - we should probably ask xml-dev for a precise + // definition of what this is actually supposed to return, and + // in exactly which circumstances. + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, propertyId); + } + } + + // + // Not recognized + // + + super.checkProperty(propertyId); + + } // checkProperty(String) + + + /** + * Adds a component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addComponent(XMLComponent component) { + + // don't add a component more than once + if (fComponents.contains(component)) { + return; + } + fComponents.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addComponent(XMLComponent) + + /** + * Adds common component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addCommonComponent(XMLComponent component) { + + // don't add a component more than once + if (fCommonComponents.contains(component)) { + return; + } + fCommonComponents.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addCommonComponent(XMLComponent) + + /** + * Adds an XML 1.1 component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addXML11Component(XMLComponent component) { + + // don't add a component more than once + if (fXML11Components.contains(component)) { + return; + } + fXML11Components.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addXML11Component(XMLComponent) + + /** + * Adds all of the component's recognized features and properties + * to the list of default recognized features and properties, and + * sets default values on the configuration for features and + * properties which were previously absent from the configuration. + * + * @param component The component whose recognized features + * and properties will be added to the configuration + */ + protected void addRecognizedParamsAndSetDefaults(XMLComponent component) { + + // register component's recognized features + String[] recognizedFeatures = component.getRecognizedFeatures(); + addRecognizedFeatures(recognizedFeatures); + + // register component's recognized properties + String[] recognizedProperties = component.getRecognizedProperties(); + addRecognizedProperties(recognizedProperties); + + // set default values + if (recognizedFeatures != null) { + for (int i = 0; i < recognizedFeatures.length; ++i) { + String featureId = recognizedFeatures[i]; + Boolean state = component.getFeatureDefault(featureId); + if (state != null) { + // Do not overwrite values already set on the configuration. + if (!fFeatures.containsKey(featureId)) { + fFeatures.put(featureId, state); + // For newly added components who recognize this feature + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + if (recognizedProperties != null) { + for (int i = 0; i < recognizedProperties.length; ++i) { + String propertyId = recognizedProperties[i]; + Object value = component.getPropertyDefault(propertyId); + if (value != null) { + // Do not overwrite values already set on the configuration. + if (!fProperties.containsKey(propertyId)) { + fProperties.put(propertyId, value); + // For newly added components who recognize this property + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + } + + private void initXML11Components() { + if (!f11Initialized) { + + // create datatype factory + fXML11DatatypeFactory = DTDDVFactory.getInstance(XML11_DATATYPE_VALIDATOR_FACTORY); + + // setup XML 1.1 DTD pipeline + fXML11DTDScanner = new XML11DTDScannerImpl(); + addXML11Component(fXML11DTDScanner); + fXML11DTDProcessor = new XML11DTDProcessor(); + addXML11Component(fXML11DTDProcessor); + + // setup XML 1.1. document pipeline - namespace aware + fXML11NSDocScanner = new XML11NSDocumentScannerImpl(); + addXML11Component(fXML11NSDocScanner); + fXML11NSDTDValidator = new XML11NSDTDValidator(); + addXML11Component(fXML11NSDTDValidator); + + f11Initialized = true; + } + } + + /** + * Returns the state of a feature. This method calls getFeature() + * on ParserConfigurationSettings, bypassing getFeature() on this + * class. + */ + boolean getFeature0(String featureId) + throws XMLConfigurationException { + return super.getFeature(featureId); + } + +} // class XML11Configuration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XML11DTDConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XML11DTDConfiguration.java new file mode 100644 index 0000000..3918c7e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XML11DTDConfiguration.java @@ -0,0 +1,1345 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XML11DTDScannerImpl; +import org.apache.xerces.impl.XML11DocumentScannerImpl; +import org.apache.xerces.impl.XML11NSDocumentScannerImpl; +import org.apache.xerces.impl.XMLDTDScannerImpl; +import org.apache.xerces.impl.XMLDocumentScannerImpl; +import org.apache.xerces.impl.XMLEntityHandler; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.XMLNSDocumentScannerImpl; +import org.apache.xerces.impl.XMLVersionDetector; +import org.apache.xerces.impl.dtd.XML11DTDProcessor; +import org.apache.xerces.impl.dtd.XML11DTDValidator; +import org.apache.xerces.impl.dtd.XML11NSDTDValidator; +import org.apache.xerces.impl.dtd.XMLDTDProcessor; +import org.apache.xerces.impl.dtd.XMLDTDValidator; +import org.apache.xerces.impl.dtd.XMLNSDTDValidator; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.util.ParserConfigurationSettings; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDScanner; +import org.apache.xerces.xni.parser.XMLDocumentScanner; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLPullParserConfiguration; + +/** + * This class is the DTD-only parser configuration + * used to parse XML 1.0 and XML 1.1 documents. + * + *

        + * This class recognizes the following features and properties: + *

          + *
        • Features + *
            + *
          • http://xml.org/sax/features/validation
          • + *
          • http://xml.org/sax/features/namespaces
          • + *
          • http://xml.org/sax/features/external-general-entities
          • + *
          • http://xml.org/sax/features/external-parameter-entities
          • + *
          • http://apache.org/xml/features/continue-after-fatal-error
          • + *
          • http://apache.org/xml/features/load-external-dtd
          • + *
          + *
        • Properties + *
            + *
          • http://xml.org/sax/properties/xml-string
          • + *
          • http://apache.org/xml/properties/internal/symbol-table
          • + *
          • http://apache.org/xml/properties/internal/error-handler
          • + *
          • http://apache.org/xml/properties/internal/entity-resolver
          • + *
          • http://apache.org/xml/properties/internal/error-reporter
          • + *
          • http://apache.org/xml/properties/internal/entity-manager
          • + *
          • http://apache.org/xml/properties/internal/document-scanner
          • + *
          • http://apache.org/xml/properties/internal/dtd-scanner
          • + *
          • http://apache.org/xml/properties/internal/grammar-pool
          • + *
          • http://apache.org/xml/properties/internal/validator/dtd
          • + *
          • http://apache.org/xml/properties/internal/datatype-validator-factory
          • + *
          + *
        + * @author Elena Litani, IBM + * @author Neil Graham, IBM + * @author Michael Glavassevich, IBM + * @author John Kim, IBM + * + * @version $Id$ + */ +public class XML11DTDConfiguration extends ParserConfigurationSettings + implements XMLPullParserConfiguration, XML11Configurable { + + // + // Constants + // + protected final static String XML11_DATATYPE_VALIDATOR_FACTORY = + "org.apache.xerces.impl.dv.dtd.XML11DTDDVFactoryImpl"; + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: external general entities. */ + protected static final String EXTERNAL_GENERAL_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE; + + /** Feature identifier: external parameter entities. */ + protected static final String EXTERNAL_PARAMETER_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE; + + /** Feature identifier: continue after fatal error. */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + /** Feature identifier: load external DTD. */ + protected static final String LOAD_EXTERNAL_DTD = + Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE; + + // property identifiers + + /** Property identifier: xml string. */ + protected static final String XML_STRING = + Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY; + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier document scanner: */ + protected static final String DOCUMENT_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_SCANNER_PROPERTY; + + /** Property identifier: DTD scanner. */ + protected static final String DTD_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY; + + /** Property identifier: grammar pool. */ + protected static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: DTD loader. */ + protected static final String DTD_PROCESSOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_PROCESSOR_PROPERTY; + + /** Property identifier: DTD validator. */ + protected static final String DTD_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; + + /** Property identifier: namespace binder. */ + protected static final String NAMESPACE_BINDER = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_BINDER_PROPERTY; + + /** Property identifier: datatype validator factory. */ + protected static final String DATATYPE_VALIDATOR_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; + + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + /** Property identifier: JAXP schema language / DOM schema-type. */ + protected static final String JAXP_SCHEMA_LANGUAGE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE; + + /** Property identifier: JAXP schema source/ DOM schema-location. */ + protected static final String JAXP_SCHEMA_SOURCE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE; + + // debugging + + /** Set to true and recompile to print exception stack trace. */ + protected static final boolean PRINT_EXCEPTION_STACK_TRACE = false; + + // + // Data + // + protected SymbolTable fSymbolTable; + protected XMLInputSource fInputSource; + protected ValidationManager fValidationManager; + protected XMLVersionDetector fVersionDetector; + protected XMLLocator fLocator; + protected Locale fLocale; + + /** XML 1.0 Components. */ + protected ArrayList fComponents; + + /** XML 1.1. Components. */ + protected ArrayList fXML11Components = null; + + /** Common components: XMLEntityManager, XMLErrorReporter */ + protected ArrayList fCommonComponents = null; + + /** The document handler. */ + protected XMLDocumentHandler fDocumentHandler; + + /** The DTD handler. */ + protected XMLDTDHandler fDTDHandler; + + /** The DTD content model handler. */ + protected XMLDTDContentModelHandler fDTDContentModelHandler; + + /** Last component in the document pipeline */ + protected XMLDocumentSource fLastComponent; + + /** + * True if a parse is in progress. This state is needed because + * some features/properties cannot be set while parsing (e.g. + * validation and namespaces). + */ + protected boolean fParseInProgress = false; + + /** + * fConfigUpdated is set to true if there has been any change to the configuration settings, + * i.e a feature or a property was changed. + */ + protected boolean fConfigUpdated = false; + + // + // XML 1.0 components + // + + /** The XML 1.0 Datatype validator factory. */ + protected DTDDVFactory fDatatypeValidatorFactory; + + /** The XML 1.0 Document scanner that does namespace binding. */ + protected XMLNSDocumentScannerImpl fNamespaceScanner; + + /** The XML 1.0 Non-namespace implementation of scanner */ + protected XMLDocumentScannerImpl fNonNSScanner; + + /** The XML 1.0 DTD Validator: binds namespaces */ + protected XMLDTDValidator fDTDValidator; + + /** The XML 1.0 DTD Validator that does not bind namespaces */ + protected XMLDTDValidator fNonNSDTDValidator; + + /** The XML 1.0 DTD scanner. */ + protected XMLDTDScanner fDTDScanner; + + /** The XML 1.0 DTD Processor . */ + protected XMLDTDProcessor fDTDProcessor; + + // + // XML 1.1 components + // + + /** The XML 1.1 datatype factory. **/ + protected DTDDVFactory fXML11DatatypeFactory = null; + + /** The XML 1.1 document scanner that does namespace binding. **/ + protected XML11NSDocumentScannerImpl fXML11NSDocScanner = null; + + /** The XML 1.1 document scanner that does not do namespace binding. **/ + protected XML11DocumentScannerImpl fXML11DocScanner = null; + + /** The XML 1.1 DTD validator that does namespace binding. **/ + protected XML11NSDTDValidator fXML11NSDTDValidator = null; + + /** The XML 1.1 DTD validator that does not do namespace binding. **/ + protected XML11DTDValidator fXML11DTDValidator = null; + + /** The XML 1.1 DTD scanner. **/ + protected XML11DTDScannerImpl fXML11DTDScanner = null; + + /** The XML 1.1 DTD processor. **/ + protected XML11DTDProcessor fXML11DTDProcessor = null; + + // + // Common components + // + + /** Grammar pool. */ + protected XMLGrammarPool fGrammarPool; + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + /** Entity manager. */ + protected XMLEntityManager fEntityManager; + + /** Current scanner */ + protected XMLDocumentScanner fCurrentScanner; + + /** Current Datatype validator factory. */ + protected DTDDVFactory fCurrentDVFactory; + + /** Current DTD scanner. */ + protected XMLDTDScanner fCurrentDTDScanner; + + /** Flag indiciating whether XML11 components have been initialized. */ + private boolean f11Initialized = false; + + // + // Constructors + // + + /** Default constructor. */ + public XML11DTDConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public XML11DTDConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public XML11DTDConfiguration(SymbolTable symbolTable, XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public XML11DTDConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + + super(parentSettings); + + // create a vector to hold all the components in use + // XML 1.0 specialized components + fComponents = new ArrayList(); + // XML 1.1 specialized components + fXML11Components = new ArrayList(); + // Common components for XML 1.1. and XML 1.0 + fCommonComponents = new ArrayList(); + + // create storage for recognized features and properties + fRecognizedFeatures = new ArrayList(); + fRecognizedProperties = new ArrayList(); + + // create table for features and properties + fFeatures = new HashMap(); + fProperties = new HashMap(); + + // add default recognized features + final String[] recognizedFeatures = + { + CONTINUE_AFTER_FATAL_ERROR, LOAD_EXTERNAL_DTD, // from XMLDTDScannerImpl + VALIDATION, + NAMESPACES, + EXTERNAL_GENERAL_ENTITIES, + EXTERNAL_PARAMETER_ENTITIES, + PARSER_SETTINGS + }; + addRecognizedFeatures(recognizedFeatures); + // set state for default features + fFeatures.put(VALIDATION, Boolean.FALSE); + fFeatures.put(NAMESPACES, Boolean.TRUE); + fFeatures.put(EXTERNAL_GENERAL_ENTITIES, Boolean.TRUE); + fFeatures.put(EXTERNAL_PARAMETER_ENTITIES, Boolean.TRUE); + fFeatures.put(CONTINUE_AFTER_FATAL_ERROR, Boolean.FALSE); + fFeatures.put(LOAD_EXTERNAL_DTD, Boolean.TRUE); + fFeatures.put(PARSER_SETTINGS, Boolean.TRUE); + + // add default recognized properties + final String[] recognizedProperties = + { + SYMBOL_TABLE, + ERROR_HANDLER, + ENTITY_RESOLVER, + ERROR_REPORTER, + ENTITY_MANAGER, + DOCUMENT_SCANNER, + DTD_SCANNER, + DTD_PROCESSOR, + DTD_VALIDATOR, + DATATYPE_VALIDATOR_FACTORY, + VALIDATION_MANAGER, + XML_STRING, + XMLGRAMMAR_POOL, + JAXP_SCHEMA_SOURCE, + JAXP_SCHEMA_LANGUAGE}; + addRecognizedProperties(recognizedProperties); + + if (symbolTable == null) { + symbolTable = new SymbolTable(); + } + fSymbolTable = symbolTable; + fProperties.put(SYMBOL_TABLE, fSymbolTable); + + fGrammarPool = grammarPool; + if (fGrammarPool != null) { + fProperties.put(XMLGRAMMAR_POOL, fGrammarPool); + } + + fEntityManager = new XMLEntityManager(); + fProperties.put(ENTITY_MANAGER, fEntityManager); + addCommonComponent(fEntityManager); + + fErrorReporter = new XMLErrorReporter(); + fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner()); + fProperties.put(ERROR_REPORTER, fErrorReporter); + addCommonComponent(fErrorReporter); + + fNamespaceScanner = new XMLNSDocumentScannerImpl(); + fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner); + addComponent((XMLComponent) fNamespaceScanner); + + fDTDScanner = new XMLDTDScannerImpl(); + fProperties.put(DTD_SCANNER, fDTDScanner); + addComponent((XMLComponent) fDTDScanner); + + fDTDProcessor = new XMLDTDProcessor(); + fProperties.put(DTD_PROCESSOR, fDTDProcessor); + addComponent((XMLComponent) fDTDProcessor); + + fDTDValidator = new XMLNSDTDValidator(); + fProperties.put(DTD_VALIDATOR, fDTDValidator); + addComponent(fDTDValidator); + + fDatatypeValidatorFactory = DTDDVFactory.getInstance(); + fProperties.put(DATATYPE_VALIDATOR_FACTORY, fDatatypeValidatorFactory); + + fValidationManager = new ValidationManager(); + fProperties.put(VALIDATION_MANAGER, fValidationManager); + + fVersionDetector = new XMLVersionDetector(); + + // add message formatters + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + + // set locale + try { + setLocale(Locale.getDefault()); + } catch (XNIException e) { + // do nothing + // REVISIT: What is the right thing to do? -Ac + } + + fConfigUpdated = false; + + } // (SymbolTable,XMLGrammarPool) + + // + // Public methods + // + /** + * Sets the input source for the document to parse. + * + * @param inputSource The document's input source. + * + * @exception XMLConfigurationException Thrown if there is a + * configuration error when initializing the + * parser. + * @exception IOException Thrown on I/O error. + * + * @see #parse(boolean) + */ + public void setInputSource(XMLInputSource inputSource) + throws XMLConfigurationException, IOException { + + // REVISIT: this method used to reset all the components and + // construct the pipeline. Now reset() is called + // in parse (boolean) just before we parse the document + // Should this method still throw exceptions..? + + fInputSource = inputSource; + + } // setInputSource(XMLInputSource) + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException { + fLocale = locale; + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + + /** + * Sets the document handler on the last component in the pipeline + * to receive information about the document. + * + * @param documentHandler The document handler. + */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + if (fLastComponent != null) { + fLastComponent.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler !=null){ + fDocumentHandler.setDocumentSource(fLastComponent); + } + } + } // setDocumentHandler(XMLDocumentHandler) + + /** Returns the registered document handler. */ + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } // getDocumentHandler():XMLDocumentHandler + + /** + * Sets the DTD handler. + * + * @param dtdHandler The DTD handler. + */ + public void setDTDHandler(XMLDTDHandler dtdHandler) { + fDTDHandler = dtdHandler; + } // setDTDHandler(XMLDTDHandler) + + /** Returns the registered DTD handler. */ + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } // getDTDHandler():XMLDTDHandler + + /** + * Sets the DTD content model handler. + * + * @param handler The DTD content model handler. + */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) { + fDTDContentModelHandler = handler; + } // setDTDContentModelHandler(XMLDTDContentModelHandler) + + /** Returns the registered DTD content model handler. */ + public XMLDTDContentModelHandler getDTDContentModelHandler() { + return fDTDContentModelHandler; + } // getDTDContentModelHandler():XMLDTDContentModelHandler + + /** + * Sets the resolver used to resolve external entities. The EntityResolver + * interface supports resolution of public and system identifiers. + * + * @param resolver The new entity resolver. Passing a null value will + * uninstall the currently installed resolver. + */ + public void setEntityResolver(XMLEntityResolver resolver) { + fProperties.put(ENTITY_RESOLVER, resolver); + } // setEntityResolver(XMLEntityResolver) + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public XMLEntityResolver getEntityResolver() { + return (XMLEntityResolver)fProperties.get(ENTITY_RESOLVER); + } // getEntityResolver():XMLEntityResolver + + /** + * 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 errorHandler The error handler. + * @exception java.lang.NullPointerException If the handler + * argument is null. + * @see #getErrorHandler + */ + public void setErrorHandler(XMLErrorHandler errorHandler) { + fProperties.put(ERROR_HANDLER, errorHandler); + } // setErrorHandler(XMLErrorHandler) + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public XMLErrorHandler getErrorHandler() { + // REVISIT: Should this be a property? + return (XMLErrorHandler)fProperties.get(ERROR_HANDLER); + } // getErrorHandler():XMLErrorHandler + + + /** + * If the application decides to terminate parsing before the xml document + * is fully parsed, the application should call this method to free any + * resource allocated during parsing. For example, close all opened streams. + */ + public void cleanup() { + fEntityManager.closeReaders(); + } + + /** + * Parses the specified input source. + * + * @param source The input source. + * + * @exception XNIException Throws exception on XNI error. + * @exception java.io.IOException Throws exception on i/o error. + */ + public void parse(XMLInputSource source) throws XNIException, IOException { + + if (fParseInProgress) { + // REVISIT - need to add new error message + throw new XNIException("FWK005 parse may not be called while parsing."); + } + fParseInProgress = true; + + try { + setInputSource(source); + parse(true); + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } finally { + fParseInProgress = false; + // close all streams opened by xerces + this.cleanup(); + } + + } // parse(InputSource) + + public boolean parse(boolean complete) throws XNIException, IOException { + // + // reset and configure pipeline and set InputSource. + if (fInputSource != null) { + try { + fValidationManager.reset(); + fVersionDetector.reset(this); + resetCommon(); + + short version = fVersionDetector.determineDocVersion(fInputSource); + // XML 1.0 + if (version == Constants.XML_VERSION_1_0) { + configurePipeline(); + reset(); + } + // XML 1.1 + else if (version == Constants.XML_VERSION_1_1) { + initXML11Components(); + configureXML11Pipeline(); + resetXML11(); + } + // Unrecoverable error reported during version detection + else { + return false; + } + + // mark configuration as fixed + fConfigUpdated = false; + + // resets and sets the pipeline. + fVersionDetector.startDocumentParsing((XMLEntityHandler) fCurrentScanner, version); + fInputSource = null; + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + } + + try { + return fCurrentScanner.scanDocument(complete); + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + + } // parse(boolean):boolean + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * @return true if the feature is supported + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + // make this feature special + if (featureId.equals(PARSER_SETTINGS)){ + return fConfigUpdated; + } + return super.getFeature(featureId); + + } // getFeature(String):boolean + + /** + * Set the state of a feature. + * + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + fConfigUpdated = true; + // forward to every XML 1.0 component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.setFeature(featureId, state); + } + // forward it to common components + count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.setFeature(featureId, state); + } + + // forward to every XML 1.1 component + count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + try{ + c.setFeature(featureId, state); + } + catch (Exception e){ + // no op + } + } + // save state if noone "objects" + super.setFeature(featureId, state); + + } // setFeature(String,boolean) + + /** + * setProperty + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + fConfigUpdated = true; + // forward to every XML 1.0 component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.setProperty(propertyId, value); + } + // forward it to every common Component + count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.setProperty(propertyId, value); + } + // forward it to every XML 1.1 component + count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + try{ + c.setProperty(propertyId, value); + } + catch (Exception e){ + // ignore it + } + } + + // store value if noone "objects" + super.setProperty(propertyId, value); + + } // setProperty(String,Object) + + + /** Returns the locale. */ + public Locale getLocale() { + return fLocale; + } // getLocale():Locale + + /** + * reset all XML 1.0 components before parsing and namespace context + */ + protected void reset() throws XNIException { + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.reset(this); + } + + } // reset() + + /** + * reset all common components before parsing + */ + protected void resetCommon() throws XNIException { + // reset common components + int count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.reset(this); + } + + } // resetCommon() + + /** + * reset all components before parsing and namespace context + */ + protected void resetXML11() throws XNIException { + // reset every component + int count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + c.reset(this); + } + + } // resetXML11() + + /** + * Configures the XML 1.1 pipeline. + * Note: this method also resets the new XML11 components. + */ + protected void configureXML11Pipeline() { + if (fCurrentDVFactory != fXML11DatatypeFactory) { + fCurrentDVFactory = fXML11DatatypeFactory; + setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); + } + if (fCurrentDTDScanner != fXML11DTDScanner) { + fCurrentDTDScanner = fXML11DTDScanner; + setProperty(DTD_SCANNER, fCurrentDTDScanner); + setProperty(DTD_PROCESSOR, fXML11DTDProcessor); + } + + fXML11DTDScanner.setDTDHandler(fXML11DTDProcessor); + fXML11DTDProcessor.setDTDSource(fXML11DTDScanner); + fXML11DTDProcessor.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXML11DTDProcessor); + } + + fXML11DTDScanner.setDTDContentModelHandler(fXML11DTDProcessor); + fXML11DTDProcessor.setDTDContentModelSource(fXML11DTDScanner); + fXML11DTDProcessor.setDTDContentModelHandler(fDTDContentModelHandler); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.setDTDContentModelSource(fXML11DTDProcessor); + } + + // setup XML 1.1 document pipeline + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + if (fCurrentScanner != fXML11NSDocScanner) { + fCurrentScanner = fXML11NSDocScanner; + setProperty(DOCUMENT_SCANNER, fXML11NSDocScanner); + setProperty(DTD_VALIDATOR, fXML11NSDTDValidator); + } + + fXML11NSDocScanner.setDTDValidator(fXML11NSDTDValidator); + fXML11NSDocScanner.setDocumentHandler(fXML11NSDTDValidator); + fXML11NSDTDValidator.setDocumentSource(fXML11NSDocScanner); + fXML11NSDTDValidator.setDocumentHandler(fDocumentHandler); + + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fXML11NSDTDValidator); + } + fLastComponent = fXML11NSDTDValidator; + + } else { + // create components + if (fXML11DocScanner == null) { + // non namespace document pipeline + fXML11DocScanner = new XML11DocumentScannerImpl(); + addXML11Component(fXML11DocScanner); + fXML11DTDValidator = new XML11DTDValidator(); + addXML11Component(fXML11DTDValidator); + } + if (fCurrentScanner != fXML11DocScanner) { + fCurrentScanner = fXML11DocScanner; + setProperty(DOCUMENT_SCANNER, fXML11DocScanner); + setProperty(DTD_VALIDATOR, fXML11DTDValidator); + } + fXML11DocScanner.setDocumentHandler(fXML11DTDValidator); + fXML11DTDValidator.setDocumentSource(fXML11DocScanner); + fXML11DTDValidator.setDocumentHandler(fDocumentHandler); + + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fXML11DTDValidator); + } + fLastComponent = fXML11DTDValidator; + } + + } // configureXML11Pipeline() + + /** Configures the pipeline. */ + protected void configurePipeline() { + if (fCurrentDVFactory != fDatatypeValidatorFactory) { + fCurrentDVFactory = fDatatypeValidatorFactory; + // use XML 1.0 datatype library + setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); + } + + // setup DTD pipeline + if (fCurrentDTDScanner != fDTDScanner) { + fCurrentDTDScanner = fDTDScanner; + setProperty(DTD_SCANNER, fCurrentDTDScanner); + setProperty(DTD_PROCESSOR, fDTDProcessor); + } + fDTDScanner.setDTDHandler(fDTDProcessor); + fDTDProcessor.setDTDSource(fDTDScanner); + fDTDProcessor.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fDTDProcessor); + } + + fDTDScanner.setDTDContentModelHandler(fDTDProcessor); + fDTDProcessor.setDTDContentModelSource(fDTDScanner); + fDTDProcessor.setDTDContentModelHandler(fDTDContentModelHandler); + if (fDTDContentModelHandler != null) { + fDTDContentModelHandler.setDTDContentModelSource(fDTDProcessor); + } + + // setup document pipeline + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + if (fCurrentScanner != fNamespaceScanner) { + fCurrentScanner = fNamespaceScanner; + setProperty(DOCUMENT_SCANNER, fNamespaceScanner); + setProperty(DTD_VALIDATOR, fDTDValidator); + } + fNamespaceScanner.setDTDValidator(fDTDValidator); + fNamespaceScanner.setDocumentHandler(fDTDValidator); + fDTDValidator.setDocumentSource(fNamespaceScanner); + fDTDValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fDTDValidator); + } + fLastComponent = fDTDValidator; + } else { + // create components + if (fNonNSScanner == null) { + fNonNSScanner = new XMLDocumentScannerImpl(); + fNonNSDTDValidator = new XMLDTDValidator(); + // add components + addComponent((XMLComponent) fNonNSScanner); + addComponent((XMLComponent) fNonNSDTDValidator); + } + if (fCurrentScanner != fNonNSScanner) { + fCurrentScanner = fNonNSScanner; + setProperty(DOCUMENT_SCANNER, fNonNSScanner); + setProperty(DTD_VALIDATOR, fNonNSDTDValidator); + } + + fNonNSScanner.setDocumentHandler(fNonNSDTDValidator); + fNonNSDTDValidator.setDocumentSource(fNonNSScanner); + fNonNSDTDValidator.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fNonNSDTDValidator); + } + fLastComponent = fNonNSDTDValidator; + } + + } // configurePipeline() + + + // features and properties + + /** + * Check a feature. If feature is know and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) throws XMLConfigurationException { + + // + // Xerces Features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/validation/dynamic + // Allows the parser to validate a document only when it + // contains a grammar. Validation is turned on/off based + // on each document instance, automatically. + // + if (suffixLength == Constants.DYNAMIC_VALIDATION_FEATURE.length() && + featureId.endsWith(Constants.DYNAMIC_VALIDATION_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE.length() && + featureId.endsWith(Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_CONTENT_MODELS_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_CONTENT_MODELS_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-dtd-grammar + // + if (suffixLength == Constants.LOAD_DTD_GRAMMAR_FEATURE.length() && + featureId.endsWith(Constants.LOAD_DTD_GRAMMAR_FEATURE)) { + return; + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-external-dtd + // + if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() && + featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_DATATYPES_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_DATATYPES_FEATURE)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + + // special performance feature: only component manager is allowed to set it. + if (suffixLength == Constants.PARSER_SETTINGS.length() && + featureId.endsWith(Constants.PARSER_SETTINGS)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + } + + // + // Not recognized + // + + super.checkFeature(featureId); + + } // checkFeature(String) + + /** + * Check a property. If the property is know and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkProperty(String propertyId) throws XMLConfigurationException { + + // + // Xerces Properties + // + + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() && + propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) { + return; + } + } + + // special cases + if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); + + // + // http://xml.org/sax/properties/xml-string + // Value type: String + // Access: read-only + // Get the literal string of characters associated with the + // current event. If the parser recognises and supports this + // property but is not currently parsing text, it should return + // null (this is a good way to check for availability before the + // parse begins). + // + if (suffixLength == Constants.XML_STRING_PROPERTY.length() && + propertyId.endsWith(Constants.XML_STRING_PROPERTY)) { + // REVISIT - we should probably ask xml-dev for a precise + // definition of what this is actually supposed to return, and + // in exactly which circumstances. + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, propertyId); + } + } + + // + // Not recognized + // + + super.checkProperty(propertyId); + + } // checkProperty(String) + + + /** + * Adds a component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addComponent(XMLComponent component) { + + // don't add a component more than once + if (fComponents.contains(component)) { + return; + } + fComponents.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addComponent(XMLComponent) + + /** + * Adds common component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addCommonComponent(XMLComponent component) { + + // don't add a component more than once + if (fCommonComponents.contains(component)) { + return; + } + fCommonComponents.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addCommonComponent(XMLComponent) + + /** + * Adds an XML 1.1 component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addXML11Component(XMLComponent component) { + + // don't add a component more than once + if (fXML11Components.contains(component)) { + return; + } + fXML11Components.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addXML11Component(XMLComponent) + + /** + * Adds all of the component's recognized features and properties + * to the list of default recognized features and properties, and + * sets default values on the configuration for features and + * properties which were previously absent from the configuration. + * + * @param component The component whose recognized features + * and properties will be added to the configuration + */ + protected void addRecognizedParamsAndSetDefaults(XMLComponent component) { + + // register component's recognized features + String[] recognizedFeatures = component.getRecognizedFeatures(); + addRecognizedFeatures(recognizedFeatures); + + // register component's recognized properties + String[] recognizedProperties = component.getRecognizedProperties(); + addRecognizedProperties(recognizedProperties); + + // set default values + if (recognizedFeatures != null) { + for (int i = 0; i < recognizedFeatures.length; ++i) { + String featureId = recognizedFeatures[i]; + Boolean state = component.getFeatureDefault(featureId); + if (state != null) { + // Do not overwrite values already set on the configuration. + if (!fFeatures.containsKey(featureId)) { + fFeatures.put(featureId, state); + // For newly added components who recognize this feature + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + if (recognizedProperties != null) { + for (int i = 0; i < recognizedProperties.length; ++i) { + String propertyId = recognizedProperties[i]; + Object value = component.getPropertyDefault(propertyId); + if (value != null) { + // Do not overwrite values already set on the configuration. + if (!fProperties.containsKey(propertyId)) { + fProperties.put(propertyId, value); + // For newly added components who recognize this property + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + } + + private void initXML11Components() { + if (!f11Initialized) { + + // create datatype factory + fXML11DatatypeFactory = DTDDVFactory.getInstance(XML11_DATATYPE_VALIDATOR_FACTORY); + + // setup XML 1.1 DTD pipeline + fXML11DTDScanner = new XML11DTDScannerImpl(); + addXML11Component(fXML11DTDScanner); + fXML11DTDProcessor = new XML11DTDProcessor(); + addXML11Component(fXML11DTDProcessor); + + // setup XML 1.1. document pipeline - namespace aware + fXML11NSDocScanner = new XML11NSDocumentScannerImpl(); + addXML11Component(fXML11NSDocScanner); + fXML11NSDTDValidator = new XML11NSDTDValidator(); + addXML11Component(fXML11NSDTDValidator); + + f11Initialized = true; + } + } + +} // class XML11DTDConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XML11NonValidatingConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XML11NonValidatingConfiguration.java new file mode 100644 index 0000000..aa61dfa --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XML11NonValidatingConfiguration.java @@ -0,0 +1,1240 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XML11DTDScannerImpl; +import org.apache.xerces.impl.XML11DocumentScannerImpl; +import org.apache.xerces.impl.XML11NSDocumentScannerImpl; +import org.apache.xerces.impl.XMLDTDScannerImpl; +import org.apache.xerces.impl.XMLDocumentScannerImpl; +import org.apache.xerces.impl.XMLEntityHandler; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.XMLNSDocumentScannerImpl; +import org.apache.xerces.impl.XMLVersionDetector; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.impl.validation.ValidationManager; +import org.apache.xerces.util.ParserConfigurationSettings; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDScanner; +import org.apache.xerces.xni.parser.XMLDocumentScanner; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLPullParserConfiguration; + +/** + * This class is the non validating parser configuration + * used to parse XML 1.0 and XML 1.1 documents. + * + * Xerces parser that uses this configuration is not conformant + * non-validating XML processor, since conformant non-validating processor is required + * to process "all the declarations they read in the internal DTD subset ... must use the information in those declarations to normalize attribute values, + * include the replacement text of internal entities, and supply default attribute values". + + * @author Elena Litani, IBM + * @author John Kim, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XML11NonValidatingConfiguration extends ParserConfigurationSettings + implements XMLPullParserConfiguration, XML11Configurable { + + // + // Constants + // + protected final static String XML11_DATATYPE_VALIDATOR_FACTORY = + "org.apache.xerces.impl.dv.dtd.XML11DTDDVFactoryImpl"; + + // feature identifiers + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: namespaces. */ + protected static final String NAMESPACES = + Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; + + /** Feature identifier: external general entities. */ + protected static final String EXTERNAL_GENERAL_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE; + + /** Feature identifier: external parameter entities. */ + protected static final String EXTERNAL_PARAMETER_ENTITIES = + Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE; + + + /** Feature identifier: continue after fatal error. */ + protected static final String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + + // property identifiers + + /** Property identifier: xml string. */ + protected static final String XML_STRING = + Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY; + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity manager. */ + protected static final String ENTITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY; + + /** Property identifier document scanner: */ + protected static final String DOCUMENT_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_SCANNER_PROPERTY; + + /** Property identifier: DTD scanner. */ + protected static final String DTD_SCANNER = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY; + + /** Property identifier: grammar pool. */ + protected static final String XMLGRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + /** Property identifier: DTD validator. */ + protected static final String DTD_VALIDATOR = + Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; + + /** Property identifier: namespace binder. */ + protected static final String NAMESPACE_BINDER = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_BINDER_PROPERTY; + + /** Property identifier: datatype validator factory. */ + protected static final String DATATYPE_VALIDATOR_FACTORY = + Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; + + protected static final String VALIDATION_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; + + // debugging + + /** Set to true and recompile to print exception stack trace. */ + protected static final boolean PRINT_EXCEPTION_STACK_TRACE = false; + + // + // Data + // + protected SymbolTable fSymbolTable; + protected XMLInputSource fInputSource; + protected ValidationManager fValidationManager; + protected XMLVersionDetector fVersionDetector; + protected XMLLocator fLocator; + protected Locale fLocale; + + /** XML 1.0 Components. */ + protected ArrayList fComponents; + + /** XML 1.1. Components. */ + protected ArrayList fXML11Components = null; + + /** Common components: XMLEntityManager, XMLErrorReporter */ + protected ArrayList fCommonComponents = null; + + /** The document handler. */ + protected XMLDocumentHandler fDocumentHandler; + + /** The DTD handler. */ + protected XMLDTDHandler fDTDHandler; + + /** The DTD content model handler. */ + protected XMLDTDContentModelHandler fDTDContentModelHandler; + + /** Last component in the document pipeline */ + protected XMLDocumentSource fLastComponent; + + /** + * True if a parse is in progress. This state is needed because + * some features/properties cannot be set while parsing (e.g. + * namespaces). + */ + protected boolean fParseInProgress = false; + + /** fConfigUpdated is set to true if there has been any change to the configuration settings, + * i.e a feature or a property was changed. + */ + protected boolean fConfigUpdated = false; + + // + // XML 1.0 components + // + + /** The XML 1.0 Datatype validator factory. */ + protected DTDDVFactory fDatatypeValidatorFactory; + + /** The XML 1.0 Document scanner that does namespace binding. */ + protected XMLNSDocumentScannerImpl fNamespaceScanner; + + /** The XML 1.0 Non-namespace implementation of scanner */ + protected XMLDocumentScannerImpl fNonNSScanner; + + /** The XML 1.0 DTD scanner. */ + protected XMLDTDScanner fDTDScanner; + + // + // XML 1.1 components + // + + /** The XML 1.1 datatype factory. **/ + protected DTDDVFactory fXML11DatatypeFactory = null; + + /** The XML 1.1 document scanner that does namespace binding. **/ + protected XML11NSDocumentScannerImpl fXML11NSDocScanner = null; + + /** The XML 1.1 document scanner that does not do namespace binding. **/ + protected XML11DocumentScannerImpl fXML11DocScanner = null; + + /** The XML 1.1 DTD scanner. **/ + protected XML11DTDScannerImpl fXML11DTDScanner = null; + + // + // Common components + // + + /** Grammar pool. */ + protected XMLGrammarPool fGrammarPool; + + /** Error reporter. */ + protected XMLErrorReporter fErrorReporter; + + /** Entity manager. */ + protected XMLEntityManager fEntityManager; + + /** Current scanner */ + protected XMLDocumentScanner fCurrentScanner; + + /** Current Datatype validator factory. */ + protected DTDDVFactory fCurrentDVFactory; + + /** Current DTD scanner. */ + protected XMLDTDScanner fCurrentDTDScanner; + + + /** Flag indiciating whether XML11 components have been initialized. */ + private boolean f11Initialized = false; + + // + // Constructors + // + + /** Default constructor. */ + public XML11NonValidatingConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public XML11NonValidatingConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public XML11NonValidatingConfiguration(SymbolTable symbolTable, XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public XML11NonValidatingConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + + super(parentSettings); + + // create a vector to hold all the components in use + // XML 1.0 specialized components + fComponents = new ArrayList(); + // XML 1.1 specialized components + fXML11Components = new ArrayList(); + // Common components for XML 1.1. and XML 1.0 + fCommonComponents = new ArrayList(); + + // create storage for recognized features and properties + fRecognizedFeatures = new ArrayList(); + fRecognizedProperties = new ArrayList(); + + // create table for features and properties + fFeatures = new HashMap(); + fProperties = new HashMap(); + + // add default recognized features + final String[] recognizedFeatures = + { + CONTINUE_AFTER_FATAL_ERROR, // from XMLDTDScannerImpl + VALIDATION, + NAMESPACES, + EXTERNAL_GENERAL_ENTITIES, + EXTERNAL_PARAMETER_ENTITIES, + PARSER_SETTINGS + }; + addRecognizedFeatures(recognizedFeatures); + + // set state for default features + fFeatures.put(VALIDATION, Boolean.FALSE); + fFeatures.put(NAMESPACES, Boolean.TRUE); + fFeatures.put(EXTERNAL_GENERAL_ENTITIES, Boolean.TRUE); + fFeatures.put(EXTERNAL_PARAMETER_ENTITIES, Boolean.TRUE); + fFeatures.put(CONTINUE_AFTER_FATAL_ERROR, Boolean.FALSE); + fFeatures.put(PARSER_SETTINGS, Boolean.TRUE); + + // add default recognized properties + final String[] recognizedProperties = + { + XML_STRING, + SYMBOL_TABLE, + ERROR_HANDLER, + ENTITY_RESOLVER, + ERROR_REPORTER, + ENTITY_MANAGER, + DOCUMENT_SCANNER, + DTD_SCANNER, + DTD_VALIDATOR, + DATATYPE_VALIDATOR_FACTORY, + VALIDATION_MANAGER, + XML_STRING, + XMLGRAMMAR_POOL, }; + addRecognizedProperties(recognizedProperties); + + if (symbolTable == null) { + symbolTable = new SymbolTable(); + } + fSymbolTable = symbolTable; + fProperties.put(SYMBOL_TABLE, fSymbolTable); + + fGrammarPool = grammarPool; + if (fGrammarPool != null) { + fProperties.put(XMLGRAMMAR_POOL, fGrammarPool); + } + + fEntityManager = new XMLEntityManager(); + fProperties.put(ENTITY_MANAGER, fEntityManager); + addCommonComponent(fEntityManager); + + fErrorReporter = new XMLErrorReporter(); + fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner()); + fProperties.put(ERROR_REPORTER, fErrorReporter); + addCommonComponent(fErrorReporter); + + fNamespaceScanner = new XMLNSDocumentScannerImpl(); + fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner); + addComponent((XMLComponent) fNamespaceScanner); + + fDTDScanner = new XMLDTDScannerImpl(); + fProperties.put(DTD_SCANNER, fDTDScanner); + addComponent((XMLComponent) fDTDScanner); + + fDatatypeValidatorFactory = DTDDVFactory.getInstance(); + fProperties.put(DATATYPE_VALIDATOR_FACTORY, fDatatypeValidatorFactory); + + fValidationManager = new ValidationManager(); + fProperties.put(VALIDATION_MANAGER, fValidationManager); + + fVersionDetector = new XMLVersionDetector(); + + // add message formatters + if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) { + XMLMessageFormatter xmft = new XMLMessageFormatter(); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft); + fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft); + } + + // set locale + try { + setLocale(Locale.getDefault()); + } catch (XNIException e) { + // do nothing + // REVISIT: What is the right thing to do? -Ac + } + + fConfigUpdated = false; + + } // (SymbolTable,XMLGrammarPool) + + /** + * Sets the input source for the document to parse. + * + * @param inputSource The document's input source. + * + * @exception XMLConfigurationException Thrown if there is a + * configuration error when initializing the + * parser. + * @exception IOException Thrown on I/O error. + * + * @see #parse(boolean) + */ + public void setInputSource(XMLInputSource inputSource) + throws XMLConfigurationException, IOException { + + // REVISIT: this method used to reset all the components and + // construct the pipeline. Now reset() is called + // in parse (boolean) just before we parse the document + // Should this method still throw exceptions..? + + fInputSource = inputSource; + + } // setInputSource(XMLInputSource) + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException { + fLocale = locale; + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + + /** + * Sets the document handler on the last component in the pipeline + * to receive information about the document. + * + * @param documentHandler The document handler. + */ + public void setDocumentHandler(XMLDocumentHandler documentHandler) { + fDocumentHandler = documentHandler; + if (fLastComponent != null) { + fLastComponent.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler !=null){ + fDocumentHandler.setDocumentSource(fLastComponent); + } + } + } // setDocumentHandler(XMLDocumentHandler) + + /** Returns the registered document handler. */ + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } // getDocumentHandler():XMLDocumentHandler + + /** + * Sets the DTD handler. + * + * @param dtdHandler The DTD handler. + */ + public void setDTDHandler(XMLDTDHandler dtdHandler) { + fDTDHandler = dtdHandler; + } // setDTDHandler(XMLDTDHandler) + + /** Returns the registered DTD handler. */ + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } // getDTDHandler():XMLDTDHandler + + /** + * Sets the DTD content model handler. + * + * @param handler The DTD content model handler. + */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) { + fDTDContentModelHandler = handler; + } // setDTDContentModelHandler(XMLDTDContentModelHandler) + + /** Returns the registered DTD content model handler. */ + public XMLDTDContentModelHandler getDTDContentModelHandler() { + return fDTDContentModelHandler; + } // getDTDContentModelHandler():XMLDTDContentModelHandler + + /** + * Sets the resolver used to resolve external entities. The EntityResolver + * interface supports resolution of public and system identifiers. + * + * @param resolver The new entity resolver. Passing a null value will + * uninstall the currently installed resolver. + */ + public void setEntityResolver(XMLEntityResolver resolver) { + fProperties.put(ENTITY_RESOLVER, resolver); + } // setEntityResolver(XMLEntityResolver) + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public XMLEntityResolver getEntityResolver() { + return (XMLEntityResolver)fProperties.get(ENTITY_RESOLVER); + } // getEntityResolver():XMLEntityResolver + + /** + * 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 errorHandler The error handler. + * @exception java.lang.NullPointerException If the handler + * argument is null. + * @see #getErrorHandler + */ + public void setErrorHandler(XMLErrorHandler errorHandler) { + fProperties.put(ERROR_HANDLER, errorHandler); + } // setErrorHandler(XMLErrorHandler) + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public XMLErrorHandler getErrorHandler() { + // REVISIT: Should this be a property? + return (XMLErrorHandler)fProperties.get(ERROR_HANDLER); + } // getErrorHandler():XMLErrorHandler + + + /** + * If the application decides to terminate parsing before the xml document + * is fully parsed, the application should call this method to free any + * resource allocated during parsing. For example, close all opened streams. + */ + public void cleanup() { + fEntityManager.closeReaders(); + } + + /** + * Parses the specified input source. + * + * @param source The input source. + * + * @exception XNIException Throws exception on XNI error. + * @exception java.io.IOException Throws exception on i/o error. + */ + public void parse(XMLInputSource source) throws XNIException, IOException { + + if (fParseInProgress) { + // REVISIT - need to add new error message + throw new XNIException("FWK005 parse may not be called while parsing."); + } + fParseInProgress = true; + + try { + setInputSource(source); + parse(true); + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } finally { + fParseInProgress = false; + // close all streams opened by xerces + this.cleanup(); + } + + } // parse(InputSource) + + public boolean parse(boolean complete) throws XNIException, IOException { + // + // reset and configure pipeline and set InputSource. + if (fInputSource != null) { + try { + fValidationManager.reset(); + fVersionDetector.reset(this); + resetCommon(); + + short version = fVersionDetector.determineDocVersion(fInputSource); + // XML 1.0 + if (version == Constants.XML_VERSION_1_0) { + configurePipeline(); + reset(); + } + // XML 1.1 + else if (version == Constants.XML_VERSION_1_1) { + initXML11Components(); + configureXML11Pipeline(); + resetXML11(); + } + // Unrecoverable error reported during version detection + else { + return false; + } + + // mark configuration as fixed + fConfigUpdated = false; + + // resets and sets the pipeline. + fVersionDetector.startDocumentParsing((XMLEntityHandler) fCurrentScanner, version); + fInputSource = null; + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + } + + try { + return fCurrentScanner.scanDocument(complete); + } catch (XNIException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (IOException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (RuntimeException ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw ex; + } catch (Exception ex) { + if (PRINT_EXCEPTION_STACK_TRACE) + ex.printStackTrace(); + throw new XNIException(ex); + } + + } // parse(boolean):boolean + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * @return true if the feature is supported + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + // make this feature special + if (featureId.equals(PARSER_SETTINGS)){ + return fConfigUpdated; + } + return super.getFeature(featureId); + + } // getFeature(String):boolean + + /** + * Set the state of a feature. + * + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + fConfigUpdated = true; + // forward to every XML 1.0 component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.setFeature(featureId, state); + } + // forward it to common components + count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.setFeature(featureId, state); + } + + // forward to every XML 1.1 component + count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + try{ + c.setFeature(featureId, state); + } + catch (Exception e){ + // no op + } + } + // save state if noone "objects" + super.setFeature(featureId, state); + + } // setFeature(String,boolean) + + /** + * setProperty + * + * @param propertyId + * @param value + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + fConfigUpdated = true; + // forward to every XML 1.0 component + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.setProperty(propertyId, value); + } + // forward it to every common Component + count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.setProperty(propertyId, value); + } + // forward it to every XML 1.1 component + count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + try{ + c.setProperty(propertyId, value); + } + catch (Exception e){ + // ignore it + } + } + + // store value if noone "objects" + super.setProperty(propertyId, value); + + } // setProperty(String,Object) + + + /** Returns the locale. */ + public Locale getLocale() { + return fLocale; + } // getLocale():Locale + + /** + * reset all XML 1.0 components before parsing and namespace context + */ + protected void reset() throws XNIException { + int count = fComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fComponents.get(i); + c.reset(this); + } + + } // reset() + + /** + * reset all common components before parsing + */ + protected void resetCommon() throws XNIException { + // reset common components + int count = fCommonComponents.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fCommonComponents.get(i); + c.reset(this); + } + + } // resetCommon() + + + /** + * reset all components before parsing and namespace context + */ + protected void resetXML11() throws XNIException { + // reset every component + int count = fXML11Components.size(); + for (int i = 0; i < count; i++) { + XMLComponent c = (XMLComponent) fXML11Components.get(i); + c.reset(this); + } + + } // resetXML11() + + + /** + * Configures the XML 1.1 pipeline. + * Note: this method also resets the new XML11 components. + */ + protected void configureXML11Pipeline() { + if (fCurrentDVFactory != fXML11DatatypeFactory) { + fCurrentDVFactory = fXML11DatatypeFactory; + setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); + } + + // setup DTD pipeline + if (fCurrentDTDScanner != fXML11DTDScanner) { + fCurrentDTDScanner = fXML11DTDScanner; + setProperty(DTD_SCANNER, fCurrentDTDScanner); + } + fXML11DTDScanner.setDTDHandler(fDTDHandler); + fXML11DTDScanner.setDTDContentModelHandler(fDTDContentModelHandler); + + // setup XML 1.1 document pipeline + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + if (fCurrentScanner != fXML11NSDocScanner) { + fCurrentScanner = fXML11NSDocScanner; + setProperty(DOCUMENT_SCANNER, fXML11NSDocScanner); + } + + fXML11NSDocScanner.setDTDValidator(null); + fXML11NSDocScanner.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fXML11NSDocScanner); + } + fLastComponent = fXML11NSDocScanner; + + } else { + // create components + if (fXML11DocScanner == null) { + // non namespace document pipeline + fXML11DocScanner = new XML11DocumentScannerImpl(); + addXML11Component(fXML11DocScanner); + } + if (fCurrentScanner != fXML11DocScanner) { + fCurrentScanner = fXML11DocScanner; + setProperty(DOCUMENT_SCANNER, fXML11DocScanner); + } + fXML11DocScanner.setDocumentHandler(fDocumentHandler); + + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fXML11DocScanner); + } + fLastComponent = fXML11DocScanner; + } + + } // configureXML11Pipeline() + + /** Configures the pipeline. */ + protected void configurePipeline() { + if (fCurrentDVFactory != fDatatypeValidatorFactory) { + fCurrentDVFactory = fDatatypeValidatorFactory; + // use XML 1.0 datatype library + setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); + } + + // setup DTD pipeline + if (fCurrentDTDScanner != fDTDScanner) { + fCurrentDTDScanner = fDTDScanner; + setProperty(DTD_SCANNER, fCurrentDTDScanner); + } + fDTDScanner.setDTDHandler(fDTDHandler); + fDTDScanner.setDTDContentModelHandler(fDTDContentModelHandler); + + // setup document pipeline + if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { + if (fCurrentScanner != fNamespaceScanner) { + fCurrentScanner = fNamespaceScanner; + setProperty(DOCUMENT_SCANNER, fNamespaceScanner); + } + fNamespaceScanner.setDTDValidator(null); + fNamespaceScanner.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fNamespaceScanner); + } + fLastComponent = fNamespaceScanner; + } else { + // create components + if (fNonNSScanner == null) { + fNonNSScanner = new XMLDocumentScannerImpl(); + // add components + addComponent((XMLComponent) fNonNSScanner); + + } + if (fCurrentScanner != fNonNSScanner) { + fCurrentScanner = fNonNSScanner; + setProperty(DOCUMENT_SCANNER, fNonNSScanner); + + } + + fNonNSScanner.setDocumentHandler(fDocumentHandler); + if (fDocumentHandler != null) { + fDocumentHandler.setDocumentSource(fNonNSScanner); + } + fLastComponent = fNonNSScanner; + } + + } // configurePipeline() + + + // features and properties + + /** + * Check a feature. If feature is know and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) throws XMLConfigurationException { + + // + // Xerces Features + // + + if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { + final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); + + // + // http://apache.org/xml/features/validation/dynamic + // Allows the parser to validate a document only when it + // contains a grammar. Validation is turned on/off based + // on each document instance, automatically. + // + if (suffixLength == Constants.DYNAMIC_VALIDATION_FEATURE.length() && + featureId.endsWith(Constants.DYNAMIC_VALIDATION_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE.length() && + featureId.endsWith(Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_CONTENT_MODELS_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_CONTENT_MODELS_FEATURE)) { + // REVISIT + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-dtd-grammar + // + if (suffixLength == Constants.LOAD_DTD_GRAMMAR_FEATURE.length() && + featureId.endsWith(Constants.LOAD_DTD_GRAMMAR_FEATURE)) { + return; + } + // + // http://apache.org/xml/features/validation/nonvalidating/load-external-dtd + // + if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() && + featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) { + return; + } + + // + // http://apache.org/xml/features/validation/default-attribute-values + // + if (suffixLength == Constants.VALIDATE_DATATYPES_FEATURE.length() && + featureId.endsWith(Constants.VALIDATE_DATATYPES_FEATURE)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + + // special performance feature: only component manager is allowed to set it. + if (suffixLength == Constants.PARSER_SETTINGS.length() && + featureId.endsWith(Constants.PARSER_SETTINGS)) { + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, featureId); + } + } + + // + // Not recognized + // + + super.checkFeature(featureId); + + } // checkFeature(String) + + /** + * Check a property. If the property is know and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkProperty(String propertyId) throws XMLConfigurationException { + + // + // Xerces Properties + // + + if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() && + propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) { + return; + } + } + + if (propertyId.startsWith(Constants.JAXP_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.JAXP_PROPERTY_PREFIX.length(); + + if (suffixLength == Constants.SCHEMA_SOURCE.length() && + propertyId.endsWith(Constants.SCHEMA_SOURCE)) { + return; + } + } + + // special cases + if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { + final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); + + // + // http://xml.org/sax/properties/xml-string + // Value type: String + // Access: read-only + // Get the literal string of characters associated with the + // current event. If the parser recognises and supports this + // property but is not currently parsing text, it should return + // null (this is a good way to check for availability before the + // parse begins). + // + if (suffixLength == Constants.XML_STRING_PROPERTY.length() && + propertyId.endsWith(Constants.XML_STRING_PROPERTY)) { + // REVISIT - we should probably ask xml-dev for a precise + // definition of what this is actually supposed to return, and + // in exactly which circumstances. + short type = XMLConfigurationException.NOT_SUPPORTED; + throw new XMLConfigurationException(type, propertyId); + } + } + + // + // Not recognized + // + + super.checkProperty(propertyId); + + } // checkProperty(String) + + + /** + * Adds a component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addComponent(XMLComponent component) { + + // don't add a component more than once + if (fComponents.contains(component)) { + return; + } + fComponents.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addComponent(XMLComponent) + + /** + * Adds common component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addCommonComponent(XMLComponent component) { + + // don't add a component more than once + if (fCommonComponents.contains(component)) { + return; + } + fCommonComponents.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addCommonComponent(XMLComponent) + + /** + * Adds an XML 1.1 component to the parser configuration. This method will + * also add all of the component's recognized features and properties + * to the list of default recognized features and properties. + * + * @param component The component to add. + */ + protected void addXML11Component(XMLComponent component) { + + // don't add a component more than once + if (fXML11Components.contains(component)) { + return; + } + fXML11Components.add(component); + addRecognizedParamsAndSetDefaults(component); + + } // addXML11Component(XMLComponent) + + /** + * Adds all of the component's recognized features and properties + * to the list of default recognized features and properties, and + * sets default values on the configuration for features and + * properties which were previously absent from the configuration. + * + * @param component The component whose recognized features + * and properties will be added to the configuration + */ + protected void addRecognizedParamsAndSetDefaults(XMLComponent component) { + + // register component's recognized features + String[] recognizedFeatures = component.getRecognizedFeatures(); + addRecognizedFeatures(recognizedFeatures); + + // register component's recognized properties + String[] recognizedProperties = component.getRecognizedProperties(); + addRecognizedProperties(recognizedProperties); + + // set default values + if (recognizedFeatures != null) { + for (int i = 0; i < recognizedFeatures.length; ++i) { + String featureId = recognizedFeatures[i]; + Boolean state = component.getFeatureDefault(featureId); + if (state != null) { + // Do not overwrite values already set on the configuration. + if (!fFeatures.containsKey(featureId)) { + fFeatures.put(featureId, state); + // For newly added components who recognize this feature + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + if (recognizedProperties != null) { + for (int i = 0; i < recognizedProperties.length; ++i) { + String propertyId = recognizedProperties[i]; + Object value = component.getPropertyDefault(propertyId); + if (value != null) { + // Do not overwrite values already set on the configuration. + if (!fProperties.containsKey(propertyId)) { + fProperties.put(propertyId, value); + // For newly added components who recognize this property + // but did not offer a default value, we need to make + // sure these components will get an opportunity to read + // the value before parsing begins. + fConfigUpdated = true; + } + } + } + } + } + + private void initXML11Components() { + if (!f11Initialized) { + + // create datatype factory + fXML11DatatypeFactory = DTDDVFactory.getInstance(XML11_DATATYPE_VALIDATOR_FACTORY); + + // setup XML 1.1 DTD pipeline + fXML11DTDScanner = new XML11DTDScannerImpl(); + addXML11Component(fXML11DTDScanner); + + // setup XML 1.1. document pipeline - namespace aware + fXML11NSDocScanner = new XML11NSDocumentScannerImpl(); + addXML11Component(fXML11NSDocScanner); + + f11Initialized = true; + } + } + +} // class XML11NonValidatingConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XMLDocumentParser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLDocumentParser.java new file mode 100644 index 0000000..b3d411c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLDocumentParser.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLParserConfiguration; + +/** + * This is a concrete vanilla XML parser class. It uses the abstract parser + * with either a BasicConfiguration object or the one specified by the + * application. + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XMLDocumentParser + extends AbstractXMLDocumentParser { + + // + // Constructors + // + + /** + * Constructs a document parser using the default basic parser + * configuration. + */ + public XMLDocumentParser() { + super((XMLParserConfiguration)ObjectFactory.createObject( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration" + )); + } // () + + /** + * Constructs a document parser using the specified parser configuration. + */ + public XMLDocumentParser(XMLParserConfiguration config) { + super(config); + } // (ParserConfiguration) + + /** + * Constructs a document parser using the specified symbol table. + */ + public XMLDocumentParser(SymbolTable symbolTable) { + super((XMLParserConfiguration)ObjectFactory.createObject( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration" + )); + fConfiguration.setProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY, symbolTable); + } // (SymbolTable) + + /** + * Constructs a document parser using the specified symbol table and + * grammar pool. + */ + public XMLDocumentParser(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + super((XMLParserConfiguration)ObjectFactory.createObject( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration" + )); + fConfiguration.setProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY, symbolTable); + fConfiguration.setProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.XMLGRAMMAR_POOL_PROPERTY, grammarPool); + } + +} // class XMLDocumentParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarCachingConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarCachingConfiguration.java new file mode 100644 index 0000000..021f1a3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarCachingConfiguration.java @@ -0,0 +1,349 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.dtd.DTDGrammar; +import org.apache.xerces.impl.dtd.XMLDTDLoader; +import org.apache.xerces.impl.xs.SchemaGrammar; +import org.apache.xerces.impl.xs.XMLSchemaLoader; +import org.apache.xerces.impl.xs.XSMessageFormatter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.SynchronizedSymbolTable; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + *

        This configuration provides a generic way of using + * Xerces's grammar caching facilities. It extends the + * XIncludeAwareParserConfiguration and thus may validate documents + * according to XML schemas or DTD's. It also allows the user to + * preparse a grammar, and to lock the grammar pool + * implementation such that no more grammars will be added.

        + *

        Using the org.apache.xerces.xni.parser property, an + * application may instantiate a Xerces SAX or DOM parser with + * this configuration. When invoked in this manner, the default + * behaviour will be elicited; to use this configuration's + * specific facilities, the user will need to reference it + * directly.

        + *

        + * In addition to the features and properties recognized by the base + * parser configuration, this class recognizes these additional + * features and properties: + *

          + *
        + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XMLGrammarCachingConfiguration + extends XIncludeAwareParserConfiguration { + + // + // Constants + // + + // a larg(ish) prime to use for a symbol table to be shared + // among + // potentially man parsers. Start one as close to 2K (20 + // times larger than normal) and see what happens... + public static final int BIG_PRIME = 2039; + + // the static symbol table to be shared amongst parsers + protected static final SynchronizedSymbolTable fStaticSymbolTable = + new SynchronizedSymbolTable(BIG_PRIME); + + // the Grammar Pool to be shared similarly + protected static final XMLGrammarPoolImpl fStaticGrammarPool = + new XMLGrammarPoolImpl(); + + // schema full checking constant + protected static final String SCHEMA_FULL_CHECKING = + Constants.XERCES_FEATURE_PREFIX+Constants.SCHEMA_FULL_CHECKING; + + // Data + + // variables needed for caching schema grammars. + protected XMLSchemaLoader fSchemaLoader; + + // the DTD grammar loader + protected XMLDTDLoader fDTDLoader; + + // + // Constructors + // + + /** Default constructor. */ + public XMLGrammarCachingConfiguration() { + this(fStaticSymbolTable, fStaticGrammarPool, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public XMLGrammarCachingConfiguration(SymbolTable symbolTable) { + this(symbolTable, fStaticGrammarPool, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public XMLGrammarCachingConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * REVISIT: + * Grammar pool will be updated when the new validation engine is + * implemented. + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public XMLGrammarCachingConfiguration(SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + + // REVISIT: may need to add some features/properties + // specific to this configuration at some point... + + // add default recognized features + // set state for default features + // add default recognized properties + // create and register missing components + fSchemaLoader = new XMLSchemaLoader(fSymbolTable); + fSchemaLoader.setProperty(XMLGRAMMAR_POOL, fGrammarPool); + + // and set up the DTD loader too: + fDTDLoader = new XMLDTDLoader(fSymbolTable, fGrammarPool); + } // (SymbolTable,XMLGrammarPool, XMLComponentManager) + + // + // Public methods + // + + /* + * lock the XMLGrammarPoolImpl object so that it does not + * accept any more grammars from the validators. + */ + public void lockGrammarPool() { + fGrammarPool.lockPool(); + } // lockGrammarPool() + + /* + * clear the XMLGrammarPoolImpl object so that it does not + * contain any more grammars. + */ + public void clearGrammarPool() { + fGrammarPool.clear(); + } // clearGrammarPool() + + /* + * unlock the XMLGrammarPoolImpl object so that it + * accepts more grammars from the validators. + */ + public void unlockGrammarPool() { + fGrammarPool.unlockPool(); + } // unlockGrammarPool() + + /** + * Parse a grammar from a location identified by an URI. + * This method also adds this grammar to the XMLGrammarPool + * + * @param type The type of the grammar to be constructed + * @param uri The location of the grammar to be constructed. + * The parser will not expand this URI or make it + * available to the EntityResolver + * @return The newly created Grammar. + * @exception XNIException thrown on an error in grammar + * construction + * @exception IOException thrown if an error is encountered + * in reading the file + */ + public Grammar parseGrammar(String type, String uri) + throws XNIException, IOException { + XMLInputSource source = new XMLInputSource(null, uri, null); + return parseGrammar(type, source); + + } + + /** + * Parse a grammar from a location identified by an + * XMLInputSource. + * This method also adds this grammar to the XMLGrammarPool + * + * @param type The type of the grammar to be constructed + * @param is The XMLInputSource containing this grammar's + * information + * If a URI is included in the systemId field, the parser will not expand this URI or make it + * available to the EntityResolver + * @return The newly created Grammar. + * @exception XNIException thrown on an error in grammar + * construction + * @exception IOException thrown if an error is encountered + * in reading the file + */ + public Grammar parseGrammar(String type, XMLInputSource + is) throws XNIException, IOException { + if(type.equals(XMLGrammarDescription.XML_SCHEMA)) { + // by default, make all XMLGrammarPoolImpl's schema grammars available to fSchemaHandler + return parseXMLSchema(is); + } else if(type.equals(XMLGrammarDescription.XML_DTD)) { + return parseDTD(is); + } + // don't know this grammar... + return null; + } // parseGrammar(String, XMLInputSource): Grammar + + // + // Protected methods + // + + // features and properties + + /** + * Check a feature. If feature is known and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkFeature(String featureId) + throws XMLConfigurationException { + + super.checkFeature(featureId); + + } // checkFeature(String) + + /** + * Check a property. If the property is known and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + protected void checkProperty(String propertyId) + throws XMLConfigurationException { + super.checkProperty(propertyId); + + } // checkProperty(String) + + // package-protected methods + + /* This method parses an XML Schema document. + * It requires a GrammarBucket parameter so that DOMASBuilder can + * extract the info it needs. + * Therefore, bucket must not be null! + */ + SchemaGrammar parseXMLSchema(XMLInputSource is) + throws IOException { + XMLEntityResolver resolver = getEntityResolver(); + if(resolver != null) { + fSchemaLoader.setEntityResolver(resolver); + } + if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { + fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter()); + } + fSchemaLoader.setProperty(ERROR_REPORTER, fErrorReporter); + + String propPrefix = Constants.XERCES_PROPERTY_PREFIX; + String propName = propPrefix + Constants.SCHEMA_LOCATION; + fSchemaLoader.setProperty(propName, getProperty(propName)); + propName = propPrefix + Constants.SCHEMA_NONS_LOCATION; + fSchemaLoader.setProperty(propName, getProperty(propName)); + propName = Constants.JAXP_PROPERTY_PREFIX+Constants.SCHEMA_SOURCE; + fSchemaLoader.setProperty(propName, getProperty(propName)); + fSchemaLoader.setFeature(SCHEMA_FULL_CHECKING, getFeature(SCHEMA_FULL_CHECKING)); + + // Should check whether the grammar with this namespace is already in + // the grammar resolver. But since we don't know the target namespace + // of the document here, we leave such check to XSDHandler + SchemaGrammar grammar = (SchemaGrammar)fSchemaLoader.loadGrammar(is); + // by default, hand it off to the grammar pool + if (grammar != null) { + fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_SCHEMA, + new Grammar[]{grammar}); + } + + return grammar; + + } // parseXMLSchema(XMLInputSource) : SchemaGrammar + + /* This method parses an external DTD entity. + */ + DTDGrammar parseDTD(XMLInputSource is) + throws IOException { + XMLEntityResolver resolver = getEntityResolver(); + if(resolver != null) { + fDTDLoader.setEntityResolver(resolver); + } + fDTDLoader.setProperty(ERROR_REPORTER, fErrorReporter); + + // Should check whether the grammar with this namespace is already in + // the grammar resolver. But since we don't know the target namespace + // of the document here, we leave such check to the application... + DTDGrammar grammar = (DTDGrammar)fDTDLoader.loadGrammar(is); + // by default, hand it off to the grammar pool + if (grammar != null) { + fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_DTD, + new Grammar[]{grammar}); + } + + return grammar; + + } // parseXMLDTD(XMLInputSource) : DTDGrammar + + +} // class XMLGrammarCachingConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarParser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarParser.java new file mode 100644 index 0000000..781d661 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarParser.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.dv.DTDDVFactory; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.parser.XMLParserConfiguration; + +/** + * @version $Id$ + */ +public abstract class XMLGrammarParser + extends XMLParser { + + // + // Data + // + + /** fDatatypeValidatorFactory */ + protected DTDDVFactory fDatatypeValidatorFactory; + + // + // Constructors + // + + /** + * Construct an XMLGrammarParser with the specified symbol table + * + * @param symbolTable + */ + protected XMLGrammarParser(SymbolTable symbolTable) { + super((XMLParserConfiguration)ObjectFactory.createObject( + "org.apache.xerces.xni.parser.XMLParserConfiguration", + "org.apache.xerces.parsers.XIncludeAwareParserConfiguration" + )); + fConfiguration.setProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY, symbolTable); + } + +} // class XMLGrammarParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarPreparser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarPreparser.java new file mode 100644 index 0000000..e8519bd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLGrammarPreparser.java @@ -0,0 +1,382 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarLoader; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + *

        This class provides an easy way for a user to preparse grammars + * of various types. By default, it knows how to preparse external + * DTD's and schemas; it provides an easy way for user applications to + * register classes that know how to parse additional grammar types. + * By default, it does no grammar caching; but it provides ways for + * user applications to do so. + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public class XMLGrammarPreparser { + + // + // Constants + // + + // feature: continue-after-fatal-error + private final static String CONTINUE_AFTER_FATAL_ERROR = + Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE; + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: grammar pool . */ + protected static final String GRAMMAR_POOL = + Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; + + // the "built-in" grammar loaders + private static final Hashtable KNOWN_LOADERS = new Hashtable(); + + static { + KNOWN_LOADERS.put(XMLGrammarDescription.XML_SCHEMA, + "org.apache.xerces.impl.xs.XMLSchemaLoader"); + KNOWN_LOADERS.put(XMLGrammarDescription.XML_DTD, + "org.apache.xerces.impl.dtd.XMLDTDLoader"); + } + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + SYMBOL_TABLE, + ERROR_REPORTER, + ERROR_HANDLER, + ENTITY_RESOLVER, + GRAMMAR_POOL, + }; + + // Data + protected final SymbolTable fSymbolTable; + protected final XMLErrorReporter fErrorReporter; + protected XMLEntityResolver fEntityResolver; + protected XMLGrammarPool fGrammarPool; + + protected Locale fLocale; + + // Hashtable holding our loaders + private final Hashtable fLoaders; + + // The number of times the configuration has been modified. + private int fModCount = 1; + + // + // Constructors + // + + /** Default constructor. */ + public XMLGrammarPreparser() { + this(new SymbolTable()); + } // () + + /** + * Constructs a preparser using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public XMLGrammarPreparser (SymbolTable symbolTable) { + fSymbolTable = symbolTable; + + fLoaders = new Hashtable(); + fErrorReporter = new XMLErrorReporter(); + setLocale(Locale.getDefault()); + fEntityResolver = new XMLEntityManager(); + // those are all the basic properties... + } // (SymbolTable) + + // + // Public methods + // + + /* + * Register a type of grammar to make it preparsable. If + * the second parameter is null, the parser will use its built-in + * facilities for that grammar type. + * This should be called by the application immediately + * after creating this object and before initializing any properties/features. + * @param type URI identifying the type of the grammar + * @param loader an object capable of preparsing that type; null if the ppreparser should use built-in knowledge. + * @return true if successful; false if no built-in knowledge of + * the type or if unable to instantiate the string we know about + */ + public boolean registerPreparser(String grammarType, XMLGrammarLoader loader) { + if(loader == null) { // none specified! + if(KNOWN_LOADERS.containsKey(grammarType)) { + // got one; just instantiate it... + String loaderName = (String)KNOWN_LOADERS.get(grammarType); + try { + ClassLoader cl = ObjectFactory.findClassLoader(); + XMLGrammarLoader gl = (XMLGrammarLoader)(ObjectFactory.newInstance(loaderName, cl, true)); + fLoaders.put(grammarType, new XMLGrammarLoaderContainer(gl)); + } catch (Exception e) { + return false; + } + return true; + } + return false; + } + // were given one + fLoaders.put(grammarType, new XMLGrammarLoaderContainer(loader)); + return true; + } // registerPreparser(String, XMLGrammarLoader): boolean + + /** + * Parse a grammar from a location identified by an + * XMLInputSource. + * This method also adds this grammar to the XMLGrammarPool + * + * @param type The type of the grammar to be constructed + * @param is The XMLInputSource containing this grammar's + * information + * If a URI is included in the systemId field, the parser will not expand this URI or make it + * available to the EntityResolver + * @return The newly created Grammar. + * @exception XNIException thrown on an error in grammar + * construction + * @exception IOException thrown if an error is encountered + * in reading the file + */ + public Grammar preparseGrammar(String type, XMLInputSource + is) throws XNIException, IOException { + if (fLoaders.containsKey(type)) { + XMLGrammarLoaderContainer xglc = (XMLGrammarLoaderContainer) fLoaders.get(type); + XMLGrammarLoader gl = xglc.loader; + if (xglc.modCount != fModCount) { + // make sure gl's been set up with all the "basic" properties: + gl.setProperty(SYMBOL_TABLE, fSymbolTable); + gl.setProperty(ENTITY_RESOLVER, fEntityResolver); + gl.setProperty(ERROR_REPORTER, fErrorReporter); + // potentially, not all will support this one... + if (fGrammarPool != null) { + try { + gl.setProperty(GRAMMAR_POOL, fGrammarPool); + } catch(Exception e) { + // too bad... + } + } + xglc.modCount = fModCount; + } + return gl.loadGrammar(is); + } + return null; + } // preparseGrammar(String, XMLInputSource): Grammar + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) { + fLocale = locale; + fErrorReporter.setLocale(locale); + } // setLocale(Locale) + + /** Return the Locale the XMLGrammarLoader is using. */ + public Locale getLocale() { + return fLocale; + } // getLocale(): Locale + + + /** + * Sets the error handler. + * + * @param errorHandler The error handler. + */ + public void setErrorHandler(XMLErrorHandler errorHandler) { + fErrorReporter.setProperty(ERROR_HANDLER, errorHandler); + } // setErrorHandler(XMLErrorHandler) + + /** Returns the registered error handler. */ + public XMLErrorHandler getErrorHandler() { + return fErrorReporter.getErrorHandler(); + } // getErrorHandler(): XMLErrorHandler + + /** + * Sets the entity resolver. + * + * @param entityResolver The new entity resolver. + */ + public void setEntityResolver(XMLEntityResolver entityResolver) { + if (fEntityResolver != entityResolver) { + // Overflow. We actually need to reset the + // modCount on every XMLGrammarLoaderContainer. + if (++fModCount < 0) { + clearModCounts(); + } + fEntityResolver = entityResolver; + } + } // setEntityResolver(XMLEntityResolver) + + /** Returns the registered entity resolver. */ + public XMLEntityResolver getEntityResolver() { + return fEntityResolver; + } // getEntityResolver(): XMLEntityResolver + + /** + * Sets the grammar pool. + * + * @param grammarPool The new grammar pool. + */ + public void setGrammarPool(XMLGrammarPool grammarPool) { + if (fGrammarPool != grammarPool) { + // Overflow. We actually need to reset the + // modCount on every XMLGrammarLoaderContainer. + if (++fModCount < 0) { + clearModCounts(); + } + fGrammarPool = grammarPool; + } + } // setGrammarPool(XMLGrammarPool) + + /** Returns the registered grammar pool. */ + public XMLGrammarPool getGrammarPool() { + return fGrammarPool; + } // getGrammarPool(): XMLGrammarPool + + // it's possible the application may want access to a certain loader to do + // some custom work. + public XMLGrammarLoader getLoader(String type) { + XMLGrammarLoaderContainer xglc = (XMLGrammarLoaderContainer) fLoaders.get(type); + return (xglc != null) ? xglc.loader : null; + } // getLoader(String): XMLGrammarLoader + + // set a feature. This method tries to set it on all + // registered loaders; it eats any resulting exceptions. If + // an app needs to know if a particular feature is supported + // by a grammar loader of a particular type, it will have + // to retrieve that loader and use the loader's setFeature method. + public void setFeature(String featureId, boolean value) { + Enumeration loaders = fLoaders.elements(); + while (loaders.hasMoreElements()) { + XMLGrammarLoader gl = ((XMLGrammarLoaderContainer)loaders.nextElement()).loader; + try { + gl.setFeature(featureId, value); + } catch(Exception e) { + // eat it up... + } + } + // since our error reporter is a property we set later, + // make sure features it understands are also set. + if(featureId.equals(CONTINUE_AFTER_FATAL_ERROR)) { + fErrorReporter.setFeature(CONTINUE_AFTER_FATAL_ERROR, value); + } + } //setFeature(String, boolean) + + // set a property. This method tries to set it on all + // registered loaders; it eats any resulting exceptions. If + // an app needs to know if a particular property is supported + // by a grammar loader of a particular type, it will have + // to retrieve that loader and use the loader's setProperty method. + //

        An application should use the explicit method + // in this class to set "standard" properties like error handler etc. + public void setProperty(String propId, Object value) { + Enumeration loaders = fLoaders.elements(); + while (loaders.hasMoreElements()) { + XMLGrammarLoader gl = ((XMLGrammarLoaderContainer)loaders.nextElement()).loader; + try { + gl.setProperty(propId, value); + } catch(Exception e) { + // eat it up... + } + } + } //setProperty(String, Object) + + // get status of feature in a particular loader. This + // catches no exceptions--including NPE's--so the application had + // better make sure the loader exists and knows about this feature. + // @param type type of grammar to look for the feature in. + // @param featureId the feature string to query. + // @return the value of the feature. + public boolean getFeature(String type, String featureId) { + XMLGrammarLoader gl = ((XMLGrammarLoaderContainer)fLoaders.get(type)).loader; + return gl.getFeature(featureId); + } // getFeature (String, String): boolean + + // get status of property in a particular loader. This + // catches no exceptions--including NPE's--so the application had + // better make sure the loader exists and knows about this property. + // For standard properties--that will be supported + // by all loaders--the specific methods should be queried! + // @param type type of grammar to look for the property in. + // @param propertyId the property string to query. + // @return the value of the property. + public Object getProperty(String type, String propertyId) { + XMLGrammarLoader gl = ((XMLGrammarLoaderContainer)fLoaders.get(type)).loader; + return gl.getProperty(propertyId); + } // getProperty(String, String): Object + + /** + * Container for an XMLGrammarLoader. Also holds the modCount + * that the XMLGrammarPreparser had the last time it was used. + */ + static class XMLGrammarLoaderContainer { + public final XMLGrammarLoader loader; + public int modCount = 0; + public XMLGrammarLoaderContainer(XMLGrammarLoader loader) { + this.loader = loader; + } + } + + private void clearModCounts() { + Enumeration loaders = fLoaders.elements(); + while (loaders.hasMoreElements()) { + XMLGrammarLoaderContainer xglc = (XMLGrammarLoaderContainer) loaders.nextElement(); + xglc.modCount = 0; + } + fModCount = 1; + } + +} // class XMLGrammarPreparser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XMLParser.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLParser.java new file mode 100644 index 0000000..f2af25a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XMLParser.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.xerces.parsers; + +import java.io.IOException; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParserConfiguration; + +/** + * Base class of all XML-related parsers. + *

        + * In addition to the features and properties recognized by the parser + * configuration, this parser recognizes these additional features and + * properties: + *

          + *
        • Properties + *
            + *
          • http://apache.org/xml/properties/internal/error-handler
          • + *
          • http://apache.org/xml/properties/internal/entity-resolver
          • + *
          + *
        + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public abstract class XMLParser { + + // + // Constants + // + + // properties + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** Property identifier: error handler. */ + protected static final String ERROR_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = { + ENTITY_RESOLVER, + ERROR_HANDLER, + }; + + // + // Data + // + + /** The parser configuration. */ + protected final XMLParserConfiguration fConfiguration; + + // + // Constructors + // + + /** + * Default Constructor. + */ + protected XMLParser(XMLParserConfiguration config) { + + // save configuration + fConfiguration = config; + + // add default recognized properties + fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES); + + } // (XMLParserConfiguration) + + // + // Public methods + // + + /** + * parse + * + * @param inputSource + * + * @exception XNIException + * @exception java.io.IOException + */ + public void parse(XMLInputSource inputSource) + throws XNIException, IOException { + + reset(); + fConfiguration.parse(inputSource); + + } // parse(XMLInputSource) + + // + // Protected methods + // + + /** + * reset all components before parsing + */ + protected void reset() throws XNIException { + } // reset() + +} // class XMLParser diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/XPointerParserConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/parsers/XPointerParserConfiguration.java new file mode 100644 index 0000000..2c595b0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/XPointerParserConfiguration.java @@ -0,0 +1,240 @@ +/* + * 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. + */ +package org.apache.xerces.parsers; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xinclude.XIncludeHandler; +import org.apache.xerces.xinclude.XIncludeNamespaceSupport; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.grammars.XMLGrammarPool; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xpointer.XPointerHandler; + +/** + * This parser configuration includes an XPointerHandler in the pipeline + * before the schema validator, or as the last component in the pipeline if there is + * no schema validator. Using this pipeline will enable processing according to the + * XML Inclusions specification with XPointers, to the conformance level described in + * XPointerHandler.. + * + * @see org.apache.xerces.xpointer.XPointerHandler + */ +public class XPointerParserConfiguration extends XML11Configuration { + + private XPointerHandler fXPointerHandler; + + private XIncludeHandler fXIncludeHandler; + + /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */ + protected static final String ALLOW_UE_AND_NOTATION_EVENTS = + Constants.SAX_FEATURE_PREFIX + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE; + + /** Feature identifier: fixup base URIs. */ + protected static final String XINCLUDE_FIXUP_BASE_URIS = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE; + + /** Feature identifier: fixup language. */ + protected static final String XINCLUDE_FIXUP_LANGUAGE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE; + + /** Property identifier: error reporter. */ + protected static final String XPOINTER_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.XPOINTER_HANDLER_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String XINCLUDE_HANDLER = + Constants.XERCES_PROPERTY_PREFIX + Constants.XINCLUDE_HANDLER_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String NAMESPACE_CONTEXT = + Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY; + + /** Default constructor. */ + public XPointerParserConfiguration() { + this(null, null, null); + } // () + + /** + * Constructs a parser configuration using the specified symbol table. + * + * @param symbolTable The symbol table to use. + */ + public XPointerParserConfiguration(SymbolTable symbolTable) { + this(symbolTable, null, null); + } // (SymbolTable) + + /** + * Constructs a parser configuration using the specified symbol table and + * grammar pool. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + */ + public XPointerParserConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool) { + this(symbolTable, grammarPool, null); + } // (SymbolTable,XMLGrammarPool) + + /** + * Constructs a parser configuration using the specified symbol table, + * grammar pool, and parent settings. + *

        + * + * @param symbolTable The symbol table to use. + * @param grammarPool The grammar pool to use. + * @param parentSettings The parent settings. + */ + public XPointerParserConfiguration( + SymbolTable symbolTable, + XMLGrammarPool grammarPool, + XMLComponentManager parentSettings) { + super(symbolTable, grammarPool, parentSettings); + + fXIncludeHandler = new XIncludeHandler(); + addCommonComponent(fXIncludeHandler); + + fXPointerHandler = new XPointerHandler(); + addCommonComponent(fXPointerHandler); + + final String[] recognizedFeatures = { + ALLOW_UE_AND_NOTATION_EVENTS, + XINCLUDE_FIXUP_BASE_URIS, + XINCLUDE_FIXUP_LANGUAGE + }; + addRecognizedFeatures(recognizedFeatures); + + // add default recognized properties + final String[] recognizedProperties = + { XINCLUDE_HANDLER, XPOINTER_HANDLER, NAMESPACE_CONTEXT }; + addRecognizedProperties(recognizedProperties); + + setFeature(ALLOW_UE_AND_NOTATION_EVENTS, true); + setFeature(XINCLUDE_FIXUP_BASE_URIS, true); + setFeature(XINCLUDE_FIXUP_LANGUAGE, true); + + setProperty(XINCLUDE_HANDLER, fXIncludeHandler); + setProperty(XPOINTER_HANDLER, fXPointerHandler); + setProperty(NAMESPACE_CONTEXT, new XIncludeNamespaceSupport()); + + + } // (SymbolTable,XMLGrammarPool)} + + + /** Configures the pipeline. */ + protected void configurePipeline() { + super.configurePipeline(); + + //configure DTD pipeline + fDTDScanner.setDTDHandler(fDTDProcessor); + fDTDProcessor.setDTDSource(fDTDScanner); + + fDTDProcessor.setDTDHandler(fXIncludeHandler); + fXIncludeHandler.setDTDSource(fDTDProcessor); + fXIncludeHandler.setDTDHandler(fXPointerHandler); + fXPointerHandler.setDTDSource(fXIncludeHandler); + fXPointerHandler.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXPointerHandler); + } + + // configure XML document pipeline: insert after DTDValidator and + // before XML Schema validator + XMLDocumentSource prev = null; + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // we don't have to worry about fSchemaValidator being null, since + // super.configurePipeline() instantiated it if the feature was set + prev = fSchemaValidator.getDocumentSource(); + } + // Otherwise, insert after the last component in the pipeline + else { + prev = fLastComponent; + fLastComponent = fXPointerHandler; + } + + XMLDocumentHandler next = prev.getDocumentHandler(); + prev.setDocumentHandler(fXIncludeHandler); + fXIncludeHandler.setDocumentSource(prev); + + if (next != null) { + fXIncludeHandler.setDocumentHandler(next); + next.setDocumentSource(fXIncludeHandler); + } + + fXIncludeHandler.setDocumentHandler(fXPointerHandler); + fXPointerHandler.setDocumentSource(fXIncludeHandler); + } // configurePipeline() + + protected void configureXML11Pipeline() { + super.configureXML11Pipeline(); + + // configure XML 1.1. DTD pipeline + fXML11DTDScanner.setDTDHandler(fXML11DTDProcessor); + fXML11DTDProcessor.setDTDSource(fXML11DTDScanner); + + fDTDProcessor.setDTDHandler(fXIncludeHandler); + fXIncludeHandler.setDTDSource(fXML11DTDProcessor); + fXIncludeHandler.setDTDHandler(fXPointerHandler); + fXPointerHandler.setDTDSource(fXIncludeHandler); + fXPointerHandler.setDTDHandler(fDTDHandler); + if (fDTDHandler != null) { + fDTDHandler.setDTDSource(fXPointerHandler); + } + + + // configure XML document pipeline: insert after DTDValidator and + // before XML Schema validator + XMLDocumentSource prev = null; + if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { + // we don't have to worry about fSchemaValidator being null, since + // super.configurePipeline() instantiated it if the feature was set + prev = fSchemaValidator.getDocumentSource(); + } + // Otherwise, insert after the last component in the pipeline + else { + prev = fLastComponent; + fLastComponent = fXPointerHandler; + } + + XMLDocumentHandler next = prev.getDocumentHandler(); + prev.setDocumentHandler(fXIncludeHandler); + fXIncludeHandler.setDocumentSource(prev); + + if (next != null) { + fXIncludeHandler.setDocumentHandler(next); + next.setDocumentSource(fXIncludeHandler); + } + + fXIncludeHandler.setDocumentHandler(fXPointerHandler); + fXPointerHandler.setDocumentSource(fXIncludeHandler); + + + } // configureXML11Pipeline() + + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + //if (propertyId.equals(XINCLUDE_HANDLER)) { + //} + + super.setProperty(propertyId, value); + } // setProperty(String,Object) +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.DTDConfiguration b/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.DTDConfiguration new file mode 100644 index 0000000..776c2ed --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.DTDConfiguration @@ -0,0 +1 @@ +org.apache.xerces.parsers.DTDConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.XML11Configuration b/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.XML11Configuration new file mode 100644 index 0000000..309631a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.XML11Configuration @@ -0,0 +1 @@ +org.apache.xerces.parsers.XML11Configuration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.XMLParserConfiguration b/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.XMLParserConfiguration new file mode 100644 index 0000000..98fa137 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/org.apache.xerces.xni.parser.XMLParserConfiguration @@ -0,0 +1 @@ +org.apache.xerces.parsers.XIncludeAwareParserConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/parsers/org.xml.sax.driver b/resources/xerces2-j-src/org/apache/xerces/parsers/org.xml.sax.driver new file mode 100644 index 0000000..409dd43 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/parsers/org.xml.sax.driver @@ -0,0 +1,2 @@ +org.apache.xerces.parsers.SAXParser + diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/DefaultNamespaceContext.java b/resources/xerces2-j-src/org/apache/xerces/stax/DefaultNamespaceContext.java new file mode 100644 index 0000000..162e6fe --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/DefaultNamespaceContext.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package org.apache.xerces.stax; + +import java.util.Collections; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; + +/** + *

        A NamespaceContext which only + * contains bindings for the xml and xmlns prefixes.

        + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class DefaultNamespaceContext implements NamespaceContext { + + /** + * Singleton instance. + */ + private static final DefaultNamespaceContext DEFAULT_NAMESPACE_CONTEXT_INSTANCE + = new DefaultNamespaceContext(); + + private DefaultNamespaceContext() {} + + /** Returns the one and only instance of this class. */ + public static DefaultNamespaceContext getInstance() { + return DEFAULT_NAMESPACE_CONTEXT_INSTANCE; + } + + public String getNamespaceURI(String prefix) { + if (prefix == null) { + throw new IllegalArgumentException("Prefix cannot be null."); + } + else if (XMLConstants.XML_NS_PREFIX.equals(prefix)) { + return XMLConstants.XML_NS_URI; + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) { + return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + } + return XMLConstants.NULL_NS_URI; + } // getNamespaceURI(String) + + public String getPrefix(String namespaceURI) { + if (namespaceURI == null) { + throw new IllegalArgumentException("Namespace URI cannot be null."); + } + else if (XMLConstants.XML_NS_URI.equals(namespaceURI)) { + return XMLConstants.XML_NS_PREFIX; + } + else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) { + return XMLConstants.XMLNS_ATTRIBUTE; + } + return null; + } // getPrefix(String) + + public Iterator getPrefixes(String namespaceURI) { + if (namespaceURI == null) { + throw new IllegalArgumentException("Namespace URI cannot be null."); + } + else if (XMLConstants.XML_NS_URI.equals(namespaceURI)) { + return new Iterator() { + boolean more = true; + public boolean hasNext() { + return more; + } + public Object next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + more = false; + return XMLConstants.XML_NS_PREFIX; + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) { + return new Iterator() { + boolean more = true; + public boolean hasNext() { + return more; + } + public Object next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + more = false; + return XMLConstants.XMLNS_ATTRIBUTE; + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + return Collections.EMPTY_LIST.iterator(); + } // getPrefixes(String) +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/EmptyLocation.java b/resources/xerces2-j-src/org/apache/xerces/stax/EmptyLocation.java new file mode 100644 index 0000000..bd2d6d3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/EmptyLocation.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.xerces.stax; + +import javax.xml.stream.Location; + +/** + *

        Location which always returns -1 + * and null from its methods.

        + * + * @xerces.internal + * + * @version $Id$ + */ +public final class EmptyLocation implements Location { + + /** + * Singleton instance. + */ + private static final EmptyLocation EMPTY_LOCATION_INSTANCE + = new EmptyLocation(); + + private EmptyLocation() {} + + /** Returns the one and only instance of this class. */ + public static EmptyLocation getInstance() { + return EMPTY_LOCATION_INSTANCE; + } + + /** + * Return the line number where the current event ends, + * returns -1 if none is available. + * @return the current line number + */ + public int getLineNumber() { + return -1; + } + + /** + * Return the column number where the current event ends, + * returns -1 if none is available. + * @return the current column number + */ + public int getColumnNumber() { + return -1; + } + + /** + * Return the byte or character offset into the input source this location + * is pointing to. If the input source is a file or a byte stream then + * this is the byte offset into that stream, but if the input source is + * a character media then the offset is the character offset. + * Returns -1 if there is no offset available. + * @return the current offset + */ + public int getCharacterOffset() { + return -1; + } + + /** + * Returns the public ID of the XML + * @return the public ID, or null if not available + */ + public String getPublicId() { + return null; + } + + /** + * Returns the system ID of the XML + * @return the system ID, or null if not available + */ + public String getSystemId() { + return null; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/ImmutableLocation.java b/resources/xerces2-j-src/org/apache/xerces/stax/ImmutableLocation.java new file mode 100644 index 0000000..4184a7b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/ImmutableLocation.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package org.apache.xerces.stax; + +import javax.xml.stream.Location; + +/** + *

        An immutable StAX Location.

        + * + * @xerces.internal + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class ImmutableLocation implements Location { + + private final int fCharacterOffset; + private final int fColumnNumber; + private final int fLineNumber; + private final String fPublicId; + private final String fSystemId; + + public ImmutableLocation(Location location) { + this(location.getCharacterOffset(), location.getColumnNumber(), + location.getLineNumber(), location.getPublicId(), + location.getSystemId()); + } + + public ImmutableLocation(int characterOffset, int columnNumber, int lineNumber, String publicId, String systemId) { + fCharacterOffset = characterOffset; + fColumnNumber = columnNumber; + fLineNumber = lineNumber; + fPublicId = publicId; + fSystemId = systemId; + } + + public int getCharacterOffset() { + return fCharacterOffset; + } + + public int getColumnNumber() { + return fColumnNumber; + } + + public int getLineNumber() { + return fLineNumber; + } + + public String getPublicId() { + return fPublicId; + } + + public String getSystemId() { + return fSystemId; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/XMLEventFactoryImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/XMLEventFactoryImpl.java new file mode 100644 index 0000000..8906fd4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/XMLEventFactoryImpl.java @@ -0,0 +1,185 @@ +/* + * 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. + */ + +package org.apache.xerces.stax; + +import java.util.Iterator; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.EndDocument; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.StartElement; + +import org.apache.xerces.stax.events.AttributeImpl; +import org.apache.xerces.stax.events.CharactersImpl; +import org.apache.xerces.stax.events.CommentImpl; +import org.apache.xerces.stax.events.DTDImpl; +import org.apache.xerces.stax.events.EndDocumentImpl; +import org.apache.xerces.stax.events.EndElementImpl; +import org.apache.xerces.stax.events.EntityReferenceImpl; +import org.apache.xerces.stax.events.NamespaceImpl; +import org.apache.xerces.stax.events.ProcessingInstructionImpl; +import org.apache.xerces.stax.events.StartDocumentImpl; +import org.apache.xerces.stax.events.StartElementImpl; + +/** + *

        Implementation of XMLEventFactory.

        + * + * @xerces.internal + * + * @version $Id$ + */ +public final class XMLEventFactoryImpl extends XMLEventFactory { + + private Location fLocation; + + public XMLEventFactoryImpl() {} + + public void setLocation(Location location) { + fLocation = location; + } + + public Attribute createAttribute(String prefix, String namespaceURI, + String localName, String value) { + return createAttribute(new QName(namespaceURI, localName, prefix), value); + } + + public Attribute createAttribute(String localName, String value) { + return createAttribute(new QName(localName), value); + } + + public Attribute createAttribute(QName name, String value) { + return new AttributeImpl(name, value, "CDATA", true, fLocation); + } + + public Namespace createNamespace(String namespaceURI) { + return createNamespace(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI); + } + + public Namespace createNamespace(String prefix, String namespaceUri) { + return new NamespaceImpl(prefix, namespaceUri, fLocation); + } + + public StartElement createStartElement(QName name, Iterator attributes, + Iterator namespaces) { + return createStartElement(name, attributes, namespaces, null); + } + + public StartElement createStartElement(String prefix, String namespaceUri, + String localName) { + return createStartElement(new QName(namespaceUri, localName, prefix), null, null); + } + + public StartElement createStartElement(String prefix, String namespaceUri, + String localName, Iterator attributes, Iterator namespaces) { + return createStartElement(new QName(namespaceUri, localName, prefix), attributes, namespaces); + } + + public StartElement createStartElement(String prefix, String namespaceUri, + String localName, Iterator attributes, Iterator namespaces, + NamespaceContext context) { + return createStartElement(new QName(namespaceUri, localName, prefix), attributes, namespaces, context); + } + + private StartElement createStartElement(QName name, Iterator attributes, + Iterator namespaces, NamespaceContext context) { + return new StartElementImpl(name, attributes, namespaces, context, fLocation); + } + + public EndElement createEndElement(QName name, Iterator namespaces) { + return new EndElementImpl(name, namespaces, fLocation); + } + + public EndElement createEndElement(String prefix, String namespaceUri, + String localName) { + return createEndElement(new QName(namespaceUri, localName, prefix), null); + } + + public EndElement createEndElement(String prefix, String namespaceUri, + String localName, Iterator namespaces) { + return createEndElement(new QName(namespaceUri, localName, prefix), namespaces); + } + + public Characters createCharacters(String content) { + return new CharactersImpl(content, XMLStreamConstants.CHARACTERS, fLocation); + } + + public Characters createCData(String content) { + return new CharactersImpl(content, XMLStreamConstants.CDATA, fLocation); + } + + public Characters createSpace(String content) { + return createCharacters(content); + } + + public Characters createIgnorableSpace(String content) { + return new CharactersImpl(content, XMLStreamConstants.SPACE, fLocation); + } + + public StartDocument createStartDocument() { + return createStartDocument(null, null); + } + + public StartDocument createStartDocument(String encoding, String version, + boolean standalone) { + return new StartDocumentImpl(encoding, encoding != null, standalone, true, version, fLocation); + } + + public StartDocument createStartDocument(String encoding, String version) { + return new StartDocumentImpl(encoding, encoding != null, false, false, version, fLocation); + } + + public StartDocument createStartDocument(String encoding) { + return createStartDocument(encoding, null); + } + + public EndDocument createEndDocument() { + return new EndDocumentImpl(fLocation); + } + + public EntityReference createEntityReference(String name, + EntityDeclaration declaration) { + return new EntityReferenceImpl(name, declaration, fLocation); + } + + public Comment createComment(String text) { + return new CommentImpl(text, fLocation); + } + + public ProcessingInstruction createProcessingInstruction(String target, + String data) { + return new ProcessingInstructionImpl(target, data, fLocation); + } + + public DTD createDTD(String dtd) { + return new DTDImpl(dtd, fLocation); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/AttributeImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/AttributeImpl.java new file mode 100644 index 0000000..18994bc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/AttributeImpl.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; + +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public class AttributeImpl extends XMLEventImpl implements Attribute { + + private final boolean fIsSpecified; + private final QName fName; + private final String fValue; + private final String fDtdType; + + /** + * Constructor. + */ + public AttributeImpl(final QName name, final String value, final String dtdType, final boolean isSpecified, final Location location) { + this(ATTRIBUTE, name, value, dtdType, isSpecified, location); + } + + protected AttributeImpl(final int type, final QName name, final String value, final String dtdType, final boolean isSpecified, final Location location) { + super(type, location); + fName = name; + fValue = value; + fDtdType = dtdType; + fIsSpecified = isSpecified; + } + + /** + * @see javax.xml.stream.events.Attribute#getName() + */ + public final QName getName() { + return fName; + } + + /** + * @see javax.xml.stream.events.Attribute#getValue() + */ + public final String getValue() { + return fValue; + } + + /** + * @see javax.xml.stream.events.Attribute#getDTDType() + */ + public final String getDTDType() { + return fDtdType; + } + + /** + * @see javax.xml.stream.events.Attribute#isSpecified() + */ + public final boolean isSpecified() { + return fIsSpecified; + } + + public final void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + // Write name + String prefix = fName.getPrefix(); + if (prefix != null && prefix.length() > 0) { + writer.write(prefix); + writer.write(':'); + } + writer.write(fName.getLocalPart()); + // Write value + writer.write("=\""); + writer.write(fValue); + writer.write('"'); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/CharactersImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/CharactersImpl.java new file mode 100644 index 0000000..c732af5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/CharactersImpl.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; + +import org.apache.xerces.util.XMLChar; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class CharactersImpl extends XMLEventImpl implements Characters { + + private final String fData; + + /** + * Standard constructor. + * @param eventType + * @param location + * @param schemaType + */ + public CharactersImpl(final String data, final int eventType, final Location location) { + super(eventType, location); + fData = (data != null) ? data : ""; + } + + /** + * @see javax.xml.stream.events.Characters#getData() + */ + public String getData() { + return fData; + } + + /** + * @see javax.xml.stream.events.Characters#isWhiteSpace() + */ + public boolean isWhiteSpace() { + final int length = fData != null ? fData.length() : 0; + if (length == 0) { + return false; + } + for (int i = 0; i < length; ++i) { + if (!XMLChar.isSpace(fData.charAt(i))) { + return false; + } + } + return true; + } + + /** + * @see javax.xml.stream.events.Characters#isCData() + */ + public boolean isCData() { + return CDATA == getEventType(); + } + + /** + * @see javax.xml.stream.events.Characters#isIgnorableWhiteSpace() + */ + public boolean isIgnorableWhiteSpace() { + return SPACE == getEventType(); + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + writer.write(fData); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/CommentImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/CommentImpl.java new file mode 100644 index 0000000..3253928 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/CommentImpl.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Comment; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class CommentImpl extends XMLEventImpl implements Comment { + + /** + * The text of the comment. Will be the empty string if there's no + * body text in the comment. + */ + private final String fText; + + /** + * @param location + */ + public CommentImpl(final String text, final Location location) { + super(COMMENT, location); + fText = (text != null) ? text : ""; + } + + /** + * @see javax.xml.stream.events.Comment#getText() + */ + public String getText() { + return fText; + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + writer.write(""); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/DTDImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/DTDImpl.java new file mode 100644 index 0000000..90f44a5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/DTDImpl.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; +import java.util.Collections; +import java.util.List; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.DTD; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class DTDImpl extends XMLEventImpl implements DTD { + + private final String fDTD; + + /** + * Constructor. + */ + public DTDImpl(final String dtd, final Location location) { + super(DTD, location); + fDTD = (dtd != null) ? dtd : null; + } + + /** + * @see javax.xml.stream.events.DTD#getDocumentTypeDeclaration() + */ + public String getDocumentTypeDeclaration() { + return fDTD; + } + + /** + * @see javax.xml.stream.events.DTD#getProcessedDTD() + */ + public Object getProcessedDTD() { + return null; + } + + /** + * @see javax.xml.stream.events.DTD#getNotations() + */ + public List getNotations() { + return Collections.EMPTY_LIST; + } + + /** + * @see javax.xml.stream.events.DTD#getEntities() + */ + public List getEntities() { + return Collections.EMPTY_LIST; + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + writer.write(fDTD); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/ElementImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/ElementImpl.java new file mode 100644 index 0000000..5b8ec35 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/ElementImpl.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.events.Namespace; + +/** + * @xerces.internal + * + * @author Lucian Holland + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +abstract class ElementImpl extends XMLEventImpl { + + /** + * The qualified name of the element that is being closed. + */ + private final QName fName; + + /** + * Namespaces declared in the current scope. + */ + private final List fNamespaces; + + /** + * Constructor. + */ + ElementImpl(final QName name, final boolean isStartElement, Iterator namespaces, final Location location) { + super(isStartElement ? START_ELEMENT : END_ELEMENT, location); + fName = name; + if (namespaces != null && namespaces.hasNext()) { + fNamespaces = new ArrayList(); + do { + Namespace ns = (Namespace) namespaces.next(); + fNamespaces.add(ns); + } + while (namespaces.hasNext()); + } + else { + fNamespaces = Collections.EMPTY_LIST; + } + } + + /** + * @see javax.xml.stream.events.StartElement#getName() + * @see javax.xml.stream.events.EndElement#getName() + */ + public final QName getName() { + return fName; + } + + /** + * @see javax.xml.stream.events.StartElement#getNamespaces() + * @see javax.xml.stream.events.EndElement#getNamespaces() + */ + public final Iterator getNamespaces() { + return createImmutableIterator(fNamespaces.iterator()); + } + + static Iterator createImmutableIterator(Iterator iter) { + return new NoRemoveIterator(iter); + } + + private static final class NoRemoveIterator implements Iterator { + + private final Iterator fWrapped; + + public NoRemoveIterator(Iterator wrapped) { + fWrapped = wrapped; + } + + /** + * @see java.util.Iterator#hasNext() + */ + public boolean hasNext() { + return fWrapped.hasNext(); + } + + /** + * @see java.util.Iterator#next() + */ + public Object next() { + return fWrapped.next(); + } + + /** + * @see java.util.Iterator#remove() + */ + public void remove() { + throw new UnsupportedOperationException("Attributes iterator is read-only."); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/EndDocumentImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/EndDocumentImpl.java new file mode 100644 index 0000000..745b4ad --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/EndDocumentImpl.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.Writer; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndDocument; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class EndDocumentImpl extends XMLEventImpl implements EndDocument { + + /** + * Constructor. + * @param location Location object for this event. + */ + public EndDocumentImpl(Location location) { + super(END_DOCUMENT, location); + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException {} +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/EndElementImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/EndElementImpl.java new file mode 100644 index 0000000..d21e111 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/EndElementImpl.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; + +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class EndElementImpl extends ElementImpl implements EndElement { + + /** + * @param location The location object for this event. + */ + public EndElementImpl(final QName name, final Iterator namespaces, final Location location) { + super(name, false, namespaces, location); + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + // Write end tags. + writer.write(" 0) { + writer.write(prefix); + writer.write(':'); + } + writer.write(name.getLocalPart()); + writer.write('>'); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/EntityDeclarationImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/EntityDeclarationImpl.java new file mode 100644 index 0000000..91e823b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/EntityDeclarationImpl.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EntityDeclaration; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class EntityDeclarationImpl extends XMLEventImpl implements + EntityDeclaration { + + private final String fPublicId; + private final String fSystemId; + private final String fName; + private final String fNotationName; + + /** + * @param eventType + * @param location + * @param schemaType + */ + public EntityDeclarationImpl(final String publicId, final String systemId, final String name, final String notationName, final Location location) { + super(ENTITY_DECLARATION, location); + fPublicId = publicId; + fSystemId = systemId; + fName = name; + fNotationName = notationName; + } + + /** + * @see javax.xml.stream.events.EntityDeclaration#getPublicId() + */ + public String getPublicId() { + return fPublicId; + } + + /** + * @see javax.xml.stream.events.EntityDeclaration#getSystemId() + */ + public String getSystemId() { + return fSystemId; + } + + /** + * @see javax.xml.stream.events.EntityDeclaration#getName() + */ + public String getName() { + return fName; + } + + /** + * @see javax.xml.stream.events.EntityDeclaration#getNotationName() + */ + public String getNotationName() { + return fNotationName; + } + + /** + * @see javax.xml.stream.events.EntityDeclaration#getReplacementText() + */ + public String getReplacementText() { + // TODO Auto-generated method stub + return null; + } + + /** + * @see javax.xml.stream.events.EntityDeclaration#getBaseURI() + */ + public String getBaseURI() { + // TODO Auto-generated method stub + return null; + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + writer.write("'); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/EntityReferenceImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/EntityReferenceImpl.java new file mode 100644 index 0000000..a69891d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/EntityReferenceImpl.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class EntityReferenceImpl extends XMLEventImpl implements + EntityReference { + + /** + * The name of the entity. + */ + private final String fName; + + /** + * The entity declaration for this entity reference. + */ + private final EntityDeclaration fDecl; + + /** + * Constructor. + * @param decl + * @param location + */ + public EntityReferenceImpl(final EntityDeclaration decl, final Location location) { + this(decl != null ? decl.getName() : "", decl, location); + } + + /** + * Constructor. + * @param name + * @param decl + * @param location + */ + public EntityReferenceImpl(final String name, final EntityDeclaration decl, final Location location) { + super(ENTITY_REFERENCE, location); + fName = (name != null) ? name : ""; + fDecl = decl; + } + + /** + * @see javax.xml.stream.events.EntityReference#getDeclaration() + */ + public EntityDeclaration getDeclaration() { + return fDecl; + } + + /** + * @see javax.xml.stream.events.EntityReference#getName() + */ + public String getName() { + return fName; + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + writer.write('&'); + writer.write(fName); + writer.write(';'); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/NamespaceImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/NamespaceImpl.java new file mode 100644 index 0000000..320931c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/NamespaceImpl.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.events.Namespace; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class NamespaceImpl extends AttributeImpl implements Namespace { + + private final String fPrefix; + private final String fNamespaceURI; + + /** + * @param location + * @param schemaType + */ + public NamespaceImpl(final String prefix, final String namespaceURI, final Location location) { + super(NAMESPACE, makeAttributeQName(prefix), namespaceURI, null, true, location); + fPrefix = (prefix == null) ? XMLConstants.DEFAULT_NS_PREFIX : prefix; + fNamespaceURI = namespaceURI; + } + + /** + * @param prefix The prefix for this namespace. + * @return A QName for the attribute that declares this namespace. + */ + private static QName makeAttributeQName(String prefix) { + if (prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) { + return new QName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE, XMLConstants.DEFAULT_NS_PREFIX); + } + return new QName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, prefix, XMLConstants.XMLNS_ATTRIBUTE); + } + + /** + * @see javax.xml.stream.events.Namespace#getPrefix() + */ + public String getPrefix() { + return fPrefix; + } + + /** + * @see javax.xml.stream.events.Namespace#getNamespaceURI() + */ + public String getNamespaceURI() { + return fNamespaceURI; + } + + /** + * @see javax.xml.stream.events.Namespace#isDefaultNamespaceDeclaration() + */ + public boolean isDefaultNamespaceDeclaration() { + return fPrefix.length() == 0; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/NotationDeclarationImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/NotationDeclarationImpl.java new file mode 100644 index 0000000..bfa6a97 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/NotationDeclarationImpl.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.NotationDeclaration; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class NotationDeclarationImpl extends XMLEventImpl implements + NotationDeclaration { + + private final String fSystemId; + private final String fPublicId; + private final String fName; + + /** + * @param eventType + * @param location + * @param schemaType + */ + public NotationDeclarationImpl(final String name, final String publicId, final String systemId, final Location location) { + super(NOTATION_DECLARATION, location); + fName = name; + fPublicId = publicId; + fSystemId = systemId; + } + + /** + * @see javax.xml.stream.events.NotationDeclaration#getName() + */ + public String getName() { + return fName; + } + + /** + * @see javax.xml.stream.events.NotationDeclaration#getPublicId() + */ + public String getPublicId() { + return fPublicId; + } + + /** + * @see javax.xml.stream.events.NotationDeclaration#getSystemId() + */ + public String getSystemId() { + return fSystemId; + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + writer.write("'); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/ProcessingInstructionImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/ProcessingInstructionImpl.java new file mode 100644 index 0000000..f7ee046 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/ProcessingInstructionImpl.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.ProcessingInstruction; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class ProcessingInstructionImpl extends XMLEventImpl implements + ProcessingInstruction { + + private final String fTarget; + private final String fData; + + /** + * @param location + */ + public ProcessingInstructionImpl(final String target, final String data, final Location location) { + super(PROCESSING_INSTRUCTION, location); + fTarget = target != null ? target : ""; + fData = data; + } + + /** + * @see javax.xml.stream.events.ProcessingInstruction#getTarget() + */ + public String getTarget() { + return fTarget; + } + + /** + * @see javax.xml.stream.events.ProcessingInstruction#getData() + */ + public String getData() { + return fData; + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + writer.write(" 0) { + writer.write(' '); + writer.write(fData); + } + writer.write("?>"); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/StartDocumentImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/StartDocumentImpl.java new file mode 100644 index 0000000..deabe3d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/StartDocumentImpl.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.StartDocument; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class StartDocumentImpl extends XMLEventImpl implements StartDocument { + + private final String fCharEncoding; + private final boolean fEncodingSet; + private final String fVersion; + private final boolean fIsStandalone; + private final boolean fStandaloneSet; + + /** + * @param location + */ + public StartDocumentImpl(final String charEncoding, final boolean encodingSet, final boolean isStandalone, final boolean standaloneSet, final String version, final Location location) { + super(START_DOCUMENT, location); + fCharEncoding = charEncoding; + fEncodingSet = encodingSet; + fIsStandalone = isStandalone; + fStandaloneSet = standaloneSet; + fVersion = version; + } + + /** + * @see javax.xml.stream.events.StartDocument#getSystemId() + */ + public String getSystemId() { + return getLocation().getSystemId(); + } + + /** + * @see javax.xml.stream.events.StartDocument#getCharacterEncodingScheme() + */ + public String getCharacterEncodingScheme() { + return fCharEncoding; + } + + /** + * @see javax.xml.stream.events.StartDocument#encodingSet() + */ + public boolean encodingSet() { + return fEncodingSet; + } + + /** + * @see javax.xml.stream.events.StartDocument#isStandalone() + */ + public boolean isStandalone() { + return fIsStandalone; + } + + /** + * @see javax.xml.stream.events.StartDocument#standaloneSet() + */ + public boolean standaloneSet() { + return fStandaloneSet; + } + + /** + * @see javax.xml.stream.events.StartDocument#getVersion() + */ + public String getVersion() { + return fVersion; + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + writer.write(" 0 ? fVersion : "1.0"); + writer.write('"'); + if (encodingSet()) { + writer.write(" encoding=\""); + writer.write(fCharEncoding); + writer.write('"'); + } + if (standaloneSet()) { + writer.write(" standalone=\""); + writer.write(fIsStandalone ? "yes" : "no"); + writer.write('"'); + } + writer.write("?>"); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/StartElementImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/StartElementImpl.java new file mode 100644 index 0000000..b61d935 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/StartElementImpl.java @@ -0,0 +1,139 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.IOException; +import java.io.Writer; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.StartElement; + +import org.apache.xerces.stax.DefaultNamespaceContext; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +public final class StartElementImpl extends ElementImpl implements StartElement { + + private static final Comparator QNAME_COMPARATOR = new Comparator() { + public int compare(Object o1, Object o2) { + if (o1.equals(o2)) { + return 0; + } + QName name1 = (QName) o1; + QName name2 = (QName) o2; + return name1.toString().compareTo(name2.toString()); + }}; + + private final Map fAttributes; + private final NamespaceContext fNamespaceContext; + + /** + * @param location + * @param schemaType + */ + public StartElementImpl(final QName name, final Iterator attributes, final Iterator namespaces, final NamespaceContext namespaceContext, final Location location) { + super(name, true, namespaces, location); + if (attributes != null && attributes.hasNext()) { + fAttributes = new TreeMap(QNAME_COMPARATOR); + do { + Attribute attr = (Attribute) attributes.next(); + fAttributes.put(attr.getName(), attr); + } + while (attributes.hasNext()); + } + else { + fAttributes = Collections.EMPTY_MAP; + } + fNamespaceContext = (namespaceContext != null) ? namespaceContext : DefaultNamespaceContext.getInstance(); + } + + /** + * @see javax.xml.stream.events.StartElement#getAttributes() + */ + public Iterator getAttributes() { + return createImmutableIterator(fAttributes.values().iterator()); + } + + /** + * @see javax.xml.stream.events.StartElement#getAttributeByName(javax.xml.namespace.QName) + */ + public Attribute getAttributeByName(final QName name) { + return (Attribute) fAttributes.get(name); + } + + /** + * @see javax.xml.stream.events.StartElement#getNamespaceContext() + */ + public NamespaceContext getNamespaceContext() { + return fNamespaceContext; + } + + /** + * @see javax.xml.stream.events.StartElement#getNamespaceURI(java.lang.String) + */ + public String getNamespaceURI(final String prefix) { + return fNamespaceContext.getNamespaceURI(prefix); + } + + public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException { + try { + // Write start tag. + writer.write('<'); + QName name = getName(); + String prefix = name.getPrefix(); + if (prefix != null && prefix.length() > 0) { + writer.write(prefix); + writer.write(':'); + } + writer.write(name.getLocalPart()); + // Write namespace declarations. + Iterator nsIter = getNamespaces(); + while (nsIter.hasNext()) { + Namespace ns = (Namespace) nsIter.next(); + writer.write(' '); + ns.writeAsEncodedUnicode(writer); + } + // Write attributes + Iterator attrIter = getAttributes(); + while (attrIter.hasNext()) { + Attribute attr = (Attribute) attrIter.next(); + writer.write(' '); + attr.writeAsEncodedUnicode(writer); + } + writer.write('>'); + } + catch (IOException ioe) { + throw new XMLStreamException(ioe); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/events/XMLEventImpl.java b/resources/xerces2-j-src/org/apache/xerces/stax/events/XMLEventImpl.java new file mode 100644 index 0000000..b54a52d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/events/XMLEventImpl.java @@ -0,0 +1,181 @@ +/* + * 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. + */ + +package org.apache.xerces.stax.events; + +import java.io.StringWriter; + +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +import org.apache.xerces.stax.EmptyLocation; +import org.apache.xerces.stax.ImmutableLocation; + +/** + * @xerces.internal + * + * @author Lucian Holland + * + * @version $Id$ + */ +abstract class XMLEventImpl implements XMLEvent { + + /** + * Constant representing the type of this event. + * {@see javax.xml.stream.XMLStreamConstants} + */ + private int fEventType; + + /** + * Location object for this event. + */ + private Location fLocation; + + /** + * Constructor. + */ + XMLEventImpl(final int eventType, final Location location) { + fEventType = eventType; + if (location != null) { + fLocation = new ImmutableLocation(location); + } + else { + fLocation = EmptyLocation.getInstance(); + } + } + + /** + * @see javax.xml.stream.events.XMLEvent#getEventType() + */ + public final int getEventType() { + return fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#getLocation() + */ + public final Location getLocation() { + return fLocation; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isStartElement() + */ + public final boolean isStartElement() { + return START_ELEMENT == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isAttribute() + */ + public final boolean isAttribute() { + return ATTRIBUTE == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isNamespace() + */ + public final boolean isNamespace() { + return NAMESPACE == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isEndElement() + */ + public final boolean isEndElement() { + return END_ELEMENT == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isEntityReference() + */ + public final boolean isEntityReference() { + return ENTITY_REFERENCE == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isProcessingInstruction() + */ + public final boolean isProcessingInstruction() { + return PROCESSING_INSTRUCTION == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isCharacters() + */ + public final boolean isCharacters() { + return CHARACTERS == fEventType || + CDATA == fEventType || + SPACE == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isStartDocument() + */ + public final boolean isStartDocument() { + return START_DOCUMENT == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#isEndDocument() + */ + public final boolean isEndDocument() { + return END_DOCUMENT == fEventType; + } + + /** + * @see javax.xml.stream.events.XMLEvent#asStartElement() + */ + public final StartElement asStartElement() { + return (StartElement) this; + } + + /** + * @see javax.xml.stream.events.XMLEvent#asEndElement() + */ + public final EndElement asEndElement() { + return (EndElement) this; + } + + /** + * @see javax.xml.stream.events.XMLEvent#asCharacters() + */ + public final Characters asCharacters() { + return (Characters) this; + } + + /** + * @see javax.xml.stream.events.XMLEvent#getSchemaType() + */ + public final QName getSchemaType() { + return null; + } + + public final String toString() { + final StringWriter writer = new StringWriter(); + try { + writeAsEncodedUnicode(writer); + } + catch (XMLStreamException xse) {} + return writer.toString(); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/stax/javax.xml.stream.XMLEventFactory b/resources/xerces2-j-src/org/apache/xerces/stax/javax.xml.stream.XMLEventFactory new file mode 100644 index 0000000..b5dd84e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/stax/javax.xml.stream.XMLEventFactory @@ -0,0 +1,2 @@ +org.apache.xerces.stax.XMLEventFactoryImpl + diff --git a/resources/xerces2-j-src/org/apache/xerces/util/AttributesProxy.java b/resources/xerces2-j-src/org/apache/xerces/util/AttributesProxy.java new file mode 100644 index 0000000..27721fc --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/AttributesProxy.java @@ -0,0 +1,190 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.xni.XMLAttributes; +import org.xml.sax.AttributeList; +import org.xml.sax.ext.Attributes2; + +/** + * Wraps {@link XMLAttributes} and makes it look like + * {@link AttributeList} and {@link Attributes2}. + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public final class AttributesProxy + implements AttributeList, Attributes2 { + + // + // Data + // + + /** XML attributes. */ + private XMLAttributes fAttributes; + + // + // Constructors + // + + public AttributesProxy(XMLAttributes attributes) { + fAttributes = attributes; + } + + // + // Public methods + // + + /** Sets the XML attributes to be wrapped. */ + public void setAttributes(XMLAttributes attributes) { + fAttributes = attributes; + } // setAttributes(XMLAttributes) + + public XMLAttributes getAttributes() { + return fAttributes; + } + + /* + * Attributes methods + */ + + public int getLength() { + return fAttributes.getLength(); + } + + public String getQName(int index) { + return fAttributes.getQName(index); + } + + public String getURI(int index) { + // This hides the fact that internally we use null instead of empty string + // SAX requires the URI to be a string or an empty string + String uri = fAttributes.getURI(index); + return uri != null ? uri : XMLSymbols.EMPTY_STRING; + } + + public String getLocalName(int index) { + return fAttributes.getLocalName(index); + } + + public String getType(int i) { + return fAttributes.getType(i); + } + + public String getType(String name) { + return fAttributes.getType(name); + } + + public String getType(String uri, String localName) { + return uri.equals(XMLSymbols.EMPTY_STRING) ? + fAttributes.getType(null, localName) : + fAttributes.getType(uri, localName); + } + + public String getValue(int i) { + return fAttributes.getValue(i); + } + + public String getValue(String name) { + return fAttributes.getValue(name); + } + + public String getValue(String uri, String localName) { + return uri.equals(XMLSymbols.EMPTY_STRING) ? + fAttributes.getValue(null, localName) : + fAttributes.getValue(uri, localName); + } + + public int getIndex(String qName) { + return fAttributes.getIndex(qName); + } + + public int getIndex(String uri, String localPart) { + return uri.equals(XMLSymbols.EMPTY_STRING) ? + fAttributes.getIndex(null, localPart) : + fAttributes.getIndex(uri, localPart); + } + + /* + * Attributes2 methods + */ + + public boolean isDeclared(int index) { + if (index < 0 || index >= fAttributes.getLength()) { + throw new ArrayIndexOutOfBoundsException(index); + } + return Boolean.TRUE.equals( + fAttributes.getAugmentations(index).getItem( + Constants.ATTRIBUTE_DECLARED)); + } + + public boolean isDeclared(String qName) { + int index = getIndex(qName); + if (index == -1) { + throw new IllegalArgumentException(qName); + } + return Boolean.TRUE.equals( + fAttributes.getAugmentations(index).getItem( + Constants.ATTRIBUTE_DECLARED)); + } + + public boolean isDeclared(String uri, String localName) { + int index = getIndex(uri, localName); + if (index == -1) { + throw new IllegalArgumentException(localName); + } + return Boolean.TRUE.equals( + fAttributes.getAugmentations(index).getItem( + Constants.ATTRIBUTE_DECLARED)); + } + + public boolean isSpecified(int index) { + if (index < 0 || index >= fAttributes.getLength()) { + throw new ArrayIndexOutOfBoundsException(index); + } + return fAttributes.isSpecified(index); + } + + public boolean isSpecified(String qName) { + int index = getIndex(qName); + if (index == -1) { + throw new IllegalArgumentException(qName); + } + return fAttributes.isSpecified(index); + } + + public boolean isSpecified(String uri, String localName) { + int index = getIndex(uri, localName); + if (index == -1) { + throw new IllegalArgumentException(localName); + } + return fAttributes.isSpecified(index); + } + + /* + * AttributeList methods + */ + + public String getName(int i) { + return fAttributes.getQName(i); + } + +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/util/AugmentationsImpl.java b/resources/xerces2-j-src/org/apache/xerces/util/AugmentationsImpl.java new file mode 100644 index 0000000..32d2a38 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/AugmentationsImpl.java @@ -0,0 +1,289 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.xerces.xni.Augmentations; + +/** + * This class provides an implementation for Augmentations interface. + * Augmentations interface defines a hashtable of additional data that could + * be passed along the document pipeline. The information can contain extra + * arguments or infoset augmentations, for example PSVI. This additional + * information is identified by a String key. + *

        + * + * @author Elena Litani, IBM + * @version $Id$ + */ +public class AugmentationsImpl implements Augmentations { + + private AugmentationsItemsContainer fAugmentationsContainer = + new SmallContainer(); + + /** + * Add additional information identified by a key to the Augmentations structure. + * + * @param key Identifier, can't be null + * @param item Additional information + * + * @return the previous value of the specified key in the Augmentations strucutre, + * or null if it did not have one. + */ + public Object putItem (String key, Object item){ + Object oldValue = fAugmentationsContainer.putItem(key, item); + + if (oldValue == null && fAugmentationsContainer.isFull()) { + fAugmentationsContainer = fAugmentationsContainer.expand(); + } + + return oldValue; + } + + /** + * Get information identified by a key from the Augmentations structure + * + * @param key Identifier, can't be null + * + * @return the value to which the key is mapped in the Augmentations structure; + * null if the key is not mapped to any value. + */ + public Object getItem(String key){ + return fAugmentationsContainer.getItem(key); + } + + /** + * Remove additional info from the Augmentations structure + * + * @param key Identifier, can't be null + */ + public Object removeItem (String key){ + return fAugmentationsContainer.removeItem(key); + } + + /** + * Returns an enumeration of the keys in the Augmentations structure + * + */ + public Enumeration keys (){ + return fAugmentationsContainer.keys(); + } + + /** + * Remove all objects from the Augmentations structure. + */ + public void removeAllItems() { + fAugmentationsContainer.clear(); + } + + public String toString() { + return fAugmentationsContainer.toString(); + } + + static abstract class AugmentationsItemsContainer { + abstract public Object putItem(Object key, Object item); + abstract public Object getItem(Object key); + abstract public Object removeItem(Object key); + abstract public Enumeration keys(); + abstract public void clear(); + abstract public boolean isFull(); + abstract public AugmentationsItemsContainer expand(); + } + + final static class SmallContainer extends AugmentationsItemsContainer { + + final static int SIZE_LIMIT = 10; + final Object[] fAugmentations = new Object[SIZE_LIMIT*2]; + int fNumEntries = 0; + + public Enumeration keys() { + return new SmallContainerKeyEnumeration(); + } + + public Object getItem(Object key) { + for (int i = 0; i < fNumEntries*2; i = i + 2) { + if (fAugmentations[i].equals(key)) { + return fAugmentations[i+1]; + } + } + + return null; + } + + public Object putItem(Object key, Object item) { + for (int i = 0; i < fNumEntries*2; i = i + 2) { + if (fAugmentations[i].equals(key)) { + Object oldValue = fAugmentations[i+1]; + fAugmentations[i+1] = item; + + return oldValue; + } + } + + fAugmentations[fNumEntries*2] = key; + fAugmentations[fNumEntries*2+1] = item; + fNumEntries++; + + return null; + } + + + public Object removeItem(Object key) { + for (int i = 0; i < fNumEntries*2; i = i + 2) { + if (fAugmentations[i].equals(key)) { + Object oldValue = fAugmentations[i+1]; + + for (int j = i; j < fNumEntries*2 - 2; j = j + 2) { + fAugmentations[j] = fAugmentations[j+2]; + fAugmentations[j+1] = fAugmentations[j+3]; + } + + fAugmentations[fNumEntries*2-2] = null; + fAugmentations[fNumEntries*2-1] = null; + fNumEntries--; + + return oldValue; + } + } + + return null; + } + + public void clear() { + for (int i = 0; i < fNumEntries*2; i = i + 2) { + fAugmentations[i] = null; + fAugmentations[i+1] = null; + } + + fNumEntries = 0; + } + + public boolean isFull() { + return (fNumEntries == SIZE_LIMIT); + } + + public AugmentationsItemsContainer expand() { + LargeContainer expandedContainer = new LargeContainer(); + + for (int i = 0; i < fNumEntries*2; i = i + 2) { + expandedContainer.putItem(fAugmentations[i], + fAugmentations[i+1]); + } + + return expandedContainer; + } + + public String toString() { + StringBuffer buff = new StringBuffer(); + buff.append("SmallContainer - fNumEntries == ").append(fNumEntries); + + for (int i = 0; i < SIZE_LIMIT*2; i=i+2) { + buff.append("\nfAugmentations["); + buff.append(i); + buff.append("] == "); + buff.append(fAugmentations[i]); + buff.append("; fAugmentations["); + buff.append(i+1); + buff.append("] == "); + buff.append(fAugmentations[i+1]); + } + + return buff.toString(); + } + + final class SmallContainerKeyEnumeration implements Enumeration { + + Object [] enumArray = new Object[fNumEntries]; + int next = 0; + + SmallContainerKeyEnumeration() { + for (int i = 0; i < fNumEntries; i++) { + enumArray[i] = fAugmentations[i*2]; + } + } + + public boolean hasMoreElements() { + return next < enumArray.length; + } + + public Object nextElement() { + if (next >= enumArray.length) { + throw new java.util.NoSuchElementException(); + } + + Object nextVal = enumArray[next]; + enumArray[next] = null; + next++; + + return nextVal; + } + } + } + + final static class LargeContainer extends AugmentationsItemsContainer { + + private final HashMap fAugmentations = new HashMap(); + + public Object getItem(Object key) { + return fAugmentations.get(key); + } + + public Object putItem(Object key, Object item) { + return fAugmentations.put(key, item); + } + + public Object removeItem(Object key) { + return fAugmentations.remove(key); + } + + public Enumeration keys() { + return Collections.enumeration(fAugmentations.keySet()); + } + + public void clear() { + fAugmentations.clear(); + } + + public boolean isFull() { + return false; + } + + public AugmentationsItemsContainer expand() { + return this; + } + + public String toString() { + StringBuffer buff = new StringBuffer(); + buff.append("LargeContainer"); + Iterator entries = fAugmentations.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + buff.append("\nkey == "); + buff.append(entry.getKey()); + buff.append("; value == "); + buff.append(entry.getValue()); + } + return buff.toString(); + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/DOMEntityResolverWrapper.java b/resources/xerces2-j-src/org/apache/xerces/util/DOMEntityResolverWrapper.java new file mode 100644 index 0000000..5cece04 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/DOMEntityResolverWrapper.java @@ -0,0 +1,167 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; + + +/** + * This class wraps DOM entity resolver to XNI entity resolver. + * + * @see LSResourceResolver + * + * @author Gopal Sharma, SUN MicroSystems Inc. + * @author Elena Litani, IBM + * @author Ramesh Mandava, Sun Microsystems + * @version $Id$ + */ +public class DOMEntityResolverWrapper + implements XMLEntityResolver { + + // + // Data + // + + /** XML 1.0 type constant according to DOM L3 LS CR spec "http://www.w3.org/TR/2003/CR-DOM-Level-3-LS-20031107" */ + private static final String XML_TYPE = "http://www.w3.org/TR/REC-xml"; + + /** XML Schema constant according to DOM L3 LS CR spec "http://www.w3.org/TR/2003/CR-DOM-Level-3-LS-20031107" */ + private static final String XSD_TYPE = "http://www.w3.org/2001/XMLSchema"; + + /** The DOM entity resolver. */ + protected LSResourceResolver fEntityResolver; + + // + // Constructors + // + + /** Default constructor. */ + public DOMEntityResolverWrapper() {} + + /** Wraps the specified DOM entity resolver. */ + public DOMEntityResolverWrapper(LSResourceResolver entityResolver) { + setEntityResolver(entityResolver); + } // LSResourceResolver + + // + // Public methods + // + + /** Sets the DOM entity resolver. */ + public void setEntityResolver(LSResourceResolver entityResolver) { + fEntityResolver = entityResolver; + } // setEntityResolver(LSResourceResolver) + + /** Returns the DOM entity resolver. */ + public LSResourceResolver getEntityResolver() { + return fEntityResolver; + } // getEntityResolver():LSResourceResolver + + // + // XMLEntityResolver methods + // + + /** + * Resolves an external parsed entity. If the entity cannot be + * resolved, this method should return null. + * + * @param resourceIdentifier description of the resource to be resolved + * @throws XNIException Thrown on general error. + * @throws IOException Thrown if resolved entity stream cannot be + * opened or some other i/o error occurs. + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) + throws XNIException, IOException { + // resolve entity using DOM entity resolver + if (fEntityResolver != null) { + // For entity resolution the type of the resource would be XML TYPE + // DOM L3 LS spec mention only the XML 1.0 recommendation right now + LSInput inputSource = + resourceIdentifier == null + ? fEntityResolver.resolveResource( + null, + null, + null, + null, + null) + : fEntityResolver.resolveResource( + getType(resourceIdentifier), + resourceIdentifier.getNamespace(), + resourceIdentifier.getPublicId(), + resourceIdentifier.getLiteralSystemId(), + resourceIdentifier.getBaseSystemId()); + if (inputSource != null) { + String publicId = inputSource.getPublicId(); + String systemId = inputSource.getSystemId(); + String baseSystemId = inputSource.getBaseURI(); + InputStream byteStream = inputSource.getByteStream(); + Reader charStream = inputSource.getCharacterStream(); + String encoding = inputSource.getEncoding(); + String data = inputSource.getStringData(); + + /** + * An LSParser looks at inputs specified in LSInput in + * the following order: characterStream, byteStream, + * stringData, systemId, publicId. + */ + XMLInputSource xmlInputSource = + new XMLInputSource(publicId, systemId, baseSystemId); + + if (charStream != null) { + xmlInputSource.setCharacterStream(charStream); + } + else if (byteStream != null) { + xmlInputSource.setByteStream((InputStream) byteStream); + } + else if (data != null && data.length() != 0) { + xmlInputSource.setCharacterStream(new StringReader(data)); + } + xmlInputSource.setEncoding(encoding); + return xmlInputSource; + } + } + + // unable to resolve entity + return null; + + } // resolveEntity(String,String,String):XMLInputSource + + /** Determines the type of resource being resolved **/ + private String getType(XMLResourceIdentifier resourceIdentifier) { + if (resourceIdentifier instanceof XMLGrammarDescription) { + XMLGrammarDescription desc = (XMLGrammarDescription) resourceIdentifier; + if (XMLGrammarDescription.XML_SCHEMA.equals(desc.getGrammarType())) { + return XSD_TYPE; + } + } + return XML_TYPE; + } // getType(XMLResourceIdentifier):String + +} // DOMEntityResolverWrapper diff --git a/resources/xerces2-j-src/org/apache/xerces/util/DOMErrorHandlerWrapper.java b/resources/xerces2-j-src/org/apache/xerces/util/DOMErrorHandlerWrapper.java new file mode 100644 index 0000000..f880057 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/DOMErrorHandlerWrapper.java @@ -0,0 +1,417 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.io.PrintWriter; +import java.util.Hashtable; + +import org.apache.xerces.dom.DOMErrorImpl; +import org.apache.xerces.dom.DOMLocatorImpl; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLParseException; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMLocator; +import org.w3c.dom.Node; + +/** + * This class handles DOM errors . + * + * @see DOMErrorHandler + * + * @author Gopal Sharma, SUN Microsystems Inc. + * @version $Id$ + */ + +// REVISIT: current implementations wraps error several times: +// XMLErrorReport.reportError creates XMLParserException (by wrapping all info) +// and goes via switch to send errors. +// DOMErrorHandlerWrapper catches calls, copies info from XMLParserException and +// sends one call back to the application +// I think we can avoid this indirection if we modify XMLErrorReporter. --el + +public class DOMErrorHandlerWrapper + implements XMLErrorHandler, DOMErrorHandler { + + + + // It keeps the reference of DOMErrorHandler of application + protected DOMErrorHandler fDomErrorHandler; + + // Error Status + boolean eStatus = true ; + + // Print writer + protected PrintWriter fOut; + + // some components may set error node + // @see DOMNormalizer. + public Node fCurrentNode; + + /** Error code for comparisons. **/ + protected final XMLErrorCode fErrorCode = new XMLErrorCode(null, null); + + protected final DOMErrorImpl fDOMError = new DOMErrorImpl(); + + + + // + // Constructors + // + + // Default constructor / + + public DOMErrorHandlerWrapper() { + fOut = new PrintWriter(System.err); + } + + + public DOMErrorHandlerWrapper(DOMErrorHandler domErrorHandler) { + fDomErrorHandler = domErrorHandler; + } // DOMErrorHandlerWrapper(DOMErrorHandler domErrorHandler) + + + // + // Public methods + // + + /** Sets the DOM error handler. */ + public void setErrorHandler(DOMErrorHandler errorHandler) { + fDomErrorHandler = errorHandler; + } // setErrorHandler(ErrorHandler) + + + public DOMErrorHandler getErrorHandler(){ + return fDomErrorHandler; + } //getErrorHandler() + + // + // XMLErrorHandler methods + // + + /** + * Reports a warning. Warnings are non-fatal and can be safely ignored + * by most applications. + * + * @param domain The domain of the warning. The domain can be any + * string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevent specification or + * document pertaining to this warning. + * @param key The warning key. This key can be any string and + * is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + + public void warning(String domain, String key, + XMLParseException exception) throws XNIException { + fDOMError.fSeverity = DOMError.SEVERITY_WARNING; + fDOMError.fException = exception; + // REVISIT: May need to lookup from DOMErrorTypeMap in the future. + fDOMError.fType = key; + fDOMError.fRelatedData = fDOMError.fMessage = exception.getMessage(); + DOMLocatorImpl locator = fDOMError.fLocator; + if (locator != null) { + locator.fColumnNumber = exception.getColumnNumber(); + locator.fLineNumber = exception.getLineNumber(); + locator.fUtf16Offset = exception.getCharacterOffset(); + locator.fUri = exception.getExpandedSystemId(); + locator.fRelatedNode = fCurrentNode; + } + if (fDomErrorHandler != null) { + fDomErrorHandler.handleError(fDOMError); + } + } // warning(String,String,XMLParseException) + + /** + * Reports an error. Errors are non-fatal and usually signify that the + * document is invalid with respect to its grammar(s). + * + * @param domain The domain of the error. The domain can be any + * string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevent specification or + * document pertaining to this error. + * @param key The error key. This key can be any string and + * is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + public void error(String domain, String key, + XMLParseException exception) throws XNIException { + fDOMError.fSeverity = DOMError.SEVERITY_ERROR; + fDOMError.fException = exception; + // REVISIT: May need to lookup from DOMErrorTypeMap in the future. + fDOMError.fType = key; + fDOMError.fRelatedData = fDOMError.fMessage = exception.getMessage(); + DOMLocatorImpl locator = fDOMError.fLocator; + if (locator != null) { + locator.fColumnNumber = exception.getColumnNumber(); + locator.fLineNumber = exception.getLineNumber(); + locator.fUtf16Offset = exception.getCharacterOffset(); + locator.fUri = exception.getExpandedSystemId(); + locator.fRelatedNode= fCurrentNode; + } + if (fDomErrorHandler != null) { + fDomErrorHandler.handleError(fDOMError); + } + } // error(String,String,XMLParseException) + + /** + * Report a fatal error. Fatal errors usually occur when the document + * is not well-formed and signifies that the parser cannot continue + * normal operation. + *

        + * Note: The error handler should always + * throw an XNIException from this method. This exception + * can either be the same exception that is passed as a parameter to + * the method or a new XNI exception object. If the registered error + * handler fails to throw an exception, the continuing operation of + * the parser is undetermined. + * + * @param domain The domain of the fatal error. The domain can be + * any string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevent specification or + * document pertaining to this fatal error. + * @param key The fatal error key. This key can be any string + * and is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + public void fatalError(String domain, String key, + XMLParseException exception) throws XNIException { + fDOMError.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + fDOMError.fException = exception; + fErrorCode.setValues(domain, key); + String domErrorType = DOMErrorTypeMap.getDOMErrorType(fErrorCode); + fDOMError.fType = (domErrorType != null) ? domErrorType : key; + fDOMError.fRelatedData = fDOMError.fMessage = exception.getMessage(); + DOMLocatorImpl locator = fDOMError.fLocator; + if (locator != null) { + locator.fColumnNumber = exception.getColumnNumber(); + locator.fLineNumber = exception.getLineNumber(); + locator.fUtf16Offset = exception.getCharacterOffset(); + locator.fUri = exception.getExpandedSystemId(); + locator.fRelatedNode = fCurrentNode; + } + if (fDomErrorHandler != null) { + fDomErrorHandler.handleError(fDOMError); + } + } // fatalError(String,String,XMLParseException) + + + public boolean handleError(DOMError error) { + printError(error); + return eStatus; + } + + /** Prints the error message. */ + + private void printError(DOMError error) { + int severity = error.getSeverity(); + fOut.print("["); + if ( severity == DOMError.SEVERITY_WARNING) { + fOut.print("Warning"); + } else if ( severity == DOMError.SEVERITY_ERROR) { + fOut.print("Error"); + } else { + fOut.print("FatalError"); + eStatus = false ; //REVISIT: Abort processing if fatal error, do we need to?? + } + fOut.print("] "); + DOMLocator locator = error.getLocation(); + if (locator != null) { + fOut.print(locator.getLineNumber()); + fOut.print(":"); + fOut.print(locator.getColumnNumber()); + fOut.print(":"); + fOut.print(locator.getByteOffset()); + fOut.print(","); + fOut.print(locator.getUtf16Offset()); + Node node = locator.getRelatedNode(); + if (node != null) { + fOut.print("["); + fOut.print(node.getNodeName()); + fOut.print("]"); + } + String systemId = locator.getUri(); + if (systemId != null) { + int index = systemId.lastIndexOf('/'); + if (index != -1) + systemId = systemId.substring(index + 1); + fOut.print(": "); + fOut.print(systemId); + } + + } + + fOut.print(":"); + fOut.print(error.getMessage()); + fOut.println(); + fOut.flush(); + + } // printError(DOMError) + + /** + * A convenience class for converting between internal + * error codes and DOM error types. + */ + private static class DOMErrorTypeMap { + + /** Map for converting internal error codes to DOM error types. **/ + private static Hashtable fgDOMErrorTypeTable; + + static { + // initialize error type table: internal error codes (represented by domain and key) need to be mapped to a DOM error type. + + // REVISIT: do well-formedness issues involving XML declaration need to be added to hash table (no XML declaration node in DOM, but Document includes xmlEncoding, xmlStandalone, xmlVersion, etc. + + fgDOMErrorTypeTable = new Hashtable(); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInCDSect"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInContent"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "TwoColonsInQName"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ColonNotLegalWithNS"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInProlog"), "wf-invalid-character"); // e.g. in Processing Instruction + + // InvalidCharInXMLDecl omitted because XML declaration is not a DOM Node + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "CDEndInContent"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "CDSectUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "DoctypeNotAllowed"), "doctype-not-allowed"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ETagRequired"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ElementUnterminated"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "EqRequiredInAttribute"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "OpenQuoteExpected"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "CloseQuoteExpected"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ETagUnterminated"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MarkupNotRecognizedInContent"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "DoctypeIllegalInContent"), "doctype-not-allowed"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInAttValue"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInPI"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInInternalSubset"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "QuoteRequiredInAttValue"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "LessthanInAttValue"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "AttributeValueUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "PITargetRequired"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "SpaceRequiredInPI"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "PIUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ReservedPITarget"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "PI_NOT_IN_ONE_ENTITY"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "PINotInOneEntity"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "EncodingDeclInvalid"), "unsupported-encoding"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "EncodingByteOrderUnsupported"), "unsupported-encoding"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInEntityValue"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInExternalSubset"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInIgnoreSect"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInPublicID"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "InvalidCharInSystemID"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "SpaceRequiredAfterSYSTEM"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "QuoteRequiredInSystemID"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "SystemIDUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "SpaceRequiredAfterPUBLIC"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "QuoteRequiredInPublicID"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "PublicIDUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "PubidCharIllegal"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "SpaceRequiredBetweenPublicAndSystem"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node (which follows !DOCTYPE) + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_ROOT_ELEMENT_TYPE_REQUIRED"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "DoctypedeclUnterminated"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "PEReferenceWithinMarkup"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_MARKUP_NOT_RECOGNIZED_IN_DTD"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_CONTENTSPEC_REQUIRED_IN_ELEMENTDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ElementDeclUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_CLOSE_PAREN_REQUIRED_IN_MIXED"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MixedContentUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "AttNameRequiredInAttDef"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "AttTypeRequiredInAttDef"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_DUPLICATE_ATTRIBUTE_DEFINITION"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_NAME_REQUIRED_IN_NOTATIONTYPE"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "NotationTypeUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_NMTOKEN_REQUIRED_IN_ENUMERATION"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "EnumerationUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_DISTINCT_TOKENS_IN_ENUMERATION"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_DISTINCT_NOTATION_IN_ENUMERATION"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "IncludeSectUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "IgnoreSectUnterminated"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "NameRequiredInPEReference"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "SemicolonRequiredInPEReference"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node (which follows !ENTITY) + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node (which follows !ENTITY %) + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_PEDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node (which follows !ENTITY %) + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node (which follows !ENTITY) + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "EntityDeclUnterminated"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_DUPLICATE_ENTITY_DEFINITION"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ExternalIDRequired"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_PUBIDLITERAL_IN_EXTERNALID"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_AFTER_PUBIDLITERAL_IN_EXTERNALID"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_SYSTEMLITERAL_IN_EXTERNALID"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_URI_FRAGMENT_IN_SYSTEMID"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node, which follows !NOTATION + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node, which follows !NOTATION + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL"), "wf-invalid-character-in-node-name"); // considered error in name of node, which follows !NOTATION + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ExternalIDorPublicIDRequired"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "NotationDeclUnterminated"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ReferenceToExternalEntity"), "wf-invalid-character"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ReferenceToUnparsedEntity"), "wf-invalid-character"); + + // REVISIT: do EntityNotDeclared, RecursiveReference, RecursiveGeneralReference, RecursivePEReference belong here? + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "EncodingNotSupported"), "unsupported-encoding"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "EncodingRequired"), "unsupported-encoding"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "IllegalQName"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ElementXMLNSPrefix"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "ElementPrefixUnbound"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "AttributePrefixUnbound"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "EmptyPrefixedAttName"), "wf-invalid-character-in-node-name"); + fgDOMErrorTypeTable.put(new XMLErrorCode(XMLMessageFormatter.XML_DOMAIN, "PrefixDeclared"), "wf-invalid-character-in-node-name"); + } + + public static String getDOMErrorType (XMLErrorCode error) { + return (String) fgDOMErrorTypeTable.get(error); + } + + private DOMErrorTypeMap () {} + } + +} // class DOMErrorHandlerWrapper diff --git a/resources/xerces2-j-src/org/apache/xerces/util/DOMInputSource.java b/resources/xerces2-j-src/org/apache/xerces/util/DOMInputSource.java new file mode 100644 index 0000000..0df00d2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/DOMInputSource.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.parser.XMLInputSource; +import org.w3c.dom.Node; + +/** + *

        An XMLInputSource analogue to javax.xml.transform.dom.DOMSource.

        + * + * @version $Id$ + */ +public final class DOMInputSource extends XMLInputSource { + + private Node fNode; + + public DOMInputSource() { + this(null); + } + + public DOMInputSource(Node node) { + super(null, getSystemIdFromNode(node), null); + fNode = node; + } + + public DOMInputSource(Node node, String systemId) { + super(null, systemId, null); + fNode = node; + } + + public Node getNode() { + return fNode; + } + + public void setNode(Node node) { + fNode = node; + } + + private static String getSystemIdFromNode(Node node) { + if (node != null) { + try { + return node.getBaseURI(); + } + // If the DOM implementation is DOM Level 2 + // then a NoSuchMethodError will be thrown. + // Just ignore it. + catch (NoSuchMethodError e) { + return null; + } + // There was a failure for some other reason + // Ignore it as well. + catch (Exception e) { + return null; + } + } + return null; + } + +} // DOMInputSource diff --git a/resources/xerces2-j-src/org/apache/xerces/util/DOMUtil.java b/resources/xerces2-j-src/org/apache/xerces/util/DOMUtil.java new file mode 100644 index 0000000..79325fd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/DOMUtil.java @@ -0,0 +1,899 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Hashtable; + +import org.apache.xerces.dom.AttrImpl; +import org.apache.xerces.dom.DocumentImpl; +import org.apache.xerces.impl.xs.opti.ElementImpl; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.ls.LSException; + +/** + * Some useful utility methods. + * This class was modified in Xerces2 with a view to abstracting as + * much as possible away from the representation of the underlying + * parsed structure (i.e., the DOM). This was done so that, if Xerces + * ever adopts an in-memory representation more efficient than the DOM + * (such as a DTM), we should easily be able to convert our schema + * parsing to utilize it. + * + * @version $Id$ + */ +public class DOMUtil { + + // + // Constructors + // + + /** This class cannot be instantiated. */ + protected DOMUtil() {} + + // + // Public static methods + // + + /** + * Copies the source tree into the specified place in a destination + * tree. The source node and its children are appended as children + * of the destination node. + *

        + * Note: This is an iterative implementation. + */ + public static void copyInto(Node src, Node dest) throws DOMException { + + // get node factory + Document factory = dest.getOwnerDocument(); + boolean domimpl = factory instanceof DocumentImpl; + + // placement variables + Node start = src; + Node parent = src; + Node place = src; + + // traverse source tree + while (place != null) { + + // copy this node + Node node = null; + int type = place.getNodeType(); + switch (type) { + case Node.CDATA_SECTION_NODE: { + node = factory.createCDATASection(place.getNodeValue()); + break; + } + case Node.COMMENT_NODE: { + node = factory.createComment(place.getNodeValue()); + break; + } + case Node.ELEMENT_NODE: { + Element element = factory.createElement(place.getNodeName()); + node = element; + NamedNodeMap attrs = place.getAttributes(); + int attrCount = attrs.getLength(); + for (int i = 0; i < attrCount; i++) { + Attr attr = (Attr)attrs.item(i); + String attrName = attr.getNodeName(); + String attrValue = attr.getNodeValue(); + element.setAttribute(attrName, attrValue); + if (domimpl && !attr.getSpecified()) { + ((AttrImpl)element.getAttributeNode(attrName)).setSpecified(false); + } + } + break; + } + case Node.ENTITY_REFERENCE_NODE: { + node = factory.createEntityReference(place.getNodeName()); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE: { + node = factory.createProcessingInstruction(place.getNodeName(), + place.getNodeValue()); + break; + } + case Node.TEXT_NODE: { + node = factory.createTextNode(place.getNodeValue()); + break; + } + default: { + throw new IllegalArgumentException("can't copy node type, "+ + type+" ("+ + place.getNodeName()+')'); + } + } + dest.appendChild(node); + + // iterate over children + if (place.hasChildNodes()) { + parent = place; + place = place.getFirstChild(); + dest = node; + } + + // advance + else { + place = place.getNextSibling(); + while (place == null && parent != start) { + place = parent.getNextSibling(); + parent = parent.getParentNode(); + dest = dest.getParentNode(); + } + } + + } + + } // copyInto(Node,Node) + + /** Finds and returns the first child element node. */ + public static Element getFirstChildElement(Node parent) { + + // search for node + Node child = parent.getFirstChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + return (Element)child; + } + child = child.getNextSibling(); + } + + // not found + return null; + + } // getFirstChildElement(Node):Element + + /** Finds and returns the first visible child element node. */ + public static Element getFirstVisibleChildElement(Node parent) { + + // search for node + Node child = parent.getFirstChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE && + !isHidden(child)) { + return (Element)child; + } + child = child.getNextSibling(); + } + + // not found + return null; + + } // getFirstChildElement(Node):Element + + /** Finds and returns the first visible child element node. */ + public static Element getFirstVisibleChildElement(Node parent, Hashtable hiddenNodes) { + + // search for node + Node child = parent.getFirstChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE && + !isHidden(child, hiddenNodes)) { + return (Element)child; + } + child = child.getNextSibling(); + } + + // not found + return null; + + } // getFirstChildElement(Node):Element + + /** Finds and returns the last child element node. + * Overload previous method for non-Xerces node impl. + */ + public static Element getLastChildElement(Node parent) { + + // search for node + Node child = parent.getLastChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + return (Element)child; + } + child = child.getPreviousSibling(); + } + + // not found + return null; + + } // getLastChildElement(Node):Element + + /** Finds and returns the last visible child element node. */ + public static Element getLastVisibleChildElement(Node parent) { + + // search for node + Node child = parent.getLastChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE && + !isHidden(child)) { + return (Element)child; + } + child = child.getPreviousSibling(); + } + + // not found + return null; + + } // getLastChildElement(Node):Element + + /** Finds and returns the last visible child element node. + * Overload previous method for non-Xerces node impl + */ + public static Element getLastVisibleChildElement(Node parent, Hashtable hiddenNodes) { + + // search for node + Node child = parent.getLastChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE && + !isHidden(child, hiddenNodes)) { + return (Element)child; + } + child = child.getPreviousSibling(); + } + + // not found + return null; + + } // getLastChildElement(Node):Element + /** Finds and returns the next sibling element node. */ + public static Element getNextSiblingElement(Node node) { + + // search for node + Node sibling = node.getNextSibling(); + while (sibling != null) { + if (sibling.getNodeType() == Node.ELEMENT_NODE) { + return (Element)sibling; + } + sibling = sibling.getNextSibling(); + } + + // not found + return null; + + } // getNextSiblingElement(Node):Element + + // get next visible (un-hidden) node. + public static Element getNextVisibleSiblingElement(Node node) { + + // search for node + Node sibling = node.getNextSibling(); + while (sibling != null) { + if (sibling.getNodeType() == Node.ELEMENT_NODE && + !isHidden(sibling)) { + return (Element)sibling; + } + sibling = sibling.getNextSibling(); + } + + // not found + return null; + + } // getNextSiblingdElement(Node):Element + + // get next visible (un-hidden) node, overload previous method for non Xerces node impl + public static Element getNextVisibleSiblingElement(Node node, Hashtable hiddenNodes) { + + // search for node + Node sibling = node.getNextSibling(); + while (sibling != null) { + if (sibling.getNodeType() == Node.ELEMENT_NODE && + !isHidden(sibling, hiddenNodes)) { + return (Element)sibling; + } + sibling = sibling.getNextSibling(); + } + + // not found + return null; + + } // getNextSiblingdElement(Node):Element + + // set this Node as being hidden + public static void setHidden(Node node) { + if (node instanceof org.apache.xerces.impl.xs.opti.NodeImpl) + ((org.apache.xerces.impl.xs.opti.NodeImpl)node).setReadOnly(true, false); + else if (node instanceof org.apache.xerces.dom.NodeImpl) + ((org.apache.xerces.dom.NodeImpl)node).setReadOnly(true, false); + } // setHidden(node):void + + // set this Node as being hidden, overloaded method + public static void setHidden(Node node, Hashtable hiddenNodes) { + if (node instanceof org.apache.xerces.impl.xs.opti.NodeImpl) { + ((org.apache.xerces.impl.xs.opti.NodeImpl)node).setReadOnly(true, false); + } + else { + hiddenNodes.put(node, ""); + } + } // setHidden(node):void + + // set this Node as being visible + public static void setVisible(Node node) { + if (node instanceof org.apache.xerces.impl.xs.opti.NodeImpl) + ((org.apache.xerces.impl.xs.opti.NodeImpl)node).setReadOnly(false, false); + else if (node instanceof org.apache.xerces.dom.NodeImpl) + ((org.apache.xerces.dom.NodeImpl)node).setReadOnly(false, false); + } // setVisible(node):void + + // set this Node as being visible, overloaded method + public static void setVisible(Node node, Hashtable hiddenNodes) { + if (node instanceof org.apache.xerces.impl.xs.opti.NodeImpl) { + ((org.apache.xerces.impl.xs.opti.NodeImpl)node).setReadOnly(false, false); + } + else { + hiddenNodes.remove(node); + } + } // setVisible(node):void + + // is this node hidden? + public static boolean isHidden(Node node) { + if (node instanceof org.apache.xerces.impl.xs.opti.NodeImpl) + return ((org.apache.xerces.impl.xs.opti.NodeImpl)node).getReadOnly(); + else if (node instanceof org.apache.xerces.dom.NodeImpl) + return ((org.apache.xerces.dom.NodeImpl)node).getReadOnly(); + return false; + } // isHidden(Node):boolean + + // is this node hidden? overloaded method + public static boolean isHidden(Node node, Hashtable hiddenNodes) { + if (node instanceof org.apache.xerces.impl.xs.opti.NodeImpl) { + return ((org.apache.xerces.impl.xs.opti.NodeImpl)node).getReadOnly(); + } + else { + return hiddenNodes.containsKey(node); + } + } // isHidden(Node):boolean + + /** Finds and returns the first child node with the given name. */ + public static Element getFirstChildElement(Node parent, String elemName) { + + // search for node + Node child = parent.getFirstChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + if (child.getNodeName().equals(elemName)) { + return (Element)child; + } + } + child = child.getNextSibling(); + } + + // not found + return null; + + } // getFirstChildElement(Node,String):Element + + /** Finds and returns the last child node with the given name. */ + public static Element getLastChildElement(Node parent, String elemName) { + + // search for node + Node child = parent.getLastChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + if (child.getNodeName().equals(elemName)) { + return (Element)child; + } + } + child = child.getPreviousSibling(); + } + + // not found + return null; + + } // getLastChildElement(Node,String):Element + + /** Finds and returns the next sibling node with the given name. */ + public static Element getNextSiblingElement(Node node, String elemName) { + + // search for node + Node sibling = node.getNextSibling(); + while (sibling != null) { + if (sibling.getNodeType() == Node.ELEMENT_NODE) { + if (sibling.getNodeName().equals(elemName)) { + return (Element)sibling; + } + } + sibling = sibling.getNextSibling(); + } + + // not found + return null; + + } // getNextSiblingdElement(Node,String):Element + + /** Finds and returns the first child node with the given qualified name. */ + public static Element getFirstChildElementNS(Node parent, + String uri, String localpart) { + + // search for node + Node child = parent.getFirstChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + String childURI = child.getNamespaceURI(); + if (childURI != null && childURI.equals(uri) && + child.getLocalName().equals(localpart)) { + return (Element)child; + } + } + child = child.getNextSibling(); + } + + // not found + return null; + + } // getFirstChildElementNS(Node,String,String):Element + + /** Finds and returns the last child node with the given qualified name. */ + public static Element getLastChildElementNS(Node parent, + String uri, String localpart) { + + // search for node + Node child = parent.getLastChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + String childURI = child.getNamespaceURI(); + if (childURI != null && childURI.equals(uri) && + child.getLocalName().equals(localpart)) { + return (Element)child; + } + } + child = child.getPreviousSibling(); + } + + // not found + return null; + + } // getLastChildElementNS(Node,String,String):Element + + /** Finds and returns the next sibling node with the given qualified name. */ + public static Element getNextSiblingElementNS(Node node, + String uri, String localpart) { + + // search for node + Node sibling = node.getNextSibling(); + while (sibling != null) { + if (sibling.getNodeType() == Node.ELEMENT_NODE) { + String siblingURI = sibling.getNamespaceURI(); + if (siblingURI != null && siblingURI.equals(uri) && + sibling.getLocalName().equals(localpart)) { + return (Element)sibling; + } + } + sibling = sibling.getNextSibling(); + } + + // not found + return null; + + } // getNextSiblingdElementNS(Node,String,String):Element + + /** Finds and returns the first child node with the given name. */ + public static Element getFirstChildElement(Node parent, String elemNames[]) { + + // search for node + Node child = parent.getFirstChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + for (int i = 0; i < elemNames.length; i++) { + if (child.getNodeName().equals(elemNames[i])) { + return (Element)child; + } + } + } + child = child.getNextSibling(); + } + + // not found + return null; + + } // getFirstChildElement(Node,String[]):Element + + /** Finds and returns the last child node with the given name. */ + public static Element getLastChildElement(Node parent, String elemNames[]) { + + // search for node + Node child = parent.getLastChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + for (int i = 0; i < elemNames.length; i++) { + if (child.getNodeName().equals(elemNames[i])) { + return (Element)child; + } + } + } + child = child.getPreviousSibling(); + } + + // not found + return null; + + } // getLastChildElement(Node,String[]):Element + + /** Finds and returns the next sibling node with the given name. */ + public static Element getNextSiblingElement(Node node, String elemNames[]) { + + // search for node + Node sibling = node.getNextSibling(); + while (sibling != null) { + if (sibling.getNodeType() == Node.ELEMENT_NODE) { + for (int i = 0; i < elemNames.length; i++) { + if (sibling.getNodeName().equals(elemNames[i])) { + return (Element)sibling; + } + } + } + sibling = sibling.getNextSibling(); + } + + // not found + return null; + + } // getNextSiblingdElement(Node,String[]):Element + + /** Finds and returns the first child node with the given qualified name. */ + public static Element getFirstChildElementNS(Node parent, + String[][] elemNames) { + + // search for node + Node child = parent.getFirstChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + for (int i = 0; i < elemNames.length; i++) { + String uri = child.getNamespaceURI(); + if (uri != null && uri.equals(elemNames[i][0]) && + child.getLocalName().equals(elemNames[i][1])) { + return (Element)child; + } + } + } + child = child.getNextSibling(); + } + + // not found + return null; + + } // getFirstChildElementNS(Node,String[][]):Element + + /** Finds and returns the last child node with the given qualified name. */ + public static Element getLastChildElementNS(Node parent, + String[][] elemNames) { + + // search for node + Node child = parent.getLastChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + for (int i = 0; i < elemNames.length; i++) { + String uri = child.getNamespaceURI(); + if (uri != null && uri.equals(elemNames[i][0]) && + child.getLocalName().equals(elemNames[i][1])) { + return (Element)child; + } + } + } + child = child.getPreviousSibling(); + } + + // not found + return null; + + } // getLastChildElementNS(Node,String[][]):Element + + /** Finds and returns the next sibling node with the given qualified name. */ + public static Element getNextSiblingElementNS(Node node, + String[][] elemNames) { + + // search for node + Node sibling = node.getNextSibling(); + while (sibling != null) { + if (sibling.getNodeType() == Node.ELEMENT_NODE) { + for (int i = 0; i < elemNames.length; i++) { + String uri = sibling.getNamespaceURI(); + if (uri != null && uri.equals(elemNames[i][0]) && + sibling.getLocalName().equals(elemNames[i][1])) { + return (Element)sibling; + } + } + } + sibling = sibling.getNextSibling(); + } + + // not found + return null; + + } // getNextSiblingdElementNS(Node,String[][]):Element + + /** + * Finds and returns the first child node with the given name and + * attribute name, value pair. + */ + public static Element getFirstChildElement(Node parent, + String elemName, + String attrName, + String attrValue) { + + // search for node + Node child = parent.getFirstChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element)child; + if (element.getNodeName().equals(elemName) && + element.getAttribute(attrName).equals(attrValue)) { + return element; + } + } + child = child.getNextSibling(); + } + + // not found + return null; + + } // getFirstChildElement(Node,String,String,String):Element + + /** + * Finds and returns the last child node with the given name and + * attribute name, value pair. + */ + public static Element getLastChildElement(Node parent, + String elemName, + String attrName, + String attrValue) { + + // search for node + Node child = parent.getLastChild(); + while (child != null) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element)child; + if (element.getNodeName().equals(elemName) && + element.getAttribute(attrName).equals(attrValue)) { + return element; + } + } + child = child.getPreviousSibling(); + } + + // not found + return null; + + } // getLastChildElement(Node,String,String,String):Element + + /** + * Finds and returns the next sibling node with the given name and + * attribute name, value pair. Since only elements have attributes, + * the node returned will be of type Node.ELEMENT_NODE. + */ + public static Element getNextSiblingElement(Node node, + String elemName, + String attrName, + String attrValue) { + + // search for node + Node sibling = node.getNextSibling(); + while (sibling != null) { + if (sibling.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element)sibling; + if (element.getNodeName().equals(elemName) && + element.getAttribute(attrName).equals(attrValue)) { + return element; + } + } + sibling = sibling.getNextSibling(); + } + + // not found + return null; + + } // getNextSiblingElement(Node,String,String,String):Element + + /** + * Returns the concatenated child text of the specified node. + * This method only looks at the immediate children of type + * Node.TEXT_NODE or the children of any child + * node that is of type Node.CDATA_SECTION_NODE + * for the concatenation. + * + * @param node The node to look at. + */ + public static String getChildText(Node node) { + + // is there anything to do? + if (node == null) { + return null; + } + + // concatenate children text + StringBuffer str = new StringBuffer(); + Node child = node.getFirstChild(); + while (child != null) { + short type = child.getNodeType(); + if (type == Node.TEXT_NODE) { + str.append(child.getNodeValue()); + } + else if (type == Node.CDATA_SECTION_NODE) { + str.append(getChildText(child)); + } + child = child.getNextSibling(); + } + + // return text value + return str.toString(); + + } // getChildText(Node):String + + // return the name of this element + public static String getName(Node node) { + return node.getNodeName(); + } // getLocalName(Element): String + + /** returns local name of this element if not null, otherwise + returns the name of the node + */ + public static String getLocalName(Node node) { + String name = node.getLocalName(); + return (name!=null)? name:node.getNodeName(); + } // getLocalName(Element): String + + public static Element getParent(Element elem) { + Node parent = elem.getParentNode(); + if (parent instanceof Element) + return (Element)parent; + return null; + } // getParent(Element):Element + + // get the Document of which this Node is a part + public static Document getDocument(Node node) { + return node.getOwnerDocument(); + } // getDocument(Node):Document + + // return this Document's root node + public static Element getRoot(Document doc) { + return doc.getDocumentElement(); + } // getRoot(Document(: Element + + // some methods for handling attributes: + + // return the right attribute node + public static Attr getAttr(Element elem, String name) { + return elem.getAttributeNode(name); + } // getAttr(Element, String):Attr + + // return the right attribute node + public static Attr getAttrNS(Element elem, String nsUri, + String localName) { + return elem.getAttributeNodeNS(nsUri, localName); + } // getAttrNS(Element, String):Attr + + // get all the attributes for an Element + public static Attr[] getAttrs(Element elem) { + NamedNodeMap attrMap = elem.getAttributes(); + Attr [] attrArray = new Attr[attrMap.getLength()]; + for (int i=0; iUsed to format JAXP 1.3 Datatype API error messages using a specified locale.

        + * + * @author Neeraj Bajaj, Sun Microsystems + * @version $Id$ + */ +public class DatatypeMessageFormatter { + + private static final String BASE_NAME = "org.apache.xerces.impl.msg.DatatypeMessages"; + + /** + * Formats a message with the specified arguments using the given + * locale information. + * + * @param locale The locale of the message. + * @param key The message key. + * @param arguments The message replacement text arguments. The order + * of the arguments must match that of the placeholders + * in the actual message. + * + * @return the formatted message. + * + * @throws MissingResourceException Thrown if the message with the + * specified key cannot be found. + */ + public static String formatMessage(Locale locale, + String key, Object[] arguments) + throws MissingResourceException { + + if (locale == null) { + locale = Locale.getDefault(); + } + final ResourceBundle resourceBundle = + ResourceBundle.getBundle(BASE_NAME, locale); + + // format message + String msg; + try { + msg = resourceBundle.getString(key); + if (arguments != null) { + try { + msg = java.text.MessageFormat.format(msg, arguments); + } + catch (Exception e) { + msg = resourceBundle.getString("FormatFailed"); + msg += " " + resourceBundle.getString(key); + } + } + } + + // error + catch (MissingResourceException e) { + msg = resourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(key, msg, key); + } + + // no message + if (msg == null) { + msg = key; + if (arguments.length > 0) { + StringBuffer str = new StringBuffer(msg); + str.append('?'); + for (int i = 0; i < arguments.length; i++) { + if (i > 0) { + str.append('&'); + } + str.append(String.valueOf(arguments[i])); + } + } + } + return msg; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/DefaultErrorHandler.java b/resources/xerces2-j-src/org/apache/xerces/util/DefaultErrorHandler.java new file mode 100644 index 0000000..4d76981 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/DefaultErrorHandler.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.io.PrintWriter; + +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLParseException; + +/** + * Default error handler. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class DefaultErrorHandler + implements XMLErrorHandler { + + // + // Data + // + + /** Print writer. */ + protected PrintWriter fOut; + + // + // Constructors + // + + /** + * Constructs an error handler that prints error messages to + * System.err. + */ + public DefaultErrorHandler() { + this(new PrintWriter(System.err)); + } // () + + /** + * Constructs an error handler that prints error messages to the + * specified PrintWriter. + */ + public DefaultErrorHandler(PrintWriter out) { + fOut = out; + } // (PrintWriter) + + // + // ErrorHandler methods + // + + /** Warning. */ + public void warning(String domain, String key, XMLParseException ex) + throws XNIException { + printError("Warning", ex); + } // warning(XMLParseException) + + /** Error. */ + public void error(String domain, String key, XMLParseException ex) + throws XNIException { + printError("Error", ex); + } // error(XMLParseException) + + /** Fatal error. */ + public void fatalError(String domain, String key, XMLParseException ex) + throws XNIException { + printError("Fatal Error", ex); + throw ex; + } // fatalError(XMLParseException) + + // + // Private methods + // + + /** Prints the error message. */ + private void printError(String type, XMLParseException ex) { + + fOut.print("["); + fOut.print(type); + fOut.print("] "); + String systemId = ex.getExpandedSystemId(); + if (systemId != null) { + int index = systemId.lastIndexOf('/'); + if (index != -1) + systemId = systemId.substring(index + 1); + fOut.print(systemId); + } + fOut.print(':'); + fOut.print(ex.getLineNumber()); + fOut.print(':'); + fOut.print(ex.getColumnNumber()); + fOut.print(": "); + fOut.print(ex.getMessage()); + fOut.println(); + fOut.flush(); + + } // printError(String,SAXParseException) + +} // class DefaultErrorHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/util/EncodingMap.java b/resources/xerces2-j-src/org/apache/xerces/util/EncodingMap.java new file mode 100644 index 0000000..45c6b61 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/EncodingMap.java @@ -0,0 +1,1028 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Hashtable; + +/** + * EncodingMap is a convenience class which handles conversions between + * IANA encoding names and Java encoding names, and vice versa. The + * encoding names used in XML instance documents must + * be the IANA encoding names specified or one of the aliases for those names + * which IANA defines. + *

        + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
        + *

        Common Name + *

        + *

        Use this name in XML files + *

        + *

        Name Type + *

        + *

        Xerces converts to this Java Encoder Name + *

        8 bit Unicode + *

        UTF-8 + *

        + *

        IANA + *

        + *

        UTF8 + *

        ISO Latin 1 + *

        ISO-8859-1 + *

        + *

        MIME + *

        + *

        ISO-8859-1 + *

        ISO Latin 2 + *

        ISO-8859-2 + *

        + *

        MIME + *

        + *

        ISO-8859-2 + *

        ISO Latin 3 + *

        ISO-8859-3 + *

        + *

        MIME + *

        + *

        ISO-8859-3 + *

        ISO Latin 4 + *

        ISO-8859-4 + *

        + *

        MIME + *

        + *

        ISO-8859-4 + *

        ISO Latin Cyrillic + *

        ISO-8859-5 + *

        + *

        MIME + *

        + *

        ISO-8859-5 + *

        ISO Latin Arabic + *

        ISO-8859-6 + *

        + *

        MIME + *

        + *

        ISO-8859-6 + *

        ISO Latin Greek + *

        ISO-8859-7 + *

        + *

        MIME + *

        + *

        ISO-8859-7 + *

        ISO Latin Hebrew + *

        ISO-8859-8 + *

        + *

        MIME + *

        + *

        ISO-8859-8 + *

        ISO Latin 5 + *

        ISO-8859-9 + *

        + *

        MIME + *

        + *

        ISO-8859-9 + *

        EBCDIC: US + *

        ebcdic-cp-us + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Canada + *

        ebcdic-cp-ca + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Netherlands + *

        ebcdic-cp-nl + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Denmark + *

        ebcdic-cp-dk + *

        + *

        IANA + *

        + *

        cp277 + *

        EBCDIC: Norway + *

        ebcdic-cp-no + *

        + *

        IANA + *

        + *

        cp277 + *

        EBCDIC: Finland + *

        ebcdic-cp-fi + *

        + *

        IANA + *

        + *

        cp278 + *

        EBCDIC: Sweden + *

        ebcdic-cp-se + *

        + *

        IANA + *

        + *

        cp278 + *

        EBCDIC: Italy + *

        ebcdic-cp-it + *

        + *

        IANA + *

        + *

        cp280 + *

        EBCDIC: Spain, Latin America + *

        ebcdic-cp-es + *

        + *

        IANA + *

        + *

        cp284 + *

        EBCDIC: Great Britain + *

        ebcdic-cp-gb + *

        + *

        IANA + *

        + *

        cp285 + *

        EBCDIC: France + *

        ebcdic-cp-fr + *

        + *

        IANA + *

        + *

        cp297 + *

        EBCDIC: Arabic + *

        ebcdic-cp-ar1 + *

        + *

        IANA + *

        + *

        cp420 + *

        EBCDIC: Hebrew + *

        ebcdic-cp-he + *

        + *

        IANA + *

        + *

        cp424 + *

        EBCDIC: Switzerland + *

        ebcdic-cp-ch + *

        + *

        IANA + *

        + *

        cp500 + *

        EBCDIC: Roece + *

        ebcdic-cp-roece + *

        + *

        IANA + *

        + *

        cp870 + *

        EBCDIC: Yugoslavia + *

        ebcdic-cp-yu + *

        + *

        IANA + *

        + *

        cp870 + *

        EBCDIC: Iceland + *

        ebcdic-cp-is + *

        + *

        IANA + *

        + *

        cp871 + *

        EBCDIC: Urdu + *

        ebcdic-cp-ar2 + *

        + *

        IANA + *

        + *

        cp918 + *

        Chinese for PRC, mixed 1/2 byte + *

        gb2312 + *

        + *

        MIME + *

        + *

        GB2312 + *

        Extended Unix Code, packed for Japanese + *

        euc-jp + *

        + *

        MIME + *

        + *

        eucjis + *

        Japanese: iso-2022-jp + *

        iso-2020-jp + *

        + *

        MIME + *

        + *

        JIS + *

        Japanese: Shift JIS + *

        Shift_JIS + *

        + *

        MIME + *

        + *

        SJIS + *

        Chinese: Big5 + *

        Big5 + *

        + *

        MIME + *

        + *

        Big5 + *

        Extended Unix Code, packed for Korean + *

        euc-kr + *

        + *

        MIME + *

        + *

        iso2022kr + *

        Cyrillic + *

        koi8-r + *

        + *

        MIME + *

        + *

        koi8-r + *

        + * + * @author TAMURA Kent, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class EncodingMap { + + // + // Data + // + + /** fIANA2JavaMap */ + protected final static Hashtable fIANA2JavaMap = new Hashtable(); + + /** fJava2IANAMap */ + protected final static Hashtable fJava2IANAMap = new Hashtable(); + + // + // Static initialization + // + + static { + + // add IANA to Java encoding mappings. + fIANA2JavaMap.put("BIG5", "Big5"); + fIANA2JavaMap.put("CSBIG5", "Big5"); + fIANA2JavaMap.put("CP037", "CP037"); + fIANA2JavaMap.put("IBM037", "CP037"); + fIANA2JavaMap.put("CSIBM037", "CP037"); + fIANA2JavaMap.put("EBCDIC-CP-US", "CP037"); + fIANA2JavaMap.put("EBCDIC-CP-CA", "CP037"); + fIANA2JavaMap.put("EBCDIC-CP-NL", "CP037"); + fIANA2JavaMap.put("EBCDIC-CP-WT", "CP037"); + fIANA2JavaMap.put("IBM273", "CP273"); + fIANA2JavaMap.put("CP273", "CP273"); + fIANA2JavaMap.put("CSIBM273", "CP273"); + fIANA2JavaMap.put("IBM277", "CP277"); + fIANA2JavaMap.put("CP277", "CP277"); + fIANA2JavaMap.put("CSIBM277", "CP277"); + fIANA2JavaMap.put("EBCDIC-CP-DK", "CP277"); + fIANA2JavaMap.put("EBCDIC-CP-NO", "CP277"); + fIANA2JavaMap.put("IBM278", "CP278"); + fIANA2JavaMap.put("CP278", "CP278"); + fIANA2JavaMap.put("CSIBM278", "CP278"); + fIANA2JavaMap.put("EBCDIC-CP-FI", "CP278"); + fIANA2JavaMap.put("EBCDIC-CP-SE", "CP278"); + fIANA2JavaMap.put("IBM280", "CP280"); + fIANA2JavaMap.put("CP280", "CP280"); + fIANA2JavaMap.put("CSIBM280", "CP280"); + fIANA2JavaMap.put("EBCDIC-CP-IT", "CP280"); + fIANA2JavaMap.put("IBM284", "CP284"); + fIANA2JavaMap.put("CP284", "CP284"); + fIANA2JavaMap.put("CSIBM284", "CP284"); + fIANA2JavaMap.put("EBCDIC-CP-ES", "CP284"); + fIANA2JavaMap.put("EBCDIC-CP-GB", "CP285"); + fIANA2JavaMap.put("IBM285", "CP285"); + fIANA2JavaMap.put("CP285", "CP285"); + fIANA2JavaMap.put("CSIBM285", "CP285"); + fIANA2JavaMap.put("EBCDIC-JP-KANA", "CP290"); + fIANA2JavaMap.put("IBM290", "CP290"); + fIANA2JavaMap.put("CP290", "CP290"); + fIANA2JavaMap.put("CSIBM290", "CP290"); + fIANA2JavaMap.put("EBCDIC-CP-FR", "CP297"); + fIANA2JavaMap.put("IBM297", "CP297"); + fIANA2JavaMap.put("CP297", "CP297"); + fIANA2JavaMap.put("CSIBM297", "CP297"); + fIANA2JavaMap.put("EBCDIC-CP-AR1", "CP420"); + fIANA2JavaMap.put("IBM420", "CP420"); + fIANA2JavaMap.put("CP420", "CP420"); + fIANA2JavaMap.put("CSIBM420", "CP420"); + fIANA2JavaMap.put("EBCDIC-CP-HE", "CP424"); + fIANA2JavaMap.put("IBM424", "CP424"); + fIANA2JavaMap.put("CP424", "CP424"); + fIANA2JavaMap.put("CSIBM424", "CP424"); + fIANA2JavaMap.put("IBM437", "CP437"); + fIANA2JavaMap.put("437", "CP437"); + fIANA2JavaMap.put("CP437", "CP437"); + fIANA2JavaMap.put("CSPC8CODEPAGE437", "CP437"); + fIANA2JavaMap.put("EBCDIC-CP-CH", "CP500"); + fIANA2JavaMap.put("IBM500", "CP500"); + fIANA2JavaMap.put("CP500", "CP500"); + fIANA2JavaMap.put("CSIBM500", "CP500"); + fIANA2JavaMap.put("EBCDIC-CP-CH", "CP500"); + fIANA2JavaMap.put("EBCDIC-CP-BE", "CP500"); + fIANA2JavaMap.put("IBM775", "CP775"); + fIANA2JavaMap.put("CP775", "CP775"); + fIANA2JavaMap.put("CSPC775BALTIC", "CP775"); + fIANA2JavaMap.put("IBM850", "CP850"); + fIANA2JavaMap.put("850", "CP850"); + fIANA2JavaMap.put("CP850", "CP850"); + fIANA2JavaMap.put("CSPC850MULTILINGUAL", "CP850"); + fIANA2JavaMap.put("IBM852", "CP852"); + fIANA2JavaMap.put("852", "CP852"); + fIANA2JavaMap.put("CP852", "CP852"); + fIANA2JavaMap.put("CSPCP852", "CP852"); + fIANA2JavaMap.put("IBM855", "CP855"); + fIANA2JavaMap.put("855", "CP855"); + fIANA2JavaMap.put("CP855", "CP855"); + fIANA2JavaMap.put("CSIBM855", "CP855"); + fIANA2JavaMap.put("IBM857", "CP857"); + fIANA2JavaMap.put("857", "CP857"); + fIANA2JavaMap.put("CP857", "CP857"); + fIANA2JavaMap.put("CSIBM857", "CP857"); + fIANA2JavaMap.put("IBM00858", "CP858"); + fIANA2JavaMap.put("CP00858", "CP858"); + fIANA2JavaMap.put("CCSID00858", "CP858"); + fIANA2JavaMap.put("IBM860", "CP860"); + fIANA2JavaMap.put("860", "CP860"); + fIANA2JavaMap.put("CP860", "CP860"); + fIANA2JavaMap.put("CSIBM860", "CP860"); + fIANA2JavaMap.put("IBM861", "CP861"); + fIANA2JavaMap.put("861", "CP861"); + fIANA2JavaMap.put("CP861", "CP861"); + fIANA2JavaMap.put("CP-IS", "CP861"); + fIANA2JavaMap.put("CSIBM861", "CP861"); + fIANA2JavaMap.put("IBM862", "CP862"); + fIANA2JavaMap.put("862", "CP862"); + fIANA2JavaMap.put("CP862", "CP862"); + fIANA2JavaMap.put("CSPC862LATINHEBREW", "CP862"); + fIANA2JavaMap.put("IBM863", "CP863"); + fIANA2JavaMap.put("863", "CP863"); + fIANA2JavaMap.put("CP863", "CP863"); + fIANA2JavaMap.put("CSIBM863", "CP863"); + fIANA2JavaMap.put("IBM864", "CP864"); + fIANA2JavaMap.put("CP864", "CP864"); + fIANA2JavaMap.put("CSIBM864", "CP864"); + fIANA2JavaMap.put("IBM865", "CP865"); + fIANA2JavaMap.put("865", "CP865"); + fIANA2JavaMap.put("CP865", "CP865"); + fIANA2JavaMap.put("CSIBM865", "CP865"); + fIANA2JavaMap.put("IBM866", "CP866"); + fIANA2JavaMap.put("866", "CP866"); + fIANA2JavaMap.put("CP866", "CP866"); + fIANA2JavaMap.put("CSIBM866", "CP866"); + fIANA2JavaMap.put("IBM868", "CP868"); + fIANA2JavaMap.put("CP868", "CP868"); + fIANA2JavaMap.put("CSIBM868", "CP868"); + fIANA2JavaMap.put("CP-AR", "CP868"); + fIANA2JavaMap.put("IBM869", "CP869"); + fIANA2JavaMap.put("CP869", "CP869"); + fIANA2JavaMap.put("CSIBM869", "CP869"); + fIANA2JavaMap.put("CP-GR", "CP869"); + fIANA2JavaMap.put("IBM870", "CP870"); + fIANA2JavaMap.put("CP870", "CP870"); + fIANA2JavaMap.put("CSIBM870", "CP870"); + fIANA2JavaMap.put("EBCDIC-CP-ROECE", "CP870"); + fIANA2JavaMap.put("EBCDIC-CP-YU", "CP870"); + fIANA2JavaMap.put("IBM871", "CP871"); + fIANA2JavaMap.put("CP871", "CP871"); + fIANA2JavaMap.put("CSIBM871", "CP871"); + fIANA2JavaMap.put("EBCDIC-CP-IS", "CP871"); + fIANA2JavaMap.put("IBM918", "CP918"); + fIANA2JavaMap.put("CP918", "CP918"); + fIANA2JavaMap.put("CSIBM918", "CP918"); + fIANA2JavaMap.put("EBCDIC-CP-AR2", "CP918"); + fIANA2JavaMap.put("IBM00924", "CP924"); + fIANA2JavaMap.put("CP00924", "CP924"); + fIANA2JavaMap.put("CCSID00924", "CP924"); + // is this an error??? + fIANA2JavaMap.put("EBCDIC-LATIN9--EURO", "CP924"); + fIANA2JavaMap.put("IBM1026", "CP1026"); + fIANA2JavaMap.put("CP1026", "CP1026"); + fIANA2JavaMap.put("CSIBM1026", "CP1026"); + fIANA2JavaMap.put("IBM01140", "Cp1140"); + fIANA2JavaMap.put("CP01140", "Cp1140"); + fIANA2JavaMap.put("CCSID01140", "Cp1140"); + fIANA2JavaMap.put("IBM01141", "Cp1141"); + fIANA2JavaMap.put("CP01141", "Cp1141"); + fIANA2JavaMap.put("CCSID01141", "Cp1141"); + fIANA2JavaMap.put("IBM01142", "Cp1142"); + fIANA2JavaMap.put("CP01142", "Cp1142"); + fIANA2JavaMap.put("CCSID01142", "Cp1142"); + fIANA2JavaMap.put("IBM01143", "Cp1143"); + fIANA2JavaMap.put("CP01143", "Cp1143"); + fIANA2JavaMap.put("CCSID01143", "Cp1143"); + fIANA2JavaMap.put("IBM01144", "Cp1144"); + fIANA2JavaMap.put("CP01144", "Cp1144"); + fIANA2JavaMap.put("CCSID01144", "Cp1144"); + fIANA2JavaMap.put("IBM01145", "Cp1145"); + fIANA2JavaMap.put("CP01145", "Cp1145"); + fIANA2JavaMap.put("CCSID01145", "Cp1145"); + fIANA2JavaMap.put("IBM01146", "Cp1146"); + fIANA2JavaMap.put("CP01146", "Cp1146"); + fIANA2JavaMap.put("CCSID01146", "Cp1146"); + fIANA2JavaMap.put("IBM01147", "Cp1147"); + fIANA2JavaMap.put("CP01147", "Cp1147"); + fIANA2JavaMap.put("CCSID01147", "Cp1147"); + fIANA2JavaMap.put("IBM01148", "Cp1148"); + fIANA2JavaMap.put("CP01148", "Cp1148"); + fIANA2JavaMap.put("CCSID01148", "Cp1148"); + fIANA2JavaMap.put("IBM01149", "Cp1149"); + fIANA2JavaMap.put("CP01149", "Cp1149"); + fIANA2JavaMap.put("CCSID01149", "Cp1149"); + fIANA2JavaMap.put("EUC-JP", "EUCJIS"); + fIANA2JavaMap.put("CSEUCPKDFMTJAPANESE", "EUCJIS"); + fIANA2JavaMap.put("EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE", "EUCJIS"); + fIANA2JavaMap.put("EUC-KR", "KSC5601"); + fIANA2JavaMap.put("CSEUCKR", "KSC5601"); + fIANA2JavaMap.put("KS_C_5601-1987", "KS_C_5601-1987"); + fIANA2JavaMap.put("ISO-IR-149", "KS_C_5601-1987"); + fIANA2JavaMap.put("KS_C_5601-1989", "KS_C_5601-1987"); + fIANA2JavaMap.put("KSC_5601", "KS_C_5601-1987"); + fIANA2JavaMap.put("KOREAN", "KS_C_5601-1987"); + fIANA2JavaMap.put("CSKSC56011987", "KS_C_5601-1987"); + fIANA2JavaMap.put("GB2312", "GB2312"); + fIANA2JavaMap.put("CSGB2312", "GB2312"); + fIANA2JavaMap.put("ISO-2022-JP", "JIS"); + fIANA2JavaMap.put("CSISO2022JP", "JIS"); + fIANA2JavaMap.put("ISO-2022-KR", "ISO2022KR"); + fIANA2JavaMap.put("CSISO2022KR", "ISO2022KR"); + fIANA2JavaMap.put("ISO-2022-CN", "ISO2022CN"); + + fIANA2JavaMap.put("X0201", "JIS0201"); + fIANA2JavaMap.put("CSISO13JISC6220JP", "JIS0201"); + fIANA2JavaMap.put("X0208", "JIS0208"); + fIANA2JavaMap.put("ISO-IR-87", "JIS0208"); + fIANA2JavaMap.put("X0208dbiJIS_X0208-1983", "JIS0208"); + fIANA2JavaMap.put("CSISO87JISX0208", "JIS0208"); + fIANA2JavaMap.put("X0212", "JIS0212"); + fIANA2JavaMap.put("ISO-IR-159", "JIS0212"); + fIANA2JavaMap.put("CSISO159JISX02121990", "JIS0212"); + fIANA2JavaMap.put("GB18030", "GB18030"); + fIANA2JavaMap.put("GBK", "GBK"); + fIANA2JavaMap.put("CP936", "GBK"); + fIANA2JavaMap.put("MS936", "GBK"); + fIANA2JavaMap.put("WINDOWS-936", "GBK"); + fIANA2JavaMap.put("SHIFT_JIS", "SJIS"); + fIANA2JavaMap.put("CSSHIFTJIS", "SJIS"); + fIANA2JavaMap.put("MS_KANJI", "SJIS"); + fIANA2JavaMap.put("WINDOWS-31J", "MS932"); + fIANA2JavaMap.put("CSWINDOWS31J", "MS932"); + + // Add support for Cp1252 and its friends + fIANA2JavaMap.put("WINDOWS-1250", "Cp1250"); + fIANA2JavaMap.put("WINDOWS-1251", "Cp1251"); + fIANA2JavaMap.put("WINDOWS-1252", "Cp1252"); + fIANA2JavaMap.put("WINDOWS-1253", "Cp1253"); + fIANA2JavaMap.put("WINDOWS-1254", "Cp1254"); + fIANA2JavaMap.put("WINDOWS-1255", "Cp1255"); + fIANA2JavaMap.put("WINDOWS-1256", "Cp1256"); + fIANA2JavaMap.put("WINDOWS-1257", "Cp1257"); + fIANA2JavaMap.put("WINDOWS-1258", "Cp1258"); + fIANA2JavaMap.put("TIS-620", "TIS620"); + + fIANA2JavaMap.put("ISO-8859-1", "ISO8859_1"); + fIANA2JavaMap.put("ISO-IR-100", "ISO8859_1"); + fIANA2JavaMap.put("ISO_8859-1", "ISO8859_1"); + fIANA2JavaMap.put("LATIN1", "ISO8859_1"); + fIANA2JavaMap.put("CSISOLATIN1", "ISO8859_1"); + fIANA2JavaMap.put("L1", "ISO8859_1"); + fIANA2JavaMap.put("IBM819", "ISO8859_1"); + fIANA2JavaMap.put("CP819", "ISO8859_1"); + + fIANA2JavaMap.put("ISO-8859-2", "ISO8859_2"); + fIANA2JavaMap.put("ISO-IR-101", "ISO8859_2"); + fIANA2JavaMap.put("ISO_8859-2", "ISO8859_2"); + fIANA2JavaMap.put("LATIN2", "ISO8859_2"); + fIANA2JavaMap.put("CSISOLATIN2", "ISO8859_2"); + fIANA2JavaMap.put("L2", "ISO8859_2"); + + fIANA2JavaMap.put("ISO-8859-3", "ISO8859_3"); + fIANA2JavaMap.put("ISO-IR-109", "ISO8859_3"); + fIANA2JavaMap.put("ISO_8859-3", "ISO8859_3"); + fIANA2JavaMap.put("LATIN3", "ISO8859_3"); + fIANA2JavaMap.put("CSISOLATIN3", "ISO8859_3"); + fIANA2JavaMap.put("L3", "ISO8859_3"); + + fIANA2JavaMap.put("ISO-8859-4", "ISO8859_4"); + fIANA2JavaMap.put("ISO-IR-110", "ISO8859_4"); + fIANA2JavaMap.put("ISO_8859-4", "ISO8859_4"); + fIANA2JavaMap.put("LATIN4", "ISO8859_4"); + fIANA2JavaMap.put("CSISOLATIN4", "ISO8859_4"); + fIANA2JavaMap.put("L4", "ISO8859_4"); + + fIANA2JavaMap.put("ISO-8859-5", "ISO8859_5"); + fIANA2JavaMap.put("ISO-IR-144", "ISO8859_5"); + fIANA2JavaMap.put("ISO_8859-5", "ISO8859_5"); + fIANA2JavaMap.put("CYRILLIC", "ISO8859_5"); + fIANA2JavaMap.put("CSISOLATINCYRILLIC", "ISO8859_5"); + + fIANA2JavaMap.put("ISO-8859-6", "ISO8859_6"); + fIANA2JavaMap.put("ISO-IR-127", "ISO8859_6"); + fIANA2JavaMap.put("ISO_8859-6", "ISO8859_6"); + fIANA2JavaMap.put("ECMA-114", "ISO8859_6"); + fIANA2JavaMap.put("ASMO-708", "ISO8859_6"); + fIANA2JavaMap.put("ARABIC", "ISO8859_6"); + fIANA2JavaMap.put("CSISOLATINARABIC", "ISO8859_6"); + + fIANA2JavaMap.put("ISO-8859-7", "ISO8859_7"); + fIANA2JavaMap.put("ISO-IR-126", "ISO8859_7"); + fIANA2JavaMap.put("ISO_8859-7", "ISO8859_7"); + fIANA2JavaMap.put("ELOT_928", "ISO8859_7"); + fIANA2JavaMap.put("ECMA-118", "ISO8859_7"); + fIANA2JavaMap.put("GREEK", "ISO8859_7"); + fIANA2JavaMap.put("CSISOLATINGREEK", "ISO8859_7"); + fIANA2JavaMap.put("GREEK8", "ISO8859_7"); + + fIANA2JavaMap.put("ISO-8859-8", "ISO8859_8"); + fIANA2JavaMap.put("ISO-8859-8-I", "ISO8859_8"); // added since this encoding only differs w.r.t. presentation + fIANA2JavaMap.put("ISO-IR-138", "ISO8859_8"); + fIANA2JavaMap.put("ISO_8859-8", "ISO8859_8"); + fIANA2JavaMap.put("HEBREW", "ISO8859_8"); + fIANA2JavaMap.put("CSISOLATINHEBREW", "ISO8859_8"); + + fIANA2JavaMap.put("ISO-8859-9", "ISO8859_9"); + fIANA2JavaMap.put("ISO-IR-148", "ISO8859_9"); + fIANA2JavaMap.put("ISO_8859-9", "ISO8859_9"); + fIANA2JavaMap.put("LATIN5", "ISO8859_9"); + fIANA2JavaMap.put("CSISOLATIN5", "ISO8859_9"); + fIANA2JavaMap.put("L5", "ISO8859_9"); + + fIANA2JavaMap.put("ISO-8859-13", "ISO8859_13"); + + fIANA2JavaMap.put("ISO-8859-15", "ISO8859_15_FDIS"); + fIANA2JavaMap.put("ISO_8859-15", "ISO8859_15_FDIS"); + fIANA2JavaMap.put("LATIN-9", "ISO8859_15_FDIS"); + + fIANA2JavaMap.put("KOI8-R", "KOI8_R"); + fIANA2JavaMap.put("CSKOI8R", "KOI8_R"); + fIANA2JavaMap.put("US-ASCII", "ASCII"); + fIANA2JavaMap.put("ISO-IR-6", "ASCII"); + fIANA2JavaMap.put("ANSI_X3.4-1968", "ASCII"); + fIANA2JavaMap.put("ANSI_X3.4-1986", "ASCII"); + fIANA2JavaMap.put("ISO_646.IRV:1991", "ASCII"); + fIANA2JavaMap.put("ASCII", "ASCII"); + fIANA2JavaMap.put("CSASCII", "ASCII"); + fIANA2JavaMap.put("ISO646-US", "ASCII"); + fIANA2JavaMap.put("US", "ASCII"); + fIANA2JavaMap.put("IBM367", "ASCII"); + fIANA2JavaMap.put("CP367", "ASCII"); + fIANA2JavaMap.put("UTF-8", "UTF8"); + fIANA2JavaMap.put("UTF-16", "UTF-16"); + fIANA2JavaMap.put("UTF-16BE", "UnicodeBig"); + fIANA2JavaMap.put("UTF-16LE", "UnicodeLittle"); + + // support for 1047, as proposed to be added to the + // IANA registry in + // http://lists.w3.org/Archives/Public/ietf-charset/2002JulSep/0049.html + fIANA2JavaMap.put("IBM-1047", "Cp1047"); + fIANA2JavaMap.put("IBM1047", "Cp1047"); + fIANA2JavaMap.put("CP1047", "Cp1047"); + + // Adding new aliases as proposed in + // http://lists.w3.org/Archives/Public/ietf-charset/2002JulSep/0058.html + fIANA2JavaMap.put("IBM-37", "CP037"); + fIANA2JavaMap.put("IBM-273", "CP273"); + fIANA2JavaMap.put("IBM-277", "CP277"); + fIANA2JavaMap.put("IBM-278", "CP278"); + fIANA2JavaMap.put("IBM-280", "CP280"); + fIANA2JavaMap.put("IBM-284", "CP284"); + fIANA2JavaMap.put("IBM-285", "CP285"); + fIANA2JavaMap.put("IBM-290", "CP290"); + fIANA2JavaMap.put("IBM-297", "CP297"); + fIANA2JavaMap.put("IBM-420", "CP420"); + fIANA2JavaMap.put("IBM-424", "CP424"); + fIANA2JavaMap.put("IBM-437", "CP437"); + fIANA2JavaMap.put("IBM-500", "CP500"); + fIANA2JavaMap.put("IBM-775", "CP775"); + fIANA2JavaMap.put("IBM-850", "CP850"); + fIANA2JavaMap.put("IBM-852", "CP852"); + fIANA2JavaMap.put("IBM-855", "CP855"); + fIANA2JavaMap.put("IBM-857", "CP857"); + fIANA2JavaMap.put("IBM-858", "CP858"); + fIANA2JavaMap.put("IBM-860", "CP860"); + fIANA2JavaMap.put("IBM-861", "CP861"); + fIANA2JavaMap.put("IBM-862", "CP862"); + fIANA2JavaMap.put("IBM-863", "CP863"); + fIANA2JavaMap.put("IBM-864", "CP864"); + fIANA2JavaMap.put("IBM-865", "CP865"); + fIANA2JavaMap.put("IBM-866", "CP866"); + fIANA2JavaMap.put("IBM-868", "CP868"); + fIANA2JavaMap.put("IBM-869", "CP869"); + fIANA2JavaMap.put("IBM-870", "CP870"); + fIANA2JavaMap.put("IBM-871", "CP871"); + fIANA2JavaMap.put("IBM-918", "CP918"); + fIANA2JavaMap.put("IBM-924", "CP924"); + fIANA2JavaMap.put("IBM-1026", "CP1026"); + fIANA2JavaMap.put("IBM-1140", "Cp1140"); + fIANA2JavaMap.put("IBM-1141", "Cp1141"); + fIANA2JavaMap.put("IBM-1142", "Cp1142"); + fIANA2JavaMap.put("IBM-1143", "Cp1143"); + fIANA2JavaMap.put("IBM-1144", "Cp1144"); + fIANA2JavaMap.put("IBM-1145", "Cp1145"); + fIANA2JavaMap.put("IBM-1146", "Cp1146"); + fIANA2JavaMap.put("IBM-1147", "Cp1147"); + fIANA2JavaMap.put("IBM-1148", "Cp1148"); + fIANA2JavaMap.put("IBM-1149", "Cp1149"); + fIANA2JavaMap.put("IBM-819", "ISO8859_1"); + fIANA2JavaMap.put("IBM-367", "ASCII"); + + // REVISIT: + // j:CNS11643 -> EUC-TW? + // ISO-2022-CN? ISO-2022-CN-EXT? + + // add Java to IANA encoding mappings + //fJava2IANAMap.put("8859_1", "US-ASCII"); // ? + fJava2IANAMap.put("ISO8859_1", "ISO-8859-1"); + fJava2IANAMap.put("ISO8859_2", "ISO-8859-2"); + fJava2IANAMap.put("ISO8859_3", "ISO-8859-3"); + fJava2IANAMap.put("ISO8859_4", "ISO-8859-4"); + fJava2IANAMap.put("ISO8859_5", "ISO-8859-5"); + fJava2IANAMap.put("ISO8859_6", "ISO-8859-6"); + fJava2IANAMap.put("ISO8859_7", "ISO-8859-7"); + fJava2IANAMap.put("ISO8859_8", "ISO-8859-8"); + fJava2IANAMap.put("ISO8859_9", "ISO-8859-9"); + fJava2IANAMap.put("ISO8859_13", "ISO-8859-13"); + fJava2IANAMap.put("ISO8859_15", "ISO-8859-15"); + fJava2IANAMap.put("ISO8859_15_FDIS", "ISO-8859-15"); + fJava2IANAMap.put("Big5", "BIG5"); + fJava2IANAMap.put("CP037", "EBCDIC-CP-US"); + fJava2IANAMap.put("CP273", "IBM273"); + fJava2IANAMap.put("CP277", "EBCDIC-CP-DK"); + fJava2IANAMap.put("CP278", "EBCDIC-CP-FI"); + fJava2IANAMap.put("CP280", "EBCDIC-CP-IT"); + fJava2IANAMap.put("CP284", "EBCDIC-CP-ES"); + fJava2IANAMap.put("CP285", "EBCDIC-CP-GB"); + fJava2IANAMap.put("CP290", "EBCDIC-JP-KANA"); + fJava2IANAMap.put("CP297", "EBCDIC-CP-FR"); + fJava2IANAMap.put("CP420", "EBCDIC-CP-AR1"); + fJava2IANAMap.put("CP424", "EBCDIC-CP-HE"); + fJava2IANAMap.put("CP437", "IBM437"); + fJava2IANAMap.put("CP500", "EBCDIC-CP-CH"); + fJava2IANAMap.put("CP775", "IBM775"); + fJava2IANAMap.put("CP850", "IBM850"); + fJava2IANAMap.put("CP852", "IBM852"); + fJava2IANAMap.put("CP855", "IBM855"); + fJava2IANAMap.put("CP857", "IBM857"); + fJava2IANAMap.put("CP858", "IBM00858"); + fJava2IANAMap.put("CP860", "IBM860"); + fJava2IANAMap.put("CP861", "IBM861"); + fJava2IANAMap.put("CP862", "IBM862"); + fJava2IANAMap.put("CP863", "IBM863"); + fJava2IANAMap.put("CP864", "IBM864"); + fJava2IANAMap.put("CP865", "IBM865"); + fJava2IANAMap.put("CP866", "IBM866"); + fJava2IANAMap.put("CP868", "IBM868"); + fJava2IANAMap.put("CP869", "IBM869"); + fJava2IANAMap.put("CP870", "EBCDIC-CP-ROECE"); + fJava2IANAMap.put("CP871", "EBCDIC-CP-IS"); + fJava2IANAMap.put("CP918", "EBCDIC-CP-AR2"); + fJava2IANAMap.put("CP924", "IBM00924"); + fJava2IANAMap.put("CP1026", "IBM1026"); + fJava2IANAMap.put("CP1140", "IBM01140"); + fJava2IANAMap.put("CP1141", "IBM01141"); + fJava2IANAMap.put("CP1142", "IBM01142"); + fJava2IANAMap.put("CP1143", "IBM01143"); + fJava2IANAMap.put("CP1144", "IBM01144"); + fJava2IANAMap.put("CP1145", "IBM01145"); + fJava2IANAMap.put("CP1146", "IBM01146"); + fJava2IANAMap.put("CP1147", "IBM01147"); + fJava2IANAMap.put("CP1148", "IBM01148"); + fJava2IANAMap.put("CP1149", "IBM01149"); + fJava2IANAMap.put("EUCJIS", "EUC-JP"); + fJava2IANAMap.put("KS_C_5601-1987", "KS_C_5601-1987"); + fJava2IANAMap.put("GB2312", "GB2312"); + fJava2IANAMap.put("ISO2022KR", "ISO-2022-KR"); + fJava2IANAMap.put("ISO2022CN", "ISO-2022-CN"); + fJava2IANAMap.put("JIS", "ISO-2022-JP"); + fJava2IANAMap.put("KOI8_R", "KOI8-R"); + fJava2IANAMap.put("KSC5601", "EUC-KR"); + fJava2IANAMap.put("GB18030", "GB18030"); + fJava2IANAMap.put("GBK", "GBK"); + fJava2IANAMap.put("SJIS", "SHIFT_JIS"); + fJava2IANAMap.put("MS932", "WINDOWS-31J"); + fJava2IANAMap.put("UTF8", "UTF-8"); + fJava2IANAMap.put("Unicode", "UTF-16"); + fJava2IANAMap.put("UnicodeBig", "UTF-16BE"); + fJava2IANAMap.put("UnicodeLittle", "UTF-16LE"); + fJava2IANAMap.put("JIS0201", "X0201"); + fJava2IANAMap.put("JIS0208", "X0208"); + fJava2IANAMap.put("JIS0212", "ISO-IR-159"); + + // proposed addition (see above for details): + fJava2IANAMap.put("CP1047", "IBM1047"); + + } // () + + // + // Constructors + // + + /** Default constructor. */ + public EncodingMap() {} + + // + // Public static methods + // + + /** + * Adds an IANA to Java encoding name mapping. + * + * @param ianaEncoding The IANA encoding name. + * @param javaEncoding The Java encoding name. + * + * @deprecated Use of this method is not recommended. Its + * effect is JVM wide and may cause unforeseen behaviour + * for other applications running in the system. + */ + public static void putIANA2JavaMapping(String ianaEncoding, + String javaEncoding) { + fIANA2JavaMap.put(ianaEncoding, javaEncoding); + } // putIANA2JavaMapping(String,String) + + /** + * Returns the Java encoding name for the specified IANA encoding name. + * + * @param ianaEncoding The IANA encoding name. + */ + public static String getIANA2JavaMapping(String ianaEncoding) { + return (String)fIANA2JavaMap.get(ianaEncoding); + } // getIANA2JavaMapping(String):String + + /** + * Removes an IANA to Java encoding name mapping. + * + * @param ianaEncoding The IANA encoding name. + * + * @deprecated Use of this method is not recommended. Its + * effect is JVM wide and may cause unforeseen behaviour + * for other applications running in the system. + */ + public static String removeIANA2JavaMapping(String ianaEncoding) { + return (String)fIANA2JavaMap.remove(ianaEncoding); + } // removeIANA2JavaMapping(String):String + + /** + * Adds a Java to IANA encoding name mapping. + * + * @param javaEncoding The Java encoding name. + * @param ianaEncoding The IANA encoding name. + * + * @deprecated Use of this method is not recommended. Its + * effect is JVM wide and may cause unforeseen behaviour + * for other applications running in the system. + */ + public static void putJava2IANAMapping(String javaEncoding, + String ianaEncoding) { + fJava2IANAMap.put(javaEncoding, ianaEncoding); + } // putJava2IANAMapping(String,String) + + /** + * Returns the IANA encoding name for the specified Java encoding name. + * + * @param javaEncoding The Java encoding name. + */ + public static String getJava2IANAMapping(String javaEncoding) { + return (String)fJava2IANAMap.get(javaEncoding); + } // getJava2IANAMapping(String):String + + /** + * Removes a Java to IANA encoding name mapping. + * + * @param javaEncoding The Java encoding name. + * + * @deprecated Use of this method is not recommended. Its + * effect is JVM wide and may cause unforeseen behaviour + * for other applications running in the system. + */ + public static String removeJava2IANAMapping(String javaEncoding) { + return (String)fJava2IANAMap.remove(javaEncoding); + } // removeJava2IANAMapping + +} // class EncodingMap diff --git a/resources/xerces2-j-src/org/apache/xerces/util/EntityResolver2Wrapper.java b/resources/xerces2-j-src/org/apache/xerces/util/EntityResolver2Wrapper.java new file mode 100644 index 0000000..4754055 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/EntityResolver2Wrapper.java @@ -0,0 +1,212 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import org.apache.xerces.impl.ExternalSubsetResolver; +import org.apache.xerces.impl.XMLEntityDescription; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLDTDDescription; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.ext.EntityResolver2; + +/** + *

        This class wraps a SAX entity resolver (EntityResolver2) in an XNI entity resolver.

        + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class EntityResolver2Wrapper + implements ExternalSubsetResolver { + + // + // Data + // + + /** An instance of SAX2 Extensions 1.1's EntityResolver2. */ + protected EntityResolver2 fEntityResolver; + + // + // Constructors + // + + /** Default constructor. */ + public EntityResolver2Wrapper() {} + + /** + *

        Creates a new instance wrapping the given SAX entity resolver.

        + * + * @param entityResolver the SAX entity resolver to wrap + */ + public EntityResolver2Wrapper(EntityResolver2 entityResolver) { + setEntityResolver(entityResolver); + } // (EntityResolver2) + + // + // Public methods + // + + /** + *

        Sets the SAX entity resolver wrapped by this object.

        + * + * @param entityResolver the SAX entity resolver to wrap + */ + public void setEntityResolver(EntityResolver2 entityResolver) { + fEntityResolver = entityResolver; + } // setEntityResolver(EntityResolver2) + + /** + *

        Returns the SAX entity resolver wrapped by this object.

        + * + * @return the SAX entity resolver wrapped by this object + */ + public EntityResolver2 getEntityResolver() { + return fEntityResolver; + } // getEntityResolver():EntityResolver2 + + // + // ExternalSubsetResolver methods + // + + /** + *

        Locates an external subset for documents which do not explicitly + * provide one. If no external subset is provided, this method should + * return null.

        + * + * @param grammarDescription a description of the DTD + * + * @throws XNIException Thrown on general error. + * @throws IOException Thrown if resolved entity stream cannot be + * opened or some other i/o error occurs. + */ + public XMLInputSource getExternalSubset(XMLDTDDescription grammarDescription) + throws XNIException, IOException { + + if (fEntityResolver != null) { + + String name = grammarDescription.getRootName(); + String baseURI = grammarDescription.getBaseSystemId(); + + // Resolve using EntityResolver2 + try { + InputSource inputSource = fEntityResolver.getExternalSubset(name, baseURI); + return (inputSource != null) ? createXMLInputSource(inputSource, baseURI) : null; + } + // error resolving external subset + catch (SAXException e) { + Exception ex = e.getException(); + if (ex == null) { + ex = e; + } + throw new XNIException(ex); + } + } + + // unable to resolve external subset + return null; + + } // getExternalSubset(XMLDTDDescription):XMLInputSource + + // + // XMLEntityResolver methods + // + + /** + * Resolves an external parsed entity. If the entity cannot be + * resolved, this method should return null. + * + * @param resourceIdentifier contains the physical co-ordinates of the resource to be resolved + * + * @throws XNIException Thrown on general error. + * @throws IOException Thrown if resolved entity stream cannot be + * opened or some other i/o error occurs. + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) + throws XNIException, IOException { + + if (fEntityResolver != null) { + + String pubId = resourceIdentifier.getPublicId(); + String sysId = resourceIdentifier.getLiteralSystemId(); + String baseURI = resourceIdentifier.getBaseSystemId(); + String name = null; + if (resourceIdentifier instanceof XMLDTDDescription) { + name = "[dtd]"; + } + else if (resourceIdentifier instanceof XMLEntityDescription) { + name = ((XMLEntityDescription) resourceIdentifier).getEntityName(); + } + + // When both pubId and sysId are null, the user's entity resolver + // can do nothing about it. We'd better not bother calling it. + // This happens when the resourceIdentifier is a GrammarDescription, + // which describes a schema grammar of some namespace, but without + // any schema location hint. -Sg + if (pubId == null && sysId == null) { + return null; + } + + // Resolve using EntityResolver2 + try { + InputSource inputSource = + fEntityResolver.resolveEntity(name, pubId, baseURI, sysId); + return (inputSource != null) ? createXMLInputSource(inputSource, baseURI) : null; + } + // error resolving entity + catch (SAXException e) { + Exception ex = e.getException(); + if (ex == null) { + ex = e; + } + throw new XNIException(ex); + } + } + + // unable to resolve entity + return null; + + } // resolveEntity(XMLResourceIdentifier):XMLInputSource + + /** + * Creates an XMLInputSource from a SAX InputSource. + */ + private XMLInputSource createXMLInputSource(InputSource source, String baseURI) { + + String publicId = source.getPublicId(); + String systemId = source.getSystemId(); + String baseSystemId = baseURI; + InputStream byteStream = source.getByteStream(); + Reader charStream = source.getCharacterStream(); + String encoding = source.getEncoding(); + XMLInputSource xmlInputSource = + new XMLInputSource(publicId, systemId, baseSystemId); + xmlInputSource.setByteStream(byteStream); + xmlInputSource.setCharacterStream(charStream); + xmlInputSource.setEncoding(encoding); + return xmlInputSource; + + } // createXMLInputSource(InputSource,String):XMLInputSource + +} // class EntityResolver2Wrapper diff --git a/resources/xerces2-j-src/org/apache/xerces/util/EntityResolverWrapper.java b/resources/xerces2-j-src/org/apache/xerces/util/EntityResolverWrapper.java new file mode 100644 index 0000000..7158562 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/EntityResolverWrapper.java @@ -0,0 +1,138 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * This class wraps a SAX entity resolver in an XNI entity resolver. + * + * @see EntityResolver + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class EntityResolverWrapper + implements XMLEntityResolver { + + // + // Data + // + + /** The SAX entity resolver. */ + protected EntityResolver fEntityResolver; + + // + // Constructors + // + + /** Default constructor. */ + public EntityResolverWrapper() {} + + /** Wraps the specified SAX entity resolver. */ + public EntityResolverWrapper(EntityResolver entityResolver) { + setEntityResolver(entityResolver); + } // (EntityResolver) + + // + // Public methods + // + + /** Sets the SAX entity resolver. */ + public void setEntityResolver(EntityResolver entityResolver) { + fEntityResolver = entityResolver; + } // setEntityResolver(EntityResolver) + + /** Returns the SAX entity resolver. */ + public EntityResolver getEntityResolver() { + return fEntityResolver; + } // getEntityResolver():EntityResolver + + // + // XMLEntityResolver methods + // + + /** + * Resolves an external parsed entity. If the entity cannot be + * resolved, this method should return null. + * + * @param resourceIdentifier contains the physical co-ordinates of the resource to be resolved + * + * @throws XNIException Thrown on general error. + * @throws IOException Thrown if resolved entity stream cannot be + * opened or some other i/o error occurs. + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) + throws XNIException, IOException { + + // When both pubId and sysId are null, the user's entity resolver + // can do nothing about it. We'd better not bother calling it. + // This happens when the resourceIdentifier is a GrammarDescription, + // which describes a schema grammar of some namespace, but without + // any schema location hint. -Sg + String pubId = resourceIdentifier.getPublicId(); + String sysId = resourceIdentifier.getExpandedSystemId(); + if (pubId == null && sysId == null) + return null; + + // resolve entity using SAX entity resolver + if (fEntityResolver != null && resourceIdentifier != null) { + try { + InputSource inputSource = fEntityResolver.resolveEntity(pubId, sysId); + if (inputSource != null) { + String publicId = inputSource.getPublicId(); + String systemId = inputSource.getSystemId(); + String baseSystemId = resourceIdentifier.getBaseSystemId(); + InputStream byteStream = inputSource.getByteStream(); + Reader charStream = inputSource.getCharacterStream(); + String encoding = inputSource.getEncoding(); + XMLInputSource xmlInputSource = + new XMLInputSource(publicId, systemId, baseSystemId); + xmlInputSource.setByteStream(byteStream); + xmlInputSource.setCharacterStream(charStream); + xmlInputSource.setEncoding(encoding); + return xmlInputSource; + } + } + + // error resolving entity + catch (SAXException e) { + Exception ex = e.getException(); + if (ex == null) { + ex = e; + } + throw new XNIException(ex); + } + } + + // unable to resolve entity + return null; + + } // resolveEntity(String,String,String):XMLInputSource +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/ErrorHandlerProxy.java b/resources/xerces2-j-src/org/apache/xerces/util/ErrorHandlerProxy.java new file mode 100644 index 0000000..83a1dad --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/ErrorHandlerProxy.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * Wraps {@link XMLErrorHandler} and make it look like a SAX {@link ErrorHandler}. + * + *

        + * The derived class should override the {@link #getErrorHandler()} method + * so that it will return the correct {@link XMLErrorHandler} instance. + * This method will be called whenever an error/warning is found. + * + *

        + * Experience shows that it is better to store the actual + * {@link XMLErrorHandler} in one place and looks up that variable, + * rather than copying it into every component that needs an error handler + * and update all of them whenever it is changed, IMO. + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * + * @version $Id$ + */ +public abstract class ErrorHandlerProxy implements ErrorHandler { + + public void error(SAXParseException e) throws SAXException { + XMLErrorHandler eh = getErrorHandler(); + if (eh instanceof ErrorHandlerWrapper) { + ((ErrorHandlerWrapper)eh).fErrorHandler.error(e); + } + else { + eh.error("","",ErrorHandlerWrapper.createXMLParseException(e)); + } + // if an XNIException is thrown, just let it go. + // REVISIT: is this OK? or should we try to wrap it into SAXException? + } + + public void fatalError(SAXParseException e) throws SAXException { + XMLErrorHandler eh = getErrorHandler(); + if (eh instanceof ErrorHandlerWrapper) { + ((ErrorHandlerWrapper)eh).fErrorHandler.fatalError(e); + } + else { + eh.fatalError("","",ErrorHandlerWrapper.createXMLParseException(e)); + } + } + + public void warning(SAXParseException e) throws SAXException { + XMLErrorHandler eh = getErrorHandler(); + if (eh instanceof ErrorHandlerWrapper) { + ((ErrorHandlerWrapper)eh).fErrorHandler.warning(e); + } + else { + eh.warning("","",ErrorHandlerWrapper.createXMLParseException(e)); + } + } + + protected abstract XMLErrorHandler getErrorHandler(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/ErrorHandlerWrapper.java b/resources/xerces2-j-src/org/apache/xerces/util/ErrorHandlerWrapper.java new file mode 100644 index 0000000..59d481b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/ErrorHandlerWrapper.java @@ -0,0 +1,230 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLParseException; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * This class wraps a SAX error handler in an XNI error handler. + * + * @see ErrorHandler + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class ErrorHandlerWrapper + implements XMLErrorHandler { + + // + // Data + // + + /** The SAX error handler. */ + protected ErrorHandler fErrorHandler; + + // + // Constructors + // + + /** Default constructor. */ + public ErrorHandlerWrapper() {} + + /** Wraps the specified SAX error handler. */ + public ErrorHandlerWrapper(ErrorHandler errorHandler) { + setErrorHandler(errorHandler); + } // (ErrorHandler) + + // + // Public methods + // + + /** Sets the SAX error handler. */ + public void setErrorHandler(ErrorHandler errorHandler) { + fErrorHandler = errorHandler; + } // setErrorHandler(ErrorHandler) + + /** Returns the SAX error handler. */ + public ErrorHandler getErrorHandler() { + return fErrorHandler; + } // getErrorHandler():ErrorHandler + + // + // XMLErrorHandler methods + // + + /** + * Reports a warning. Warnings are non-fatal and can be safely ignored + * by most applications. + * + * @param domain The domain of the warning. The domain can be any + * string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevent specification or + * document pertaining to this warning. + * @param key The warning key. This key can be any string and + * is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + public void warning(String domain, String key, + XMLParseException exception) throws XNIException { + + if (fErrorHandler != null) { + SAXParseException saxException = createSAXParseException(exception); + + try { + fErrorHandler.warning(saxException); + } + catch (SAXParseException e) { + throw createXMLParseException(e); + } + catch (SAXException e) { + throw createXNIException(e); + } + } + + } // warning(String,String,XMLParseException) + + /** + * Reports an error. Errors are non-fatal and usually signify that the + * document is invalid with respect to its grammar(s). + * + * @param domain The domain of the error. The domain can be any + * string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevent specification or + * document pertaining to this error. + * @param key The error key. This key can be any string and + * is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + public void error(String domain, String key, + XMLParseException exception) throws XNIException { + + if (fErrorHandler != null) { + SAXParseException saxException = createSAXParseException(exception); + + try { + fErrorHandler.error(saxException); + } + catch (SAXParseException e) { + throw createXMLParseException(e); + } + catch (SAXException e) { + throw createXNIException(e); + } + } + + } // error(String,String,XMLParseException) + + /** + * Report a fatal error. Fatal errors usually occur when the document + * is not well-formed and signifies that the parser cannot continue + * normal operation. + *

        + * Note: The error handler should always + * throw an XNIException from this method. This exception + * can either be the same exception that is passed as a parameter to + * the method or a new XNI exception object. If the registered error + * handler fails to throw an exception, the continuing operation of + * the parser is undetermined. + * + * @param domain The domain of the fatal error. The domain can be + * any string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevent specification or + * document pertaining to this fatal error. + * @param key The fatal error key. This key can be any string + * and is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + public void fatalError(String domain, String key, + XMLParseException exception) throws XNIException { + + if (fErrorHandler != null) { + SAXParseException saxException = createSAXParseException(exception); + + try { + fErrorHandler.fatalError(saxException); + } + catch (SAXParseException e) { + throw createXMLParseException(e); + } + catch (SAXException e) { + throw createXNIException(e); + } + } + + } // fatalError(String,String,XMLParseException) + + // + // Protected methods + // + + /** Creates a SAXParseException from an XMLParseException. */ + protected static SAXParseException createSAXParseException(XMLParseException exception) { + return new SAXParseException(exception.getMessage(), + exception.getPublicId(), + exception.getExpandedSystemId(), + exception.getLineNumber(), + exception.getColumnNumber(), + exception.getException()); + } // createSAXParseException(XMLParseException):SAXParseException + + /** Creates an XMLParseException from a SAXParseException. */ + protected static XMLParseException createXMLParseException(SAXParseException exception) { + final String fPublicId = exception.getPublicId(); + final String fExpandedSystemId = exception.getSystemId(); + final int fLineNumber = exception.getLineNumber(); + final int fColumnNumber = exception.getColumnNumber(); + XMLLocator location = new XMLLocator() { + public String getPublicId() { return fPublicId; } + public String getExpandedSystemId() { return fExpandedSystemId; } + public String getBaseSystemId() { return null; } + public String getLiteralSystemId() { return null; } + public int getColumnNumber() { return fColumnNumber; } + public int getLineNumber() { return fLineNumber; } + public int getCharacterOffset() { return -1; } + public String getEncoding() { return null; } + public String getXMLVersion() { return null; } + }; + return new XMLParseException(location, exception.getMessage(),exception); + } // createXMLParseException(SAXParseException):XMLParseException + + /** Creates an XNIException from a SAXException. + NOTE: care should be taken *not* to call this with a SAXParseException; this will + lose information!!! */ + protected static XNIException createXNIException(SAXException exception) { + return new XNIException(exception.getMessage(),exception); + } // createXNIException(SAXException):XMLParseException +} // class ErrorHandlerWrapper diff --git a/resources/xerces2-j-src/org/apache/xerces/util/HTTPInputSource.java b/resources/xerces2-j-src/org/apache/xerces/util/HTTPInputSource.java new file mode 100644 index 0000000..5224141 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/HTTPInputSource.java @@ -0,0 +1,192 @@ +/* + * 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. + */ +package org.apache.xerces.util; + +import java.io.InputStream; +import java.io.Reader; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * This class represents an input source for an XML resource + * retrievable over HTTP. In addition to the properties + * provided by an XMLInputSource an HTTP input + * source also has HTTP request properties and a preference + * whether HTTP redirects will be followed. Note that these + * properties will only be used if reading this input source + * will induce an HTTP connection. + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class HTTPInputSource extends XMLInputSource { + + // + // Data + // + + /** Preference for whether HTTP redirects should be followed. **/ + protected boolean fFollowRedirects = true; + + /** HTTP request properties. **/ + protected Map fHTTPRequestProperties = new HashMap(); + + // + // Constructors + // + + /** + * Constructs an input source from just the public and system + * identifiers, leaving resolution of the entity and opening of + * the input stream up to the caller. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + */ + public HTTPInputSource(String publicId, String systemId, String baseSystemId) { + super(publicId, systemId, baseSystemId); + } // (String,String,String) + + /** + * Constructs an input source from a XMLResourceIdentifier + * object, leaving resolution of the entity and opening of + * the input stream up to the caller. + * + * @param resourceIdentifier the XMLResourceIdentifier containing the information + */ + public HTTPInputSource(XMLResourceIdentifier resourceIdentifier) { + super(resourceIdentifier); + } // (XMLResourceIdentifier) + + /** + * Constructs an input source from a byte stream. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + * @param byteStream The byte stream. + * @param encoding The encoding of the byte stream, if known. + */ + public HTTPInputSource(String publicId, String systemId, + String baseSystemId, InputStream byteStream, String encoding) { + super(publicId, systemId, baseSystemId, byteStream, encoding); + } // (String,String,String,InputStream,String) + + /** + * Constructs an input source from a character stream. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + * @param charStream The character stream. + * @param encoding The original encoding of the byte stream + * used by the reader, if known. + */ + public HTTPInputSource(String publicId, String systemId, + String baseSystemId, Reader charStream, String encoding) { + super(publicId, systemId, baseSystemId, charStream, encoding); + } // (String,String,String,Reader,String) + + // + // Public methods + // + + /** + * Returns the preference whether HTTP redirects should + * be followed. By default HTTP redirects will be followed. + */ + public boolean getFollowHTTPRedirects() { + return fFollowRedirects; + } // getFollowHTTPRedirects():boolean + + + /** + * Sets the preference whether HTTP redirects should + * be followed. By default HTTP redirects will be followed. + */ + public void setFollowHTTPRedirects(boolean followRedirects) { + fFollowRedirects = followRedirects; + } // setFollowHTTPRedirects(boolean) + + /** + * Returns the value of the request property + * associated with the given property name. + * + * @param key the name of the request property + * @return the value of the request property or + * null if this property has not + * been set + */ + public String getHTTPRequestProperty(String key) { + return (String) fHTTPRequestProperties.get(key); + } // getHTTPRequestProperty(String):String + + /** + * Returns an iterator for the request properties this + * input source contains. Each object returned by the + * iterator is an instance of java.util.Map.Entry + * where each key and value are a pair of strings corresponding + * to the name and value of a request property. + * + * @return an iterator for the request properties this + * input source contains + */ + public Iterator getHTTPRequestProperties() { + return fHTTPRequestProperties.entrySet().iterator(); + } // getHTTPRequestProperties():Iterator + + /** + * Sets the value of the request property + * associated with the given property name. + * + * @param key the name of the request property + * @param value the value of the request property + */ + public void setHTTPRequestProperty(String key, String value) { + if (value != null) { + fHTTPRequestProperties.put(key, value); + } + else { + fHTTPRequestProperties.remove(key); + } + } // setHTTPRequestProperty(String,String) + +} // class HTTPInputSource diff --git a/resources/xerces2-j-src/org/apache/xerces/util/IntStack.java b/resources/xerces2-j-src/org/apache/xerces/util/IntStack.java new file mode 100644 index 0000000..54ade38 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/IntStack.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +/** + * A simple integer based stack. + * + * moved to org.apache.xerces.util by neilg to support the + * XPathMatcher. + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public final class IntStack { + + // + // Data + // + + /** Stack depth. */ + private int fDepth; + + /** Stack data. */ + private int[] fData; + + // + // Public methods + // + + /** Returns the size of the stack. */ + public int size() { + return fDepth; + } + + /** Pushes a value onto the stack. */ + public void push(int value) { + ensureCapacity(fDepth + 1); + fData[fDepth++] = value; + } + + /** Peeks at the top of the stack. */ + public int peek() { + return fData[fDepth - 1]; + } + + /** Returns the element at the specified depth in the stack. */ + public int elementAt(int depth) { + return fData[depth]; + } + + /** Pops a value off of the stack. */ + public int pop() { + return fData[--fDepth]; + } + + /** Clears the stack. */ + public void clear() { + fDepth = 0; + } + + // debugging + + /** Prints the stack. */ + public void print() { + System.out.print('('); + System.out.print(fDepth); + System.out.print(") {"); + for (int i = 0; i < fDepth; i++) { + if (i == 3) { + System.out.print(" ..."); + break; + } + System.out.print(' '); + System.out.print(fData[i]); + if (i < fDepth - 1) { + System.out.print(','); + } + } + System.out.print(" }"); + System.out.println(); + } + + // + // Private methods + // + + /** Ensures capacity. */ + private void ensureCapacity(int size) { + if (fData == null) { + fData = new int[32]; + } + else if (fData.length <= size) { + int[] newdata = new int[fData.length * 2]; + System.arraycopy(fData, 0, newdata, 0, fData.length); + fData = newdata; + } + } + +} // class IntStack diff --git a/resources/xerces2-j-src/org/apache/xerces/util/JAXPNamespaceContextWrapper.java b/resources/xerces2-j-src/org/apache/xerces/util/JAXPNamespaceContextWrapper.java new file mode 100644 index 0000000..088b4d0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/JAXPNamespaceContextWrapper.java @@ -0,0 +1,145 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.TreeSet; +import java.util.Vector; + +import javax.xml.XMLConstants; + +import org.apache.xerces.xni.NamespaceContext; + +/** + *

        A read-only XNI wrapper around a JAXP NamespaceContext.

        + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class JAXPNamespaceContextWrapper implements NamespaceContext { + + private javax.xml.namespace.NamespaceContext fNamespaceContext; + private SymbolTable fSymbolTable; + private List fPrefixes; + private final Vector fAllPrefixes = new Vector(); + + private int[] fContext = new int[8]; + private int fCurrentContext; + + public JAXPNamespaceContextWrapper(SymbolTable symbolTable) { + setSymbolTable(symbolTable); + } + + public void setNamespaceContext(javax.xml.namespace.NamespaceContext context) { + fNamespaceContext = context; + } + + public javax.xml.namespace.NamespaceContext getNamespaceContext() { + return fNamespaceContext; + } + + public void setSymbolTable(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + } + + public SymbolTable getSymbolTable() { + return fSymbolTable; + } + + public void setDeclaredPrefixes(List prefixes) { + fPrefixes = prefixes; + } + + public List getDeclaredPrefixes() { + return fPrefixes; + } + + /* + * NamespaceContext methods + */ + + public String getURI(String prefix) { + if (fNamespaceContext != null) { + String uri = fNamespaceContext.getNamespaceURI(prefix); + if (uri != null && !XMLConstants.NULL_NS_URI.equals(uri)) { + return (fSymbolTable != null) ? fSymbolTable.addSymbol(uri) : uri.intern(); + } + } + return null; + } + + public String getPrefix(String uri) { + if (fNamespaceContext != null) { + if (uri == null) { + uri = XMLConstants.NULL_NS_URI; + } + String prefix = fNamespaceContext.getPrefix(uri); + if (prefix == null) { + prefix = XMLConstants.DEFAULT_NS_PREFIX; + } + return (fSymbolTable != null) ? fSymbolTable.addSymbol(prefix) : prefix.intern(); + } + return null; + } + + public Enumeration getAllPrefixes() { + // There may be duplicate prefixes in the list so we + // first transfer them to a set to ensure uniqueness. + return Collections.enumeration(new TreeSet(fAllPrefixes)); + } + + public void pushContext() { + // extend the array, if necessary + if (fCurrentContext + 1 == fContext.length) { + int[] contextarray = new int[fContext.length * 2]; + System.arraycopy(fContext, 0, contextarray, 0, fContext.length); + fContext = contextarray; + } + // push context + fContext[++fCurrentContext] = fAllPrefixes.size(); + if (fPrefixes != null) { + fAllPrefixes.addAll(fPrefixes); + } + } + + public void popContext() { + fAllPrefixes.setSize(fContext[fCurrentContext--]); + } + + public boolean declarePrefix(String prefix, String uri) { + return true; + } + + public int getDeclaredPrefixCount() { + return (fPrefixes != null) ? fPrefixes.size() : 0; + } + + public String getDeclaredPrefixAt(int index) { + return (String) fPrefixes.get(index); + } + + public void reset() { + fCurrentContext = 0; + fContext[fCurrentContext] = 0; + fAllPrefixes.clear(); + } + +} // JAXPNamespaceContextWrapper diff --git a/resources/xerces2-j-src/org/apache/xerces/util/LocatorProxy.java b/resources/xerces2-j-src/org/apache/xerces/util/LocatorProxy.java new file mode 100644 index 0000000..f1648f3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/LocatorProxy.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.XMLLocator; +import org.xml.sax.Locator; +import org.xml.sax.ext.Locator2; + +/** + * Wraps {@link XMLLocator} and make it look like a SAX {@link Locator}. + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class LocatorProxy implements Locator2 { + + // + // Data + // + + /** XML locator. */ + private final XMLLocator fLocator; + + // + // Constructors + // + + /** Constructs an XML locator proxy. */ + public LocatorProxy(XMLLocator locator) { + fLocator = locator; + } + + // + // Locator methods + // + + /** Public identifier. */ + public String getPublicId() { + return fLocator.getPublicId(); + } + + /** System identifier. */ + public String getSystemId() { + return fLocator.getExpandedSystemId(); + } + + /** Line number. */ + public int getLineNumber() { + return fLocator.getLineNumber(); + } + + /** Column number. */ + public int getColumnNumber() { + return fLocator.getColumnNumber(); + } + + // + // Locator2 methods + // + + public String getXMLVersion() { + return fLocator.getXMLVersion(); + } + + public String getEncoding() { + return fLocator.getEncoding(); + } + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/MessageFormatter.java b/resources/xerces2-j-src/org/apache/xerces/util/MessageFormatter.java new file mode 100644 index 0000000..e1cdac7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/MessageFormatter.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Locale; +import java.util.MissingResourceException; + +/** + * This interface provides a generic message formatting mechanism and + * is useful for producing messages that must be localized and/or formatted + * with replacement text. + * + * @see org.apache.xerces.impl.XMLErrorReporter + * + * @author Andy Clark + * + * @version $Id$ + */ +public interface MessageFormatter { + + // + // MessageFormatter methods + // + + /** + * Formats a message with the specified arguments using the given + * locale information. + * + * @param locale The locale of the message. + * @param key The message key. + * @param arguments The message replacement text arguments. The order + * of the arguments must match that of the placeholders + * in the actual message. + * + * @return Returns the formatted message. + * + * @throws MissingResourceException Thrown if the message with the + * specified key cannot be found. + */ + public String formatMessage(Locale locale, String key, Object[] arguments) + throws MissingResourceException; + +} // interface MessageFormatter diff --git a/resources/xerces2-j-src/org/apache/xerces/util/NamespaceSupport.java b/resources/xerces2-j-src/org/apache/xerces/util/NamespaceSupport.java new file mode 100644 index 0000000..d527309 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/NamespaceSupport.java @@ -0,0 +1,331 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +import org.apache.xerces.xni.NamespaceContext; + +/** + * Namespace support for XML document handlers. This class doesn't + * perform any error checking and assumes that all strings passed + * as arguments to methods are unique symbols. The SymbolTable class + * can be used for this purpose. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class NamespaceSupport implements NamespaceContext { + + // + // Data + // + + /** + * Namespace binding information. This array is composed of a + * series of tuples containing the namespace binding information: + * <prefix, uri>. The default size can be set to anything + * as long as it is a power of 2 greater than 1. + * + * @see #fNamespaceSize + * @see #fContext + */ + protected String[] fNamespace = new String[16 * 2]; + + /** The top of the namespace information array. */ + protected int fNamespaceSize; + + // NOTE: The constructor depends on the initial context size + // being at least 1. -Ac + + /** + * Context indexes. This array contains indexes into the namespace + * information array. The index at the current context is the start + * index of declared namespace bindings and runs to the size of the + * namespace information array. + * + * @see #fNamespaceSize + */ + protected int[] fContext = new int[8]; + + /** The current context. */ + protected int fCurrentContext; + + protected String[] fPrefixes = new String[16]; + + // + // Constructors + // + + /** Default constructor. */ + public NamespaceSupport() { + } // () + + /** + * Constructs a namespace context object and initializes it with + * the prefixes declared in the specified context. + */ + public NamespaceSupport(NamespaceContext context) { + pushContext(); + // copy declaration in the context + Enumeration prefixes = context.getAllPrefixes(); + while (prefixes.hasMoreElements()){ + String prefix = (String)prefixes.nextElement(); + String uri = context.getURI(prefix); + declarePrefix(prefix, uri); + } + } // (NamespaceContext) + + + // + // Public methods + // + + /** + * @see org.apache.xerces.xni.NamespaceContext#reset() + */ + public void reset() { + + // reset namespace and context info + fNamespaceSize = 0; + fCurrentContext = 0; + fContext[fCurrentContext] = fNamespaceSize; + + // bind "xml" prefix to the XML uri + fNamespace[fNamespaceSize++] = XMLSymbols.PREFIX_XML; + fNamespace[fNamespaceSize++] = NamespaceContext.XML_URI; + // bind "xmlns" prefix to the XMLNS uri + fNamespace[fNamespaceSize++] = XMLSymbols.PREFIX_XMLNS; + fNamespace[fNamespaceSize++] = NamespaceContext.XMLNS_URI; + ++fCurrentContext; + + } // reset(SymbolTable) + + + /** + * @see org.apache.xerces.xni.NamespaceContext#pushContext() + */ + public void pushContext() { + + // extend the array, if necessary + if (fCurrentContext + 1 == fContext.length) { + int[] contextarray = new int[fContext.length * 2]; + System.arraycopy(fContext, 0, contextarray, 0, fContext.length); + fContext = contextarray; + } + + // push context + fContext[++fCurrentContext] = fNamespaceSize; + + } // pushContext() + + + /** + * @see org.apache.xerces.xni.NamespaceContext#popContext() + */ + public void popContext() { + fNamespaceSize = fContext[fCurrentContext--]; + } // popContext() + + /** + * @see org.apache.xerces.xni.NamespaceContext#declarePrefix(String, String) + */ + public boolean declarePrefix(String prefix, String uri) { + // ignore "xml" and "xmlns" prefixes + if (prefix == XMLSymbols.PREFIX_XML || prefix == XMLSymbols.PREFIX_XMLNS) { + return false; + } + + // see if prefix already exists in current context + for (int i = fNamespaceSize; i > fContext[fCurrentContext]; i -= 2) { + if (fNamespace[i - 2] == prefix) { + // REVISIT: [Q] Should the new binding override the + // previously declared binding or should it + // it be ignored? -Ac + // NOTE: The SAX2 "NamespaceSupport" helper allows + // re-bindings with the new binding overwriting + // the previous binding. -Ac + fNamespace[i - 1] = uri; + return true; + } + } + + // resize array, if needed + if (fNamespaceSize == fNamespace.length) { + String[] namespacearray = new String[fNamespaceSize * 2]; + System.arraycopy(fNamespace, 0, namespacearray, 0, fNamespaceSize); + fNamespace = namespacearray; + } + + // bind prefix to uri in current context + fNamespace[fNamespaceSize++] = prefix; + fNamespace[fNamespaceSize++] = uri; + + return true; + + } // declarePrefix(String,String):boolean + + /** + * @see org.apache.xerces.xni.NamespaceContext#getURI(String) + */ + public String getURI(String prefix) { + + // find prefix in current context + for (int i = fNamespaceSize; i > 0; i -= 2) { + if (fNamespace[i - 2] == prefix) { + return fNamespace[i - 1]; + } + } + + // prefix not found + return null; + + } // getURI(String):String + + + /** + * @see org.apache.xerces.xni.NamespaceContext#getPrefix(String) + */ + public String getPrefix(String uri) { + + // find uri in current context + for (int i = fNamespaceSize; i > 0; i -= 2) { + if (fNamespace[i - 1] == uri) { + if (getURI(fNamespace[i - 2]) == uri) + return fNamespace[i - 2]; + } + } + + // uri not found + return null; + + } // getPrefix(String):String + + + /** + * @see org.apache.xerces.xni.NamespaceContext#getDeclaredPrefixCount() + */ + public int getDeclaredPrefixCount() { + return (fNamespaceSize - fContext[fCurrentContext]) / 2; + } // getDeclaredPrefixCount():int + + /** + * @see org.apache.xerces.xni.NamespaceContext#getDeclaredPrefixAt(int) + */ + public String getDeclaredPrefixAt(int index) { + return fNamespace[fContext[fCurrentContext] + index * 2]; + } // getDeclaredPrefixAt(int):String + + /** + * @see org.apache.xerces.xni.NamespaceContext#getAllPrefixes() + */ + public Enumeration getAllPrefixes() { + int count = 0; + if (fPrefixes.length < (fNamespace.length/2)) { + // resize prefix array + String[] prefixes = new String[fNamespaceSize]; + fPrefixes = prefixes; + } + String prefix = null; + boolean unique = true; + for (int i = 2; i < (fNamespaceSize-2); i += 2) { + prefix = fNamespace[i + 2]; + for (int k=0;k 0; i -= 2) { + if (fNamespace[i - 2] == prefix) { + return true; + } + } + + // prefix not found + return false; + } + + protected final class Prefixes implements Enumeration { + private String[] prefixes; + private int counter = 0; + private int size = 0; + + /** + * Constructor for Prefixes. + */ + public Prefixes(String [] prefixes, int size) { + this.prefixes = prefixes; + this.size = size; + } + + /** + * @see java.util.Enumeration#hasMoreElements() + */ + public boolean hasMoreElements() { + return (counter< size); + } + + /** + * @see java.util.Enumeration#nextElement() + */ + public Object nextElement() { + if (counter< size){ + return fPrefixes[counter++]; + } + throw new NoSuchElementException("Illegal access to Namespace prefixes enumeration."); + } + + public String toString(){ + StringBuffer buf = new StringBuffer(); + for (int i=0;i + * This class can be constructed with a "parent" settings object + * (in the form of an XMLComponentManager) that allows + * parser configuration settings to be "chained" together. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class ParserConfigurationSettings + implements XMLComponentManager { + + protected static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + // + // Data + // + + // data + + /** Recognized properties. */ + protected ArrayList fRecognizedProperties; + + /** Properties. */ + protected HashMap fProperties; + + /** Recognized features. */ + protected ArrayList fRecognizedFeatures; + + /** Features. */ + protected HashMap fFeatures; + + /** Parent parser configuration settings. */ + protected XMLComponentManager fParentSettings; + + // + // Constructors + // + + /** Default Constructor. */ + public ParserConfigurationSettings() { + this(null); + } // () + + /** + * Constructs a parser configuration settings object with a + * parent settings object. + */ + public ParserConfigurationSettings(XMLComponentManager parent) { + + // create storage for recognized features and properties + fRecognizedFeatures = new ArrayList(); + fRecognizedProperties = new ArrayList(); + + // create table for features and properties + fFeatures = new HashMap(); + fProperties = new HashMap(); + + // save parent + fParentSettings = parent; + + } // (XMLComponentManager) + + // + // XMLParserConfiguration methods + // + + /** + * Allows a parser to add parser specific features to be recognized + * and managed by the parser configuration. + * + * @param featureIds An array of the additional feature identifiers + * to be recognized. + */ + public void addRecognizedFeatures(String[] featureIds) { + + // add recognized features + int featureIdsCount = featureIds != null ? featureIds.length : 0; + for (int i = 0; i < featureIdsCount; i++) { + String featureId = featureIds[i]; + if (!fRecognizedFeatures.contains(featureId)) { + fRecognizedFeatures.add(featureId); + } + } + + } // addRecognizedFeatures(String[]) + + /** + * Set the state of a feature. + * + * Set the state of any feature in a SAX2 parser. The parser + * might not recognize the feature, and if it does recognize + * it, it might not be able to fulfill the request. + * + * @param featureId The unique identifier (URI) of the feature. + * @param state The requested state of the feature (true or false). + * + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + + // check and store + checkFeature(featureId); + + fFeatures.put(featureId, state ? Boolean.TRUE : Boolean.FALSE); + } // setFeature(String,boolean) + + /** + * Allows a parser to add parser specific properties to be recognized + * and managed by the parser configuration. + * + * @param propertyIds An array of the additional property identifiers + * to be recognized. + */ + public void addRecognizedProperties(String[] propertyIds) { + + // add recognizedProperties + int propertyIdsCount = propertyIds != null ? propertyIds.length : 0; + for (int i = 0; i < propertyIdsCount; i++) { + String propertyId = propertyIds[i]; + if (!fRecognizedProperties.contains(propertyId)) { + fRecognizedProperties.add(propertyId); + } + } + + } // addRecognizedProperties(String[]) + + /** + * setProperty + * + * @param propertyId + * @param value + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // check and store + checkProperty(propertyId); + fProperties.put(propertyId, value); + + } // setProperty(String,Object) + + // + // XMLComponentManager methods + // + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * @return true if the feature is supported + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException { + + Boolean state = (Boolean) fFeatures.get(featureId); + + if (state == null) { + checkFeature(featureId); + return false; + } + return state.booleanValue(); + + } // getFeature(String):boolean + + /** + * Returns the value of a property. + * + * @param propertyId The property identifier. + * @return the value of the property + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException { + + Object propertyValue = fProperties.get(propertyId); + + if (propertyValue == null) { + checkProperty(propertyId); + } + + return propertyValue; + + } // getProperty(String):Object + + // + // Protected methods + // + + /** + * Check a feature. If feature is known and supported, this method simply + * returns. Otherwise, the appropriate exception is thrown. + * + * @param featureId The unique identifier (URI) of the feature. + * + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + protected void checkFeature(String featureId) + throws XMLConfigurationException { + + // check feature + if (!fRecognizedFeatures.contains(featureId)) { + if (fParentSettings != null) { + fParentSettings.getFeature(featureId); + } + else { + short type = XMLConfigurationException.NOT_RECOGNIZED; + throw new XMLConfigurationException(type, featureId); + } + } + + } // checkFeature(String) + + /** + * Check a property. If the property is known and supported, this method + * simply returns. Otherwise, the appropriate exception is thrown. + * + * @param propertyId The unique identifier (URI) of the property + * being set. + * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the + * requested feature is not known. + */ + protected void checkProperty(String propertyId) + throws XMLConfigurationException { + + // check property + if (!fRecognizedProperties.contains(propertyId)) { + if (fParentSettings != null) { + fParentSettings.getProperty(propertyId); + } + else { + short type = XMLConfigurationException.NOT_RECOGNIZED; + throw new XMLConfigurationException(type, propertyId); + } + } + + } // checkProperty(String) + +} // class ParserConfigurationSettings diff --git a/resources/xerces2-j-src/org/apache/xerces/util/PrimeNumberSequenceGenerator.java b/resources/xerces2-j-src/org/apache/xerces/util/PrimeNumberSequenceGenerator.java new file mode 100644 index 0000000..7d92fba --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/PrimeNumberSequenceGenerator.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Random; + +/** + * Fills an array with a random sequence of prime numbers. + * + * @xerces.internal + * + * @version $Id$ + */ +final class PrimeNumberSequenceGenerator { + + private static int [] PRIMES = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727}; + + static void generateSequence(int[] arrayToFill) { + Random r = new Random(); + for (int i = 0; i < arrayToFill.length; ++i) { + arrayToFill[i] = PRIMES[r.nextInt(PRIMES.length)]; + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/SAXInputSource.java b/resources/xerces2-j-src/org/apache/xerces/util/SAXInputSource.java new file mode 100644 index 0000000..a3ffe7f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/SAXInputSource.java @@ -0,0 +1,162 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.io.InputStream; +import java.io.Reader; + +import org.apache.xerces.xni.parser.XMLInputSource; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; + +/** + *

        An XMLInputSource analogue to javax.xml.transform.sax.SAXSource.

        + * + * @version $Id$ + */ +public final class SAXInputSource extends XMLInputSource { + + private XMLReader fXMLReader; + private InputSource fInputSource; + + public SAXInputSource() { + this(null); + } + + public SAXInputSource(InputSource inputSource) { + this(null, inputSource); + } + + public SAXInputSource(XMLReader reader, InputSource inputSource) { + super(inputSource != null ? inputSource.getPublicId() : null, + inputSource != null ? inputSource.getSystemId() : null, null); + if (inputSource != null) { + setByteStream(inputSource.getByteStream()); + setCharacterStream(inputSource.getCharacterStream()); + setEncoding(inputSource.getEncoding()); + } + fInputSource = inputSource; + fXMLReader = reader; + } + + public void setXMLReader(XMLReader reader) { + fXMLReader = reader; + } + + public XMLReader getXMLReader() { + return fXMLReader; + } + + public void setInputSource(InputSource inputSource) { + if (inputSource != null) { + setPublicId(inputSource.getPublicId()); + setSystemId(inputSource.getSystemId()); + setByteStream(inputSource.getByteStream()); + setCharacterStream(inputSource.getCharacterStream()); + setEncoding(inputSource.getEncoding()); + } + else { + setPublicId(null); + setSystemId(null); + setByteStream(null); + setCharacterStream(null); + setEncoding(null); + } + fInputSource = inputSource; + } + + public InputSource getInputSource() { + return fInputSource; + } + + /** + * Sets the public identifier. + * + * @param publicId The new public identifier. + */ + public void setPublicId(String publicId) { + super.setPublicId(publicId); + if (fInputSource == null) { + fInputSource = new InputSource(); + } + fInputSource.setPublicId(publicId); + } // setPublicId(String) + + /** + * Sets the system identifier. + * + * @param systemId The new system identifier. + */ + public void setSystemId(String systemId) { + super.setSystemId(systemId); + if (fInputSource == null) { + fInputSource = new InputSource(); + } + fInputSource.setSystemId(systemId); + } // setSystemId(String) + + /** + * Sets the byte stream. If the byte stream is not already opened + * when this object is instantiated, then the code that opens the + * stream should also set the byte stream on this object. Also, if + * the encoding is auto-detected, then the encoding should also be + * set on this object. + * + * @param byteStream The new byte stream. + */ + public void setByteStream(InputStream byteStream) { + super.setByteStream(byteStream); + if (fInputSource == null) { + fInputSource = new InputSource(); + } + fInputSource.setByteStream(byteStream); + } // setByteStream(InputStream) + + /** + * Sets the character stream. If the character stream is not already + * opened when this object is instantiated, then the code that opens + * the stream should also set the character stream on this object. + * Also, the encoding of the byte stream used by the reader should + * also be set on this object, if known. + * + * @param charStream The new character stream. + * + * @see #setEncoding + */ + public void setCharacterStream(Reader charStream) { + super.setCharacterStream(charStream); + if (fInputSource == null) { + fInputSource = new InputSource(); + } + fInputSource.setCharacterStream(charStream); + } // setCharacterStream(Reader) + + /** + * Sets the encoding of the stream. + * + * @param encoding The new encoding. + */ + public void setEncoding(String encoding) { + super.setEncoding(encoding); + if (fInputSource == null) { + fInputSource = new InputSource(); + } + fInputSource.setEncoding(encoding); + } // setEncoding(String) + +} // SAXInputSource diff --git a/resources/xerces2-j-src/org/apache/xerces/util/SAXLocatorWrapper.java b/resources/xerces2-j-src/org/apache/xerces/util/SAXLocatorWrapper.java new file mode 100644 index 0000000..7d0c63e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/SAXLocatorWrapper.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.XMLLocator; +import org.xml.sax.Locator; +import org.xml.sax.ext.Locator2; + +/** + *

        A light wrapper around a SAX locator. This is useful + * when bridging between SAX and XNI components.

        + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class SAXLocatorWrapper implements XMLLocator { + + private Locator fLocator = null; + private Locator2 fLocator2 = null; + + public SAXLocatorWrapper() {} + + public void setLocator(Locator locator) { + fLocator = locator; + if (locator instanceof Locator2 || locator == null) { + fLocator2 = (Locator2) locator; + } + } + + public Locator getLocator() { + return fLocator; + } + + /* + * XMLLocator methods + */ + + public String getPublicId() { + if (fLocator != null) { + return fLocator.getPublicId(); + } + return null; + } + + public String getLiteralSystemId() { + if (fLocator != null) { + return fLocator.getSystemId(); + } + return null; + } + + public String getBaseSystemId() { + return null; + } + + public String getExpandedSystemId() { + return getLiteralSystemId(); + } + + public int getLineNumber() { + if (fLocator != null) { + return fLocator.getLineNumber(); + } + return -1; + } + + public int getColumnNumber() { + if (fLocator != null) { + return fLocator.getColumnNumber(); + } + return -1; + } + + public int getCharacterOffset() { + return -1; + } + + public String getEncoding() { + if (fLocator2 != null) { + return fLocator2.getEncoding(); + } + return null; + } + + public String getXMLVersion() { + if (fLocator2 != null) { + return fLocator2.getXMLVersion(); + } + return null; + } + +} // SAXLocatorWrapper diff --git a/resources/xerces2-j-src/org/apache/xerces/util/SAXMessageFormatter.java b/resources/xerces2-j-src/org/apache/xerces/util/SAXMessageFormatter.java new file mode 100644 index 0000000..d2aad90 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/SAXMessageFormatter.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * Used to format SAX error messages using a specified locale. + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class SAXMessageFormatter { + + /** + * Formats a message with the specified arguments using the given + * locale information. + * + * @param locale The locale of the message. + * @param key The message key. + * @param arguments The message replacement text arguments. The order + * of the arguments must match that of the placeholders + * in the actual message. + * + * @return the formatted message. + * + * @throws MissingResourceException Thrown if the message with the + * specified key cannot be found. + */ + public static String formatMessage(Locale locale, + String key, Object[] arguments) + throws MissingResourceException { + + if (locale == null) { + locale = Locale.getDefault(); + } + final ResourceBundle resourceBundle = + ResourceBundle.getBundle("org.apache.xerces.impl.msg.SAXMessages", locale); + + // format message + String msg; + try { + msg = resourceBundle.getString(key); + if (arguments != null) { + try { + msg = java.text.MessageFormat.format(msg, arguments); + } + catch (Exception e) { + msg = resourceBundle.getString("FormatFailed"); + msg += " " + resourceBundle.getString(key); + } + } + } + + // error + catch (MissingResourceException e) { + msg = resourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(key, msg, key); + } + + // no message + if (msg == null) { + msg = key; + if (arguments.length > 0) { + StringBuffer str = new StringBuffer(msg); + str.append('?'); + for (int i = 0; i < arguments.length; i++) { + if (i > 0) { + str.append('&'); + } + str.append(String.valueOf(arguments[i])); + } + } + } + return msg; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/SecurityManager.java b/resources/xerces2-j-src/org/apache/xerces/util/SecurityManager.java new file mode 100644 index 0000000..9efae53 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/SecurityManager.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +/** + * This class is a container for parser settings that relate to + * security, or more specifically, it is intended to be used to prevent denial-of-service + * attacks from being launched against a system running Xerces. + * Any component that is aware of a denial-of-service attack that can arise + * from its processing of a certain kind of document may query its Component Manager + * for the property (http://apache.org/xml/properties/security-manager) + * whose value will be an instance of this class. + * If no value has been set for the property, the component should proceed in the "usual" (spec-compliant) + * manner. If a value has been set, then it must be the case that the component in + * question needs to know what method of this class to query. This class + * will provide defaults for all known security issues, but will also provide + * setters so that those values can be tailored by applications that care. + * + * @author Neil Graham, IBM + * + * @version $Id$ + */ +public final class SecurityManager { + + // + // Constants + // + + /** Default value for entity expansion limit. **/ + private final static int DEFAULT_ENTITY_EXPANSION_LIMIT = 100000; + + /** Default value of number of nodes created. **/ + private final static int DEFAULT_MAX_OCCUR_NODE_LIMIT = 3000; + + // + // Data + // + + /** Entity expansion limit. **/ + private int entityExpansionLimit; + + /** W3C XML Schema maxOccurs limit. **/ + private int maxOccurLimit; + + /** + * Default constructor. Establishes default values + * for known security vulnerabilities. + */ + public SecurityManager() { + entityExpansionLimit = DEFAULT_ENTITY_EXPANSION_LIMIT; + maxOccurLimit = DEFAULT_MAX_OCCUR_NODE_LIMIT ; + } + + /** + *

        Sets the number of entity expansions that the + * parser should permit in a document.

        + * + * @param limit the number of entity expansions + * permitted in a document + */ + public void setEntityExpansionLimit(int limit) { + entityExpansionLimit = limit; + } + + /** + *

        Returns the number of entity expansions + * that the parser permits in a document.

        + * + * @return the number of entity expansions + * permitted in a document + */ + public int getEntityExpansionLimit() { + return entityExpansionLimit; + } + + /** + *

        Sets the limit of the number of content model nodes + * that may be created when building a grammar for a W3C + * XML Schema that contains maxOccurs attributes with values + * other than "unbounded".

        + * + * @param limit the maximum value for maxOccurs other + * than "unbounded" + */ + public void setMaxOccurNodeLimit(int limit){ + maxOccurLimit = limit; + } + + /** + *

        Returns the limit of the number of content model nodes + * that may be created when building a grammar for a W3C + * XML Schema that contains maxOccurs attributes with values + * other than "unbounded".

        + * + * @return the maximum value for maxOccurs other + * than "unbounded" + */ + public int getMaxOccurNodeLimit(){ + return maxOccurLimit; + } + +} // class SecurityManager + diff --git a/resources/xerces2-j-src/org/apache/xerces/util/ShadowedSymbolTable.java b/resources/xerces2-j-src/org/apache/xerces/util/ShadowedSymbolTable.java new file mode 100644 index 0000000..9dcab0d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/ShadowedSymbolTable.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + + +/** + * Shadowed symbol table. + * + * The table has a reference to the main symbol table and is + * not allowed to add new symbols to the main symbol table. + * New symbols are added to the shadow symbol table and are local + * to the component using this table. + * + * @author Andy Clark IBM + * @version $Id$ + */ + +public final class ShadowedSymbolTable +extends SymbolTable { + + // + // Data + // + + /** Main symbol table. */ + protected SymbolTable fSymbolTable; + + // + // Constructors + // + + /** Constructs a shadow of the specified symbol table. */ + public ShadowedSymbolTable(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + } // (SymbolTable) + + // + // SymbolTable methods + // + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param symbol The new symbol. + */ + public String addSymbol(String symbol) { + + if (fSymbolTable.containsSymbol(symbol)) { + return fSymbolTable.addSymbol(symbol); + } + return super.addSymbol(symbol); + + } // addSymbol(String) + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param buffer The buffer containing the new symbol. + * @param offset The offset into the buffer of the new symbol. + * @param length The length of the new symbol in the buffer. + */ + public String addSymbol(char[] buffer, int offset, int length) { + + if (fSymbolTable.containsSymbol(buffer, offset, length)) { + return fSymbolTable.addSymbol(buffer, offset, length); + } + return super.addSymbol(buffer, offset, length); + + } // addSymbol(char[],int,int):String + + /** + * Returns a hashcode value for the specified symbol. The value + * returned by this method must be identical to the value returned + * by the hash(char[],int,int) method when called + * with the character array that comprises the symbol string. + * + * @param symbol The symbol to hash. + */ + public int hash(String symbol) { + return fSymbolTable.hash(symbol); + } // hash(String):int + + /** + * Returns a hashcode value for the specified symbol information. + * The value returned by this method must be identical to the value + * returned by the hash(String) method when called + * with the string object created from the symbol information. + * + * @param buffer The character buffer containing the symbol. + * @param offset The offset into the character buffer of the start + * of the symbol. + * @param length The length of the symbol. + */ + public int hash(char[] buffer, int offset, int length) { + return fSymbolTable.hash(buffer, offset, length); + } // hash(char[],int,int):int + +} // class ShadowedSymbolTable diff --git a/resources/xerces2-j-src/org/apache/xerces/util/SoftReferenceSymbolTable.java b/resources/xerces2-j-src/org/apache/xerces/util/SoftReferenceSymbolTable.java new file mode 100644 index 0000000..d8b9cef --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/SoftReferenceSymbolTable.java @@ -0,0 +1,458 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; + +/** + * This symbol table uses SoftReferences to its String entries, which means that table entries + * that have no references to them can be garbage collected when memory is needed. Thus, in + * documents with very very large numbers of unique strings, using this SymbolTable will prevent + * an out of memory error from occurring. + * + * @see SymbolTable + * + * @author Peter McCracken, IBM + * + * @version $Id$ + */ +/* + * This class extends SymbolTable. Logically, it would make more sense if it and SymbolTable + * shared a common interface, because despite almost identical logic, SoftReferenceSymbolTable + * shares almost no code with SymbolTable (because of necessary checks for null table entries + * in the code). I've chosen to avoid making the interface because we don't want to slow down + * the vastly more common case of using the regular SymbolTable. We also don't want to change + * SymbolTable, since it's a public class that's probably commonly in use by many applications. + * -PJM + */ +public class SoftReferenceSymbolTable extends SymbolTable { + + /* + * This variable masks the fBuckets variable used by SymbolTable. + */ + protected SREntry[] fBuckets = null; + + private final ReferenceQueue fReferenceQueue; + + // + // Constructors + // + + /** + * Constructs a new, empty SymbolTable with the specified initial + * capacity and the specified load factor. + * + * @param initialCapacity the initial capacity of the SymbolTable. + * @param loadFactor the load factor of the SymbolTable. + * @throws IllegalArgumentException if the initial capacity is less + * than zero, or if the load factor is nonpositive. + */ + public SoftReferenceSymbolTable(int initialCapacity, float loadFactor) { + /* + * The Entry buckets in the base class are not used by this class. + * We call super() with 1 as the initial capacity to minimize the + * memory used by the field in the base class. + */ + super(1, loadFactor); + + if (initialCapacity < 0) { + throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); + } + + if (loadFactor <= 0 || Float.isNaN(loadFactor)) { + throw new IllegalArgumentException("Illegal Load: " + loadFactor); + } + + if (initialCapacity == 0) { + initialCapacity = 1; + } + + fLoadFactor = loadFactor; + fTableSize = initialCapacity; + fBuckets = new SREntry[fTableSize]; + fThreshold = (int)(fTableSize * loadFactor); + fCount = 0; + + fReferenceQueue = new ReferenceQueue(); + } + + /** + * Constructs a new, empty SymbolTable with the specified initial capacity + * and default load factor, which is 0.75. + * + * @param initialCapacity the initial capacity of the hashtable. + * @throws IllegalArgumentException if the initial capacity is less + * than zero. + */ + public SoftReferenceSymbolTable(int initialCapacity) { + this(initialCapacity, 0.75f); + } + + /** + * Constructs a new, empty SymbolTable with a default initial capacity (101) + * and load factor, which is 0.75. + */ + public SoftReferenceSymbolTable() { + this(TABLE_SIZE, 0.75f); + } + + // + // Public methods + // + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param symbol The new symbol. + */ + public String addSymbol(String symbol) { + clean(); + // search for identical symbol + int collisionCount = 0; + int bucket = hash(symbol) % fTableSize; + for (SREntry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + SREntryData data = (SREntryData)entry.get(); + if (data == null) { + continue; + } + if (data.symbol.equals(symbol)) { + return data.symbol; + } + ++collisionCount; + } + return addSymbol0(symbol, bucket, collisionCount); + } // addSymbol(String):String + + private String addSymbol0(String symbol, int bucket, int collisionCount) { + if (fCount >= fThreshold) { + // Rehash the table if the threshold is exceeded + rehash(); + bucket = hash(symbol) % fTableSize; + } + else if (collisionCount >= fCollisionThreshold) { + // Select a new hash function and rehash the table if + // the collision threshold is exceeded. + rebalance(); + bucket = hash(symbol) % fTableSize; + } + + // add new entry + symbol = symbol.intern(); + SREntry entry = new SREntry(symbol, fBuckets[bucket], bucket, fReferenceQueue); + fBuckets[bucket] = entry; + ++fCount; + return symbol; + } // addSymbol0(String,int,int):String + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param buffer The buffer containing the new symbol. + * @param offset The offset into the buffer of the new symbol. + * @param length The length of the new symbol in the buffer. + */ + public String addSymbol(char[] buffer, int offset, int length) { + clean(); + // search for identical symbol + int collisionCount = 0; + int bucket = hash(buffer, offset, length) % fTableSize; + OUTER: for (SREntry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + SREntryData data = (SREntryData)entry.get(); + if (data == null) { + continue; + } + if (length == data.characters.length) { + for (int i = 0; i < length; i++) { + if (buffer[offset + i] != data.characters[i]) { + ++collisionCount; + continue OUTER; + } + } + return data.symbol; + } + ++collisionCount; + } + return addSymbol0(buffer, offset, length, bucket, collisionCount); + } // addSymbol(char[],int,int):String + + private String addSymbol0(char[] buffer, int offset, int length, int bucket, int collisionCount) { + if (fCount >= fThreshold) { + // Rehash the table if the threshold is exceeded + rehash(); + bucket = hash(buffer, offset, length) % fTableSize; + } + else if (collisionCount >= fCollisionThreshold) { + // Select a new hash function and rehash the table if + // the collision threshold is exceeded. + rebalance(); + bucket = hash(buffer, offset, length) % fTableSize; + } + + // add new entry + String symbol = new String(buffer, offset, length).intern(); + SREntry entry = new SREntry(symbol, buffer, offset, length, fBuckets[bucket], bucket, fReferenceQueue); + fBuckets[bucket] = entry; + ++fCount; + return symbol; + } // addSymbol0(char[],int,int,int,int):String + + /** + * Increases the capacity of and internally reorganizes this + * SymbolTable, in order to accommodate and access its entries more + * efficiently. This method is called automatically when the + * number of keys in the SymbolTable exceeds this hashtable's capacity + * and load factor. + */ + protected void rehash() { + rehashCommon(fBuckets.length * 2 + 1); + } + + /** + * Reduces the capacity of and internally reorganizes this + * SymbolTable, in order to accommodate and access its entries in + * a more memory efficient way. This method is called automatically when + * the number of keys in the SymbolTable drops below 25% of this + * hashtable's load factor (as a result of SoftReferences which have + * been cleared). + */ + protected void compact() { + rehashCommon(((int) (fCount / fLoadFactor)) * 2 + 1); + } + + /** + * Randomly selects a new hash function and reorganizes this SymbolTable + * in order to more evenly distribute its entries across the table. This + * method is called automatically when the number keys in one of the + * SymbolTable's buckets exceeds the given collision threshold. + */ + protected void rebalance() { + if (fHashMultipliers == null) { + fHashMultipliers = new int[MULTIPLIERS_SIZE]; + } + PrimeNumberSequenceGenerator.generateSequence(fHashMultipliers); + rehashCommon(fBuckets.length); + } + + private void rehashCommon(final int newCapacity) { + + final int oldCapacity = fBuckets.length; + final SREntry[] oldTable = fBuckets; + final SREntry[] newTable = new SREntry[newCapacity]; + + fThreshold = (int)(newCapacity * fLoadFactor); + fBuckets = newTable; + fTableSize = fBuckets.length; + + for (int i = oldCapacity ; i-- > 0 ;) { + for (SREntry old = oldTable[i] ; old != null ; ) { + SREntry e = old; + old = old.next; + + SREntryData data = (SREntryData)e.get(); + if (data != null) { + int index = hash(data.symbol) % newCapacity; + if (newTable[index] != null) { + newTable[index].prev = e; + } + e.bucket = index; + e.next = newTable[index]; + newTable[index] = e; + } + else { + e.bucket = -1; + e.next = null; + --fCount; + } + e.prev = null; + } + } + } + + /** + * Returns true if the symbol table already contains the specified + * symbol. + * + * @param symbol The symbol to look for. + */ + public boolean containsSymbol(String symbol) { + + // search for identical symbol + int bucket = hash(symbol) % fTableSize; + int length = symbol.length(); + OUTER: for (SREntry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + SREntryData data = (SREntryData)entry.get(); + if (data == null) { + continue; + } + if (length == data.characters.length) { + for (int i = 0; i < length; i++) { + if (symbol.charAt(i) != data.characters[i]) { + continue OUTER; + } + } + return true; + } + } + + return false; + + } // containsSymbol(String):boolean + + /** + * Returns true if the symbol table already contains the specified + * symbol. + * + * @param buffer The buffer containing the symbol to look for. + * @param offset The offset into the buffer. + * @param length The length of the symbol in the buffer. + */ + public boolean containsSymbol(char[] buffer, int offset, int length) { + + // search for identical symbol + int bucket = hash(buffer, offset, length) % fTableSize; + OUTER: for (SREntry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + SREntryData data = (SREntryData)entry.get(); + if (data == null) { + continue; + } + if (length == data.characters.length) { + for (int i = 0; i < length; i++) { + if (buffer[offset + i] != data.characters[i]) { + continue OUTER; + } + } + return true; + } + } + + return false; + + } // containsSymbol(char[],int,int):boolean + + private void removeEntry(SREntry entry) { + final int bucket = entry.bucket; + if (bucket >= 0) { + if (entry.next != null) { + entry.next.prev = entry.prev; + } + if (entry.prev != null) { + entry.prev.next = entry.next; + } + else { + fBuckets[bucket] = entry.next; + } + --fCount; + } + } + + /** + * Removes stale symbols from the table. + */ + private void clean() { + SREntry entry = (SREntry)fReferenceQueue.poll(); + if (entry != null) { + do { + removeEntry(entry); + entry = (SREntry)fReferenceQueue.poll(); + } + while (entry != null); + // Reduce the number of buckets if the number of items + // in the table has dropped below 25% of the threshold. + if (fCount < (fThreshold >> 2)) { + compact(); + } + } + } + + // + // Classes + // + + /** + * This class is a symbol table entry. Each entry acts as a node + * in a doubly-linked list. + * + * The "SR" stands for SoftReference. + */ + protected static final class SREntry extends SoftReference { + + /** The next entry. */ + public SREntry next; + + /** The previous entry. */ + public SREntry prev; + + /** The bucket this entry is contained in; -1 if it has been removed from the table. */ + public int bucket; + + // + // Constructors + // + + /** + * Constructs a new entry from the specified symbol and next entry + * reference. + */ + public SREntry(String internedSymbol, SREntry next, int bucket, ReferenceQueue q) { + super(new SREntryData(internedSymbol), q); + initialize(next, bucket); + } + + /** + * Constructs a new entry from the specified symbol information and + * next entry reference. + */ + public SREntry(String internedSymbol, char[] ch, int offset, int length, SREntry next, int bucket, ReferenceQueue q) { + super(new SREntryData(internedSymbol, ch, offset, length), q); + initialize(next, bucket); + } + + private void initialize(SREntry next, int bucket) { + this.next = next; + if (next != null) { + next.prev = this; + } + this.prev = null; + this.bucket = bucket; + } + } // class Entry + + protected static final class SREntryData { + public final String symbol; + public final char[] characters; + + public SREntryData(String internedSymbol) { + this.symbol = internedSymbol; + characters = new char[symbol.length()]; + symbol.getChars(0, characters.length, characters, 0); + } + + public SREntryData(String internedSymbol, char[] ch, int offset, int length) { + this.symbol = internedSymbol; + characters = new char[length]; + System.arraycopy(ch, offset, characters, 0, length); + } + } +} // class SoftReferenceSymbolTable diff --git a/resources/xerces2-j-src/org/apache/xerces/util/StAXInputSource.java b/resources/xerces2-j-src/org/apache/xerces/util/StAXInputSource.java new file mode 100644 index 0000000..ffc65e7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/StAXInputSource.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + *

        An XMLInputSource analogue to javax.xml.transform.stax.StAXSource.

        + * + * @version $Id$ + */ +public final class StAXInputSource extends XMLInputSource { + + private final XMLStreamReader fStreamReader; + private final XMLEventReader fEventReader; + private final boolean fConsumeRemainingContent; + + public StAXInputSource(XMLStreamReader source) { + this(source, false); + } + + public StAXInputSource(XMLStreamReader source, boolean consumeRemainingContent) { + super(null, getStreamReaderSystemId(source), null); + if (source == null) { + throw new IllegalArgumentException("XMLStreamReader parameter cannot be null."); + } + fStreamReader = source; + fEventReader = null; + fConsumeRemainingContent = consumeRemainingContent; + } + + public StAXInputSource(XMLEventReader source) { + this(source, false); + } + + public StAXInputSource(XMLEventReader source, boolean consumeRemainingContent) { + super(null, getEventReaderSystemId(source), null); + if (source == null) { + throw new IllegalArgumentException("XMLEventReader parameter cannot be null."); + } + fStreamReader = null; + fEventReader = source; + fConsumeRemainingContent = consumeRemainingContent; + } + + public XMLStreamReader getXMLStreamReader() { + return fStreamReader; + } + + public XMLEventReader getXMLEventReader() { + return fEventReader; + } + + public boolean shouldConsumeRemainingContent() { + return fConsumeRemainingContent; + } + + public void setSystemId(String systemId){ + throw new UnsupportedOperationException("Cannot set the system ID on a StAXInputSource"); + } + + private static String getStreamReaderSystemId(XMLStreamReader reader) { + if (reader != null) { + return reader.getLocation().getSystemId(); + } + return null; + } + + private static String getEventReaderSystemId(XMLEventReader reader) { + try { + if (reader != null) { + return reader.peek().getLocation().getSystemId(); + } + } + catch (XMLStreamException e) {} + return null; + } + +} // StAXInputSource diff --git a/resources/xerces2-j-src/org/apache/xerces/util/StAXLocationWrapper.java b/resources/xerces2-j-src/org/apache/xerces/util/StAXLocationWrapper.java new file mode 100644 index 0000000..00f11ae --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/StAXLocationWrapper.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import javax.xml.stream.Location; + +import org.apache.xerces.xni.XMLLocator; + +/** + *

        A light wrapper around a StAX location. This is useful + * when bridging between StAX and XNI components.

        + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class StAXLocationWrapper implements XMLLocator { + + private Location fLocation = null; + + public StAXLocationWrapper() {} + + public void setLocation(Location location) { + fLocation = location; + } + + public Location getLocation() { + return fLocation; + } + + /* + * XMLLocator methods + */ + + public String getPublicId() { + if (fLocation != null) { + return fLocation.getPublicId(); + } + return null; + } + + public String getLiteralSystemId() { + if (fLocation != null) { + return fLocation.getSystemId(); + } + return null; + } + + public String getBaseSystemId() { + return null; + } + + public String getExpandedSystemId() { + return getLiteralSystemId(); + } + + public int getLineNumber() { + if (fLocation != null) { + return fLocation.getLineNumber(); + } + return -1; + } + + public int getColumnNumber() { + if (fLocation != null) { + return fLocation.getColumnNumber(); + } + return -1; + } + + public int getCharacterOffset() { + if (fLocation != null) { + return fLocation.getCharacterOffset(); + } + return -1; + } + + public String getEncoding() { + return null; + } + + public String getXMLVersion() { + return null; + } + +} // StAXLocationWrapper diff --git a/resources/xerces2-j-src/org/apache/xerces/util/SymbolHash.java b/resources/xerces2-j-src/org/apache/xerces/util/SymbolHash.java new file mode 100644 index 0000000..f2c001a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/SymbolHash.java @@ -0,0 +1,326 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +/** + * This class is an unsynchronized hash table primary used for String + * to Object mapping. + *

        + * The hash code uses the same algorithm as SymbolTable class. + * + * @author Elena Litani + * @version $Id$ + */ +public class SymbolHash { + + // + // Constants + // + + /** Default table size. */ + protected static final int TABLE_SIZE = 101; + + /** Maximum hash collisions per bucket. */ + protected static final int MAX_HASH_COLLISIONS = 40; + + protected static final int MULTIPLIERS_SIZE = 1 << 5; + protected static final int MULTIPLIERS_MASK = MULTIPLIERS_SIZE - 1; + + // + // Data + // + + /** Actual table size **/ + protected int fTableSize; + + /** Buckets. */ + protected Entry[] fBuckets; + + /** Number of elements. */ + protected int fNum = 0; + + /** + * Array of randomly selected hash function multipliers or null + * if the default String.hashCode() function should be used. + */ + protected int[] fHashMultipliers; + + // + // Constructors + // + + /** Constructs a key table with the default size. */ + public SymbolHash() { + this(TABLE_SIZE); + } + + /** + * Constructs a key table with a given size. + * + * @param size the size of the key table. + */ + public SymbolHash(int size) { + fTableSize = size; + fBuckets = new Entry[fTableSize]; + } + + // + // Public methods + // + + /** + * Adds the key/value mapping to the key table. If the key already exists, + * the previous value associated with this key is overwritten by the new + * value. + * + * @param key + * @param value + */ + public void put(Object key, Object value) { + + // search for identical key + int collisionCount = 0; + final int hash = hash(key); + int bucket = hash % fTableSize; + for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (key.equals(entry.key)) { + // replace old value + entry.value = value; + return; + } + ++collisionCount; + } + + if (fNum >= fTableSize) { + // Rehash the table if the number of entries + // would exceed the number of buckets. + rehash(); + bucket = hash % fTableSize; + } + else if (collisionCount >= MAX_HASH_COLLISIONS && key instanceof String) { + // Select a new hash function and rehash the table if + // MAX_HASH_COLLISIONS is exceeded. + rebalance(); + bucket = hash(key) % fTableSize; + } + + // create new entry + Entry entry = new Entry(key, value, fBuckets[bucket]); + fBuckets[bucket] = entry; + ++fNum; + } + + /** + * Get the value associated with the given key. + * + * @param key + * @return the value associated with the given key. + */ + public Object get(Object key) { + int bucket = hash(key) % fTableSize; + Entry entry = search(key, bucket); + if (entry != null) { + return entry.value; + } + return null; + } + + /** + * Get the number of key/value pairs stored in this table. + * + * @return the number of key/value pairs stored in this table. + */ + public int getLength() { + return fNum; + } + + /** + * Add all values to the given array. The array must have enough entry. + * + * @param elements the array to store the elements + * @param from where to start store element in the array + * @return number of elements copied to the array + */ + public int getValues(Object[] elements, int from) { + for (int i=0, j=0; i 0;) { + for (Entry old = oldTable[i]; old != null; ) { + Entry e = old; + old = old.next; + + int index = hash(e.key) % newCapacity; + e.next = newTable[index]; + newTable[index] = e; + } + } + } + + // + // Classes + // + + /** + * This class is a key table entry. Each entry acts as a node + * in a linked list. + */ + protected static final class Entry { + // key/value + public Object key; + public Object value; + /** The next entry. */ + public Entry next; + + public Entry() { + key = null; + value = null; + next = null; + } + + public Entry(Object key, Object value, Entry next) { + this.key = key; + this.value = value; + this.next = next; + } + + public Entry makeClone() { + Entry entry = new Entry(); + entry.key = key; + entry.value = value; + if (next != null) + entry.next = next.makeClone(); + return entry; + } + } // entry + +} // class SymbolHash + diff --git a/resources/xerces2-j-src/org/apache/xerces/util/SymbolTable.java b/resources/xerces2-j-src/org/apache/xerces/util/SymbolTable.java new file mode 100644 index 0000000..b7be36a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/SymbolTable.java @@ -0,0 +1,495 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +/** + * This class is a symbol table implementation that guarantees that + * strings used as identifiers are unique references. Multiple calls + * to addSymbol will always return the same string + * reference. + *

        + * The symbol table performs the same task as String.intern() + * with the following differences: + *

          + *
        • + * A new string object does not need to be created in order to + * retrieve a unique reference. Symbols can be added by using + * a series of characters in a character array. + *
        • + *
        • + * Users of the symbol table can provide their own symbol hashing + * implementation. For example, a simple string hashing algorithm + * may fail to produce a balanced set of hashcodes for symbols + * that are mostly unique. Strings with similar leading + * characters are especially prone to this poor hashing behavior. + *
        • + *
        + * + * An instance of SymbolTable has two parameters that affect its + * performance: initial capacity and load factor. The + * capacity is the number of buckets in the SymbolTable, and the + * initial capacity is simply the capacity at the time the SymbolTable + * is created. Note that the SymbolTable is open: in the case of a "hash + * collision", a single bucket stores multiple entries, which must be searched + * sequentially. The load factor is a measure of how full the SymbolTable + * is allowed to get before its capacity is automatically increased. + * When the number of entries in the SymbolTable exceeds the product of the load + * factor and the current capacity, the capacity is increased by calling the + * rehash method.

        + * + * Generally, the default load factor (.75) offers a good tradeoff between + * time and space costs. Higher values decrease the space overhead but + * increase the time cost to look up an entry (which is reflected in most + * SymbolTable operations, including addSymbol and containsSymbol).

        + * + * The initial capacity controls a tradeoff between wasted space and the + * need for rehash operations, which are time-consuming. + * No rehash operations will ever occur if the initial + * capacity is greater than the maximum number of entries the + * Hashtable will contain divided by its load factor. However, + * setting the initial capacity too high can waste space.

        + * + * If many entries are to be made into a SymbolTable, + * creating it with a sufficiently large capacity may allow the + * entries to be inserted more efficiently than letting it perform + * automatic rehashing as needed to grow the table.

        + + * @see SymbolHash + * + * @author Andy Clark + * @author John Kim, IBM + * + * @version $Id$ + */ +public class SymbolTable { + + // + // Constants + // + + /** Default table size. */ + protected static final int TABLE_SIZE = 101; + + /** Maximum hash collisions per bucket for a table with load factor == 1. */ + protected static final int MAX_HASH_COLLISIONS = 40; + + protected static final int MULTIPLIERS_SIZE = 1 << 5; + protected static final int MULTIPLIERS_MASK = MULTIPLIERS_SIZE - 1; + + // + // Data + // + + /** Buckets. */ + protected Entry[] fBuckets = null; + + /** actual table size **/ + protected int fTableSize; + + /** The total number of entries in the hash table. */ + protected transient int fCount; + + /** The table is rehashed when its size exceeds this threshold. (The + * value of this field is (int)(capacity * loadFactor).) */ + protected int fThreshold; + + /** The load factor for the SymbolTable. */ + protected float fLoadFactor; + + /** + * A new hash function is selected and the table is rehashed when + * the number of keys in the bucket exceeds this threshold. + */ + protected final int fCollisionThreshold; + + /** + * Array of randomly selected hash function multipliers or null + * if the default String.hashCode() function should be used. + */ + protected int[] fHashMultipliers; + + // + // Constructors + // + + /** + * Constructs a new, empty SymbolTable with the specified initial + * capacity and the specified load factor. + * + * @param initialCapacity the initial capacity of the SymbolTable. + * @param loadFactor the load factor of the SymbolTable. + * @throws IllegalArgumentException if the initial capacity is less + * than zero, or if the load factor is nonpositive. + */ + public SymbolTable(int initialCapacity, float loadFactor) { + + if (initialCapacity < 0) { + throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); + } + + if (loadFactor <= 0 || Float.isNaN(loadFactor)) { + throw new IllegalArgumentException("Illegal Load: " + loadFactor); + } + + if (initialCapacity == 0) { + initialCapacity = 1; + } + + fLoadFactor = loadFactor; + fTableSize = initialCapacity; + fBuckets = new Entry[fTableSize]; + fThreshold = (int)(fTableSize * loadFactor); + fCollisionThreshold = (int)(MAX_HASH_COLLISIONS * loadFactor); + fCount = 0; + } + + /** + * Constructs a new, empty SymbolTable with the specified initial capacity + * and default load factor, which is 0.75. + * + * @param initialCapacity the initial capacity of the hashtable. + * @throws IllegalArgumentException if the initial capacity is less + * than zero. + */ + public SymbolTable(int initialCapacity) { + this(initialCapacity, 0.75f); + } + + /** + * Constructs a new, empty SymbolTable with a default initial capacity (101) + * and load factor, which is 0.75. + */ + public SymbolTable() { + this(TABLE_SIZE, 0.75f); + } + + // + // Public methods + // + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param symbol The new symbol. + */ + public String addSymbol(String symbol) { + + // search for identical symbol + int collisionCount = 0; + int bucket = hash(symbol) % fTableSize; + for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (entry.symbol.equals(symbol)) { + return entry.symbol; + } + ++collisionCount; + } + return addSymbol0(symbol, bucket, collisionCount); + + } // addSymbol(String):String + + private String addSymbol0(String symbol, int bucket, int collisionCount) { + + if (fCount >= fThreshold) { + // Rehash the table if the threshold is exceeded + rehash(); + bucket = hash(symbol) % fTableSize; + } + else if (collisionCount >= fCollisionThreshold) { + // Select a new hash function and rehash the table if + // the collision threshold is exceeded. + rebalance(); + bucket = hash(symbol) % fTableSize; + } + + // create new entry + Entry entry = new Entry(symbol, fBuckets[bucket]); + fBuckets[bucket] = entry; + ++fCount; + return entry.symbol; + + } // addSymbol0(String,int,int):String + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param buffer The buffer containing the new symbol. + * @param offset The offset into the buffer of the new symbol. + * @param length The length of the new symbol in the buffer. + */ + public String addSymbol(char[] buffer, int offset, int length) { + + // search for identical symbol + int collisionCount = 0; + int bucket = hash(buffer, offset, length) % fTableSize; + OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (length == entry.characters.length) { + for (int i = 0; i < length; i++) { + if (buffer[offset + i] != entry.characters[i]) { + ++collisionCount; + continue OUTER; + } + } + return entry.symbol; + } + ++collisionCount; + } + return addSymbol0(buffer, offset, length, bucket, collisionCount); + + } // addSymbol(char[],int,int):String + + private String addSymbol0(char[] buffer, int offset, int length, int bucket, int collisionCount) { + + if (fCount >= fThreshold) { + // Rehash the table if the threshold is exceeded + rehash(); + bucket = hash(buffer, offset, length) % fTableSize; + } + else if (collisionCount >= fCollisionThreshold) { + // Select a new hash function and rehash the table if + // the collision threshold is exceeded. + rebalance(); + bucket = hash(buffer, offset, length) % fTableSize; + } + + // add new entry + Entry entry = new Entry(buffer, offset, length, fBuckets[bucket]); + fBuckets[bucket] = entry; + ++fCount; + return entry.symbol; + + } // addSymbol0(char[],int,int,int,int):String + + /** + * Returns a hashcode value for the specified symbol. The value + * returned by this method must be identical to the value returned + * by the hash(char[],int,int) method when called + * with the character array that comprises the symbol string. + * + * @param symbol The symbol to hash. + */ + public int hash(String symbol) { + if (fHashMultipliers == null) { + return symbol.hashCode() & 0x7FFFFFFF; + } + return hash0(symbol); + } // hash(String):int + + private int hash0(String symbol) { + int code = 0; + final int length = symbol.length(); + final int[] multipliers = fHashMultipliers; + for (int i = 0; i < length; ++i) { + code = code * multipliers[i & MULTIPLIERS_MASK] + symbol.charAt(i); + } + return code & 0x7FFFFFFF; + } // hash0(String):int + + /** + * Returns a hashcode value for the specified symbol information. + * The value returned by this method must be identical to the value + * returned by the hash(String) method when called + * with the string object created from the symbol information. + * + * @param buffer The character buffer containing the symbol. + * @param offset The offset into the character buffer of the start + * of the symbol. + * @param length The length of the symbol. + */ + public int hash(char[] buffer, int offset, int length) { + if (fHashMultipliers == null) { + int code = 0; + for (int i = 0; i < length; ++i) { + code = code * 31 + buffer[offset + i]; + } + return code & 0x7FFFFFFF; + } + return hash0(buffer, offset, length); + + } // hash(char[],int,int):int + + private int hash0(char[] buffer, int offset, int length) { + int code = 0; + final int[] multipliers = fHashMultipliers; + for (int i = 0; i < length; ++i) { + code = code * multipliers[i & MULTIPLIERS_MASK] + buffer[offset + i]; + } + return code & 0x7FFFFFFF; + } // hash0(char[],int,int):int + + /** + * Increases the capacity of and internally reorganizes this + * SymbolTable, in order to accommodate and access its entries more + * efficiently. This method is called automatically when the + * number of keys in the SymbolTable exceeds this hashtable's capacity + * and load factor. + */ + protected void rehash() { + rehashCommon(fBuckets.length * 2 + 1); + } + + /** + * Randomly selects a new hash function and reorganizes this SymbolTable + * in order to more evenly distribute its entries across the table. This + * method is called automatically when the number keys in one of the + * SymbolTable's buckets exceeds the given collision threshold. + */ + protected void rebalance() { + if (fHashMultipliers == null) { + fHashMultipliers = new int[MULTIPLIERS_SIZE]; + } + PrimeNumberSequenceGenerator.generateSequence(fHashMultipliers); + rehashCommon(fBuckets.length); + } + + private void rehashCommon(final int newCapacity) { + + int oldCapacity = fBuckets.length; + Entry[] oldTable = fBuckets; + + Entry[] newTable = new Entry[newCapacity]; + + fThreshold = (int)(newCapacity * fLoadFactor); + fBuckets = newTable; + fTableSize = fBuckets.length; + + for (int i = oldCapacity ; i-- > 0 ;) { + for (Entry old = oldTable[i] ; old != null ; ) { + Entry e = old; + old = old.next; + + int index = hash(e.symbol) % newCapacity; + e.next = newTable[index]; + newTable[index] = e; + } + } + } + + /** + * Returns true if the symbol table already contains the specified + * symbol. + * + * @param symbol The symbol to look for. + */ + public boolean containsSymbol(String symbol) { + + // search for identical symbol + int bucket = hash(symbol) % fTableSize; + int length = symbol.length(); + OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (length == entry.characters.length) { + for (int i = 0; i < length; i++) { + if (symbol.charAt(i) != entry.characters[i]) { + continue OUTER; + } + } + return true; + } + } + + return false; + + } // containsSymbol(String):boolean + + /** + * Returns true if the symbol table already contains the specified + * symbol. + * + * @param buffer The buffer containing the symbol to look for. + * @param offset The offset into the buffer. + * @param length The length of the symbol in the buffer. + */ + public boolean containsSymbol(char[] buffer, int offset, int length) { + + // search for identical symbol + int bucket = hash(buffer, offset, length) % fTableSize; + OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (length == entry.characters.length) { + for (int i = 0; i < length; i++) { + if (buffer[offset + i] != entry.characters[i]) { + continue OUTER; + } + } + return true; + } + } + + return false; + + } // containsSymbol(char[],int,int):boolean + + // + // Classes + // + + /** + * This class is a symbol table entry. Each entry acts as a node + * in a linked list. + */ + protected static final class Entry { + + // + // Data + // + + /** Symbol. */ + public final String symbol; + + /** + * Symbol characters. This information is duplicated here for + * comparison performance. + */ + public final char[] characters; + + /** The next entry. */ + public Entry next; + + // + // Constructors + // + + /** + * Constructs a new entry from the specified symbol and next entry + * reference. + */ + public Entry(String symbol, Entry next) { + this.symbol = symbol.intern(); + characters = new char[symbol.length()]; + symbol.getChars(0, characters.length, characters, 0); + this.next = next; + } + + /** + * Constructs a new entry from the specified symbol information and + * next entry reference. + */ + public Entry(char[] ch, int offset, int length, Entry next) { + characters = new char[length]; + System.arraycopy(ch, offset, characters, 0, length); + symbol = new String(characters).intern(); + this.next = next; + } + + } // class Entry + +} // class SymbolTable diff --git a/resources/xerces2-j-src/org/apache/xerces/util/SynchronizedSymbolTable.java b/resources/xerces2-j-src/org/apache/xerces/util/SynchronizedSymbolTable.java new file mode 100644 index 0000000..6cf3e06 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/SynchronizedSymbolTable.java @@ -0,0 +1,127 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +/** + * Synchronized symbol table. + * + * This class moved into the util package since it's needed by multiple + * other classes (CachingParserPool, XMLGrammarCachingConfiguration). + * + * @author Andy Clark, IBM + * @version $Id$ + */ + +public final class SynchronizedSymbolTable + extends SymbolTable { + + // + // Data + // + + /** Main symbol table. */ + protected SymbolTable fSymbolTable; + + // + // Constructors + // + + /** Constructs a synchronized symbol table. */ + public SynchronizedSymbolTable(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + } // (SymbolTable) + + // construct synchronized symbol table of default size + public SynchronizedSymbolTable() { + fSymbolTable = new SymbolTable(); + } // init() + + // construct synchronized symbol table of given size + public SynchronizedSymbolTable(int size) { + fSymbolTable = new SymbolTable(size); + } // init(int) + + // + // SymbolTable methods + // + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param symbol The new symbol. + */ + public String addSymbol(String symbol) { + + synchronized (fSymbolTable) { + return fSymbolTable.addSymbol(symbol); + } + + } // addSymbol(String) + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param buffer The buffer containing the new symbol. + * @param offset The offset into the buffer of the new symbol. + * @param length The length of the new symbol in the buffer. + */ + public String addSymbol(char[] buffer, int offset, int length) { + + synchronized (fSymbolTable) { + return fSymbolTable.addSymbol(buffer, offset, length); + } + + } // addSymbol(char[],int,int):String + + /** + * Returns true if the symbol table already contains the specified + * symbol. + * + * @param symbol The symbol to look for. + */ + public boolean containsSymbol(String symbol) { + + synchronized (fSymbolTable) { + return fSymbolTable.containsSymbol(symbol); + } + + } // containsSymbol(String):boolean + + /** + * Returns true if the symbol table already contains the specified + * symbol. + * + * @param buffer The buffer containing the symbol to look for. + * @param offset The offset into the buffer. + * @param length The length of the symbol in the buffer. + */ + public boolean containsSymbol(char[] buffer, int offset, int length) { + + synchronized (fSymbolTable) { + return fSymbolTable.containsSymbol(buffer, offset, length); + } + + } // containsSymbol(char[],int,int):boolean + +} // class SynchronizedSymbolTable diff --git a/resources/xerces2-j-src/org/apache/xerces/util/URI.java b/resources/xerces2-j-src/org/apache/xerces/util/URI.java new file mode 100644 index 0000000..72684ec --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/URI.java @@ -0,0 +1,2187 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.io.IOException; +import java.io.Serializable; +import java.util.Locale; + +/********************************************************************** +* A class to represent a Uniform Resource Identifier (URI). This class +* is designed to handle the parsing of URIs and provide access to +* the various components (scheme, host, port, userinfo, path, query +* string and fragment) that may constitute a URI. +*

        +* Parsing of a URI specification is done according to the URI +* syntax described in +* RFC 2396, +* and amended by +* RFC 2732. +*

        +* Every absolute URI consists of a scheme, followed by a colon (':'), +* followed by a scheme-specific part. For URIs that follow the +* "generic URI" syntax, the scheme-specific part begins with two +* slashes ("//") and may be followed by an authority segment (comprised +* of user information, host, and port), path segment, query segment +* and fragment. Note that RFC 2396 no longer specifies the use of the +* parameters segment and excludes the "user:password" syntax as part of +* the authority segment. If "user:password" appears in a URI, the entire +* user/password string is stored as userinfo. +*

        +* For URIs that do not follow the "generic URI" syntax (e.g. mailto), +* the entire scheme-specific part is treated as the "path" portion +* of the URI. +*

        +* Note that, unlike the java.net.URL class, this class does not provide +* any built-in network access functionality nor does it provide any +* scheme-specific functionality (for example, it does not know a +* default port for a specific scheme). Rather, it only knows the +* grammar and basic set of operations that can be applied to a URI. +* +* @version $Id$ +* +**********************************************************************/ + public class URI implements Serializable { + + /******************************************************************* + * MalformedURIExceptions are thrown in the process of building a URI + * or setting fields on a URI when an operation would result in an + * invalid URI specification. + * + ********************************************************************/ + public static class MalformedURIException extends IOException { + + /** Serialization version. */ + static final long serialVersionUID = -6695054834342951930L; + + /****************************************************************** + * Constructs a MalformedURIException with no specified + * detail message. + ******************************************************************/ + public MalformedURIException() { + super(); + } + + /***************************************************************** + * Constructs a MalformedURIException with the + * specified detail message. + * + * @param p_msg the detail message. + ******************************************************************/ + public MalformedURIException(String p_msg) { + super(p_msg); + } + } + + /** Serialization version. */ + static final long serialVersionUID = 1601921774685357214L; + + private static final byte [] fgLookupTable = new byte[128]; + + /** + * Character Classes + */ + + /** reserved characters ;/?:@&=+$,[] */ + //RFC 2732 added '[' and ']' as reserved characters + private static final int RESERVED_CHARACTERS = 0x01; + + /** URI punctuation mark characters: -_.!~*'() - these, combined with + alphanumerics, constitute the "unreserved" characters */ + private static final int MARK_CHARACTERS = 0x02; + + /** scheme can be composed of alphanumerics and these characters: +-. */ + private static final int SCHEME_CHARACTERS = 0x04; + + /** userinfo can be composed of unreserved, escaped and these + characters: ;:&=+$, */ + private static final int USERINFO_CHARACTERS = 0x08; + + /** ASCII letter characters */ + private static final int ASCII_ALPHA_CHARACTERS = 0x10; + + /** ASCII digit characters */ + private static final int ASCII_DIGIT_CHARACTERS = 0x20; + + /** ASCII hex characters */ + private static final int ASCII_HEX_CHARACTERS = 0x40; + + /** Path characters */ + private static final int PATH_CHARACTERS = 0x80; + + /** Mask for alpha-numeric characters */ + private static final int MASK_ALPHA_NUMERIC = ASCII_ALPHA_CHARACTERS | ASCII_DIGIT_CHARACTERS; + + /** Mask for unreserved characters */ + private static final int MASK_UNRESERVED_MASK = MASK_ALPHA_NUMERIC | MARK_CHARACTERS; + + /** Mask for URI allowable characters except for % */ + private static final int MASK_URI_CHARACTER = MASK_UNRESERVED_MASK | RESERVED_CHARACTERS; + + /** Mask for scheme characters */ + private static final int MASK_SCHEME_CHARACTER = MASK_ALPHA_NUMERIC | SCHEME_CHARACTERS; + + /** Mask for userinfo characters */ + private static final int MASK_USERINFO_CHARACTER = MASK_UNRESERVED_MASK | USERINFO_CHARACTERS; + + /** Mask for path characters */ + private static final int MASK_PATH_CHARACTER = MASK_UNRESERVED_MASK | PATH_CHARACTERS; + + static { + // Add ASCII Digits and ASCII Hex Numbers + for (int i = '0'; i <= '9'; ++i) { + fgLookupTable[i] |= ASCII_DIGIT_CHARACTERS | ASCII_HEX_CHARACTERS; + } + + // Add ASCII Letters and ASCII Hex Numbers + for (int i = 'A'; i <= 'F'; ++i) { + fgLookupTable[i] |= ASCII_ALPHA_CHARACTERS | ASCII_HEX_CHARACTERS; + fgLookupTable[i+0x00000020] |= ASCII_ALPHA_CHARACTERS | ASCII_HEX_CHARACTERS; + } + + // Add ASCII Letters + for (int i = 'G'; i <= 'Z'; ++i) { + fgLookupTable[i] |= ASCII_ALPHA_CHARACTERS; + fgLookupTable[i+0x00000020] |= ASCII_ALPHA_CHARACTERS; + } + + // Add Reserved Characters + fgLookupTable[';'] |= RESERVED_CHARACTERS; + fgLookupTable['/'] |= RESERVED_CHARACTERS; + fgLookupTable['?'] |= RESERVED_CHARACTERS; + fgLookupTable[':'] |= RESERVED_CHARACTERS; + fgLookupTable['@'] |= RESERVED_CHARACTERS; + fgLookupTable['&'] |= RESERVED_CHARACTERS; + fgLookupTable['='] |= RESERVED_CHARACTERS; + fgLookupTable['+'] |= RESERVED_CHARACTERS; + fgLookupTable['$'] |= RESERVED_CHARACTERS; + fgLookupTable[','] |= RESERVED_CHARACTERS; + fgLookupTable['['] |= RESERVED_CHARACTERS; + fgLookupTable[']'] |= RESERVED_CHARACTERS; + + // Add Mark Characters + fgLookupTable['-'] |= MARK_CHARACTERS; + fgLookupTable['_'] |= MARK_CHARACTERS; + fgLookupTable['.'] |= MARK_CHARACTERS; + fgLookupTable['!'] |= MARK_CHARACTERS; + fgLookupTable['~'] |= MARK_CHARACTERS; + fgLookupTable['*'] |= MARK_CHARACTERS; + fgLookupTable['\''] |= MARK_CHARACTERS; + fgLookupTable['('] |= MARK_CHARACTERS; + fgLookupTable[')'] |= MARK_CHARACTERS; + + // Add Scheme Characters + fgLookupTable['+'] |= SCHEME_CHARACTERS; + fgLookupTable['-'] |= SCHEME_CHARACTERS; + fgLookupTable['.'] |= SCHEME_CHARACTERS; + + // Add Userinfo Characters + fgLookupTable[';'] |= USERINFO_CHARACTERS; + fgLookupTable[':'] |= USERINFO_CHARACTERS; + fgLookupTable['&'] |= USERINFO_CHARACTERS; + fgLookupTable['='] |= USERINFO_CHARACTERS; + fgLookupTable['+'] |= USERINFO_CHARACTERS; + fgLookupTable['$'] |= USERINFO_CHARACTERS; + fgLookupTable[','] |= USERINFO_CHARACTERS; + + // Add Path Characters + fgLookupTable[';'] |= PATH_CHARACTERS; + fgLookupTable['/'] |= PATH_CHARACTERS; + fgLookupTable[':'] |= PATH_CHARACTERS; + fgLookupTable['@'] |= PATH_CHARACTERS; + fgLookupTable['&'] |= PATH_CHARACTERS; + fgLookupTable['='] |= PATH_CHARACTERS; + fgLookupTable['+'] |= PATH_CHARACTERS; + fgLookupTable['$'] |= PATH_CHARACTERS; + fgLookupTable[','] |= PATH_CHARACTERS; + } + + /** Stores the scheme (usually the protocol) for this URI. */ + private String m_scheme = null; + + /** If specified, stores the userinfo for this URI; otherwise null */ + private String m_userinfo = null; + + /** If specified, stores the host for this URI; otherwise null */ + private String m_host = null; + + /** If specified, stores the port for this URI; otherwise -1 */ + private int m_port = -1; + + /** If specified, stores the registry based authority for this URI; otherwise -1 */ + private String m_regAuthority = null; + + /** If specified, stores the path for this URI; otherwise null */ + private String m_path = null; + + /** If specified, stores the query string for this URI; otherwise + null. */ + private String m_queryString = null; + + /** If specified, stores the fragment for this URI; otherwise null */ + private String m_fragment = null; + + /** + * Construct a new and uninitialized URI. + */ + public URI() { + } + + /** + * Construct a new URI from another URI. All fields for this URI are + * set equal to the fields of the URI passed in. + * + * @param p_other the URI to copy (cannot be null) + */ + public URI(URI p_other) { + initialize(p_other); + } + + /** + * Construct a new URI from a URI specification string. If the + * specification follows the "generic URI" syntax, (two slashes + * following the first colon), the specification will be parsed + * accordingly - setting the scheme, userinfo, host,port, path, query + * string and fragment fields as necessary. If the specification does + * not follow the "generic URI" syntax, the specification is parsed + * into a scheme and scheme-specific part (stored as the path) only. + * + * @param p_uriSpec the URI specification string (cannot be null or + * empty) + * + * @exception MalformedURIException if p_uriSpec violates any syntax + * rules + */ + public URI(String p_uriSpec) throws MalformedURIException { + this((URI)null, p_uriSpec); + } + + /** + * Construct a new URI from a URI specification string. If the + * specification follows the "generic URI" syntax, (two slashes + * following the first colon), the specification will be parsed + * accordingly - setting the scheme, userinfo, host,port, path, query + * string and fragment fields as necessary. If the specification does + * not follow the "generic URI" syntax, the specification is parsed + * into a scheme and scheme-specific part (stored as the path) only. + * Construct a relative URI if boolean is assigned to "true" + * and p_uriSpec is not valid absolute URI, instead of throwing an exception. + * + * @param p_uriSpec the URI specification string (cannot be null or + * empty) + * @param allowNonAbsoluteURI true to permit non-absolute URIs, + * false otherwise. + * + * @exception MalformedURIException if p_uriSpec violates any syntax + * rules + */ + public URI(String p_uriSpec, boolean allowNonAbsoluteURI) throws MalformedURIException { + this((URI)null, p_uriSpec, allowNonAbsoluteURI); + } + + /** + * Construct a new URI from a base URI and a URI specification string. + * The URI specification string may be a relative URI. + * + * @param p_base the base URI (cannot be null if p_uriSpec is null or + * empty) + * @param p_uriSpec the URI specification string (cannot be null or + * empty if p_base is null) + * + * @exception MalformedURIException if p_uriSpec violates any syntax + * rules + */ + public URI(URI p_base, String p_uriSpec) throws MalformedURIException { + initialize(p_base, p_uriSpec); + } + + /** + * Construct a new URI from a base URI and a URI specification string. + * The URI specification string may be a relative URI. + * Construct a relative URI if boolean is assigned to "true" + * and p_uriSpec is not valid absolute URI and p_base is null + * instead of throwing an exception. + * + * @param p_base the base URI (cannot be null if p_uriSpec is null or + * empty) + * @param p_uriSpec the URI specification string (cannot be null or + * empty if p_base is null) + * @param allowNonAbsoluteURI true to permit non-absolute URIs, + * false otherwise. + * + * @exception MalformedURIException if p_uriSpec violates any syntax + * rules + */ + public URI(URI p_base, String p_uriSpec, boolean allowNonAbsoluteURI) throws MalformedURIException { + initialize(p_base, p_uriSpec, allowNonAbsoluteURI); + } + + /** + * Construct a new URI that does not follow the generic URI syntax. + * Only the scheme and scheme-specific part (stored as the path) are + * initialized. + * + * @param p_scheme the URI scheme (cannot be null or empty) + * @param p_schemeSpecificPart the scheme-specific part (cannot be + * null or empty) + * + * @exception MalformedURIException if p_scheme violates any + * syntax rules + */ + public URI(String p_scheme, String p_schemeSpecificPart) + throws MalformedURIException { + if (p_scheme == null || p_scheme.trim().length() == 0) { + throw new MalformedURIException( + "Cannot construct URI with null/empty scheme!"); + } + if (p_schemeSpecificPart == null || + p_schemeSpecificPart.trim().length() == 0) { + throw new MalformedURIException( + "Cannot construct URI with null/empty scheme-specific part!"); + } + setScheme(p_scheme); + setPath(p_schemeSpecificPart); + } + + /** + * Construct a new URI that follows the generic URI syntax from its + * component parts. Each component is validated for syntax and some + * basic semantic checks are performed as well. See the individual + * setter methods for specifics. + * + * @param p_scheme the URI scheme (cannot be null or empty) + * @param p_host the hostname, IPv4 address or IPv6 reference for the URI + * @param p_path the URI path - if the path contains '?' or '#', + * then the query string and/or fragment will be + * set from the path; however, if the query and + * fragment are specified both in the path and as + * separate parameters, an exception is thrown + * @param p_queryString the URI query string (cannot be specified + * if path is null) + * @param p_fragment the URI fragment (cannot be specified if path + * is null) + * + * @exception MalformedURIException if any of the parameters violates + * syntax rules or semantic rules + */ + public URI(String p_scheme, String p_host, String p_path, + String p_queryString, String p_fragment) + throws MalformedURIException { + this(p_scheme, null, p_host, -1, p_path, p_queryString, p_fragment); + } + + /** + * Construct a new URI that follows the generic URI syntax from its + * component parts. Each component is validated for syntax and some + * basic semantic checks are performed as well. See the individual + * setter methods for specifics. + * + * @param p_scheme the URI scheme (cannot be null or empty) + * @param p_userinfo the URI userinfo (cannot be specified if host + * is null) + * @param p_host the hostname, IPv4 address or IPv6 reference for the URI + * @param p_port the URI port (may be -1 for "unspecified"; cannot + * be specified if host is null) + * @param p_path the URI path - if the path contains '?' or '#', + * then the query string and/or fragment will be + * set from the path; however, if the query and + * fragment are specified both in the path and as + * separate parameters, an exception is thrown + * @param p_queryString the URI query string (cannot be specified + * if path is null) + * @param p_fragment the URI fragment (cannot be specified if path + * is null) + * + * @exception MalformedURIException if any of the parameters violates + * syntax rules or semantic rules + */ + public URI(String p_scheme, String p_userinfo, + String p_host, int p_port, String p_path, + String p_queryString, String p_fragment) + throws MalformedURIException { + if (p_scheme == null || p_scheme.trim().length() == 0) { + throw new MalformedURIException("Scheme is required!"); + } + + if (p_host == null) { + if (p_userinfo != null) { + throw new MalformedURIException( + "Userinfo may not be specified if host is not specified!"); + } + if (p_port != -1) { + throw new MalformedURIException( + "Port may not be specified if host is not specified!"); + } + } + + if (p_path != null) { + if (p_path.indexOf('?') != -1 && p_queryString != null) { + throw new MalformedURIException( + "Query string cannot be specified in path and query string!"); + } + + if (p_path.indexOf('#') != -1 && p_fragment != null) { + throw new MalformedURIException( + "Fragment cannot be specified in both the path and fragment!"); + } + } + + setScheme(p_scheme); + setHost(p_host); + setPort(p_port); + setUserinfo(p_userinfo); + setPath(p_path); + setQueryString(p_queryString); + setFragment(p_fragment); + } + + /** + * Initialize all fields of this URI from another URI. + * + * @param p_other the URI to copy (cannot be null) + */ + private void initialize(URI p_other) { + m_scheme = p_other.getScheme(); + m_userinfo = p_other.getUserinfo(); + m_host = p_other.getHost(); + m_port = p_other.getPort(); + m_regAuthority = p_other.getRegBasedAuthority(); + m_path = p_other.getPath(); + m_queryString = p_other.getQueryString(); + m_fragment = p_other.getFragment(); + } + + /** + * Initializes this URI from a base URI and a URI specification string. + * See RFC 2396 Section 4 and Appendix B for specifications on parsing + * the URI and Section 5 for specifications on resolving relative URIs + * and relative paths. + * + * @param p_base the base URI (may be null if p_uriSpec is an absolute + * URI) + * @param p_uriSpec the URI spec string which may be an absolute or + * relative URI (can only be null/empty if p_base + * is not null) + * @param allowNonAbsoluteURI true to permit non-absolute URIs, + * in case of relative URI, false otherwise. + * + * @exception MalformedURIException if p_base is null and p_uriSpec + * is not an absolute URI or if + * p_uriSpec violates syntax rules + */ + private void initialize(URI p_base, String p_uriSpec, boolean allowNonAbsoluteURI) + throws MalformedURIException { + + String uriSpec = p_uriSpec; + int uriSpecLen = (uriSpec != null) ? uriSpec.length() : 0; + + if (p_base == null && uriSpecLen == 0) { + if (allowNonAbsoluteURI) { + m_path = ""; + return; + } + throw new MalformedURIException("Cannot initialize URI with empty parameters."); + } + + // just make a copy of the base if spec is empty + if (uriSpecLen == 0) { + initialize(p_base); + return; + } + + int index = 0; + + // Check for scheme, which must be before '/', '?' or '#'. + int colonIdx = uriSpec.indexOf(':'); + if (colonIdx != -1) { + final int searchFrom = colonIdx - 1; + // search backwards starting from character before ':'. + int slashIdx = uriSpec.lastIndexOf('/', searchFrom); + int queryIdx = uriSpec.lastIndexOf('?', searchFrom); + int fragmentIdx = uriSpec.lastIndexOf('#', searchFrom); + + if (colonIdx == 0 || slashIdx != -1 || + queryIdx != -1 || fragmentIdx != -1) { + // A standalone base is a valid URI according to spec + if (colonIdx == 0 || (p_base == null && fragmentIdx != 0 && !allowNonAbsoluteURI)) { + throw new MalformedURIException("No scheme found in URI."); + } + } + else { + initializeScheme(uriSpec); + index = m_scheme.length()+1; + + // Neither 'scheme:' or 'scheme:#fragment' are valid URIs. + if (colonIdx == uriSpecLen - 1 || uriSpec.charAt(colonIdx+1) == '#') { + throw new MalformedURIException("Scheme specific part cannot be empty."); + } + } + } + else if (p_base == null && uriSpec.indexOf('#') != 0 && !allowNonAbsoluteURI) { + throw new MalformedURIException("No scheme found in URI."); + } + + // Two slashes means we may have authority, but definitely means we're either + // matching net_path or abs_path. These two productions are ambiguous in that + // every net_path (except those containing an IPv6Reference) is an abs_path. + // RFC 2396 resolves this ambiguity by applying a greedy left most matching rule. + // Try matching net_path first, and if that fails we don't have authority so + // then attempt to match abs_path. + // + // net_path = "//" authority [ abs_path ] + // abs_path = "/" path_segments + if (((index+1) < uriSpecLen) && + (uriSpec.charAt(index) == '/' && uriSpec.charAt(index+1) == '/')) { + index += 2; + int startPos = index; + + // Authority will be everything up to path, query or fragment + char testChar = '\0'; + while (index < uriSpecLen) { + testChar = uriSpec.charAt(index); + if (testChar == '/' || testChar == '?' || testChar == '#') { + break; + } + index++; + } + + // Attempt to parse authority. If the section is an empty string + // this is a valid server based authority, so set the host to this + // value. + if (index > startPos) { + // If we didn't find authority we need to back up. Attempt to + // match against abs_path next. + if (!initializeAuthority(uriSpec.substring(startPos, index))) { + index = startPos - 2; + } + } + else { + m_host = ""; + } + } + + initializePath(uriSpec, index); + + // Resolve relative URI to base URI - see RFC 2396 Section 5.2 + // In some cases, it might make more sense to throw an exception + // (when scheme is specified is the string spec and the base URI + // is also specified, for example), but we're just following the + // RFC specifications + if (p_base != null) { + absolutize(p_base); + } + } + + /** + * Initializes this URI from a base URI and a URI specification string. + * See RFC 2396 Section 4 and Appendix B for specifications on parsing + * the URI and Section 5 for specifications on resolving relative URIs + * and relative paths. + * + * @param p_base the base URI (may be null if p_uriSpec is an absolute + * URI) + * @param p_uriSpec the URI spec string which may be an absolute or + * relative URI (can only be null/empty if p_base + * is not null) + * + * @exception MalformedURIException if p_base is null and p_uriSpec + * is not an absolute URI or if + * p_uriSpec violates syntax rules + */ + private void initialize(URI p_base, String p_uriSpec) + throws MalformedURIException { + + String uriSpec = p_uriSpec; + int uriSpecLen = (uriSpec != null) ? uriSpec.length() : 0; + + if (p_base == null && uriSpecLen == 0) { + throw new MalformedURIException( + "Cannot initialize URI with empty parameters."); + } + + // just make a copy of the base if spec is empty + if (uriSpecLen == 0) { + initialize(p_base); + return; + } + + int index = 0; + + // Check for scheme, which must be before '/', '?' or '#'. + int colonIdx = uriSpec.indexOf(':'); + if (colonIdx != -1) { + final int searchFrom = colonIdx - 1; + // search backwards starting from character before ':'. + int slashIdx = uriSpec.lastIndexOf('/', searchFrom); + int queryIdx = uriSpec.lastIndexOf('?', searchFrom); + int fragmentIdx = uriSpec.lastIndexOf('#', searchFrom); + + if (colonIdx == 0 || slashIdx != -1 || + queryIdx != -1 || fragmentIdx != -1) { + // A standalone base is a valid URI according to spec + if (colonIdx == 0 || (p_base == null && fragmentIdx != 0)) { + throw new MalformedURIException("No scheme found in URI."); + } + } + else { + initializeScheme(uriSpec); + index = m_scheme.length()+1; + + // Neither 'scheme:' or 'scheme:#fragment' are valid URIs. + if (colonIdx == uriSpecLen - 1 || uriSpec.charAt(colonIdx+1) == '#') { + throw new MalformedURIException("Scheme specific part cannot be empty."); + } + } + } + else if (p_base == null && uriSpec.indexOf('#') != 0) { + throw new MalformedURIException("No scheme found in URI."); + } + + // Two slashes means we may have authority, but definitely means we're either + // matching net_path or abs_path. These two productions are ambiguous in that + // every net_path (except those containing an IPv6Reference) is an abs_path. + // RFC 2396 resolves this ambiguity by applying a greedy left most matching rule. + // Try matching net_path first, and if that fails we don't have authority so + // then attempt to match abs_path. + // + // net_path = "//" authority [ abs_path ] + // abs_path = "/" path_segments + if (((index+1) < uriSpecLen) && + (uriSpec.charAt(index) == '/' && uriSpec.charAt(index+1) == '/')) { + index += 2; + int startPos = index; + + // Authority will be everything up to path, query or fragment + char testChar = '\0'; + while (index < uriSpecLen) { + testChar = uriSpec.charAt(index); + if (testChar == '/' || testChar == '?' || testChar == '#') { + break; + } + index++; + } + + // Attempt to parse authority. If the section is an empty string + // this is a valid server based authority, so set the host to this + // value. + if (index > startPos) { + // If we didn't find authority we need to back up. Attempt to + // match against abs_path next. + if (!initializeAuthority(uriSpec.substring(startPos, index))) { + index = startPos - 2; + } + } + else { + m_host = ""; + } + } + + initializePath(uriSpec, index); + + // Resolve relative URI to base URI - see RFC 2396 Section 5.2 + // In some cases, it might make more sense to throw an exception + // (when scheme is specified is the string spec and the base URI + // is also specified, for example), but we're just following the + // RFC specifications + if (p_base != null) { + absolutize(p_base); + } + } + + /** + * Absolutize URI with given base URI. + * + * @param p_base base URI for absolutization + */ + public void absolutize(URI p_base) { + + // check to see if this is the current doc - RFC 2396 5.2 #2 + // note that this is slightly different from the RFC spec in that + // we don't include the check for query string being null + // - this handles cases where the urispec is just a query + // string or a fragment (e.g. "?y" or "#s") - + // see which + // identified this as a bug in the RFC + if (m_path.length() == 0 && m_scheme == null && + m_host == null && m_regAuthority == null) { + m_scheme = p_base.getScheme(); + m_userinfo = p_base.getUserinfo(); + m_host = p_base.getHost(); + m_port = p_base.getPort(); + m_regAuthority = p_base.getRegBasedAuthority(); + m_path = p_base.getPath(); + + if (m_queryString == null) { + m_queryString = p_base.getQueryString(); + + if (m_fragment == null) { + m_fragment = p_base.getFragment(); + } + } + return; + } + + // check for scheme - RFC 2396 5.2 #3 + // if we found a scheme, it means absolute URI, so we're done + if (m_scheme == null) { + m_scheme = p_base.getScheme(); + } + else { + return; + } + + // check for authority - RFC 2396 5.2 #4 + // if we found a host, then we've got a network path, so we're done + if (m_host == null && m_regAuthority == null) { + m_userinfo = p_base.getUserinfo(); + m_host = p_base.getHost(); + m_port = p_base.getPort(); + m_regAuthority = p_base.getRegBasedAuthority(); + } + else { + return; + } + + // check for absolute path - RFC 2396 5.2 #5 + if (m_path.length() > 0 && + m_path.startsWith("/")) { + return; + } + + // if we get to this point, we need to resolve relative path + // RFC 2396 5.2 #6 + String path = ""; + String basePath = p_base.getPath(); + + // 6a - get all but the last segment of the base URI path + if (basePath != null && basePath.length() > 0) { + int lastSlash = basePath.lastIndexOf('/'); + if (lastSlash != -1) { + path = basePath.substring(0, lastSlash+1); + } + } + else if (m_path.length() > 0) { + path = "/"; + } + + // 6b - append the relative URI path + path = path.concat(m_path); + + // 6c - remove all "./" where "." is a complete path segment + int index = -1; + while ((index = path.indexOf("/./")) != -1) { + path = path.substring(0, index+1).concat(path.substring(index+3)); + } + + // 6d - remove "." if path ends with "." as a complete path segment + if (path.endsWith("/.")) { + path = path.substring(0, path.length()-1); + } + + // 6e - remove all "/../" where "" is a complete + // path segment not equal to ".." + index = 1; + int segIndex = -1; + String tempString = null; + + while ((index = path.indexOf("/../", index)) > 0) { + tempString = path.substring(0, path.indexOf("/../")); + segIndex = tempString.lastIndexOf('/'); + if (segIndex != -1) { + if (!tempString.substring(segIndex).equals("..")) { + path = path.substring(0, segIndex+1).concat(path.substring(index+4)); + index = segIndex; + } + else { + index += 4; + } + } + else { + index += 4; + } + } + + // 6f - remove ending "/.." where "" is a + // complete path segment + if (path.endsWith("/..")) { + tempString = path.substring(0, path.length()-3); + segIndex = tempString.lastIndexOf('/'); + if (segIndex != -1) { + path = path.substring(0, segIndex+1); + } + } + m_path = path; + } + + /** + * Initialize the scheme for this URI from a URI string spec. + * + * @param p_uriSpec the URI specification (cannot be null) + * + * @exception MalformedURIException if URI does not have a conformant + * scheme + */ + private void initializeScheme(String p_uriSpec) + throws MalformedURIException { + int uriSpecLen = p_uriSpec.length(); + int index = 0; + String scheme = null; + char testChar = '\0'; + + while (index < uriSpecLen) { + testChar = p_uriSpec.charAt(index); + if (testChar == ':' || testChar == '/' || + testChar == '?' || testChar == '#') { + break; + } + index++; + } + scheme = p_uriSpec.substring(0, index); + + if (scheme.length() == 0) { + throw new MalformedURIException("No scheme found in URI."); + } + else { + setScheme(scheme); + } + } + + /** + * Initialize the authority (either server or registry based) + * for this URI from a URI string spec. + * + * @param p_uriSpec the URI specification (cannot be null) + * + * @return true if the given string matched server or registry + * based authority + */ + private boolean initializeAuthority(String p_uriSpec) { + + int index = 0; + int start = 0; + int end = p_uriSpec.length(); + + char testChar = '\0'; + String userinfo = null; + + // userinfo is everything up to @ + if (p_uriSpec.indexOf('@', start) != -1) { + while (index < end) { + testChar = p_uriSpec.charAt(index); + if (testChar == '@') { + break; + } + index++; + } + userinfo = p_uriSpec.substring(start, index); + index++; + } + + // host is everything up to last ':', or up to + // and including ']' if followed by ':'. + String host = null; + start = index; + boolean hasPort = false; + if (index < end) { + if (p_uriSpec.charAt(start) == '[') { + int bracketIndex = p_uriSpec.indexOf(']', start); + index = (bracketIndex != -1) ? bracketIndex : end; + if (index+1 < end && p_uriSpec.charAt(index+1) == ':') { + ++index; + hasPort = true; + } + else { + index = end; + } + } + else { + int colonIndex = p_uriSpec.lastIndexOf(':', end); + index = (colonIndex > start) ? colonIndex : end; + hasPort = (index != end); + } + } + host = p_uriSpec.substring(start, index); + int port = -1; + if (host.length() > 0) { + // port + if (hasPort) { + index++; + start = index; + while (index < end) { + index++; + } + String portStr = p_uriSpec.substring(start, index); + if (portStr.length() > 0) { + // REVISIT: Remove this code. + /** for (int i = 0; i < portStr.length(); i++) { + if (!isDigit(portStr.charAt(i))) { + throw new MalformedURIException( + portStr + + " is invalid. Port should only contain digits!"); + } + }**/ + // REVISIT: Remove this code. + // Store port value as string instead of integer. + try { + port = Integer.parseInt(portStr); + if (port == -1) --port; + } + catch (NumberFormatException nfe) { + port = -2; + } + } + } + } + + if (isValidServerBasedAuthority(host, port, userinfo)) { + m_host = host; + m_port = port; + m_userinfo = userinfo; + return true; + } + // Note: Registry based authority is being removed from a + // new spec for URI which would obsolete RFC 2396. If the + // spec is added to XML errata, processing of reg_name + // needs to be removed. - mrglavas. + else if (isValidRegistryBasedAuthority(p_uriSpec)) { + m_regAuthority = p_uriSpec; + return true; + } + return false; + } + + /** + * Determines whether the components host, port, and user info + * are valid as a server authority. + * + * @param host the host component of authority + * @param port the port number component of authority + * @param userinfo the user info component of authority + * + * @return true if the given host, port, and userinfo compose + * a valid server authority + */ + private boolean isValidServerBasedAuthority(String host, int port, String userinfo) { + + // Check if the host is well formed. + if (!isWellFormedAddress(host)) { + return false; + } + + // Check that port is well formed if it exists. + // REVISIT: There's no restriction on port value ranges, but + // perform the same check as in setPort to be consistent. Pass + // in a string to this method instead of an integer. + if (port < -1 || port > 65535) { + return false; + } + + // Check that userinfo is well formed if it exists. + if (userinfo != null) { + // Userinfo can contain alphanumerics, mark characters, escaped + // and ';',':','&','=','+','$',',' + int index = 0; + int end = userinfo.length(); + char testChar = '\0'; + while (index < end) { + testChar = userinfo.charAt(index); + if (testChar == '%') { + if (index+2 >= end || + !isHex(userinfo.charAt(index+1)) || + !isHex(userinfo.charAt(index+2))) { + return false; + } + index += 2; + } + else if (!isUserinfoCharacter(testChar)) { + return false; + } + ++index; + } + } + return true; + } + + /** + * Determines whether the given string is a registry based authority. + * + * @param authority the authority component of a URI + * + * @return true if the given string is a registry based authority + */ + private boolean isValidRegistryBasedAuthority(String authority) { + int index = 0; + int end = authority.length(); + char testChar; + + while (index < end) { + testChar = authority.charAt(index); + + // check for valid escape sequence + if (testChar == '%') { + if (index+2 >= end || + !isHex(authority.charAt(index+1)) || + !isHex(authority.charAt(index+2))) { + return false; + } + index += 2; + } + // can check against path characters because the set + // is the same except for '/' which we've already excluded. + else if (!isPathCharacter(testChar)) { + return false; + } + ++index; + } + return true; + } + + /** + * Initialize the path for this URI from a URI string spec. + * + * @param p_uriSpec the URI specification (cannot be null) + * @param p_nStartIndex the index to begin scanning from + * + * @exception MalformedURIException if p_uriSpec violates syntax rules + */ + private void initializePath(String p_uriSpec, int p_nStartIndex) + throws MalformedURIException { + if (p_uriSpec == null) { + throw new MalformedURIException( + "Cannot initialize path from null string!"); + } + + int index = p_nStartIndex; + int start = p_nStartIndex; + int end = p_uriSpec.length(); + char testChar = '\0'; + + // path - everything up to query string or fragment + if (start < end) { + // RFC 2732 only allows '[' and ']' to appear in the opaque part. + if (getScheme() == null || p_uriSpec.charAt(start) == '/') { + + // Scan path. + // abs_path = "/" path_segments + // rel_path = rel_segment [ abs_path ] + while (index < end) { + testChar = p_uriSpec.charAt(index); + + // check for valid escape sequence + if (testChar == '%') { + if (index+2 >= end || + !isHex(p_uriSpec.charAt(index+1)) || + !isHex(p_uriSpec.charAt(index+2))) { + throw new MalformedURIException( + "Path contains invalid escape sequence!"); + } + index += 2; + } + // Path segments cannot contain '[' or ']' since pchar + // production was not changed by RFC 2732. + else if (!isPathCharacter(testChar)) { + if (testChar == '?' || testChar == '#') { + break; + } + throw new MalformedURIException( + "Path contains invalid character: " + testChar); + } + ++index; + } + } + else { + + // Scan opaque part. + // opaque_part = uric_no_slash *uric + while (index < end) { + testChar = p_uriSpec.charAt(index); + + if (testChar == '?' || testChar == '#') { + break; + } + + // check for valid escape sequence + if (testChar == '%') { + if (index+2 >= end || + !isHex(p_uriSpec.charAt(index+1)) || + !isHex(p_uriSpec.charAt(index+2))) { + throw new MalformedURIException( + "Opaque part contains invalid escape sequence!"); + } + index += 2; + } + // If the scheme specific part is opaque, it can contain '[' + // and ']'. uric_no_slash wasn't modified by RFC 2732, which + // I've interpreted as an error in the spec, since the + // production should be equivalent to (uric - '/'), and uric + // contains '[' and ']'. - mrglavas + else if (!isURICharacter(testChar)) { + throw new MalformedURIException( + "Opaque part contains invalid character: " + testChar); + } + ++index; + } + } + } + m_path = p_uriSpec.substring(start, index); + + // query - starts with ? and up to fragment or end + if (testChar == '?') { + index++; + start = index; + while (index < end) { + testChar = p_uriSpec.charAt(index); + if (testChar == '#') { + break; + } + if (testChar == '%') { + if (index+2 >= end || + !isHex(p_uriSpec.charAt(index+1)) || + !isHex(p_uriSpec.charAt(index+2))) { + throw new MalformedURIException( + "Query string contains invalid escape sequence!"); + } + index += 2; + } + else if (!isURICharacter(testChar)) { + throw new MalformedURIException( + "Query string contains invalid character: " + testChar); + } + index++; + } + m_queryString = p_uriSpec.substring(start, index); + } + + // fragment - starts with # + if (testChar == '#') { + index++; + start = index; + while (index < end) { + testChar = p_uriSpec.charAt(index); + + if (testChar == '%') { + if (index+2 >= end || + !isHex(p_uriSpec.charAt(index+1)) || + !isHex(p_uriSpec.charAt(index+2))) { + throw new MalformedURIException( + "Fragment contains invalid escape sequence!"); + } + index += 2; + } + else if (!isURICharacter(testChar)) { + throw new MalformedURIException( + "Fragment contains invalid character: "+testChar); + } + index++; + } + m_fragment = p_uriSpec.substring(start, index); + } + } + + /** + * Get the scheme for this URI. + * + * @return the scheme for this URI + */ + public String getScheme() { + return m_scheme; + } + + /** + * Get the scheme-specific part for this URI (everything following the + * scheme and the first colon). See RFC 2396 Section 5.2 for spec. + * + * @return the scheme-specific part for this URI + */ + public String getSchemeSpecificPart() { + StringBuffer schemespec = new StringBuffer(); + + if (m_host != null || m_regAuthority != null) { + schemespec.append("//"); + + // Server based authority. + if (m_host != null) { + + if (m_userinfo != null) { + schemespec.append(m_userinfo); + schemespec.append('@'); + } + + schemespec.append(m_host); + + if (m_port != -1) { + schemespec.append(':'); + schemespec.append(m_port); + } + } + // Registry based authority. + else { + schemespec.append(m_regAuthority); + } + } + + if (m_path != null) { + schemespec.append((m_path)); + } + + if (m_queryString != null) { + schemespec.append('?'); + schemespec.append(m_queryString); + } + + if (m_fragment != null) { + schemespec.append('#'); + schemespec.append(m_fragment); + } + + return schemespec.toString(); + } + + /** + * Get the userinfo for this URI. + * + * @return the userinfo for this URI (null if not specified). + */ + public String getUserinfo() { + return m_userinfo; + } + + /** + * Get the host for this URI. + * + * @return the host for this URI (null if not specified). + */ + public String getHost() { + return m_host; + } + + /** + * Get the port for this URI. + * + * @return the port for this URI (-1 if not specified). + */ + public int getPort() { + return m_port; + } + + /** + * Get the registry based authority for this URI. + * + * @return the registry based authority (null if not specified). + */ + public String getRegBasedAuthority() { + return m_regAuthority; + } + + /** + * Get the authority for this URI. + * + * @return the authority + */ + public String getAuthority() { + StringBuffer authority = new StringBuffer(); + if (m_host != null || m_regAuthority != null) { + authority.append("//"); + + // Server based authority. + if (m_host != null) { + + if (m_userinfo != null) { + authority.append(m_userinfo); + authority.append('@'); + } + + authority.append(m_host); + + if (m_port != -1) { + authority.append(':'); + authority.append(m_port); + } + } + // Registry based authority. + else { + authority.append(m_regAuthority); + } + } + return authority.toString(); + } + + /** + * Get the path for this URI (optionally with the query string and + * fragment). + * + * @param p_includeQueryString if true (and query string is not null), + * then a "?" followed by the query string + * will be appended + * @param p_includeFragment if true (and fragment is not null), + * then a "#" followed by the fragment + * will be appended + * + * @return the path for this URI possibly including the query string + * and fragment + */ + public String getPath(boolean p_includeQueryString, + boolean p_includeFragment) { + StringBuffer pathString = new StringBuffer(m_path); + + if (p_includeQueryString && m_queryString != null) { + pathString.append('?'); + pathString.append(m_queryString); + } + + if (p_includeFragment && m_fragment != null) { + pathString.append('#'); + pathString.append(m_fragment); + } + return pathString.toString(); + } + + /** + * Get the path for this URI. Note that the value returned is the path + * only and does not include the query string or fragment. + * + * @return the path for this URI. + */ + public String getPath() { + return m_path; + } + + /** + * Get the query string for this URI. + * + * @return the query string for this URI. Null is returned if there + * was no "?" in the URI spec, empty string if there was a + * "?" but no query string following it. + */ + public String getQueryString() { + return m_queryString; + } + + /** + * Get the fragment for this URI. + * + * @return the fragment for this URI. Null is returned if there + * was no "#" in the URI spec, empty string if there was a + * "#" but no fragment following it. + */ + public String getFragment() { + return m_fragment; + } + + /** + * Set the scheme for this URI. The scheme is converted to lowercase + * before it is set. + * + * @param p_scheme the scheme for this URI (cannot be null) + * + * @exception MalformedURIException if p_scheme is not a conformant + * scheme name + */ + public void setScheme(String p_scheme) throws MalformedURIException { + if (p_scheme == null) { + throw new MalformedURIException( + "Cannot set scheme from null string!"); + } + if (!isConformantSchemeName(p_scheme)) { + throw new MalformedURIException("The scheme is not conformant."); + } + + m_scheme = p_scheme.toLowerCase(Locale.ENGLISH); + } + + /** + * Set the userinfo for this URI. If a non-null value is passed in and + * the host value is null, then an exception is thrown. + * + * @param p_userinfo the userinfo for this URI + * + * @exception MalformedURIException if p_userinfo contains invalid + * characters + */ + public void setUserinfo(String p_userinfo) throws MalformedURIException { + if (p_userinfo == null) { + m_userinfo = null; + return; + } + else { + if (m_host == null) { + throw new MalformedURIException( + "Userinfo cannot be set when host is null!"); + } + + // userinfo can contain alphanumerics, mark characters, escaped + // and ';',':','&','=','+','$',',' + int index = 0; + int end = p_userinfo.length(); + char testChar = '\0'; + while (index < end) { + testChar = p_userinfo.charAt(index); + if (testChar == '%') { + if (index+2 >= end || + !isHex(p_userinfo.charAt(index+1)) || + !isHex(p_userinfo.charAt(index+2))) { + throw new MalformedURIException( + "Userinfo contains invalid escape sequence!"); + } + } + else if (!isUserinfoCharacter(testChar)) { + throw new MalformedURIException( + "Userinfo contains invalid character:"+testChar); + } + index++; + } + } + m_userinfo = p_userinfo; + } + + /** + *

        Set the host for this URI. If null is passed in, the userinfo + * field is also set to null and the port is set to -1.

        + * + *

        Note: This method overwrites registry based authority if it + * previously existed in this URI.

        + * + * @param p_host the host for this URI + * + * @exception MalformedURIException if p_host is not a valid IP + * address or DNS hostname. + */ + public void setHost(String p_host) throws MalformedURIException { + if (p_host == null || p_host.length() == 0) { + if (p_host != null) { + m_regAuthority = null; + } + m_host = p_host; + m_userinfo = null; + m_port = -1; + return; + } + else if (!isWellFormedAddress(p_host)) { + throw new MalformedURIException("Host is not a well formed address!"); + } + m_host = p_host; + m_regAuthority = null; + } + + /** + * Set the port for this URI. -1 is used to indicate that the port is + * not specified, otherwise valid port numbers are between 0 and 65535. + * If a valid port number is passed in and the host field is null, + * an exception is thrown. + * + * @param p_port the port number for this URI + * + * @exception MalformedURIException if p_port is not -1 and not a + * valid port number + */ + public void setPort(int p_port) throws MalformedURIException { + if (p_port >= 0 && p_port <= 65535) { + if (m_host == null) { + throw new MalformedURIException( + "Port cannot be set when host is null!"); + } + } + else if (p_port != -1) { + throw new MalformedURIException("Invalid port number!"); + } + m_port = p_port; + } + + /** + *

        Sets the registry based authority for this URI.

        + * + *

        Note: This method overwrites server based authority + * if it previously existed in this URI.

        + * + * @param authority the registry based authority for this URI + * + * @exception MalformedURIException it authority is not a + * well formed registry based authority + */ + public void setRegBasedAuthority(String authority) + throws MalformedURIException { + + if (authority == null) { + m_regAuthority = null; + return; + } + // reg_name = 1*( unreserved | escaped | "$" | "," | + // ";" | ":" | "@" | "&" | "=" | "+" ) + else if (authority.length() < 1 || + !isValidRegistryBasedAuthority(authority) || + authority.indexOf('/') != -1) { + throw new MalformedURIException("Registry based authority is not well formed."); + } + m_regAuthority = authority; + m_host = null; + m_userinfo = null; + m_port = -1; + } + + /** + * Set the path for this URI. If the supplied path is null, then the + * query string and fragment are set to null as well. If the supplied + * path includes a query string and/or fragment, these fields will be + * parsed and set as well. Note that, for URIs following the "generic + * URI" syntax, the path specified should start with a slash. + * For URIs that do not follow the generic URI syntax, this method + * sets the scheme-specific part. + * + * @param p_path the path for this URI (may be null) + * + * @exception MalformedURIException if p_path contains invalid + * characters + */ + public void setPath(String p_path) throws MalformedURIException { + if (p_path == null) { + m_path = null; + m_queryString = null; + m_fragment = null; + } + else { + initializePath(p_path, 0); + } + } + + /** + * Append to the end of the path of this URI. If the current path does + * not end in a slash and the path to be appended does not begin with + * a slash, a slash will be appended to the current path before the + * new segment is added. Also, if the current path ends in a slash + * and the new segment begins with a slash, the extra slash will be + * removed before the new segment is appended. + * + * @param p_addToPath the new segment to be added to the current path + * + * @exception MalformedURIException if p_addToPath contains syntax + * errors + */ + public void appendPath(String p_addToPath) + throws MalformedURIException { + if (p_addToPath == null || p_addToPath.trim().length() == 0) { + return; + } + + if (!isURIString(p_addToPath)) { + throw new MalformedURIException( + "Path contains invalid character!"); + } + + if (m_path == null || m_path.trim().length() == 0) { + if (p_addToPath.startsWith("/")) { + m_path = p_addToPath; + } + else { + m_path = "/" + p_addToPath; + } + } + else if (m_path.endsWith("/")) { + if (p_addToPath.startsWith("/")) { + m_path = m_path.concat(p_addToPath.substring(1)); + } + else { + m_path = m_path.concat(p_addToPath); + } + } + else { + if (p_addToPath.startsWith("/")) { + m_path = m_path.concat(p_addToPath); + } + else { + m_path = m_path.concat("/" + p_addToPath); + } + } + } + + /** + * Set the query string for this URI. A non-null value is valid only + * if this is an URI conforming to the generic URI syntax and + * the path value is not null. + * + * @param p_queryString the query string for this URI + * + * @exception MalformedURIException if p_queryString is not null and this + * URI does not conform to the generic + * URI syntax or if the path is null + */ + public void setQueryString(String p_queryString) throws MalformedURIException { + if (p_queryString == null) { + m_queryString = null; + } + else if (!isGenericURI()) { + throw new MalformedURIException( + "Query string can only be set for a generic URI!"); + } + else if (getPath() == null) { + throw new MalformedURIException( + "Query string cannot be set when path is null!"); + } + else if (!isURIString(p_queryString)) { + throw new MalformedURIException( + "Query string contains invalid character!"); + } + else { + m_queryString = p_queryString; + } + } + + /** + * Set the fragment for this URI. A non-null value is valid only + * if this is a URI conforming to the generic URI syntax and + * the path value is not null. + * + * @param p_fragment the fragment for this URI + * + * @exception MalformedURIException if p_fragment is not null and this + * URI does not conform to the generic + * URI syntax or if the path is null + */ + public void setFragment(String p_fragment) throws MalformedURIException { + if (p_fragment == null) { + m_fragment = null; + } + else if (!isGenericURI()) { + throw new MalformedURIException( + "Fragment can only be set for a generic URI!"); + } + else if (getPath() == null) { + throw new MalformedURIException( + "Fragment cannot be set when path is null!"); + } + else if (!isURIString(p_fragment)) { + throw new MalformedURIException( + "Fragment contains invalid character!"); + } + else { + m_fragment = p_fragment; + } + } + + /** + * Determines if the passed-in Object is equivalent to this URI. + * + * @param p_test the Object to test for equality. + * + * @return true if p_test is a URI with all values equal to this + * URI, false otherwise + */ + public boolean equals(Object p_test) { + if (p_test instanceof URI) { + URI testURI = (URI) p_test; + if (((m_scheme == null && testURI.m_scheme == null) || + (m_scheme != null && testURI.m_scheme != null && + m_scheme.equals(testURI.m_scheme))) && + ((m_userinfo == null && testURI.m_userinfo == null) || + (m_userinfo != null && testURI.m_userinfo != null && + m_userinfo.equals(testURI.m_userinfo))) && + ((m_host == null && testURI.m_host == null) || + (m_host != null && testURI.m_host != null && + m_host.equals(testURI.m_host))) && + m_port == testURI.m_port && + ((m_path == null && testURI.m_path == null) || + (m_path != null && testURI.m_path != null && + m_path.equals(testURI.m_path))) && + ((m_queryString == null && testURI.m_queryString == null) || + (m_queryString != null && testURI.m_queryString != null && + m_queryString.equals(testURI.m_queryString))) && + ((m_fragment == null && testURI.m_fragment == null) || + (m_fragment != null && testURI.m_fragment != null && + m_fragment.equals(testURI.m_fragment)))) { + return true; + } + } + return false; + } + + /** + * Get the URI as a string specification. See RFC 2396 Section 5.2. + * + * @return the URI string specification + */ + public String toString() { + StringBuffer uriSpecString = new StringBuffer(); + + if (m_scheme != null) { + uriSpecString.append(m_scheme); + uriSpecString.append(':'); + } + uriSpecString.append(getSchemeSpecificPart()); + return uriSpecString.toString(); + } + + /** + * Get the indicator as to whether this URI uses the "generic URI" + * syntax. + * + * @return true if this URI uses the "generic URI" syntax, false + * otherwise + */ + public boolean isGenericURI() { + // presence of the host (whether valid or empty) means + // double-slashes which means generic uri + return (m_host != null); + } + + /** + * Returns whether this URI represents an absolute URI. + * + * @return true if this URI represents an absolute URI, false + * otherwise + */ + public boolean isAbsoluteURI() { + // presence of the scheme means absolute uri + return (m_scheme != null); + } + + /** + * Determine whether a scheme conforms to the rules for a scheme name. + * A scheme is conformant if it starts with an alphanumeric, and + * contains only alphanumerics, '+','-' and '.'. + * + * @return true if the scheme is conformant, false otherwise + */ + public static boolean isConformantSchemeName(String p_scheme) { + if (p_scheme == null || p_scheme.trim().length() == 0) { + return false; + } + + if (!isAlpha(p_scheme.charAt(0))) { + return false; + } + + char testChar; + int schemeLength = p_scheme.length(); + for (int i = 1; i < schemeLength; ++i) { + testChar = p_scheme.charAt(i); + if (!isSchemeCharacter(testChar)) { + return false; + } + } + + return true; + } + + /** + * Determine whether a string is syntactically capable of representing + * a valid IPv4 address, IPv6 reference or the domain name of a network host. + * A valid IPv4 address consists of four decimal digit groups separated by a + * '.'. Each group must consist of one to three digits. See RFC 2732 Section 3, + * and RFC 2373 Section 2.2, for the definition of IPv6 references. A hostname + * consists of domain labels (each of which must begin and end with an alphanumeric + * but may contain '-') separated & by a '.'. See RFC 2396 Section 3.2.2. + * + * @return true if the string is a syntactically valid IPv4 address, + * IPv6 reference or hostname + */ + public static boolean isWellFormedAddress(String address) { + if (address == null) { + return false; + } + + int addrLength = address.length(); + if (addrLength == 0) { + return false; + } + + // Check if the host is a valid IPv6reference. + if (address.startsWith("[")) { + return isWellFormedIPv6Reference(address); + } + + // Cannot start with a '.', '-', or end with a '-'. + if (address.startsWith(".") || + address.startsWith("-") || + address.endsWith("-")) { + return false; + } + + // rightmost domain label starting with digit indicates IP address + // since top level domain label can only start with an alpha + // see RFC 2396 Section 3.2.2 + int index = address.lastIndexOf('.'); + if (address.endsWith(".")) { + index = address.substring(0, index).lastIndexOf('.'); + } + + if (index+1 < addrLength && isDigit(address.charAt(index+1))) { + return isWellFormedIPv4Address(address); + } + else { + // hostname = *( domainlabel "." ) toplabel [ "." ] + // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum + // toplabel = alpha | alpha *( alphanum | "-" ) alphanum + + // RFC 2396 states that hostnames take the form described in + // RFC 1034 (Section 3) and RFC 1123 (Section 2.1). According + // to RFC 1034, hostnames are limited to 255 characters. + if (addrLength > 255) { + return false; + } + + // domain labels can contain alphanumerics and '-" + // but must start and end with an alphanumeric + char testChar; + int labelCharCount = 0; + + for (int i = 0; i < addrLength; i++) { + testChar = address.charAt(i); + if (testChar == '.') { + if (!isAlphanum(address.charAt(i-1))) { + return false; + } + if (i+1 < addrLength && !isAlphanum(address.charAt(i+1))) { + return false; + } + labelCharCount = 0; + } + else if (!isAlphanum(testChar) && testChar != '-') { + return false; + } + // RFC 1034: Labels must be 63 characters or less. + else if (++labelCharCount > 63) { + return false; + } + } + } + return true; + } + + /** + *

        Determines whether a string is an IPv4 address as defined by + * RFC 2373, and under the further constraint that it must be a 32-bit + * address. Though not expressed in the grammar, in order to satisfy + * the 32-bit address constraint, each segment of the address cannot + * be greater than 255 (8 bits of information).

        + * + *

        IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT

        + * + * @return true if the string is a syntactically valid IPv4 address + */ + public static boolean isWellFormedIPv4Address(String address) { + + int addrLength = address.length(); + char testChar; + int numDots = 0; + int numDigits = 0; + + // make sure that 1) we see only digits and dot separators, 2) that + // any dot separator is preceded and followed by a digit and + // 3) that we find 3 dots + // + // RFC 2732 amended RFC 2396 by replacing the definition + // of IPv4address with the one defined by RFC 2373. - mrglavas + // + // IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT + // + // One to three digits must be in each segment. + for (int i = 0; i < addrLength; i++) { + testChar = address.charAt(i); + if (testChar == '.') { + if ((i > 0 && !isDigit(address.charAt(i-1))) || + (i+1 < addrLength && !isDigit(address.charAt(i+1)))) { + return false; + } + numDigits = 0; + if (++numDots > 3) { + return false; + } + } + else if (!isDigit(testChar)) { + return false; + } + // Check that that there are no more than three digits + // in this segment. + else if (++numDigits > 3) { + return false; + } + // Check that this segment is not greater than 255. + else if (numDigits == 3) { + char first = address.charAt(i-2); + char second = address.charAt(i-1); + if (!(first < '2' || + (first == '2' && + (second < '5' || + (second == '5' && testChar <= '5'))))) { + return false; + } + } + } + return (numDots == 3); + } + + /** + *

        Determines whether a string is an IPv6 reference as defined + * by RFC 2732, where IPv6address is defined in RFC 2373. The + * IPv6 address is parsed according to Section 2.2 of RFC 2373, + * with the additional constraint that the address be composed of + * 128 bits of information.

        + * + *

        IPv6reference = "[" IPv6address "]"

        + * + *

        Note: The BNF expressed in RFC 2373 Appendix B does not + * accurately describe section 2.2, and was in fact removed from + * RFC 3513, the successor of RFC 2373.

        + * + * @return true if the string is a syntactically valid IPv6 reference + */ + public static boolean isWellFormedIPv6Reference(String address) { + + int addrLength = address.length(); + int index = 1; + int end = addrLength-1; + + // Check if string is a potential match for IPv6reference. + if (!(addrLength > 2 && address.charAt(0) == '[' + && address.charAt(end) == ']')) { + return false; + } + + // Counter for the number of 16-bit sections read in the address. + int [] counter = new int[1]; + + // Scan hex sequence before possible '::' or IPv4 address. + index = scanHexSequence(address, index, end, counter); + if (index == -1) { + return false; + } + // Address must contain 128-bits of information. + else if (index == end) { + return (counter[0] == 8); + } + + if (index+1 < end && address.charAt(index) == ':') { + if (address.charAt(index+1) == ':') { + // '::' represents at least one 16-bit group of zeros. + if (++counter[0] > 8) { + return false; + } + index += 2; + // Trailing zeros will fill out the rest of the address. + if (index == end) { + return true; + } + } + // If the second character wasn't ':', in order to be valid, + // the remainder of the string must match IPv4Address, + // and we must have read exactly 6 16-bit groups. + else { + return (counter[0] == 6) && + isWellFormedIPv4Address(address.substring(index+1, end)); + } + } + else { + return false; + } + + // 3. Scan hex sequence after '::'. + int prevCount = counter[0]; + index = scanHexSequence(address, index, end, counter); + + // We've either reached the end of the string, the address ends in + // an IPv4 address, or it is invalid. scanHexSequence has already + // made sure that we have the right number of bits. + return (index == end) || + (index != -1 && isWellFormedIPv4Address( + address.substring((counter[0] > prevCount) ? index+1 : index, end))); + } + + /** + * Helper method for isWellFormedIPv6Reference which scans the + * hex sequences of an IPv6 address. It returns the index of the + * next character to scan in the address, or -1 if the string + * cannot match a valid IPv6 address. + * + * @param address the string to be scanned + * @param index the beginning index (inclusive) + * @param end the ending index (exclusive) + * @param counter a counter for the number of 16-bit sections read + * in the address + * + * @return the index of the next character to scan, or -1 if the + * string cannot match a valid IPv6 address + */ + private static int scanHexSequence (String address, int index, int end, int [] counter) { + + char testChar; + int numDigits = 0; + int start = index; + + // Trying to match the following productions: + // hexseq = hex4 *( ":" hex4) + // hex4 = 1*4HEXDIG + for (; index < end; ++index) { + testChar = address.charAt(index); + if (testChar == ':') { + // IPv6 addresses are 128-bit, so there can be at most eight sections. + if (numDigits > 0 && ++counter[0] > 8) { + return -1; + } + // This could be '::'. + if (numDigits == 0 || ((index+1 < end) && address.charAt(index+1) == ':')) { + return index; + } + numDigits = 0; + } + // This might be invalid or an IPv4address. If it's potentially an IPv4address, + // backup to just after the last valid character that matches hexseq. + else if (!isHex(testChar)) { + if (testChar == '.' && numDigits < 4 && numDigits > 0 && counter[0] <= 6) { + int back = index - numDigits - 1; + return (back >= start) ? back : (back+1); + } + return -1; + } + // There can be at most 4 hex digits per group. + else if (++numDigits > 4) { + return -1; + } + } + return (numDigits > 0 && ++counter[0] <= 8) ? end : -1; + } + + + /** + * Determine whether a char is a digit. + * + * @return true if the char is betweeen '0' and '9', false otherwise + */ + private static boolean isDigit(char p_char) { + return p_char >= '0' && p_char <= '9'; + } + + /** + * Determine whether a character is a hexadecimal character. + * + * @return true if the char is betweeen '0' and '9', 'a' and 'f' + * or 'A' and 'F', false otherwise + */ + private static boolean isHex(char p_char) { + return (p_char <= 'f' && (fgLookupTable[p_char] & ASCII_HEX_CHARACTERS) != 0); + } + + /** + * Determine whether a char is an alphabetic character: a-z or A-Z + * + * @return true if the char is alphabetic, false otherwise + */ + private static boolean isAlpha(char p_char) { + return ((p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z' )); + } + + /** + * Determine whether a char is an alphanumeric: 0-9, a-z or A-Z + * + * @return true if the char is alphanumeric, false otherwise + */ + private static boolean isAlphanum(char p_char) { + return (p_char <= 'z' && (fgLookupTable[p_char] & MASK_ALPHA_NUMERIC) != 0); + } + + /** + * Determine whether a character is a reserved character: + * ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '[', or ']' + * + * @return true if the string contains any reserved characters + */ + private static boolean isReservedCharacter(char p_char) { + return (p_char <= ']' && (fgLookupTable[p_char] & RESERVED_CHARACTERS) != 0); + } + + /** + * Determine whether a char is an unreserved character. + * + * @return true if the char is unreserved, false otherwise + */ + private static boolean isUnreservedCharacter(char p_char) { + return (p_char <= '~' && (fgLookupTable[p_char] & MASK_UNRESERVED_MASK) != 0); + } + + /** + * Determine whether a char is a URI character (reserved or + * unreserved, not including '%' for escaped octets). + * + * @return true if the char is a URI character, false otherwise + */ + private static boolean isURICharacter (char p_char) { + return (p_char <= '~' && (fgLookupTable[p_char] & MASK_URI_CHARACTER) != 0); + } + + /** + * Determine whether a char is a scheme character. + * + * @return true if the char is a scheme character, false otherwise + */ + private static boolean isSchemeCharacter (char p_char) { + return (p_char <= 'z' && (fgLookupTable[p_char] & MASK_SCHEME_CHARACTER) != 0); + } + + /** + * Determine whether a char is a userinfo character. + * + * @return true if the char is a userinfo character, false otherwise + */ + private static boolean isUserinfoCharacter (char p_char) { + return (p_char <= 'z' && (fgLookupTable[p_char] & MASK_USERINFO_CHARACTER) != 0); + } + + /** + * Determine whether a char is a path character. + * + * @return true if the char is a path character, false otherwise + */ + private static boolean isPathCharacter (char p_char) { + return (p_char <= '~' && (fgLookupTable[p_char] & MASK_PATH_CHARACTER) != 0); + } + + + /** + * Determine whether a given string contains only URI characters (also + * called "uric" in RFC 2396). uric consist of all reserved + * characters, unreserved characters and escaped characters. + * + * @return true if the string is comprised of uric, false otherwise + */ + private static boolean isURIString(String p_uric) { + if (p_uric == null) { + return false; + } + int end = p_uric.length(); + char testChar = '\0'; + for (int i = 0; i < end; i++) { + testChar = p_uric.charAt(i); + if (testChar == '%') { + if (i+2 >= end || + !isHex(p_uric.charAt(i+1)) || + !isHex(p_uric.charAt(i+2))) { + return false; + } + else { + i += 2; + continue; + } + } + if (isURICharacter(testChar)) { + continue; + } + else { + return false; + } + } + return true; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XML11Char.java b/resources/xerces2-j-src/org/apache/xerces/util/XML11Char.java new file mode 100644 index 0000000..fbdbc5d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XML11Char.java @@ -0,0 +1,413 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Arrays; + +/** + * This class defines the basic properties of characters in XML 1.1. The data + * in this class can be used to verify that a character is a valid + * XML 1.1 character or if the character is a space, name start, or name + * character. + *

        + * A series of convenience methods are supplied to ease the burden + * of the developer. Using the character as an index into the XML11CHARS + * array and applying the appropriate mask flag (e.g. + * MASK_VALID), yields the same results as calling the + * convenience methods. There is one exception: check the comments + * for the isValid method for details. + * + * @author Glenn Marcy, IBM + * @author Andy Clark, IBM + * @author Arnaud Le Hors, IBM + * @author Neil Graham, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XML11Char { + + // + // Constants + // + + /** Character flags for XML 1.1. */ + private static final byte XML11CHARS [] = new byte [1 << 16]; + + /** XML 1.1 Valid character mask. */ + public static final int MASK_XML11_VALID = 0x01; + + /** XML 1.1 Space character mask. */ + public static final int MASK_XML11_SPACE = 0x02; + + /** XML 1.1 Name start character mask. */ + public static final int MASK_XML11_NAME_START = 0x04; + + /** XML 1.1 Name character mask. */ + public static final int MASK_XML11_NAME = 0x08; + + /** XML 1.1 control character mask */ + public static final int MASK_XML11_CONTROL = 0x10; + + /** XML 1.1 content for external entities (valid - "special" chars - control chars) */ + public static final int MASK_XML11_CONTENT = 0x20; + + /** XML namespaces 1.1 NCNameStart */ + public static final int MASK_XML11_NCNAME_START = 0x40; + + /** XML namespaces 1.1 NCName */ + public static final int MASK_XML11_NCNAME = 0x80; + + /** XML 1.1 content for internal entities (valid - "special" chars) */ + public static final int MASK_XML11_CONTENT_INTERNAL = MASK_XML11_CONTROL | MASK_XML11_CONTENT; + + // + // Static initialization + // + + static { + + // Initializing the Character Flag Array + // Code generated by: XML11CharGenerator. + + Arrays.fill(XML11CHARS, 1, 9, (byte) 17 ); // Fill 8 of value (byte) 17 + XML11CHARS[9] = 35; + XML11CHARS[10] = 3; + Arrays.fill(XML11CHARS, 11, 13, (byte) 17 ); // Fill 2 of value (byte) 17 + XML11CHARS[13] = 3; + Arrays.fill(XML11CHARS, 14, 32, (byte) 17 ); // Fill 18 of value (byte) 17 + XML11CHARS[32] = 35; + Arrays.fill(XML11CHARS, 33, 38, (byte) 33 ); // Fill 5 of value (byte) 33 + XML11CHARS[38] = 1; + Arrays.fill(XML11CHARS, 39, 45, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(XML11CHARS, 45, 47, (byte) -87 ); // Fill 2 of value (byte) -87 + XML11CHARS[47] = 33; + Arrays.fill(XML11CHARS, 48, 58, (byte) -87 ); // Fill 10 of value (byte) -87 + XML11CHARS[58] = 45; + XML11CHARS[59] = 33; + XML11CHARS[60] = 1; + Arrays.fill(XML11CHARS, 61, 65, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(XML11CHARS, 65, 91, (byte) -19 ); // Fill 26 of value (byte) -19 + Arrays.fill(XML11CHARS, 91, 93, (byte) 33 ); // Fill 2 of value (byte) 33 + XML11CHARS[93] = 1; + XML11CHARS[94] = 33; + XML11CHARS[95] = -19; + XML11CHARS[96] = 33; + Arrays.fill(XML11CHARS, 97, 123, (byte) -19 ); // Fill 26 of value (byte) -19 + Arrays.fill(XML11CHARS, 123, 127, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(XML11CHARS, 127, 133, (byte) 17 ); // Fill 6 of value (byte) 17 + XML11CHARS[133] = 35; + Arrays.fill(XML11CHARS, 134, 160, (byte) 17 ); // Fill 26 of value (byte) 17 + Arrays.fill(XML11CHARS, 160, 183, (byte) 33 ); // Fill 23 of value (byte) 33 + XML11CHARS[183] = -87; + Arrays.fill(XML11CHARS, 184, 192, (byte) 33 ); // Fill 8 of value (byte) 33 + Arrays.fill(XML11CHARS, 192, 215, (byte) -19 ); // Fill 23 of value (byte) -19 + XML11CHARS[215] = 33; + Arrays.fill(XML11CHARS, 216, 247, (byte) -19 ); // Fill 31 of value (byte) -19 + XML11CHARS[247] = 33; + Arrays.fill(XML11CHARS, 248, 768, (byte) -19 ); // Fill 520 of value (byte) -19 + Arrays.fill(XML11CHARS, 768, 880, (byte) -87 ); // Fill 112 of value (byte) -87 + Arrays.fill(XML11CHARS, 880, 894, (byte) -19 ); // Fill 14 of value (byte) -19 + XML11CHARS[894] = 33; + Arrays.fill(XML11CHARS, 895, 8192, (byte) -19 ); // Fill 7297 of value (byte) -19 + Arrays.fill(XML11CHARS, 8192, 8204, (byte) 33 ); // Fill 12 of value (byte) 33 + Arrays.fill(XML11CHARS, 8204, 8206, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(XML11CHARS, 8206, 8232, (byte) 33 ); // Fill 26 of value (byte) 33 + XML11CHARS[8232] = 35; + Arrays.fill(XML11CHARS, 8233, 8255, (byte) 33 ); // Fill 22 of value (byte) 33 + Arrays.fill(XML11CHARS, 8255, 8257, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(XML11CHARS, 8257, 8304, (byte) 33 ); // Fill 47 of value (byte) 33 + Arrays.fill(XML11CHARS, 8304, 8592, (byte) -19 ); // Fill 288 of value (byte) -19 + Arrays.fill(XML11CHARS, 8592, 11264, (byte) 33 ); // Fill 2672 of value (byte) 33 + Arrays.fill(XML11CHARS, 11264, 12272, (byte) -19 ); // Fill 1008 of value (byte) -19 + Arrays.fill(XML11CHARS, 12272, 12289, (byte) 33 ); // Fill 17 of value (byte) 33 + Arrays.fill(XML11CHARS, 12289, 55296, (byte) -19 ); // Fill 43007 of value (byte) -19 + Arrays.fill(XML11CHARS, 57344, 63744, (byte) 33 ); // Fill 6400 of value (byte) 33 + Arrays.fill(XML11CHARS, 63744, 64976, (byte) -19 ); // Fill 1232 of value (byte) -19 + Arrays.fill(XML11CHARS, 64976, 65008, (byte) 33 ); // Fill 32 of value (byte) 33 + Arrays.fill(XML11CHARS, 65008, 65534, (byte) -19 ); // Fill 526 of value (byte) -19 + + } // () + + // + // Public static methods + // + + /** + * Returns true if the specified character is a space character + * as amdended in the XML 1.1 specification. + * + * @param c The character to check. + */ + public static boolean isXML11Space(int c) { + return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_SPACE) != 0); + } // isXML11Space(int):boolean + + /** + * Returns true if the specified character is valid. This method + * also checks the surrogate character range from 0x10000 to 0x10FFFF. + *

        + * If the program chooses to apply the mask directly to the + * XML11CHARS array, then they are responsible for checking + * the surrogate character range. + * + * @param c The character to check. + */ + public static boolean isXML11Valid(int c) { + return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_VALID) != 0) + || (0x10000 <= c && c <= 0x10FFFF); + } // isXML11Valid(int):boolean + + /** + * Returns true if the specified character is invalid. + * + * @param c The character to check. + */ + public static boolean isXML11Invalid(int c) { + return !isXML11Valid(c); + } // isXML11Invalid(int):boolean + + /** + * Returns true if the specified character is valid and permitted outside + * of a character reference. + * That is, this method will return false for the same set as + * isXML11Valid, except it also reports false for "control characters". + * + * @param c The character to check. + */ + public static boolean isXML11ValidLiteral(int c) { + return ((c < 0x10000 && ((XML11CHARS[c] & MASK_XML11_VALID) != 0 && (XML11CHARS[c] & MASK_XML11_CONTROL) == 0)) + || (0x10000 <= c && c <= 0x10FFFF)); + } // isXML11ValidLiteral(int):boolean + + /** + * Returns true if the specified character can be considered + * content in an external parsed entity. + * + * @param c The character to check. + */ + public static boolean isXML11Content(int c) { + return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_CONTENT) != 0) || + (0x10000 <= c && c <= 0x10FFFF); + } // isXML11Content(int):boolean + + /** + * Returns true if the specified character can be considered + * content in an internal parsed entity. + * + * @param c The character to check. + */ + public static boolean isXML11InternalEntityContent(int c) { + return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_CONTENT_INTERNAL) != 0) || + (0x10000 <= c && c <= 0x10FFFF); + } // isXML11InternalEntityContent(int):boolean + + /** + * Returns true if the specified character is a valid name start + * character as defined by production [4] in the XML 1.1 + * specification. + * + * @param c The character to check. + */ + public static boolean isXML11NameStart(int c) { + return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_NAME_START) != 0) + || (0x10000 <= c && c < 0xF0000); + } // isXML11NameStart(int):boolean + + /** + * Returns true if the specified character is a valid name + * character as defined by production [4a] in the XML 1.1 + * specification. + * + * @param c The character to check. + */ + public static boolean isXML11Name(int c) { + return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_NAME) != 0) + || (c >= 0x10000 && c < 0xF0000); + } // isXML11Name(int):boolean + + /** + * Returns true if the specified character is a valid NCName start + * character as defined by production [4] in Namespaces in XML + * 1.1 recommendation. + * + * @param c The character to check. + */ + public static boolean isXML11NCNameStart(int c) { + return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_NCNAME_START) != 0) + || (0x10000 <= c && c < 0xF0000); + } // isXML11NCNameStart(int):boolean + + /** + * Returns true if the specified character is a valid NCName + * character as defined by production [5] in Namespaces in XML + * 1.1 recommendation. + * + * @param c The character to check. + */ + public static boolean isXML11NCName(int c) { + return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_NCNAME) != 0) + || (0x10000 <= c && c < 0xF0000); + } // isXML11NCName(int):boolean + + /** + * Returns whether the given character is a valid + * high surrogate for a name character. This includes + * all high surrogates for characters [0x10000-0xEFFFF]. + * In other words everything excluding planes 15 and 16. + * + * @param c The character to check. + */ + public static boolean isXML11NameHighSurrogate(int c) { + return (0xD800 <= c && c <= 0xDB7F); + } + + /* + * [5] Name ::= NameStartChar NameChar* + */ + /** + * Check to see if a string is a valid Name according to [5] + * in the XML 1.1 Recommendation + * + * @param name string to check + * @return true if name is a valid Name + */ + public static boolean isXML11ValidName(String name) { + final int length = name.length(); + if (length == 0) { + return false; + } + int i = 1; + char ch = name.charAt(0); + if (!isXML11NameStart(ch)) { + if (length > 1 && isXML11NameHighSurrogate(ch)) { + char ch2 = name.charAt(1); + if (!XMLChar.isLowSurrogate(ch2) || + !isXML11NameStart(XMLChar.supplemental(ch, ch2))) { + return false; + } + i = 2; + } + else { + return false; + } + } + while (i < length) { + ch = name.charAt(i); + if (!isXML11Name(ch)) { + if (++i < length && isXML11NameHighSurrogate(ch)) { + char ch2 = name.charAt(i); + if (!XMLChar.isLowSurrogate(ch2) || + !isXML11Name(XMLChar.supplemental(ch, ch2))) { + return false; + } + } + else { + return false; + } + } + ++i; + } + return true; + } // isXML11ValidName(String):boolean + + /* + * from the namespace 1.1 rec + * [4] NCName ::= NCNameStartChar NCNameChar* + */ + /** + * Check to see if a string is a valid NCName according to [4] + * from the XML Namespaces 1.1 Recommendation + * + * @param ncName string to check + * @return true if name is a valid NCName + */ + public static boolean isXML11ValidNCName(String ncName) { + final int length = ncName.length(); + if (length == 0) { + return false; + } + int i = 1; + char ch = ncName.charAt(0); + if (!isXML11NCNameStart(ch)) { + if (length > 1 && isXML11NameHighSurrogate(ch)) { + char ch2 = ncName.charAt(1); + if (!XMLChar.isLowSurrogate(ch2) || + !isXML11NCNameStart(XMLChar.supplemental(ch, ch2))) { + return false; + } + i = 2; + } + else { + return false; + } + } + while (i < length) { + ch = ncName.charAt(i); + if (!isXML11NCName(ch)) { + if (++i < length && isXML11NameHighSurrogate(ch)) { + char ch2 = ncName.charAt(i); + if (!XMLChar.isLowSurrogate(ch2) || + !isXML11NCName(XMLChar.supplemental(ch, ch2))) { + return false; + } + } + else { + return false; + } + } + ++i; + } + return true; + } // isXML11ValidNCName(String):boolean + + /* + * [7] Nmtoken ::= (NameChar)+ + */ + /** + * Check to see if a string is a valid Nmtoken according to [7] + * in the XML 1.1 Recommendation + * + * @param nmtoken string to check + * @return true if nmtoken is a valid Nmtoken + */ + public static boolean isXML11ValidNmtoken(String nmtoken) { + final int length = nmtoken.length(); + if (length == 0) { + return false; + } + for (int i = 0; i < length; ++i) { + char ch = nmtoken.charAt(i); + if (!isXML11Name(ch)) { + if (++i < length && isXML11NameHighSurrogate(ch)) { + char ch2 = nmtoken.charAt(i); + if (!XMLChar.isLowSurrogate(ch2) || + !isXML11Name(XMLChar.supplemental(ch, ch2))) { + return false; + } + } + else { + return false; + } + } + } + return true; + } // isXML11ValidName(String):boolean + +} // class XML11Char + diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLAttributesImpl.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLAttributesImpl.java new file mode 100644 index 0000000..695731e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLAttributesImpl.java @@ -0,0 +1,1204 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; + +/** + * The XMLAttributesImpl class is an implementation of the XMLAttributes + * interface which defines a collection of attributes for an element. + * In the parser, the document source would scan the entire start element + * and collect the attributes. The attributes are communicated to the + * document handler in the startElement method. + *

        + * The attributes are read-write so that subsequent stages in the document + * pipeline can modify the values or change the attributes that are + * propogated to the next stage. + * + * @see org.apache.xerces.xni.XMLDocumentHandler#startElement + * + * @author Andy Clark, IBM + * @author Elena Litani, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XMLAttributesImpl + implements XMLAttributes { + + // + // Constants + // + + /** Default table size. */ + protected static final int TABLE_SIZE = 101; + + /** Maximum hash collisions per bucket. */ + protected static final int MAX_HASH_COLLISIONS = 40; + + protected static final int MULTIPLIERS_SIZE = 1 << 5; + protected static final int MULTIPLIERS_MASK = MULTIPLIERS_SIZE - 1; + + /** + * Threshold at which an instance is treated + * as a large attribute list. + */ + protected static final int SIZE_LIMIT = 20; + + // + // Data + // + + // features + + /** Namespaces. */ + protected boolean fNamespaces = true; + + // data + + /** + * Usage count for the attribute table view. + * Incremented each time all attributes are removed + * when the attribute table view is in use. + */ + protected int fLargeCount = 1; + + /** Attribute count. */ + protected int fLength; + + /** Attribute information. */ + protected Attribute[] fAttributes = new Attribute[4]; + + /** + * Hashtable of attribute information. + * Provides an alternate view of the attribute specification. + */ + protected Attribute[] fAttributeTableView; + + /** + * Tracks whether each chain in the hash table is stale + * with respect to the current state of this object. + * A chain is stale if its state is not the same as the number + * of times the attribute table view has been used. + */ + protected int[] fAttributeTableViewChainState; + + /** + * Actual number of buckets in the table view. + */ + protected int fTableViewBuckets; + + /** + * Indicates whether the table view contains consistent data. + */ + protected boolean fIsTableViewConsistent; + + /** + * Array of randomly selected hash function multipliers or null + * if the default String.hashCode() function should be used. + */ + protected int[] fHashMultipliers; + + // + // Constructors + // + + /** Default constructor. */ + public XMLAttributesImpl() { + this(TABLE_SIZE); + } + + /** + * @param tableSize initial size of table view + */ + public XMLAttributesImpl(int tableSize) { + fTableViewBuckets = tableSize; + for (int i = 0; i < fAttributes.length; i++) { + fAttributes[i] = new Attribute(); + } + } // () + + // + // Public methods + // + + /** + * Sets whether namespace processing is being performed. This state + * is needed to return the correct value from the getLocalName method. + * + * @param namespaces True if namespace processing is turned on. + * + * @see #getLocalName + */ + public void setNamespaces(boolean namespaces) { + fNamespaces = namespaces; + } // setNamespaces(boolean) + + // + // XMLAttributes methods + // + + /** + * Adds an attribute. The attribute's non-normalized value of the + * attribute will have the same value as the attribute value until + * set using the setNonNormalizedValue method. Also, + * the added attribute will be marked as specified in the XML instance + * document unless set otherwise using the setSpecified + * method. + *

        + * Note: If an attribute of the same name already + * exists, the old values for the attribute are replaced by the new + * values. + * + * @param name The attribute name. + * @param type The attribute type. The type name is determined by + * the type specified for this attribute in the DTD. + * For example: "CDATA", "ID", "NMTOKEN", etc. However, + * attributes of type enumeration will have the type + * value specified as the pipe ('|') separated list of + * the enumeration values prefixed by an open + * parenthesis and suffixed by a close parenthesis. + * For example: "(true|false)". + * @param value The attribute value. + * + * @return Returns the attribute index. + * + * @see #setNonNormalizedValue + * @see #setSpecified + */ + public int addAttribute(QName name, String type, String value) { + + int index; + if (fLength < SIZE_LIMIT) { + index = name.uri != null && name.uri.length() != 0 + ? getIndexFast(name.uri, name.localpart) + : getIndexFast(name.rawname); + + if (index == -1) { + index = fLength; + if (fLength++ == fAttributes.length) { + Attribute[] attributes = new Attribute[fAttributes.length + 4]; + System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length); + for (int i = fAttributes.length; i < attributes.length; i++) { + attributes[i] = new Attribute(); + } + fAttributes = attributes; + } + } + } + else if (name.uri == null || + name.uri.length() == 0 || + (index = getIndexFast(name.uri, name.localpart)) == -1) { + + /** + * If attributes were removed from the list after the table + * becomes in use this isn't reflected in the table view. It's + * assumed that once a user starts removing attributes they're + * not likely to add more. We only make the view consistent if + * the user of this class adds attributes, removes them, and + * then adds more. + */ + if (!fIsTableViewConsistent || fLength == SIZE_LIMIT || + (fLength > SIZE_LIMIT && fLength > fTableViewBuckets)) { + prepareAndPopulateTableView(); + fIsTableViewConsistent = true; + } + + int bucket = getTableViewBucket(name.rawname); + + // The chain is stale. + // This must be a unique attribute. + if (fAttributeTableViewChainState[bucket] != fLargeCount) { + index = fLength; + if (fLength++ == fAttributes.length) { + Attribute[] attributes = new Attribute[fAttributes.length << 1]; + System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length); + for (int i = fAttributes.length; i < attributes.length; i++) { + attributes[i] = new Attribute(); + } + fAttributes = attributes; + } + + // Update table view. + fAttributeTableViewChainState[bucket] = fLargeCount; + fAttributes[index].next = null; + fAttributeTableView[bucket] = fAttributes[index]; + } + // This chain is active. + // We need to check if any of the attributes has the same rawname. + else { + // Search the table. + int collisionCount = 0; + Attribute found = fAttributeTableView[bucket]; + while (found != null) { + if (found.name.rawname == name.rawname) { + break; + } + found = found.next; + ++collisionCount; + } + // This attribute is unique. + if (found == null) { + index = fLength; + if (fLength++ == fAttributes.length) { + Attribute[] attributes = new Attribute[fAttributes.length << 1]; + System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length); + for (int i = fAttributes.length; i < attributes.length; i++) { + attributes[i] = new Attribute(); + } + fAttributes = attributes; + } + // Select a new hash function and rehash the table view + // if the collision threshold is exceeded. + if (collisionCount >= MAX_HASH_COLLISIONS) { + // The current attribute will be processed in the rehash. + // Need to set its name first. + fAttributes[index].name.setValues(name); + rebalanceTableView(fLength); + } + else { + // Update table view + fAttributes[index].next = fAttributeTableView[bucket]; + fAttributeTableView[bucket] = fAttributes[index]; + } + } + // Duplicate. We still need to find the index. + else { + index = getIndexFast(name.rawname); + } + } + } + + // set values + Attribute attribute = fAttributes[index]; + attribute.name.setValues(name); + attribute.type = type; + attribute.value = value; + attribute.nonNormalizedValue = value; + attribute.specified = false; + + // clear augmentations + attribute.augs.removeAllItems(); + + return index; + + } // addAttribute(QName,String,XMLString) + + /** + * Removes all of the attributes. This method will also remove all + * entities associated to the attributes. + */ + public void removeAllAttributes() { + fLength = 0; + } // removeAllAttributes() + + /** + * Removes the attribute at the specified index. + *

        + * Note: This operation changes the indexes of all + * attributes following the attribute at the specified index. + * + * @param attrIndex The attribute index. + */ + public void removeAttributeAt(int attrIndex) { + fIsTableViewConsistent = false; + if (attrIndex < fLength - 1) { + Attribute removedAttr = fAttributes[attrIndex]; + System.arraycopy(fAttributes, attrIndex + 1, + fAttributes, attrIndex, fLength - attrIndex - 1); + // Make the discarded Attribute object available for re-use + // by tucking it after the Attributes that are still in use + fAttributes[fLength-1] = removedAttr; + } + fLength--; + } // removeAttributeAt(int) + + /** + * Sets the name of the attribute at the specified index. + * + * @param attrIndex The attribute index. + * @param attrName The new attribute name. + */ + public void setName(int attrIndex, QName attrName) { + fAttributes[attrIndex].name.setValues(attrName); + } // setName(int,QName) + + /** + * Sets the fields in the given QName structure with the values + * of the attribute name at the specified index. + * + * @param attrIndex The attribute index. + * @param attrName The attribute name structure to fill in. + */ + public void getName(int attrIndex, QName attrName) { + attrName.setValues(fAttributes[attrIndex].name); + } // getName(int,QName) + + /** + * Sets the type of the attribute at the specified index. + * + * @param attrIndex The attribute index. + * @param attrType The attribute type. The type name is determined by + * the type specified for this attribute in the DTD. + * For example: "CDATA", "ID", "NMTOKEN", etc. However, + * attributes of type enumeration will have the type + * value specified as the pipe ('|') separated list of + * the enumeration values prefixed by an open + * parenthesis and suffixed by a close parenthesis. + * For example: "(true|false)". + */ + public void setType(int attrIndex, String attrType) { + fAttributes[attrIndex].type = attrType; + } // setType(int,String) + + /** + * Sets the value of the attribute at the specified index. This + * method will overwrite the non-normalized value of the attribute. + * + * @param attrIndex The attribute index. + * @param attrValue The new attribute value. + * + * @see #setNonNormalizedValue + */ + public void setValue(int attrIndex, String attrValue) { + Attribute attribute = fAttributes[attrIndex]; + attribute.value = attrValue; + attribute.nonNormalizedValue = attrValue; + } // setValue(int,String) + + /** + * Sets the non-normalized value of the attribute at the specified + * index. + * + * @param attrIndex The attribute index. + * @param attrValue The new non-normalized attribute value. + */ + public void setNonNormalizedValue(int attrIndex, String attrValue) { + if (attrValue == null) { + attrValue = fAttributes[attrIndex].value; + } + fAttributes[attrIndex].nonNormalizedValue = attrValue; + } // setNonNormalizedValue(int,String) + + /** + * Returns the non-normalized value of the attribute at the specified + * index. If no non-normalized value is set, this method will return + * the same value as the getValue(int) method. + * + * @param attrIndex The attribute index. + */ + public String getNonNormalizedValue(int attrIndex) { + String value = fAttributes[attrIndex].nonNormalizedValue; + return value; + } // getNonNormalizedValue(int):String + + /** + * Sets whether an attribute is specified in the instance document + * or not. + * + * @param attrIndex The attribute index. + * @param specified True if the attribute is specified in the instance + * document. + */ + public void setSpecified(int attrIndex, boolean specified) { + fAttributes[attrIndex].specified = specified; + } // setSpecified(int,boolean) + + /** + * Returns true if the attribute is specified in the instance document. + * + * @param attrIndex The attribute index. + */ + public boolean isSpecified(int attrIndex) { + return fAttributes[attrIndex].specified; + } // isSpecified(int):boolean + + // + // AttributeList and Attributes methods + // + + /** + * Return the number of attributes in the list. + * + *

        Once you know the number of attributes, you can iterate + * through the list.

        + * + * @return The number of attributes in the list. + */ + public int getLength() { + return fLength; + } // getLength():int + + /** + * Look up an attribute's type by index. + * + *

        The attribute type is one of the strings "CDATA", "ID", + * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", + * or "NOTATION" (always in upper case).

        + * + *

        If the parser has not read a declaration for the attribute, + * or if the parser does not report attribute types, then it must + * return the value "CDATA" as stated in the XML 1.0 Recommentation + * (clause 3.3.3, "Attribute-Value Normalization").

        + * + *

        For an enumerated attribute that is not a notation, the + * parser will report the type as "NMTOKEN".

        + * + * @param index The attribute index (zero-based). + * @return The attribute's type as a string, or null if the + * index is out of range. + * @see #getLength + */ + public String getType(int index) { + if (index < 0 || index >= fLength) { + return null; + } + return getReportableType(fAttributes[index].type); + } // getType(int):String + + /** + * Look up an attribute's type by XML 1.0 qualified name. + * + *

        See {@link #getType(int) getType(int)} for a description + * of the possible types.

        + * + * @param qname The XML 1.0 qualified name. + * @return The attribute type as a string, or null if the + * attribute is not in the list or if qualified names + * are not available. + */ + public String getType(String qname) { + int index = getIndex(qname); + return index != -1 ? getReportableType(fAttributes[index].type) : null; + } // getType(String):String + + /** + * Look up an attribute's value by index. + * + *

        If the attribute value is a list of tokens (IDREFS, + * ENTITIES, or NMTOKENS), the tokens will be concatenated + * into a single string with each token separated by a + * single space.

        + * + * @param index The attribute index (zero-based). + * @return The attribute's value as a string, or null if the + * index is out of range. + * @see #getLength + */ + public String getValue(int index) { + if (index < 0 || index >= fLength) { + return null; + } + return fAttributes[index].value; + } // getValue(int):String + + /** + * Look up an attribute's value by XML 1.0 qualified name. + * + *

        See {@link #getValue(int) getValue(int)} for a description + * of the possible values.

        + * + * @param qname The XML 1.0 qualified name. + * @return The attribute value as a string, or null if the + * attribute is not in the list or if qualified names + * are not available. + */ + public String getValue(String qname) { + int index = getIndex(qname); + return index != -1 ? fAttributes[index].value : null; + } // getValue(String):String + + // + // AttributeList methods + // + + /** + * Return the name of an attribute in this list (by position). + * + *

        The names must be unique: the SAX parser shall not include the + * same attribute twice. Attributes without values (those declared + * #IMPLIED without a value specified in the start tag) will be + * omitted from the list.

        + * + *

        If the attribute name has a namespace prefix, the prefix + * will still be attached.

        + * + * @param index The index of the attribute in the list (starting at 0). + * @return The name of the indexed attribute, or null + * if the index is out of range. + * @see #getLength + */ + public String getName(int index) { + if (index < 0 || index >= fLength) { + return null; + } + return fAttributes[index].name.rawname; + } // getName(int):String + + // + // Attributes methods + // + + /** + * Look up the index of an attribute by XML 1.0 qualified name. + * + * @param qName The qualified (prefixed) name. + * @return The index of the attribute, or -1 if it does not + * appear in the list. + */ + public int getIndex(String qName) { + for (int i = 0; i < fLength; i++) { + Attribute attribute = fAttributes[i]; + if (attribute.name.rawname != null && + attribute.name.rawname.equals(qName)) { + return i; + } + } + return -1; + } // getIndex(String):int + + /** + * Look up the index of an attribute by Namespace name. + * + * @param uri The Namespace URI, or null if + * the name has no Namespace URI. + * @param localPart The attribute's local name. + * @return The index of the attribute, or -1 if it does not + * appear in the list. + */ + public int getIndex(String uri, String localPart) { + for (int i = 0; i < fLength; i++) { + Attribute attribute = fAttributes[i]; + if (attribute.name.localpart != null && + attribute.name.localpart.equals(localPart) && + ((uri==attribute.name.uri) || + (uri!=null && attribute.name.uri!=null && attribute.name.uri.equals(uri)))) + { + return i; + } + } + return -1; + } // getIndex(String,String):int + + /** + * Look up an attribute's local name by index. + * + * @param index The attribute index (zero-based). + * @return The local name, or the empty string if Namespace + * processing is not being performed, or null + * if the index is out of range. + * @see #getLength + */ + public String getLocalName(int index) { + if (!fNamespaces) { + return ""; + } + if (index < 0 || index >= fLength) { + return null; + } + return fAttributes[index].name.localpart; + } // getLocalName(int):String + + /** + * Look up an attribute's XML 1.0 qualified name by index. + * + * @param index The attribute index (zero-based). + * @return The XML 1.0 qualified name, or the empty string + * if none is available, or null if the index + * is out of range. + * @see #getLength + */ + public String getQName(int index) { + if (index < 0 || index >= fLength) { + return null; + } + String rawname = fAttributes[index].name.rawname; + return rawname != null ? rawname : ""; + } // getQName(int):String + + /** + * Look up an attribute's type by Namespace name. + * + *

        See {@link #getType(int) getType(int)} for a description + * of the possible types.

        + * + * @param uri The Namespace URI, or null if the + * name has no Namespace URI. + * @param localName The local name of the attribute. + * @return The attribute type as a string, or null if the + * attribute is not in the list or if Namespace + * processing is not being performed. + */ + public String getType(String uri, String localName) { + if (!fNamespaces) { + return null; + } + int index = getIndex(uri, localName); + return index != -1 ? getReportableType(fAttributes[index].type) : null; + } // getType(String,String):String + + /** + * Returns the prefix of the attribute at the specified index. + * + * @param index The index of the attribute. + */ + public String getPrefix(int index) { + if (index < 0 || index >= fLength) { + return null; + } + String prefix = fAttributes[index].name.prefix; + // REVISIT: The empty string is not entered in the symbol table! + return prefix != null ? prefix : ""; + } // getPrefix(int):String + + /** + * Look up an attribute's Namespace URI by index. + * + * @param index The attribute index (zero-based). + * @return The Namespace URI + * @see #getLength + */ + public String getURI(int index) { + if (index < 0 || index >= fLength) { + return null; + } + String uri = fAttributes[index].name.uri; + return uri; + } // getURI(int):String + + /** + * Look up an attribute's value by Namespace name. + * + *

        See {@link #getValue(int) getValue(int)} for a description + * of the possible values.

        + * + * @param uri The Namespace URI, or null if the + * @param localName The local name of the attribute. + * @return The attribute value as a string, or null if the + * attribute is not in the list. + */ + public String getValue(String uri, String localName) { + int index = getIndex(uri, localName); + return index != -1 ? getValue(index) : null; + } // getValue(String,String):String + + + /** + * Look up an augmentations by Namespace name. + * + * @param uri The Namespace URI, or null if the + * @param localName The local name of the attribute. + * @return Augmentations + */ + public Augmentations getAugmentations (String uri, String localName) { + int index = getIndex(uri, localName); + return index != -1 ? fAttributes[index].augs : null; + } + + /** + * Look up an augmentation by XML 1.0 qualified name. + *

        + * + * @param qName The XML 1.0 qualified name. + * + * @return Augmentations + * + */ + public Augmentations getAugmentations(String qName){ + int index = getIndex(qName); + return index != -1 ? fAttributes[index].augs : null; + } + + /** + * Look up an augmentations by attributes index. + * + * @param attributeIndex The attribute index. + * @return Augmentations + */ + public Augmentations getAugmentations (int attributeIndex){ + if (attributeIndex < 0 || attributeIndex >= fLength) { + return null; + } + return fAttributes[attributeIndex].augs; + } + + /** + * Sets the augmentations of the attribute at the specified index. + * + * @param attrIndex The attribute index. + * @param augs The augmentations. + */ + public void setAugmentations(int attrIndex, Augmentations augs) { + fAttributes[attrIndex].augs = augs; + } + + /** + * Sets the uri of the attribute at the specified index. + * + * @param attrIndex The attribute index. + * @param uri Namespace uri + */ + public void setURI(int attrIndex, String uri) { + fAttributes[attrIndex].name.uri = uri; + } // getURI(int,QName) + + // Implementation methods + + /** + * Look up the index of an attribute by XML 1.0 qualified name. + *

        + * Note: + * This method uses reference comparison, and thus should + * only be used internally. We cannot use this method in any + * code exposed to users as they may not pass in unique strings. + * + * @param qName The qualified (prefixed) name. + * @return The index of the attribute, or -1 if it does not + * appear in the list. + */ + public int getIndexFast(String qName) { + for (int i = 0; i < fLength; ++i) { + Attribute attribute = fAttributes[i]; + if (attribute.name.rawname == qName) { + return i; + } + } + return -1; + } // getIndexFast(String):int + + /** + * Adds an attribute. The attribute's non-normalized value of the + * attribute will have the same value as the attribute value until + * set using the setNonNormalizedValue method. Also, + * the added attribute will be marked as specified in the XML instance + * document unless set otherwise using the setSpecified + * method. + *

        + * This method differs from addAttribute in that it + * does not check if an attribute of the same name already exists + * in the list before adding it. In order to improve performance + * of namespace processing, this method allows uniqueness checks + * to be deferred until all the namespace information is available + * after the entire attribute specification has been read. + *

        + * Caution: If this method is called it should + * not be mixed with calls to addAttribute unless + * it has been determined that all the attribute names are unique. + * + * @param name the attribute name + * @param type the attribute type + * @param value the attribute value + * + * @see #setNonNormalizedValue + * @see #setSpecified + * @see #checkDuplicatesNS + */ + public void addAttributeNS(QName name, String type, String value) { + int index = fLength; + if (fLength++ == fAttributes.length) { + Attribute[] attributes; + if (fLength < SIZE_LIMIT) { + attributes = new Attribute[fAttributes.length + 4]; + } + else { + attributes = new Attribute[fAttributes.length << 1]; + } + System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length); + for (int i = fAttributes.length; i < attributes.length; i++) { + attributes[i] = new Attribute(); + } + fAttributes = attributes; + } + + // set values + Attribute attribute = fAttributes[index]; + attribute.name.setValues(name); + attribute.type = type; + attribute.value = value; + attribute.nonNormalizedValue = value; + attribute.specified = false; + + // clear augmentations + attribute.augs.removeAllItems(); + } + + /** + * Checks for duplicate expanded names (local part and namespace name + * pairs) in the attribute specification. If a duplicate is found its + * name is returned. + *

        + * This should be called once all the in-scope namespaces for the element + * enclosing these attributes is known, and after all the attributes + * have gone through namespace binding. + * + * @return the name of a duplicate attribute found in the search, + * otherwise null. + */ + public QName checkDuplicatesNS() { + // If the list is small check for duplicates using pairwise comparison. + final int length = fLength; + if (length <= SIZE_LIMIT) { + final Attribute[] attributes = fAttributes; + for (int i = 0; i < length - 1; ++i) { + Attribute att1 = attributes[i]; + for (int j = i + 1; j < length; ++j) { + Attribute att2 = attributes[j]; + if (att1.name.localpart == att2.name.localpart && + att1.name.uri == att2.name.uri) { + return att2.name; + } + } + } + return null; + } + // If the list is large check duplicates using a hash table. + else { + return checkManyDuplicatesNS(); + } + } + + private QName checkManyDuplicatesNS() { + // We don't want this table view to be read if someone calls + // addAttribute so we invalidate it up front. + fIsTableViewConsistent = false; + + prepareTableView(); + + Attribute attr; + int bucket; + + final int length = fLength; + final Attribute[] attributes = fAttributes; + final Attribute[] attributeTableView = fAttributeTableView; + final int[] attributeTableViewChainState = fAttributeTableViewChainState; + int largeCount = fLargeCount; + + for (int i = 0; i < length; ++i) { + attr = attributes[i]; + bucket = getTableViewBucket(attr.name.localpart, attr.name.uri); + + // The chain is stale. + // This must be a unique attribute. + if (attributeTableViewChainState[bucket] != largeCount) { + attributeTableViewChainState[bucket] = largeCount; + attr.next = null; + attributeTableView[bucket] = attr; + } + // This chain is active. + // We need to check if any of the attributes has the same name. + else { + // Search the table. + int collisionCount = 0; + Attribute found = attributeTableView[bucket]; + while (found != null) { + if (found.name.localpart == attr.name.localpart && + found.name.uri == attr.name.uri) { + return attr.name; + } + found = found.next; + ++collisionCount; + } + + // Select a new hash function and rehash the table view + // if the collision threshold is exceeded. + if (collisionCount >= MAX_HASH_COLLISIONS) { + // The current attribute will be processed in the rehash. + rebalanceTableViewNS(i+1); + largeCount = fLargeCount; + } + else { + // Update table view + attr.next = attributeTableView[bucket]; + attributeTableView[bucket] = attr; + } + } + } + return null; + } + + /** + * Look up the index of an attribute by Namespace name. + *

        + * Note: + * This method uses reference comparison, and thus should + * only be used internally. We cannot use this method in any + * code exposed to users as they may not pass in unique strings. + * + * @param uri The Namespace URI, or null if + * the name has no Namespace URI. + * @param localPart The attribute's local name. + * @return The index of the attribute, or -1 if it does not + * appear in the list. + */ + public int getIndexFast(String uri, String localPart) { + for (int i = 0; i < fLength; ++i) { + Attribute attribute = fAttributes[i]; + if (attribute.name.localpart == localPart && + attribute.name.uri == uri) { + return i; + } + } + return -1; + } // getIndexFast(String,String):int + + /** + * Returns the value passed in or NMTOKEN if it's an enumerated type. + * + * @param type attribute type + * @return the value passed in or NMTOKEN if it's an enumerated type. + */ + private String getReportableType(String type) { + + if (type.charAt(0) == '(') { + return "NMTOKEN"; + } + return type; + } + + /** + * Returns the position in the table view + * where the given attribute name would be hashed. + * + * @param qname the attribute name + * @return the position in the table view where the given attribute + * would be hashed + */ + protected int getTableViewBucket(String qname) { + return (hash(qname) & 0x7FFFFFFF) % fTableViewBuckets; + } + + /** + * Returns the position in the table view + * where the given attribute name would be hashed. + * + * @param localpart the local part of the attribute + * @param uri the namespace name of the attribute + * @return the position in the table view where the given attribute + * would be hashed + */ + protected int getTableViewBucket(String localpart, String uri) { + if (uri == null) { + return (hash(localpart) & 0x7FFFFFFF) % fTableViewBuckets; + } + else { + return (hash(localpart, uri) & 0x7FFFFFFF) % fTableViewBuckets; + } + } + + private int hash(String localpart) { + if (fHashMultipliers == null) { + return localpart.hashCode(); + } + return hash0(localpart); + } // hash(String):int + + private int hash(String localpart, String uri) { + if (fHashMultipliers == null) { + return localpart.hashCode() + uri.hashCode() * 31; + } + return hash0(localpart) + hash0(uri) * fHashMultipliers[MULTIPLIERS_SIZE]; + } // hash(String,String):int + + private int hash0(String symbol) { + int code = 0; + final int length = symbol.length(); + final int[] multipliers = fHashMultipliers; + for (int i = 0; i < length; ++i) { + code = code * multipliers[i & MULTIPLIERS_MASK] + symbol.charAt(i); + } + return code; + } // hash0(String):int + + /** + * Purges all elements from the table view. + */ + protected void cleanTableView() { + if (++fLargeCount < 0) { + // Overflow. We actually need to visit the chain state array. + if (fAttributeTableViewChainState != null) { + for (int i = fTableViewBuckets - 1; i >= 0; --i) { + fAttributeTableViewChainState[i] = 0; + } + } + fLargeCount = 1; + } + } + + /** + * Increases the capacity of the table view. + */ + private void growTableView() { + final int length = fLength; + int tableViewBuckets = fTableViewBuckets; + do { + tableViewBuckets = (tableViewBuckets << 1) + 1; + if (tableViewBuckets < 0) { + tableViewBuckets = Integer.MAX_VALUE; + break; + } + } + while (length > tableViewBuckets); + fTableViewBuckets = tableViewBuckets; + fAttributeTableView = null; + fLargeCount = 1; + } + + /** + * Prepares the table view of the attributes list for use. + */ + protected void prepareTableView() { + if (fLength > fTableViewBuckets) { + growTableView(); + } + if (fAttributeTableView == null) { + fAttributeTableView = new Attribute[fTableViewBuckets]; + fAttributeTableViewChainState = new int[fTableViewBuckets]; + } + else { + cleanTableView(); + } + } + + /** + * Prepares the table view of the attributes list for use, + * and populates it with the attributes which have been + * previously read. + */ + protected void prepareAndPopulateTableView() { + prepareAndPopulateTableView(fLength); + } + + private void prepareAndPopulateTableView(final int count) { + prepareTableView(); + // Need to populate the hash table with the attributes we've processed so far. + Attribute attr; + int bucket; + for (int i = 0; i < count; ++i) { + attr = fAttributes[i]; + bucket = getTableViewBucket(attr.name.rawname); + if (fAttributeTableViewChainState[bucket] != fLargeCount) { + fAttributeTableViewChainState[bucket] = fLargeCount; + attr.next = null; + fAttributeTableView[bucket] = attr; + } + else { + // Update table view + attr.next = fAttributeTableView[bucket]; + fAttributeTableView[bucket] = attr; + } + } + } + + private void prepareAndPopulateTableViewNS(final int count) { + prepareTableView(); + // Need to populate the hash table with the attributes we've processed so far. + Attribute attr; + int bucket; + for (int i = 0; i < count; ++i) { + attr = fAttributes[i]; + bucket = getTableViewBucket(attr.name.localpart, attr.name.uri); + if (fAttributeTableViewChainState[bucket] != fLargeCount) { + fAttributeTableViewChainState[bucket] = fLargeCount; + attr.next = null; + fAttributeTableView[bucket] = attr; + } + else { + // Update table view + attr.next = fAttributeTableView[bucket]; + fAttributeTableView[bucket] = attr; + } + } + } + + /** + * Randomly selects a new hash function and reorganizes the table view + * in order to more evenly distribute its entries. This method is called + * automatically when the number of attributes in one bucket exceeds + * MAX_HASH_COLLISIONS. + */ + private void rebalanceTableView(final int count) { + if (fHashMultipliers == null) { + fHashMultipliers = new int[MULTIPLIERS_SIZE + 1]; + } + PrimeNumberSequenceGenerator.generateSequence(fHashMultipliers); + prepareAndPopulateTableView(count); + } + + /** + * Randomly selects a new hash function and reorganizes the table view + * in order to more evenly distribute its entries. This method is called + * automatically when the number of attributes in one bucket exceeds + * MAX_HASH_COLLISIONS. + */ + private void rebalanceTableViewNS(final int count) { + if (fHashMultipliers == null) { + fHashMultipliers = new int[MULTIPLIERS_SIZE + 1]; + } + PrimeNumberSequenceGenerator.generateSequence(fHashMultipliers); + prepareAndPopulateTableViewNS(count); + } + + // + // Classes + // + + /** + * Attribute information. + * + * @author Andy Clark, IBM + */ + static class Attribute { + + // + // Data + // + + // basic info + + /** Name. */ + public final QName name = new QName(); + + /** Type. */ + public String type; + + /** Value. */ + public String value; + + /** Non-normalized value. */ + public String nonNormalizedValue; + + /** Specified. */ + public boolean specified; + + /** + * Augmentations information for this attribute. + * XMLAttributes has no knowledge if any augmentations + * were attached to Augmentations. + */ + public Augmentations augs = new AugmentationsImpl(); + + // Additional data for attribute table view + + /** Pointer to the next attribute in the chain. **/ + public Attribute next; + + } // class Attribute + +} // class XMLAttributesImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLCatalogResolver.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLCatalogResolver.java new file mode 100644 index 0000000..35dbe4a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLCatalogResolver.java @@ -0,0 +1,579 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.io.IOException; + +import javax.xml.parsers.SAXParserFactory; + +import org.apache.xerces.dom.DOMInputImpl; +import org.apache.xerces.jaxp.SAXParserFactoryImpl; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xml.resolver.Catalog; +import org.apache.xml.resolver.CatalogManager; +import org.apache.xml.resolver.readers.OASISXMLCatalogReader; +import org.apache.xml.resolver.readers.SAXCatalogReader; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.ext.EntityResolver2; + +/** + *

        The catalog resolver handles the resolution of external + * identifiers and URI references through XML catalogs. This + * component supports XML catalogs defined by the + * + * OASIS XML Catalogs Specification. It encapsulates the + * XML Commons resolver. + * An instance of this class may be registered on the parser + * as a SAX entity resolver, as a DOM LSResourceResolver or + * as an XNI entity resolver by setting the property + * (http://apache.org/xml/properties/internal/entity-resolver).

        + * + *

        It is intended that this class may be used standalone to perform + * catalog resolution outside of a parsing context. It may be shared + * between several parsers and the application.

        + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XMLCatalogResolver + implements XMLEntityResolver, EntityResolver2, LSResourceResolver { + + /** Internal catalog manager for Apache catalogs. **/ + private CatalogManager fResolverCatalogManager = null; + + /** Internal catalog structure. **/ + private Catalog fCatalog = null; + + /** An array of catalog URIs. **/ + private String [] fCatalogsList = null; + + /** + * Indicates whether the list of catalogs has + * changed since it was processed. + */ + private boolean fCatalogsChanged = true; + + /** Application specified prefer public setting. **/ + private boolean fPreferPublic = true; + + /** + * Indicates whether the application desires that + * the parser or some other component performing catalog + * resolution should use the literal system identifier + * instead of the expanded system identifier. + */ + private boolean fUseLiteralSystemId = true; + + /** + *

        Constructs a catalog resolver with a default configuration.

        + */ + public XMLCatalogResolver () { + this(null, true); + } + + /** + *

        Constructs a catalog resolver with the given + * list of entry files.

        + * + * @param catalogs an ordered array list of absolute URIs + */ + public XMLCatalogResolver (String [] catalogs) { + this(catalogs, true); + } + + /** + *

        Constructs a catalog resolver with the given + * list of entry files and the preference for whether + * system or public matches are preferred.

        + * + * @param catalogs an ordered array list of absolute URIs + * @param preferPublic the prefer public setting + */ + public XMLCatalogResolver (String [] catalogs, boolean preferPublic) { + init(catalogs, preferPublic); + } + + /** + *

        Returns the initial list of catalog entry files.

        + * + * @return the initial list of catalog entry files + */ + public final synchronized String [] getCatalogList () { + return (fCatalogsList != null) + ? (String[]) fCatalogsList.clone() : null; + } + + /** + *

        Sets the initial list of catalog entry files. + * If there were any catalog mappings cached from + * the previous list they will be replaced by catalog + * mappings from the new list the next time the catalog + * is queried.

        + * + * @param catalogs an ordered array list of absolute URIs + */ + public final synchronized void setCatalogList (String [] catalogs) { + fCatalogsChanged = true; + fCatalogsList = (catalogs != null) + ? (String[]) catalogs.clone() : null; + } + + /** + *

        Forces the cache of catalog mappings to be cleared.

        + */ + public final synchronized void clear () { + fCatalog = null; + } + + /** + *

        Returns the preference for whether system or public + * matches are preferred. This is used in the absence + * of any occurrence of the prefer attribute + * on the catalog entry of a catalog. If this + * property has not yet been explicitly set its value is + * true.

        + * + * @return the prefer public setting + */ + public final boolean getPreferPublic () { + return fPreferPublic; + } + + /** + *

        Sets the preference for whether system or public + * matches are preferred. This is used in the absence + * of any occurrence of the prefer attribute + * on the catalog entry of a catalog.

        + * + * @param preferPublic the prefer public setting + */ + public final void setPreferPublic (boolean preferPublic) { + fPreferPublic = preferPublic; + fResolverCatalogManager.setPreferPublic(preferPublic); + } + + /** + *

        Returns the preference for whether the literal system + * identifier should be used when resolving system + * identifiers when both it and the expanded system + * identifier are available. If this property has not yet + * been explicitly set its value is true.

        + * + * @return the preference for using literal system identifiers + * for catalog resolution + * + * @see #setUseLiteralSystemId + */ + public final boolean getUseLiteralSystemId () { + return fUseLiteralSystemId; + } + + /** + *

        Sets the preference for whether the literal system + * identifier should be used when resolving system + * identifiers when both it and the expanded system + * identifier are available.

        + * + *

        The literal system identifier is the URI as it was + * provided before absolutization. It may be embedded within + * an entity. It may be provided externally or it may be the + * result of redirection. For example, redirection may + * have come from the protocol level through HTTP or from + * an application's entity resolver.

        + * + *

        The expanded system identifier is an absolute URI + * which is the result of resolving the literal system + * identifier against a base URI.

        + * + * @param useLiteralSystemId the preference for using + * literal system identifiers for catalog resolution + */ + public final void setUseLiteralSystemId (boolean useLiteralSystemId) { + fUseLiteralSystemId = useLiteralSystemId; + } + + /** + *

        Resolves an external entity. If the entity cannot be + * resolved, this method should return null. This + * method returns an input source if an entry was found in the + * catalog for the given external identifier. It should be + * overridden if other behaviour is required.

        + * + * @param publicId the public identifier, or null if none was supplied + * @param systemId the system identifier + * + * @throws SAXException any SAX exception, possibly wrapping another exception + * @throws IOException thrown if some i/o error occurs + */ + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + + String resolvedId = null; + if (publicId != null && systemId != null) { + resolvedId = resolvePublic(publicId, systemId); + } + else if (systemId != null) { + resolvedId = resolveSystem(systemId); + } + + if (resolvedId != null) { + InputSource source = new InputSource(resolvedId); + source.setPublicId(publicId); + return source; + } + return null; + } + + /** + *

        Resolves an external entity. If the entity cannot be + * resolved, this method should return null. This + * method returns an input source if an entry was found in the + * catalog for the given external identifier. It should be + * overridden if other behaviour is required.

        + * + * @param name the identifier of the external entity + * @param publicId the public identifier, or null if none was supplied + * @param baseURI the URI with respect to which relative systemIDs are interpreted. + * @param systemId the system identifier + * + * @throws SAXException any SAX exception, possibly wrapping another exception + * @throws IOException thrown if some i/o error occurs + */ + public InputSource resolveEntity(String name, String publicId, + String baseURI, String systemId) throws SAXException, IOException { + + String resolvedId = null; + + if (!getUseLiteralSystemId() && baseURI != null) { + // Attempt to resolve the system identifier against the base URI. + try { + URI uri = new URI(new URI(baseURI), systemId); + systemId = uri.toString(); + } + // Ignore the exception. Fallback to the literal system identifier. + catch (URI.MalformedURIException ex) {} + } + + if (publicId != null && systemId != null) { + resolvedId = resolvePublic(publicId, systemId); + } + else if (systemId != null) { + resolvedId = resolveSystem(systemId); + } + + if (resolvedId != null) { + InputSource source = new InputSource(resolvedId); + source.setPublicId(publicId); + return source; + } + return null; + } + + /** + *

        Locates an external subset for documents which do not explicitly + * provide one. This method always returns null. It + * should be overrided if other behaviour is required.

        + * + * @param name the identifier of the document root element + * @param baseURI the document's base URI + * + * @throws SAXException any SAX exception, possibly wrapping another exception + * @throws IOException thrown if some i/o error occurs + */ + public InputSource getExternalSubset(String name, String baseURI) + throws SAXException, IOException { + return null; + } + + /** + *

        Resolves a resource using the catalog. This method interprets that + * the namespace URI corresponds to uri entries in the catalog. + * Where both a namespace and an external identifier exist, the namespace + * takes precedence.

        + * + * @param type the type of the resource being resolved + * @param namespaceURI the namespace of the resource being resolved, + * or null if none was supplied + * @param publicId the public identifier of the resource being resolved, + * or null if none was supplied + * @param systemId the system identifier of the resource being resolved, + * or null if none was supplied + * @param baseURI the absolute base URI of the resource being parsed, + * or null if there is no base URI + */ + public LSInput resolveResource(String type, String namespaceURI, + String publicId, String systemId, String baseURI) { + + String resolvedId = null; + + try { + // The namespace is useful for resolving namespace aware + // grammars such as XML schema. Let it take precedence over + // the external identifier if one exists. + if (namespaceURI != null) { + resolvedId = resolveURI(namespaceURI); + } + + if (!getUseLiteralSystemId() && baseURI != null) { + // Attempt to resolve the system identifier against the base URI. + try { + URI uri = new URI(new URI(baseURI), systemId); + systemId = uri.toString(); + } + // Ignore the exception. Fallback to the literal system identifier. + catch (URI.MalformedURIException ex) {} + } + + // Resolve against an external identifier if one exists. This + // is useful for resolving DTD external subsets and other + // external entities. For XML schemas if there was no namespace + // mapping we might be able to resolve a system identifier + // specified as a location hint. + if (resolvedId == null) { + if (publicId != null && systemId != null) { + resolvedId = resolvePublic(publicId, systemId); + } + else if (systemId != null) { + resolvedId = resolveSystem(systemId); + } + } + } + // Ignore IOException. It cannot be thrown from this method. + catch (IOException ex) {} + + if (resolvedId != null) { + return new DOMInputImpl(publicId, resolvedId, baseURI); + } + return null; + } + + + /** + *

        Resolves an external entity. If the entity cannot be + * resolved, this method should return null. This + * method only calls resolveIdentifier and returns + * an input source if an entry was found in the catalog. It + * should be overridden if other behaviour is required.

        + * + * @param resourceIdentifier location of the XML resource to resolve + * + * @throws XNIException thrown on general error + * @throws IOException thrown if some i/o error occurs + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) + throws XNIException, IOException { + + String resolvedId = resolveIdentifier(resourceIdentifier); + if (resolvedId != null) { + return new XMLInputSource(resourceIdentifier.getPublicId(), + resolvedId, + resourceIdentifier.getBaseSystemId()); + } + return null; + } + + /** + *

        Resolves an identifier using the catalog. This method interprets that + * the namespace of the identifier corresponds to uri entries in the catalog. + * Where both a namespace and an external identifier exist, the namespace + * takes precedence.

        + * + * @param resourceIdentifier the identifier to resolve + * + * @throws XNIException thrown on general error + * @throws IOException thrown if some i/o error occurs + */ + public String resolveIdentifier(XMLResourceIdentifier resourceIdentifier) + throws IOException, XNIException { + + String resolvedId = null; + + // The namespace is useful for resolving namespace aware + // grammars such as XML schema. Let it take precedence over + // the external identifier if one exists. + String namespace = resourceIdentifier.getNamespace(); + if (namespace != null) { + resolvedId = resolveURI(namespace); + } + + // Resolve against an external identifier if one exists. This + // is useful for resolving DTD external subsets and other + // external entities. For XML schemas if there was no namespace + // mapping we might be able to resolve a system identifier + // specified as a location hint. + if (resolvedId == null) { + String publicId = resourceIdentifier.getPublicId(); + String systemId = getUseLiteralSystemId() + ? resourceIdentifier.getLiteralSystemId() + : resourceIdentifier.getExpandedSystemId(); + if (publicId != null && systemId != null) { + resolvedId = resolvePublic(publicId, systemId); + } + else if (systemId != null) { + resolvedId = resolveSystem(systemId); + } + } + return resolvedId; + } + + /** + *

        Returns the URI mapping in the catalog for the given + * external identifier or null if no mapping + * exists. If the system identifier is an URN in the + * publicid namespace it is converted into + * a public identifier by URN "unwrapping" as specified + * in the XML Catalogs specification.

        + * + * @param systemId the system identifier to locate in the catalog + * + * @return the mapped URI or null if no mapping + * was found in the catalog + * + * @throws IOException if an i/o error occurred while reading + * the catalog + */ + public final synchronized String resolveSystem (String systemId) + throws IOException { + + if (fCatalogsChanged) { + parseCatalogs(); + fCatalogsChanged = false; + } + return (fCatalog != null) + ? fCatalog.resolveSystem(systemId) : null; + } + + /** + *

        Returns the URI mapping in the catalog for the given + * external identifier or null if no mapping + * exists. Public identifiers are normalized before + * comparison.

        + * + * @param publicId the public identifier to locate in the catalog + * @param systemId the system identifier to locate in the catalog + * + * @return the mapped URI or null if no mapping + * was found in the catalog + * + * @throws IOException if an i/o error occurred while reading + * the catalog + */ + public final synchronized String resolvePublic (String publicId, String systemId) + throws IOException { + + if (fCatalogsChanged) { + parseCatalogs(); + fCatalogsChanged = false; + } + return (fCatalog != null) + ? fCatalog.resolvePublic(publicId, systemId) : null; + } + + /** + *

        Returns the URI mapping in the catalog for the given URI + * reference or null if no mapping exists. + * URI comparison is case sensitive. If the URI reference + * is an URN in the publicid namespace + * it is converted into a public identifier by URN "unwrapping" + * as specified in the XML Catalogs specification and then + * resolution is performed following the semantics of + * external identifier resolution.

        + * + * @param uri the URI to locate in the catalog + * + * @return the mapped URI or null if no mapping + * was found in the catalog + * + * @throws IOException if an i/o error occurred while reading + * the catalog + */ + public final synchronized String resolveURI (String uri) + throws IOException { + + if (fCatalogsChanged) { + parseCatalogs(); + fCatalogsChanged = false; + } + return (fCatalog != null) + ? fCatalog.resolveURI(uri) : null; + } + + /** + * Initialization. Create a CatalogManager and set all + * the properties upfront. This prevents JVM wide system properties + * or a property file somewhere in the environment from affecting + * the behaviour of this catalog resolver. + */ + private void init (String [] catalogs, boolean preferPublic) { + fCatalogsList = (catalogs != null) ? (String[]) catalogs.clone() : null; + fPreferPublic = preferPublic; + fResolverCatalogManager = new CatalogManager(); + fResolverCatalogManager.setAllowOasisXMLCatalogPI(false); + fResolverCatalogManager.setCatalogClassName("org.apache.xml.resolver.Catalog"); + fResolverCatalogManager.setCatalogFiles(""); + fResolverCatalogManager.setIgnoreMissingProperties(true); + fResolverCatalogManager.setPreferPublic(fPreferPublic); + fResolverCatalogManager.setRelativeCatalogs(false); + fResolverCatalogManager.setUseStaticCatalog(false); + fResolverCatalogManager.setVerbosity(0); + } + + /** + * Instruct the Catalog to parse each of the + * catalogs in the list. Only the first catalog will actually be + * parsed immediately. The others will be queued and read if + * they are needed later. + */ + private void parseCatalogs () throws IOException { + if (fCatalogsList != null) { + fCatalog = new Catalog(fResolverCatalogManager); + attachReaderToCatalog(fCatalog); + for (int i = 0; i < fCatalogsList.length; ++i) { + String catalog = fCatalogsList[i]; + if (catalog != null && catalog.length() > 0) { + fCatalog.parseCatalog(catalog); + } + } + } + else { + fCatalog = null; + } + } + + /** + * Attaches the reader to the catalog. + */ + private void attachReaderToCatalog (Catalog catalog) { + + SAXParserFactory spf = new SAXParserFactoryImpl(); + spf.setNamespaceAware(true); + spf.setValidating(false); + + SAXCatalogReader saxReader = new SAXCatalogReader(spf); + saxReader.setCatalogParser(OASISXMLCatalogReader.namespaceName, "catalog", + "org.apache.xml.resolver.readers.OASISXMLCatalogReader"); + catalog.addReader("application/xml", saxReader); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLChar.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLChar.java new file mode 100644 index 0000000..f2e1e50 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLChar.java @@ -0,0 +1,1062 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import java.util.Arrays; + +/** + * This class defines the basic XML character properties. The data + * in this class can be used to verify that a character is a valid + * XML character or if the character is a space, name start, or name + * character. + *

        + * A series of convenience methods are supplied to ease the burden + * of the developer. Because inlining the checks can improve per + * character performance, the tables of character properties are + * public. Using the character as an index into the CHARS + * array and applying the appropriate mask flag (e.g. + * MASK_VALID), yields the same results as calling the + * convenience methods. There is one exception: check the comments + * for the isValid method for details. + * + * @author Glenn Marcy, IBM + * @author Andy Clark, IBM + * @author Eric Ye, IBM + * @author Arnaud Le Hors, IBM + * @author Michael Glavassevich, IBM + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id$ + */ +public class XMLChar { + + // + // Constants + // + + /** Character flags. */ + private static final byte[] CHARS = new byte[1 << 16]; + + /** Valid character mask. */ + public static final int MASK_VALID = 0x01; + + /** Space character mask. */ + public static final int MASK_SPACE = 0x02; + + /** Name start character mask. */ + public static final int MASK_NAME_START = 0x04; + + /** Name character mask. */ + public static final int MASK_NAME = 0x08; + + /** Pubid character mask. */ + public static final int MASK_PUBID = 0x10; + + /** + * Content character mask. Special characters are those that can + * be considered the start of markup, such as '<' and '&'. + * The various newline characters are considered special as well. + * All other valid XML characters can be considered content. + *

        + * This is an optimization for the inner loop of character scanning. + */ + public static final int MASK_CONTENT = 0x20; + + /** NCName start character mask. */ + public static final int MASK_NCNAME_START = 0x40; + + /** NCName character mask. */ + public static final int MASK_NCNAME = 0x80; + + // + // Static initialization + // + + static { + + // Initializing the Character Flag Array + // Code generated by: XMLCharGenerator. + + CHARS[9] = 35; + CHARS[10] = 19; + CHARS[13] = 19; + CHARS[32] = 51; + CHARS[33] = 49; + CHARS[34] = 33; + Arrays.fill(CHARS, 35, 38, (byte) 49 ); // Fill 3 of value (byte) 49 + CHARS[38] = 1; + Arrays.fill(CHARS, 39, 45, (byte) 49 ); // Fill 6 of value (byte) 49 + Arrays.fill(CHARS, 45, 47, (byte) -71 ); // Fill 2 of value (byte) -71 + CHARS[47] = 49; + Arrays.fill(CHARS, 48, 58, (byte) -71 ); // Fill 10 of value (byte) -71 + CHARS[58] = 61; + CHARS[59] = 49; + CHARS[60] = 1; + CHARS[61] = 49; + CHARS[62] = 33; + Arrays.fill(CHARS, 63, 65, (byte) 49 ); // Fill 2 of value (byte) 49 + Arrays.fill(CHARS, 65, 91, (byte) -3 ); // Fill 26 of value (byte) -3 + Arrays.fill(CHARS, 91, 93, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[93] = 1; + CHARS[94] = 33; + CHARS[95] = -3; + CHARS[96] = 33; + Arrays.fill(CHARS, 97, 123, (byte) -3 ); // Fill 26 of value (byte) -3 + Arrays.fill(CHARS, 123, 183, (byte) 33 ); // Fill 60 of value (byte) 33 + CHARS[183] = -87; + Arrays.fill(CHARS, 184, 192, (byte) 33 ); // Fill 8 of value (byte) 33 + Arrays.fill(CHARS, 192, 215, (byte) -19 ); // Fill 23 of value (byte) -19 + CHARS[215] = 33; + Arrays.fill(CHARS, 216, 247, (byte) -19 ); // Fill 31 of value (byte) -19 + CHARS[247] = 33; + Arrays.fill(CHARS, 248, 306, (byte) -19 ); // Fill 58 of value (byte) -19 + Arrays.fill(CHARS, 306, 308, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 308, 319, (byte) -19 ); // Fill 11 of value (byte) -19 + Arrays.fill(CHARS, 319, 321, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 321, 329, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[329] = 33; + Arrays.fill(CHARS, 330, 383, (byte) -19 ); // Fill 53 of value (byte) -19 + CHARS[383] = 33; + Arrays.fill(CHARS, 384, 452, (byte) -19 ); // Fill 68 of value (byte) -19 + Arrays.fill(CHARS, 452, 461, (byte) 33 ); // Fill 9 of value (byte) 33 + Arrays.fill(CHARS, 461, 497, (byte) -19 ); // Fill 36 of value (byte) -19 + Arrays.fill(CHARS, 497, 500, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 500, 502, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 502, 506, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 506, 536, (byte) -19 ); // Fill 30 of value (byte) -19 + Arrays.fill(CHARS, 536, 592, (byte) 33 ); // Fill 56 of value (byte) 33 + Arrays.fill(CHARS, 592, 681, (byte) -19 ); // Fill 89 of value (byte) -19 + Arrays.fill(CHARS, 681, 699, (byte) 33 ); // Fill 18 of value (byte) 33 + Arrays.fill(CHARS, 699, 706, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 706, 720, (byte) 33 ); // Fill 14 of value (byte) 33 + Arrays.fill(CHARS, 720, 722, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 722, 768, (byte) 33 ); // Fill 46 of value (byte) 33 + Arrays.fill(CHARS, 768, 838, (byte) -87 ); // Fill 70 of value (byte) -87 + Arrays.fill(CHARS, 838, 864, (byte) 33 ); // Fill 26 of value (byte) 33 + Arrays.fill(CHARS, 864, 866, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 866, 902, (byte) 33 ); // Fill 36 of value (byte) 33 + CHARS[902] = -19; + CHARS[903] = -87; + Arrays.fill(CHARS, 904, 907, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[907] = 33; + CHARS[908] = -19; + CHARS[909] = 33; + Arrays.fill(CHARS, 910, 930, (byte) -19 ); // Fill 20 of value (byte) -19 + CHARS[930] = 33; + Arrays.fill(CHARS, 931, 975, (byte) -19 ); // Fill 44 of value (byte) -19 + CHARS[975] = 33; + Arrays.fill(CHARS, 976, 983, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 983, 986, (byte) 33 ); // Fill 3 of value (byte) 33 + CHARS[986] = -19; + CHARS[987] = 33; + CHARS[988] = -19; + CHARS[989] = 33; + CHARS[990] = -19; + CHARS[991] = 33; + CHARS[992] = -19; + CHARS[993] = 33; + Arrays.fill(CHARS, 994, 1012, (byte) -19 ); // Fill 18 of value (byte) -19 + Arrays.fill(CHARS, 1012, 1025, (byte) 33 ); // Fill 13 of value (byte) 33 + Arrays.fill(CHARS, 1025, 1037, (byte) -19 ); // Fill 12 of value (byte) -19 + CHARS[1037] = 33; + Arrays.fill(CHARS, 1038, 1104, (byte) -19 ); // Fill 66 of value (byte) -19 + CHARS[1104] = 33; + Arrays.fill(CHARS, 1105, 1117, (byte) -19 ); // Fill 12 of value (byte) -19 + CHARS[1117] = 33; + Arrays.fill(CHARS, 1118, 1154, (byte) -19 ); // Fill 36 of value (byte) -19 + CHARS[1154] = 33; + Arrays.fill(CHARS, 1155, 1159, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 1159, 1168, (byte) 33 ); // Fill 9 of value (byte) 33 + Arrays.fill(CHARS, 1168, 1221, (byte) -19 ); // Fill 53 of value (byte) -19 + Arrays.fill(CHARS, 1221, 1223, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1223, 1225, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 1225, 1227, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1227, 1229, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 1229, 1232, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 1232, 1260, (byte) -19 ); // Fill 28 of value (byte) -19 + Arrays.fill(CHARS, 1260, 1262, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1262, 1270, (byte) -19 ); // Fill 8 of value (byte) -19 + Arrays.fill(CHARS, 1270, 1272, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1272, 1274, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 1274, 1329, (byte) 33 ); // Fill 55 of value (byte) 33 + Arrays.fill(CHARS, 1329, 1367, (byte) -19 ); // Fill 38 of value (byte) -19 + Arrays.fill(CHARS, 1367, 1369, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[1369] = -19; + Arrays.fill(CHARS, 1370, 1377, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 1377, 1415, (byte) -19 ); // Fill 38 of value (byte) -19 + Arrays.fill(CHARS, 1415, 1425, (byte) 33 ); // Fill 10 of value (byte) 33 + Arrays.fill(CHARS, 1425, 1442, (byte) -87 ); // Fill 17 of value (byte) -87 + CHARS[1442] = 33; + Arrays.fill(CHARS, 1443, 1466, (byte) -87 ); // Fill 23 of value (byte) -87 + CHARS[1466] = 33; + Arrays.fill(CHARS, 1467, 1470, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[1470] = 33; + CHARS[1471] = -87; + CHARS[1472] = 33; + Arrays.fill(CHARS, 1473, 1475, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[1475] = 33; + CHARS[1476] = -87; + Arrays.fill(CHARS, 1477, 1488, (byte) 33 ); // Fill 11 of value (byte) 33 + Arrays.fill(CHARS, 1488, 1515, (byte) -19 ); // Fill 27 of value (byte) -19 + Arrays.fill(CHARS, 1515, 1520, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 1520, 1523, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 1523, 1569, (byte) 33 ); // Fill 46 of value (byte) 33 + Arrays.fill(CHARS, 1569, 1595, (byte) -19 ); // Fill 26 of value (byte) -19 + Arrays.fill(CHARS, 1595, 1600, (byte) 33 ); // Fill 5 of value (byte) 33 + CHARS[1600] = -87; + Arrays.fill(CHARS, 1601, 1611, (byte) -19 ); // Fill 10 of value (byte) -19 + Arrays.fill(CHARS, 1611, 1619, (byte) -87 ); // Fill 8 of value (byte) -87 + Arrays.fill(CHARS, 1619, 1632, (byte) 33 ); // Fill 13 of value (byte) 33 + Arrays.fill(CHARS, 1632, 1642, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 1642, 1648, (byte) 33 ); // Fill 6 of value (byte) 33 + CHARS[1648] = -87; + Arrays.fill(CHARS, 1649, 1720, (byte) -19 ); // Fill 71 of value (byte) -19 + Arrays.fill(CHARS, 1720, 1722, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1722, 1727, (byte) -19 ); // Fill 5 of value (byte) -19 + CHARS[1727] = 33; + Arrays.fill(CHARS, 1728, 1743, (byte) -19 ); // Fill 15 of value (byte) -19 + CHARS[1743] = 33; + Arrays.fill(CHARS, 1744, 1748, (byte) -19 ); // Fill 4 of value (byte) -19 + CHARS[1748] = 33; + CHARS[1749] = -19; + Arrays.fill(CHARS, 1750, 1765, (byte) -87 ); // Fill 15 of value (byte) -87 + Arrays.fill(CHARS, 1765, 1767, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 1767, 1769, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[1769] = 33; + Arrays.fill(CHARS, 1770, 1774, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 1774, 1776, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1776, 1786, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 1786, 2305, (byte) 33 ); // Fill 519 of value (byte) 33 + Arrays.fill(CHARS, 2305, 2308, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2308] = 33; + Arrays.fill(CHARS, 2309, 2362, (byte) -19 ); // Fill 53 of value (byte) -19 + Arrays.fill(CHARS, 2362, 2364, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2364] = -87; + CHARS[2365] = -19; + Arrays.fill(CHARS, 2366, 2382, (byte) -87 ); // Fill 16 of value (byte) -87 + Arrays.fill(CHARS, 2382, 2385, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2385, 2389, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 2389, 2392, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2392, 2402, (byte) -19 ); // Fill 10 of value (byte) -19 + Arrays.fill(CHARS, 2402, 2404, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2404, 2406, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2406, 2416, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 2416, 2433, (byte) 33 ); // Fill 17 of value (byte) 33 + Arrays.fill(CHARS, 2433, 2436, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2436] = 33; + Arrays.fill(CHARS, 2437, 2445, (byte) -19 ); // Fill 8 of value (byte) -19 + Arrays.fill(CHARS, 2445, 2447, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2447, 2449, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2449, 2451, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2451, 2473, (byte) -19 ); // Fill 22 of value (byte) -19 + CHARS[2473] = 33; + Arrays.fill(CHARS, 2474, 2481, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2481] = 33; + CHARS[2482] = -19; + Arrays.fill(CHARS, 2483, 2486, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2486, 2490, (byte) -19 ); // Fill 4 of value (byte) -19 + Arrays.fill(CHARS, 2490, 2492, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2492] = -87; + CHARS[2493] = 33; + Arrays.fill(CHARS, 2494, 2501, (byte) -87 ); // Fill 7 of value (byte) -87 + Arrays.fill(CHARS, 2501, 2503, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2503, 2505, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2505, 2507, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2507, 2510, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 2510, 2519, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[2519] = -87; + Arrays.fill(CHARS, 2520, 2524, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2524, 2526, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2526] = 33; + Arrays.fill(CHARS, 2527, 2530, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 2530, 2532, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2532, 2534, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2534, 2544, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 2544, 2546, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2546, 2562, (byte) 33 ); // Fill 16 of value (byte) 33 + CHARS[2562] = -87; + Arrays.fill(CHARS, 2563, 2565, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2565, 2571, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 2571, 2575, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2575, 2577, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2577, 2579, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2579, 2601, (byte) -19 ); // Fill 22 of value (byte) -19 + CHARS[2601] = 33; + Arrays.fill(CHARS, 2602, 2609, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2609] = 33; + Arrays.fill(CHARS, 2610, 2612, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2612] = 33; + Arrays.fill(CHARS, 2613, 2615, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2615] = 33; + Arrays.fill(CHARS, 2616, 2618, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2618, 2620, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2620] = -87; + CHARS[2621] = 33; + Arrays.fill(CHARS, 2622, 2627, (byte) -87 ); // Fill 5 of value (byte) -87 + Arrays.fill(CHARS, 2627, 2631, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2631, 2633, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2633, 2635, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2635, 2638, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 2638, 2649, (byte) 33 ); // Fill 11 of value (byte) 33 + Arrays.fill(CHARS, 2649, 2653, (byte) -19 ); // Fill 4 of value (byte) -19 + CHARS[2653] = 33; + CHARS[2654] = -19; + Arrays.fill(CHARS, 2655, 2662, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 2662, 2674, (byte) -87 ); // Fill 12 of value (byte) -87 + Arrays.fill(CHARS, 2674, 2677, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 2677, 2689, (byte) 33 ); // Fill 12 of value (byte) 33 + Arrays.fill(CHARS, 2689, 2692, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2692] = 33; + Arrays.fill(CHARS, 2693, 2700, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2700] = 33; + CHARS[2701] = -19; + CHARS[2702] = 33; + Arrays.fill(CHARS, 2703, 2706, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[2706] = 33; + Arrays.fill(CHARS, 2707, 2729, (byte) -19 ); // Fill 22 of value (byte) -19 + CHARS[2729] = 33; + Arrays.fill(CHARS, 2730, 2737, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2737] = 33; + Arrays.fill(CHARS, 2738, 2740, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2740] = 33; + Arrays.fill(CHARS, 2741, 2746, (byte) -19 ); // Fill 5 of value (byte) -19 + Arrays.fill(CHARS, 2746, 2748, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2748] = -87; + CHARS[2749] = -19; + Arrays.fill(CHARS, 2750, 2758, (byte) -87 ); // Fill 8 of value (byte) -87 + CHARS[2758] = 33; + Arrays.fill(CHARS, 2759, 2762, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2762] = 33; + Arrays.fill(CHARS, 2763, 2766, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 2766, 2784, (byte) 33 ); // Fill 18 of value (byte) 33 + CHARS[2784] = -19; + Arrays.fill(CHARS, 2785, 2790, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 2790, 2800, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 2800, 2817, (byte) 33 ); // Fill 17 of value (byte) 33 + Arrays.fill(CHARS, 2817, 2820, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2820] = 33; + Arrays.fill(CHARS, 2821, 2829, (byte) -19 ); // Fill 8 of value (byte) -19 + Arrays.fill(CHARS, 2829, 2831, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2831, 2833, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2833, 2835, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2835, 2857, (byte) -19 ); // Fill 22 of value (byte) -19 + CHARS[2857] = 33; + Arrays.fill(CHARS, 2858, 2865, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2865] = 33; + Arrays.fill(CHARS, 2866, 2868, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2868, 2870, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2870, 2874, (byte) -19 ); // Fill 4 of value (byte) -19 + Arrays.fill(CHARS, 2874, 2876, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2876] = -87; + CHARS[2877] = -19; + Arrays.fill(CHARS, 2878, 2884, (byte) -87 ); // Fill 6 of value (byte) -87 + Arrays.fill(CHARS, 2884, 2887, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2887, 2889, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2889, 2891, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2891, 2894, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 2894, 2902, (byte) 33 ); // Fill 8 of value (byte) 33 + Arrays.fill(CHARS, 2902, 2904, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2904, 2908, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2908, 2910, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2910] = 33; + Arrays.fill(CHARS, 2911, 2914, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 2914, 2918, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2918, 2928, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 2928, 2946, (byte) 33 ); // Fill 18 of value (byte) 33 + Arrays.fill(CHARS, 2946, 2948, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[2948] = 33; + Arrays.fill(CHARS, 2949, 2955, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 2955, 2958, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2958, 2961, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[2961] = 33; + Arrays.fill(CHARS, 2962, 2966, (byte) -19 ); // Fill 4 of value (byte) -19 + Arrays.fill(CHARS, 2966, 2969, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2969, 2971, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2971] = 33; + CHARS[2972] = -19; + CHARS[2973] = 33; + Arrays.fill(CHARS, 2974, 2976, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2976, 2979, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2979, 2981, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2981, 2984, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2984, 2987, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 2987, 2990, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2990, 2998, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[2998] = 33; + Arrays.fill(CHARS, 2999, 3002, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 3002, 3006, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3006, 3011, (byte) -87 ); // Fill 5 of value (byte) -87 + Arrays.fill(CHARS, 3011, 3014, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 3014, 3017, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3017] = 33; + Arrays.fill(CHARS, 3018, 3022, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 3022, 3031, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[3031] = -87; + Arrays.fill(CHARS, 3032, 3047, (byte) 33 ); // Fill 15 of value (byte) 33 + Arrays.fill(CHARS, 3047, 3056, (byte) -87 ); // Fill 9 of value (byte) -87 + Arrays.fill(CHARS, 3056, 3073, (byte) 33 ); // Fill 17 of value (byte) 33 + Arrays.fill(CHARS, 3073, 3076, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3076] = 33; + Arrays.fill(CHARS, 3077, 3085, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[3085] = 33; + Arrays.fill(CHARS, 3086, 3089, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[3089] = 33; + Arrays.fill(CHARS, 3090, 3113, (byte) -19 ); // Fill 23 of value (byte) -19 + CHARS[3113] = 33; + Arrays.fill(CHARS, 3114, 3124, (byte) -19 ); // Fill 10 of value (byte) -19 + CHARS[3124] = 33; + Arrays.fill(CHARS, 3125, 3130, (byte) -19 ); // Fill 5 of value (byte) -19 + Arrays.fill(CHARS, 3130, 3134, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3134, 3141, (byte) -87 ); // Fill 7 of value (byte) -87 + CHARS[3141] = 33; + Arrays.fill(CHARS, 3142, 3145, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3145] = 33; + Arrays.fill(CHARS, 3146, 3150, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 3150, 3157, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 3157, 3159, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 3159, 3168, (byte) 33 ); // Fill 9 of value (byte) 33 + Arrays.fill(CHARS, 3168, 3170, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3170, 3174, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3174, 3184, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3184, 3202, (byte) 33 ); // Fill 18 of value (byte) 33 + Arrays.fill(CHARS, 3202, 3204, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[3204] = 33; + Arrays.fill(CHARS, 3205, 3213, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[3213] = 33; + Arrays.fill(CHARS, 3214, 3217, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[3217] = 33; + Arrays.fill(CHARS, 3218, 3241, (byte) -19 ); // Fill 23 of value (byte) -19 + CHARS[3241] = 33; + Arrays.fill(CHARS, 3242, 3252, (byte) -19 ); // Fill 10 of value (byte) -19 + CHARS[3252] = 33; + Arrays.fill(CHARS, 3253, 3258, (byte) -19 ); // Fill 5 of value (byte) -19 + Arrays.fill(CHARS, 3258, 3262, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3262, 3269, (byte) -87 ); // Fill 7 of value (byte) -87 + CHARS[3269] = 33; + Arrays.fill(CHARS, 3270, 3273, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3273] = 33; + Arrays.fill(CHARS, 3274, 3278, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 3278, 3285, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 3285, 3287, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 3287, 3294, (byte) 33 ); // Fill 7 of value (byte) 33 + CHARS[3294] = -19; + CHARS[3295] = 33; + Arrays.fill(CHARS, 3296, 3298, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3298, 3302, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3302, 3312, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3312, 3330, (byte) 33 ); // Fill 18 of value (byte) 33 + Arrays.fill(CHARS, 3330, 3332, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[3332] = 33; + Arrays.fill(CHARS, 3333, 3341, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[3341] = 33; + Arrays.fill(CHARS, 3342, 3345, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[3345] = 33; + Arrays.fill(CHARS, 3346, 3369, (byte) -19 ); // Fill 23 of value (byte) -19 + CHARS[3369] = 33; + Arrays.fill(CHARS, 3370, 3386, (byte) -19 ); // Fill 16 of value (byte) -19 + Arrays.fill(CHARS, 3386, 3390, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3390, 3396, (byte) -87 ); // Fill 6 of value (byte) -87 + Arrays.fill(CHARS, 3396, 3398, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3398, 3401, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3401] = 33; + Arrays.fill(CHARS, 3402, 3406, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 3406, 3415, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[3415] = -87; + Arrays.fill(CHARS, 3416, 3424, (byte) 33 ); // Fill 8 of value (byte) 33 + Arrays.fill(CHARS, 3424, 3426, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3426, 3430, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3430, 3440, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3440, 3585, (byte) 33 ); // Fill 145 of value (byte) 33 + Arrays.fill(CHARS, 3585, 3631, (byte) -19 ); // Fill 46 of value (byte) -19 + CHARS[3631] = 33; + CHARS[3632] = -19; + CHARS[3633] = -87; + Arrays.fill(CHARS, 3634, 3636, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3636, 3643, (byte) -87 ); // Fill 7 of value (byte) -87 + Arrays.fill(CHARS, 3643, 3648, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 3648, 3654, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 3654, 3663, (byte) -87 ); // Fill 9 of value (byte) -87 + CHARS[3663] = 33; + Arrays.fill(CHARS, 3664, 3674, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3674, 3713, (byte) 33 ); // Fill 39 of value (byte) 33 + Arrays.fill(CHARS, 3713, 3715, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[3715] = 33; + CHARS[3716] = -19; + Arrays.fill(CHARS, 3717, 3719, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3719, 3721, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[3721] = 33; + CHARS[3722] = -19; + Arrays.fill(CHARS, 3723, 3725, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[3725] = -19; + Arrays.fill(CHARS, 3726, 3732, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(CHARS, 3732, 3736, (byte) -19 ); // Fill 4 of value (byte) -19 + CHARS[3736] = 33; + Arrays.fill(CHARS, 3737, 3744, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[3744] = 33; + Arrays.fill(CHARS, 3745, 3748, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[3748] = 33; + CHARS[3749] = -19; + CHARS[3750] = 33; + CHARS[3751] = -19; + Arrays.fill(CHARS, 3752, 3754, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3754, 3756, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[3756] = 33; + Arrays.fill(CHARS, 3757, 3759, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[3759] = 33; + CHARS[3760] = -19; + CHARS[3761] = -87; + Arrays.fill(CHARS, 3762, 3764, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3764, 3770, (byte) -87 ); // Fill 6 of value (byte) -87 + CHARS[3770] = 33; + Arrays.fill(CHARS, 3771, 3773, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[3773] = -19; + Arrays.fill(CHARS, 3774, 3776, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3776, 3781, (byte) -19 ); // Fill 5 of value (byte) -19 + CHARS[3781] = 33; + CHARS[3782] = -87; + CHARS[3783] = 33; + Arrays.fill(CHARS, 3784, 3790, (byte) -87 ); // Fill 6 of value (byte) -87 + Arrays.fill(CHARS, 3790, 3792, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3792, 3802, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3802, 3864, (byte) 33 ); // Fill 62 of value (byte) 33 + Arrays.fill(CHARS, 3864, 3866, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 3866, 3872, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(CHARS, 3872, 3882, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3882, 3893, (byte) 33 ); // Fill 11 of value (byte) 33 + CHARS[3893] = -87; + CHARS[3894] = 33; + CHARS[3895] = -87; + CHARS[3896] = 33; + CHARS[3897] = -87; + Arrays.fill(CHARS, 3898, 3902, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3902, 3904, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 3904, 3912, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[3912] = 33; + Arrays.fill(CHARS, 3913, 3946, (byte) -19 ); // Fill 33 of value (byte) -19 + Arrays.fill(CHARS, 3946, 3953, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 3953, 3973, (byte) -87 ); // Fill 20 of value (byte) -87 + CHARS[3973] = 33; + Arrays.fill(CHARS, 3974, 3980, (byte) -87 ); // Fill 6 of value (byte) -87 + Arrays.fill(CHARS, 3980, 3984, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3984, 3990, (byte) -87 ); // Fill 6 of value (byte) -87 + CHARS[3990] = 33; + CHARS[3991] = -87; + CHARS[3992] = 33; + Arrays.fill(CHARS, 3993, 4014, (byte) -87 ); // Fill 21 of value (byte) -87 + Arrays.fill(CHARS, 4014, 4017, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 4017, 4024, (byte) -87 ); // Fill 7 of value (byte) -87 + CHARS[4024] = 33; + CHARS[4025] = -87; + Arrays.fill(CHARS, 4026, 4256, (byte) 33 ); // Fill 230 of value (byte) 33 + Arrays.fill(CHARS, 4256, 4294, (byte) -19 ); // Fill 38 of value (byte) -19 + Arrays.fill(CHARS, 4294, 4304, (byte) 33 ); // Fill 10 of value (byte) 33 + Arrays.fill(CHARS, 4304, 4343, (byte) -19 ); // Fill 39 of value (byte) -19 + Arrays.fill(CHARS, 4343, 4352, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[4352] = -19; + CHARS[4353] = 33; + Arrays.fill(CHARS, 4354, 4356, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[4356] = 33; + Arrays.fill(CHARS, 4357, 4360, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[4360] = 33; + CHARS[4361] = -19; + CHARS[4362] = 33; + Arrays.fill(CHARS, 4363, 4365, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[4365] = 33; + Arrays.fill(CHARS, 4366, 4371, (byte) -19 ); // Fill 5 of value (byte) -19 + Arrays.fill(CHARS, 4371, 4412, (byte) 33 ); // Fill 41 of value (byte) 33 + CHARS[4412] = -19; + CHARS[4413] = 33; + CHARS[4414] = -19; + CHARS[4415] = 33; + CHARS[4416] = -19; + Arrays.fill(CHARS, 4417, 4428, (byte) 33 ); // Fill 11 of value (byte) 33 + CHARS[4428] = -19; + CHARS[4429] = 33; + CHARS[4430] = -19; + CHARS[4431] = 33; + CHARS[4432] = -19; + Arrays.fill(CHARS, 4433, 4436, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 4436, 4438, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 4438, 4441, (byte) 33 ); // Fill 3 of value (byte) 33 + CHARS[4441] = -19; + Arrays.fill(CHARS, 4442, 4447, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 4447, 4450, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[4450] = 33; + CHARS[4451] = -19; + CHARS[4452] = 33; + CHARS[4453] = -19; + CHARS[4454] = 33; + CHARS[4455] = -19; + CHARS[4456] = 33; + CHARS[4457] = -19; + Arrays.fill(CHARS, 4458, 4461, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 4461, 4463, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 4463, 4466, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 4466, 4468, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[4468] = 33; + CHARS[4469] = -19; + Arrays.fill(CHARS, 4470, 4510, (byte) 33 ); // Fill 40 of value (byte) 33 + CHARS[4510] = -19; + Arrays.fill(CHARS, 4511, 4520, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[4520] = -19; + Arrays.fill(CHARS, 4521, 4523, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[4523] = -19; + Arrays.fill(CHARS, 4524, 4526, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 4526, 4528, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 4528, 4535, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 4535, 4537, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[4537] = 33; + CHARS[4538] = -19; + CHARS[4539] = 33; + Arrays.fill(CHARS, 4540, 4547, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 4547, 4587, (byte) 33 ); // Fill 40 of value (byte) 33 + CHARS[4587] = -19; + Arrays.fill(CHARS, 4588, 4592, (byte) 33 ); // Fill 4 of value (byte) 33 + CHARS[4592] = -19; + Arrays.fill(CHARS, 4593, 4601, (byte) 33 ); // Fill 8 of value (byte) 33 + CHARS[4601] = -19; + Arrays.fill(CHARS, 4602, 7680, (byte) 33 ); // Fill 3078 of value (byte) 33 + Arrays.fill(CHARS, 7680, 7836, (byte) -19 ); // Fill 156 of value (byte) -19 + Arrays.fill(CHARS, 7836, 7840, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 7840, 7930, (byte) -19 ); // Fill 90 of value (byte) -19 + Arrays.fill(CHARS, 7930, 7936, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(CHARS, 7936, 7958, (byte) -19 ); // Fill 22 of value (byte) -19 + Arrays.fill(CHARS, 7958, 7960, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 7960, 7966, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 7966, 7968, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 7968, 8006, (byte) -19 ); // Fill 38 of value (byte) -19 + Arrays.fill(CHARS, 8006, 8008, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 8008, 8014, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 8014, 8016, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 8016, 8024, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[8024] = 33; + CHARS[8025] = -19; + CHARS[8026] = 33; + CHARS[8027] = -19; + CHARS[8028] = 33; + CHARS[8029] = -19; + CHARS[8030] = 33; + Arrays.fill(CHARS, 8031, 8062, (byte) -19 ); // Fill 31 of value (byte) -19 + Arrays.fill(CHARS, 8062, 8064, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 8064, 8117, (byte) -19 ); // Fill 53 of value (byte) -19 + CHARS[8117] = 33; + Arrays.fill(CHARS, 8118, 8125, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[8125] = 33; + CHARS[8126] = -19; + Arrays.fill(CHARS, 8127, 8130, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 8130, 8133, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[8133] = 33; + Arrays.fill(CHARS, 8134, 8141, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 8141, 8144, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 8144, 8148, (byte) -19 ); // Fill 4 of value (byte) -19 + Arrays.fill(CHARS, 8148, 8150, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 8150, 8156, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 8156, 8160, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 8160, 8173, (byte) -19 ); // Fill 13 of value (byte) -19 + Arrays.fill(CHARS, 8173, 8178, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 8178, 8181, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[8181] = 33; + Arrays.fill(CHARS, 8182, 8189, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 8189, 8400, (byte) 33 ); // Fill 211 of value (byte) 33 + Arrays.fill(CHARS, 8400, 8413, (byte) -87 ); // Fill 13 of value (byte) -87 + Arrays.fill(CHARS, 8413, 8417, (byte) 33 ); // Fill 4 of value (byte) 33 + CHARS[8417] = -87; + Arrays.fill(CHARS, 8418, 8486, (byte) 33 ); // Fill 68 of value (byte) 33 + CHARS[8486] = -19; + Arrays.fill(CHARS, 8487, 8490, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 8490, 8492, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 8492, 8494, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[8494] = -19; + Arrays.fill(CHARS, 8495, 8576, (byte) 33 ); // Fill 81 of value (byte) 33 + Arrays.fill(CHARS, 8576, 8579, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 8579, 12293, (byte) 33 ); // Fill 3714 of value (byte) 33 + CHARS[12293] = -87; + CHARS[12294] = 33; + CHARS[12295] = -19; + Arrays.fill(CHARS, 12296, 12321, (byte) 33 ); // Fill 25 of value (byte) 33 + Arrays.fill(CHARS, 12321, 12330, (byte) -19 ); // Fill 9 of value (byte) -19 + Arrays.fill(CHARS, 12330, 12336, (byte) -87 ); // Fill 6 of value (byte) -87 + CHARS[12336] = 33; + Arrays.fill(CHARS, 12337, 12342, (byte) -87 ); // Fill 5 of value (byte) -87 + Arrays.fill(CHARS, 12342, 12353, (byte) 33 ); // Fill 11 of value (byte) 33 + Arrays.fill(CHARS, 12353, 12437, (byte) -19 ); // Fill 84 of value (byte) -19 + Arrays.fill(CHARS, 12437, 12441, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 12441, 12443, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 12443, 12445, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 12445, 12447, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 12447, 12449, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 12449, 12539, (byte) -19 ); // Fill 90 of value (byte) -19 + CHARS[12539] = 33; + Arrays.fill(CHARS, 12540, 12543, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 12543, 12549, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(CHARS, 12549, 12589, (byte) -19 ); // Fill 40 of value (byte) -19 + Arrays.fill(CHARS, 12589, 19968, (byte) 33 ); // Fill 7379 of value (byte) 33 + Arrays.fill(CHARS, 19968, 40870, (byte) -19 ); // Fill 20902 of value (byte) -19 + Arrays.fill(CHARS, 40870, 44032, (byte) 33 ); // Fill 3162 of value (byte) 33 + Arrays.fill(CHARS, 44032, 55204, (byte) -19 ); // Fill 11172 of value (byte) -19 + Arrays.fill(CHARS, 55204, 55296, (byte) 33 ); // Fill 92 of value (byte) 33 + Arrays.fill(CHARS, 57344, 65534, (byte) 33 ); // Fill 8190 of value (byte) 33 + + } // () + + // + // Public static methods + // + + /** + * Returns true if the specified character is a supplemental character. + * + * @param c The character to check. + */ + public static boolean isSupplemental(int c) { + return (c >= 0x10000 && c <= 0x10FFFF); + } + + /** + * Returns true the supplemental character corresponding to the given + * surrogates. + * + * @param h The high surrogate. + * @param l The low surrogate. + */ + public static int supplemental(char h, char l) { + return (h - 0xD800) * 0x400 + (l - 0xDC00) + 0x10000; + } + + /** + * Returns the high surrogate of a supplemental character + * + * @param c The supplemental character to "split". + */ + public static char highSurrogate(int c) { + return (char) (((c - 0x00010000) >> 10) + 0xD800); + } + + /** + * Returns the low surrogate of a supplemental character + * + * @param c The supplemental character to "split". + */ + public static char lowSurrogate(int c) { + return (char) (((c - 0x00010000) & 0x3FF) + 0xDC00); + } + + /** + * Returns whether the given character is a high surrogate + * + * @param c The character to check. + */ + public static boolean isHighSurrogate(int c) { + return (0xD800 <= c && c <= 0xDBFF); + } + + /** + * Returns whether the given character is a low surrogate + * + * @param c The character to check. + */ + public static boolean isLowSurrogate(int c) { + return (0xDC00 <= c && c <= 0xDFFF); + } + + + /** + * Returns true if the specified character is valid. This method + * also checks the surrogate character range from 0x10000 to 0x10FFFF. + *

        + * If the program chooses to apply the mask directly to the + * CHARS array, then they are responsible for checking + * the surrogate character range. + * + * @param c The character to check. + */ + public static boolean isValid(int c) { + return (c < 0x10000 && (CHARS[c] & MASK_VALID) != 0) || + (0x10000 <= c && c <= 0x10FFFF); + } // isValid(int):boolean + + /** + * Returns true if the specified character is invalid. + * + * @param c The character to check. + */ + public static boolean isInvalid(int c) { + return !isValid(c); + } // isInvalid(int):boolean + + /** + * Returns true if the specified character can be considered content. + * + * @param c The character to check. + */ + public static boolean isContent(int c) { + return (c < 0x10000 && (CHARS[c] & MASK_CONTENT) != 0) || + (0x10000 <= c && c <= 0x10FFFF); + } // isContent(int):boolean + + /** + * Returns true if the specified character can be considered markup. + * Markup characters include '<', '&', and '%'. + * + * @param c The character to check. + */ + public static boolean isMarkup(int c) { + return c == '<' || c == '&' || c == '%'; + } // isMarkup(int):boolean + + /** + * Returns true if the specified character is a space character + * as defined by production [3] in the XML 1.0 specification. + * + * @param c The character to check. + */ + public static boolean isSpace(int c) { + return c <= 0x20 && (CHARS[c] & MASK_SPACE) != 0; + } // isSpace(int):boolean + + /** + * Returns true if the specified character is a valid name start + * character as defined by production [5] in the XML 1.0 + * specification. + * + * @param c The character to check. + */ + public static boolean isNameStart(int c) { + return c < 0x10000 && (CHARS[c] & MASK_NAME_START) != 0; + } // isNameStart(int):boolean + + /** + * Returns true if the specified character is a valid name + * character as defined by production [4] in the XML 1.0 + * specification. + * + * @param c The character to check. + */ + public static boolean isName(int c) { + return c < 0x10000 && (CHARS[c] & MASK_NAME) != 0; + } // isName(int):boolean + + /** + * Returns true if the specified character is a valid NCName start + * character as defined by production [4] in Namespaces in XML + * recommendation. + * + * @param c The character to check. + */ + public static boolean isNCNameStart(int c) { + return c < 0x10000 && (CHARS[c] & MASK_NCNAME_START) != 0; + } // isNCNameStart(int):boolean + + /** + * Returns true if the specified character is a valid NCName + * character as defined by production [5] in Namespaces in XML + * recommendation. + * + * @param c The character to check. + */ + public static boolean isNCName(int c) { + return c < 0x10000 && (CHARS[c] & MASK_NCNAME) != 0; + } // isNCName(int):boolean + + /** + * Returns true if the specified character is a valid Pubid + * character as defined by production [13] in the XML 1.0 + * specification. + * + * @param c The character to check. + */ + public static boolean isPubid(int c) { + return c < 0x10000 && (CHARS[c] & MASK_PUBID) != 0; + } // isPubid(int):boolean + + /* + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + */ + /** + * Check to see if a string is a valid Name according to [5] + * in the XML 1.0 Recommendation + * + * @param name string to check + * @return true if name is a valid Name + */ + public static boolean isValidName(String name) { + final int length = name.length(); + if (length == 0) { + return false; + } + char ch = name.charAt(0); + if (!isNameStart(ch)) { + return false; + } + for (int i = 1; i < length; ++i) { + ch = name.charAt(i); + if (!isName(ch)) { + return false; + } + } + return true; + } // isValidName(String):boolean + + /* + * from the namespace rec + * [4] NCName ::= (Letter | '_') (NCNameChar)* + */ + /** + * Check to see if a string is a valid NCName according to [4] + * from the XML Namespaces 1.0 Recommendation + * + * @param ncName string to check + * @return true if name is a valid NCName + */ + public static boolean isValidNCName(String ncName) { + final int length = ncName.length(); + if (length == 0) { + return false; + } + char ch = ncName.charAt(0); + if (!isNCNameStart(ch)) { + return false; + } + for (int i = 1; i < length; ++i) { + ch = ncName.charAt(i); + if (!isNCName(ch)) { + return false; + } + } + return true; + } // isValidNCName(String):boolean + + /* + * [7] Nmtoken ::= (NameChar)+ + */ + /** + * 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 static boolean isValidNmtoken(String nmtoken) { + final int length = nmtoken.length(); + if (length == 0) { + return false; + } + for (int i = 0; i < length; ++i) { + char ch = nmtoken.charAt(i); + if (!isName(ch)) { + return false; + } + } + return true; + } // isValidName(String):boolean + + + + + + // encodings + + /** + * Returns true if the encoding name is a valid IANA encoding. + * This method does not verify that there is a decoder available + * for this encoding, only that the characters are valid for an + * IANA encoding name. + * + * @param ianaEncoding The IANA encoding name. + */ + public static boolean isValidIANAEncoding(String ianaEncoding) { + if (ianaEncoding != null) { + int length = ianaEncoding.length(); + if (length > 0) { + char c = ianaEncoding.charAt(0); + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + for (int i = 1; i < length; i++) { + c = ianaEncoding.charAt(i); + if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && + (c < '0' || c > '9') && c != '.' && c != '_' && + c != '-') { + return false; + } + } + return true; + } + } + } + return false; + } // isValidIANAEncoding(String):boolean + + /** + * Returns true if the encoding name is a valid Java encoding. + * This method does not verify that there is a decoder available + * for this encoding, only that the characters are valid for an + * Java encoding name. + * + * @param javaEncoding The Java encoding name. + */ + public static boolean isValidJavaEncoding(String javaEncoding) { + if (javaEncoding != null) { + int length = javaEncoding.length(); + if (length > 0) { + for (int i = 1; i < length; i++) { + char c = javaEncoding.charAt(i); + if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && + (c < '0' || c > '9') && c != '.' && c != '_' && + c != '-') { + return false; + } + } + return true; + } + } + return false; + } // isValidIANAEncoding(String):boolean + + // other methods + + /** + * Trims space characters as defined by production [3] in + * the XML 1.0 specification from both ends of the given string. + * + * @param value the string to be trimmed + * @return the given string with the space characters trimmed + * from both ends + */ + public static String trim(String value) { + int start; + int end; + final int lengthMinusOne = value.length() - 1; + for (start = 0; start <= lengthMinusOne; ++start) { + if (!isSpace(value.charAt(start))) { + break; + } + } + for (end = lengthMinusOne; end >= start; --end) { + if (!isSpace(value.charAt(end))) { + break; + } + } + if (start == 0 && end == lengthMinusOne) { + return value; + } + if (start > lengthMinusOne) { + return ""; + } + return value.substring(start, end + 1); + } // trim(String):String + +} // class XMLChar diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLEntityDescriptionImpl.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLEntityDescriptionImpl.java new file mode 100644 index 0000000..af47915 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLEntityDescriptionImpl.java @@ -0,0 +1,179 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.impl.XMLEntityDescription; + +/** + *

        This class is an implementation of the XMLEntityDescription + * interface which describes the properties of an entity.

        + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public class XMLEntityDescriptionImpl + extends XMLResourceIdentifierImpl + implements XMLEntityDescription { + + // + // Constructors + // + + /** Constructs an empty entity description. */ + public XMLEntityDescriptionImpl() {} // () + + /** + * Constructs an entity description. + * + * @param entityName The name of the entity. + * @param publicId The public identifier. + * @param literalSystemId The literal system identifier. + * @param baseSystemId The base system identifier. + * @param expandedSystemId The expanded system identifier. + */ + public XMLEntityDescriptionImpl(String entityName, String publicId, String literalSystemId, + String baseSystemId, String expandedSystemId) { + setDescription(entityName, publicId, literalSystemId, baseSystemId, expandedSystemId); + } // (String,String,String,String,String) + + /** + * Constructs a resource identifier. + * + * @param entityName The name of the entity. + * @param publicId The public identifier. + * @param literalSystemId The literal system identifier. + * @param baseSystemId The base system identifier. + * @param expandedSystemId The expanded system identifier. + * @param namespace The namespace. + */ + public XMLEntityDescriptionImpl(String entityName, String publicId, String literalSystemId, + String baseSystemId, String expandedSystemId, String namespace) { + setDescription(entityName, publicId, literalSystemId, baseSystemId, expandedSystemId, namespace); + } // (String,String,String,String,String,String) + + // + // Data + // + + /** The name of the entity. */ + protected String fEntityName; + + // + // Public methods + // + + /** + * Sets the name of the entity. + * + * @param name the name of the entity + */ + public void setEntityName(String name) { + fEntityName = name; + } // setEntityName(String) + + /** + * Returns the name of the entity. + * + * @return the name of the entity + */ + public String getEntityName() { + return fEntityName; + } // getEntityName():String + + /** + *

        Sets the values of this entity description.

        + * + * @param entityName The name of the entity. + * @param publicId The public identifier. + * @param literalSystemId The literal system identifier. + * @param baseSystemId The base system identifier. + * @param expandedSystemId The expanded system identifier. + */ + public void setDescription(String entityName, String publicId, String literalSystemId, + String baseSystemId, String expandedSystemId) { + setDescription(entityName, publicId, literalSystemId, baseSystemId, expandedSystemId, null); + } // setDescription(String,String,String,String,String) + + /** + *

        Sets the values of this entity description.

        + * + * @param entityName The name of the entity. + * @param publicId The public identifier. + * @param literalSystemId The literal system identifier. + * @param baseSystemId The base system identifier. + * @param expandedSystemId The expanded system identifier. + * @param namespace The namespace. + */ + public void setDescription(String entityName, String publicId, String literalSystemId, + String baseSystemId, String expandedSystemId, String namespace) { + fEntityName = entityName; + setValues(publicId, literalSystemId, baseSystemId, expandedSystemId, namespace); + } // setDescription(String,String,String,String,String,String) + + /** + *

        Clears the values.

        + */ + public void clear() { + super.clear(); + fEntityName = null; + } // clear() + + // + // Object methods + // + + /** Returns a hash code for this object. */ + public int hashCode() { + int code = super.hashCode(); + if (fEntityName != null) { + code += fEntityName.hashCode(); + } + return code; + } // hashCode():int + + /** Returns a string representation of this object. */ + public String toString() { + StringBuffer str = new StringBuffer(); + if (fEntityName != null) { + str.append(fEntityName); + } + str.append(':'); + if (fPublicId != null) { + str.append(fPublicId); + } + str.append(':'); + if (fLiteralSystemId != null) { + str.append(fLiteralSystemId); + } + str.append(':'); + if (fBaseSystemId != null) { + str.append(fBaseSystemId); + } + str.append(':'); + if (fExpandedSystemId != null) { + str.append(fExpandedSystemId); + } + str.append(':'); + if (fNamespace != null) { + str.append(fNamespace); + } + return str.toString(); + } // toString():String + +} // XMLEntityDescriptionImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLErrorCode.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLErrorCode.java new file mode 100644 index 0000000..4be52f8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLErrorCode.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +/** + *

        A structure that represents an error code, characterized by + * a domain and a message key.

        + * + * @author Naela Nissar, IBM + * + * @version $Id$ + */ +final class XMLErrorCode { + + // + // Data + // + + /** error domain **/ + private String fDomain; + + /** message key **/ + private String fKey; + + /** + *

        Constructs an XMLErrorCode with the given domain and key.

        + * + * @param domain The error domain. + * @param key The key of the error message. + */ + public XMLErrorCode(String domain, String key) { + fDomain = domain; + fKey = key; + } + + /** + *

        Convenience method to set the values of an XMLErrorCode.

        + * + * @param domain The error domain. + * @param key The key of the error message. + */ + public void setValues(String domain, String key) { + fDomain = domain; + fKey = key; + } + + /** + *

        Indicates whether some other object is equal to this XMLErrorCode.

        + * + * @param obj the object with which to compare. + */ + public boolean equals(Object obj) { + if (!(obj instanceof XMLErrorCode)) + return false; + XMLErrorCode err = (XMLErrorCode) obj; + return (fDomain.equals(err.fDomain) && fKey.equals(err.fKey)); + } + + /** + *

        Returns a hash code value for this XMLErrorCode.

        + * + * @return a hash code value for this XMLErrorCode. + */ + public int hashCode() { + return fDomain.hashCode() + fKey.hashCode(); + } +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLGrammarPoolImpl.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLGrammarPoolImpl.java new file mode 100644 index 0000000..1044c0a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLGrammarPoolImpl.java @@ -0,0 +1,364 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.grammars.Grammar; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.grammars.XMLGrammarPool; + +/** + * Stores grammars in a pool associated to a specific key. This grammar pool + * implementation stores two types of grammars: those keyed by the root element + * name, and those keyed by the grammar's target namespace. + * + * This is the default implementation of the GrammarPool interface. + * As we move forward, this will become more function-rich and robust. + * + * @author Jeffrey Rodriguez, IBM + * @author Andy Clark, IBM + * @author Neil Graham, IBM + * @author Pavani Mukthipudi, Sun Microsystems + * @author Neeraj Bajaj, SUN Microsystems + * + * @version $Id$ + */ +public class XMLGrammarPoolImpl implements XMLGrammarPool { + + // + // Constants + // + + /** Default size. */ + protected static final int TABLE_SIZE = 11; + + // + // Data + // + + /** Grammars. */ + protected Entry[] fGrammars = null; + + // whether this pool is locked + protected boolean fPoolIsLocked; + + // the number of grammars in the pool + protected int fGrammarCount = 0; + + private static final boolean DEBUG = false ; + + // + // Constructors + // + + /** Constructs a grammar pool with a default number of buckets. */ + public XMLGrammarPoolImpl() { + fGrammars = new Entry[TABLE_SIZE]; + fPoolIsLocked = false; + } // () + + /** Constructs a grammar pool with a specified number of buckets. */ + public XMLGrammarPoolImpl(int initialCapacity) { + fGrammars = new Entry[initialCapacity]; + fPoolIsLocked = false; + } + + // + // XMLGrammarPool methods + // + + /*

        Retrieve the initial known set of grammars. This method is + * called by a validator before the validation starts. The application + * can provide an initial set of grammars available to the current + * validation attempt.

        + * + * @param grammarType The type of the grammar, from the + * org.apache.xerces.xni.grammars.XMLGrammarDescription + * interface. + * @return The set of grammars the validator may put in its "bucket" + */ + public Grammar [] retrieveInitialGrammarSet (String grammarType) { + synchronized (fGrammars) { + int grammarSize = fGrammars.length ; + Grammar [] tempGrammars = new Grammar[fGrammarCount]; + int pos = 0; + for (int i = 0; i < grammarSize; i++) { + for (Entry e = fGrammars[i]; e != null; e = e.next) { + if (e.desc.getGrammarType().equals(grammarType)) { + tempGrammars[pos++] = e.grammar; + } + } + } + Grammar[] toReturn = new Grammar[pos]; + System.arraycopy(tempGrammars, 0, toReturn, 0, pos); + return toReturn; + } + } // retrieveInitialGrammarSet (String): Grammar[] + + /*

        Return the final set of grammars that the validator ended up + * with. This method is called after the validation finishes. The + * application may then choose to cache some of the returned grammars.

        + *

        In this implementation, we make our choice based on whether this object + * is "locked"--that is, whether the application has instructed + * us not to accept any new grammars.

        + * + * @param grammarType The type of the grammars being returned; + * @param grammars An array containing the set of grammars being + * returned; order is not significant. + */ + public void cacheGrammars(String grammarType, Grammar[] grammars) { + if(!fPoolIsLocked) { + for (int i = 0; i < grammars.length; i++) { + if(DEBUG) { + System.out.println("CACHED GRAMMAR " + (i+1) ) ; + Grammar temp = grammars[i] ; + //print(temp.getGrammarDescription()); + } + putGrammar(grammars[i]); + } + } + } // cacheGrammars(String, Grammar[]); + + /*

        This method requests that the application retrieve a grammar + * corresponding to the given GrammarIdentifier from its cache. + * If it cannot do so it must return null; the parser will then + * call the EntityResolver.

        + * An application must not call its EntityResolver itself + * from this method; this may result in infinite recursions. + * + * This implementation chooses to use the root element name to identify a DTD grammar + * and the target namespace to identify a Schema grammar. + * + * @param desc The description of the Grammar being requested. + * @return The Grammar corresponding to this description or null if + * no such Grammar is known. + */ + public Grammar retrieveGrammar(XMLGrammarDescription desc) { + if(DEBUG){ + System.out.println("RETRIEVING GRAMMAR FROM THE APPLICATION WITH FOLLOWING DESCRIPTION :"); + //print(desc); + } + return getGrammar(desc); + } // retrieveGrammar(XMLGrammarDescription): Grammar + + // + // Public methods + // + + /** + * Puts the specified grammar into the grammar pool and associates it to + * its root element name or its target namespace. + * + * @param grammar The Grammar. + */ + public void putGrammar(Grammar grammar) { + if(!fPoolIsLocked) { + synchronized (fGrammars) { + XMLGrammarDescription desc = grammar.getGrammarDescription(); + int hash = hashCode(desc); + int index = (hash & 0x7FFFFFFF) % fGrammars.length; + for (Entry entry = fGrammars[index]; entry != null; entry = entry.next) { + if (entry.hash == hash && equals(entry.desc, desc)) { + entry.grammar = grammar; + return; + } + } + // create a new entry + Entry entry = new Entry(hash, desc, grammar, fGrammars[index]); + fGrammars[index] = entry; + fGrammarCount++; + } + } + } // putGrammar(Grammar) + + /** + * Returns the grammar associated to the specified grammar description. + * Currently, the root element name is used as the key for DTD grammars + * and the target namespace is used as the key for Schema grammars. + * + * @param desc The Grammar Description. + */ + public Grammar getGrammar(XMLGrammarDescription desc) { + synchronized (fGrammars) { + int hash = hashCode(desc); + int index = (hash & 0x7FFFFFFF) % fGrammars.length; + for (Entry entry = fGrammars[index] ; entry != null ; entry = entry.next) { + if ((entry.hash == hash) && equals(entry.desc, desc)) { + return entry.grammar; + } + } + return null; + } + } // getGrammar(XMLGrammarDescription):Grammar + + /** + * Removes the grammar associated to the specified grammar description from the + * grammar pool and returns the removed grammar. Currently, the root element name + * is used as the key for DTD grammars and the target namespace is used + * as the key for Schema grammars. + * + * @param desc The Grammar Description. + * @return The removed grammar. + */ + public Grammar removeGrammar(XMLGrammarDescription desc) { + synchronized (fGrammars) { + int hash = hashCode(desc); + int index = (hash & 0x7FFFFFFF) % fGrammars.length; + for (Entry entry = fGrammars[index], prev = null ; entry != null ; prev = entry, entry = entry.next) { + if ((entry.hash == hash) && equals(entry.desc, desc)) { + if (prev != null) { + prev.next = entry.next; + } + else { + fGrammars[index] = entry.next; + } + Grammar tempGrammar = entry.grammar; + entry.grammar = null; + fGrammarCount--; + return tempGrammar; + } + } + return null; + } + } // removeGrammar(XMLGrammarDescription):Grammar + + /** + * Returns true if the grammar pool contains a grammar associated + * to the specified grammar description. Currently, the root element name + * is used as the key for DTD grammars and the target namespace is used + * as the key for Schema grammars. + * + * @param desc The Grammar Description. + */ + public boolean containsGrammar(XMLGrammarDescription desc) { + synchronized (fGrammars) { + int hash = hashCode(desc); + int index = (hash & 0x7FFFFFFF) % fGrammars.length; + for (Entry entry = fGrammars[index] ; entry != null ; entry = entry.next) { + if ((entry.hash == hash) && equals(entry.desc, desc)) { + return true; + } + } + return false; + } + } // containsGrammar(XMLGrammarDescription):boolean + + /*

        Sets this grammar pool to a "locked" state--i.e., + * no new grammars will be added until it is "unlocked". + */ + public void lockPool() { + fPoolIsLocked = true; + } // lockPool() + + /*

        Sets this grammar pool to an "unlocked" state--i.e., + * new grammars will be added when putGrammar or cacheGrammars + * are called. + */ + public void unlockPool() { + fPoolIsLocked = false; + } // unlockPool() + + /* + *

        This method clears the pool-i.e., removes references + * to all the grammars in it.

        + */ + public void clear() { + for (int i=0; iA light wrapper around an XMLLocator.

        + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + */ +public final class XMLLocatorWrapper implements XMLLocator { + + private XMLLocator fLocator = null; + + public XMLLocatorWrapper() {} + + public void setLocator(XMLLocator locator) { + fLocator = locator; + } + + public XMLLocator getLocator() { + return fLocator; + } + + /* + * XMLLocator methods + */ + + public String getPublicId() { + if (fLocator != null) { + return fLocator.getPublicId(); + } + return null; + } + + public String getLiteralSystemId() { + if (fLocator != null) { + return fLocator.getLiteralSystemId(); + } + return null; + } + + public String getBaseSystemId() { + if (fLocator != null) { + return fLocator.getBaseSystemId(); + } + return null; + } + + public String getExpandedSystemId() { + if (fLocator != null) { + return fLocator.getExpandedSystemId(); + } + return null; + } + + public int getLineNumber() { + if (fLocator != null) { + return fLocator.getLineNumber(); + } + return -1; + } + + public int getColumnNumber() { + if (fLocator != null) { + return fLocator.getColumnNumber(); + } + return -1; + } + + public int getCharacterOffset() { + if (fLocator != null) { + return fLocator.getCharacterOffset(); + } + return -1; + } + + public String getEncoding() { + if (fLocator != null) { + return fLocator.getEncoding(); + } + return null; + } + + public String getXMLVersion() { + if (fLocator != null) { + return fLocator.getXMLVersion(); + } + return null; + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLResourceIdentifierImpl.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLResourceIdentifierImpl.java new file mode 100644 index 0000000..c463457 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLResourceIdentifierImpl.java @@ -0,0 +1,228 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.XMLResourceIdentifier; + +/** + * The XMLResourceIdentifierImpl class is an implementation of the + * XMLResourceIdentifier interface which defines the location identity + * of a resource. + * + * @author Andy Clark + * + * @version $Id$ + */ +public class XMLResourceIdentifierImpl + implements XMLResourceIdentifier { + + // + // Data + // + + /** The public identifier. */ + protected String fPublicId; + + /** The literal system identifier. */ + protected String fLiteralSystemId; + + /** The base system identifier. */ + protected String fBaseSystemId; + + /** The expanded system identifier. */ + protected String fExpandedSystemId; + + /** The namespace of the resource. */ + protected String fNamespace; + + // + // Constructors + // + + /** Constructs an empty resource identifier. */ + public XMLResourceIdentifierImpl() {} // () + + /** + * Constructs a resource identifier. + * + * @param publicId The public identifier. + * @param literalSystemId The literal system identifier. + * @param baseSystemId The base system identifier. + * @param expandedSystemId The expanded system identifier. + */ + public XMLResourceIdentifierImpl(String publicId, + String literalSystemId, String baseSystemId, + String expandedSystemId) { + setValues(publicId, literalSystemId, baseSystemId, + expandedSystemId, null); + } // (String,String,String,String) + + /** + * Constructs a resource identifier. + * + * @param publicId The public identifier. + * @param literalSystemId The literal system identifier. + * @param baseSystemId The base system identifier. + * @param expandedSystemId The expanded system identifier. + * @param namespace The namespace. + */ + public XMLResourceIdentifierImpl(String publicId, String literalSystemId, + String baseSystemId, String expandedSystemId, + String namespace) { + setValues(publicId, literalSystemId, baseSystemId, + expandedSystemId, namespace); + } // (String,String,String,String,String) + + // + // Public methods + // + + /** Sets the values of the resource identifier. */ + public void setValues(String publicId, String literalSystemId, + String baseSystemId, String expandedSystemId) { + setValues(publicId, literalSystemId, baseSystemId, + expandedSystemId, null); + } // setValues(String,String,String,String) + + /** Sets the values of the resource identifier. */ + public void setValues(String publicId, String literalSystemId, + String baseSystemId, String expandedSystemId, + String namespace) { + fPublicId = publicId; + fLiteralSystemId = literalSystemId; + fBaseSystemId = baseSystemId; + fExpandedSystemId = expandedSystemId; + fNamespace = namespace; + } // setValues(String,String,String,String,String) + + /** Clears the values. */ + public void clear() { + fPublicId = null; + fLiteralSystemId = null; + fBaseSystemId = null; + fExpandedSystemId = null; + fNamespace = null; + } // clear() + + /** Sets the public identifier. */ + public void setPublicId(String publicId) { + fPublicId = publicId; + } // setPublicId(String) + + /** Sets the literal system identifier. */ + public void setLiteralSystemId(String literalSystemId) { + fLiteralSystemId = literalSystemId; + } // setLiteralSystemId(String) + + /** Sets the base system identifier. */ + public void setBaseSystemId(String baseSystemId) { + fBaseSystemId = baseSystemId; + } // setBaseSystemId(String) + + /** Sets the expanded system identifier. */ + public void setExpandedSystemId(String expandedSystemId) { + fExpandedSystemId = expandedSystemId; + } // setExpandedSystemId(String) + + /** Sets the namespace of the resource. */ + public void setNamespace(String namespace) { + fNamespace = namespace; + } // setNamespace(String) + + // + // XMLResourceIdentifier methods + // + + /** Returns the public identifier. */ + public String getPublicId() { + return fPublicId; + } // getPublicId():String + + /** Returns the literal system identifier. */ + public String getLiteralSystemId() { + return fLiteralSystemId; + } // getLiteralSystemId():String + + /** + * Returns the base URI against which the literal SystemId is to be resolved. + */ + public String getBaseSystemId() { + return fBaseSystemId; + } // getBaseSystemId():String + + /** Returns the expanded system identifier. */ + public String getExpandedSystemId() { + return fExpandedSystemId; + } // getExpandedSystemId():String + + /** Returns the namespace of the resource. */ + public String getNamespace() { + return fNamespace; + } // getNamespace():String + + // + // Object methods + // + + /** Returns a hash code for this object. */ + public int hashCode() { + int code = 0; + if (fPublicId != null) { + code += fPublicId.hashCode(); + } + if (fLiteralSystemId != null) { + code += fLiteralSystemId.hashCode(); + } + if (fBaseSystemId != null) { + code += fBaseSystemId.hashCode(); + } + if (fExpandedSystemId != null) { + code += fExpandedSystemId.hashCode(); + } + if (fNamespace != null) { + code += fNamespace.hashCode(); + } + return code; + } // hashCode():int + + /** Returns a string representation of this object. */ + public String toString() { + StringBuffer str = new StringBuffer(); + if (fPublicId != null) { + str.append(fPublicId); + } + str.append(':'); + if (fLiteralSystemId != null) { + str.append(fLiteralSystemId); + } + str.append(':'); + if (fBaseSystemId != null) { + str.append(fBaseSystemId); + } + str.append(':'); + if (fExpandedSystemId != null) { + str.append(fExpandedSystemId); + } + str.append(':'); + if (fNamespace != null) { + str.append(fNamespace); + } + return str.toString(); + } // toString():String + +} // class XMLResourceIdentifierImpl diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLStringBuffer.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLStringBuffer.java new file mode 100644 index 0000000..82db3d3 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLStringBuffer.java @@ -0,0 +1,176 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +import org.apache.xerces.xni.XMLString; + +/** + * XMLString is a structure used to pass character arrays. However, + * XMLStringBuffer is a buffer in which characters can be appended + * and extends XMLString so that it can be passed to methods + * expecting an XMLString object. This is a safe operation because + * it is assumed that any callee will not modify + * the contents of the XMLString structure. + *

        + * The contents of the string are managed by the string buffer. As + * characters are appended, the string buffer will grow as needed. + *

        + * Note: Never set the ch, + * offset, and length fields directly. + * These fields are managed by the string buffer. In order to reset + * the buffer, call clear(). + * + * @author Andy Clark, IBM + * @author Eric Ye, IBM + * + * @version $Id$ + */ +public class XMLStringBuffer + extends XMLString { + + // + // Constants + // + + /** Default buffer size (32). */ + public static final int DEFAULT_SIZE = 32; + + // + // Constructors + // + + /** + * + */ + public XMLStringBuffer() { + this(DEFAULT_SIZE); + } // () + + /** + * + * + * @param size + */ + public XMLStringBuffer(int size) { + ch = new char[size]; + } // (int) + + /** Constructs a string buffer from a char. */ + public XMLStringBuffer(char c) { + this(1); + append(c); + } // (char) + + /** Constructs a string buffer from a String. */ + public XMLStringBuffer(String s) { + this(s.length()); + append(s); + } // (String) + + /** Constructs a string buffer from the specified character array. */ + public XMLStringBuffer(char[] ch, int offset, int length) { + this(length); + append(ch, offset, length); + } // (char[],int,int) + + /** Constructs a string buffer from the specified XMLString. */ + public XMLStringBuffer(XMLString s) { + this(s.length); + append(s); + } // (XMLString) + + // + // Public methods + // + + /** Clears the string buffer. */ + public void clear() { + offset = 0; + length = 0; + } + + /** + * append + * + * @param c + */ + public void append(char c) { + if (this.length + 1 > this.ch.length) { + int newLength = this.ch.length * 2; + if (newLength < this.ch.length + DEFAULT_SIZE) { + newLength = this.ch.length + DEFAULT_SIZE; + } + char[] newch = new char[newLength]; + System.arraycopy(this.ch, 0, newch, 0, this.length); + this.ch = newch; + } + this.ch[this.length] = c; + this.length++; + } // append(char) + + /** + * append + * + * @param s + */ + public void append(String s) { + int length = s.length(); + if (this.length + length > this.ch.length) { + int newLength = this.ch.length * 2; + if (newLength < this.length + length + DEFAULT_SIZE) { + newLength = this.ch.length + length + DEFAULT_SIZE; + } + char[] newch = new char[newLength]; + System.arraycopy(this.ch, 0, newch, 0, this.length); + this.ch = newch; + } + s.getChars(0, length, this.ch, this.length); + this.length += length; + } // append(String) + + /** + * append + * + * @param ch + * @param offset + * @param length + */ + public void append(char[] ch, int offset, int length) { + if (this.length + length > this.ch.length) { + int newLength = this.ch.length * 2; + if (newLength < this.length + length + DEFAULT_SIZE) { + newLength = this.ch.length + length + DEFAULT_SIZE; + } + char[] newch = new char[newLength]; + System.arraycopy(this.ch, 0, newch, 0, this.length); + this.ch = newch; + } + System.arraycopy(ch, offset, this.ch, this.length, length); + this.length += length; + } // append(char[],int,int) + + /** + * append + * + * @param s + */ + public void append(XMLString s) { + append(s.ch, s.offset, s.length); + } // append(XMLString) + +} // class XMLStringBuffer diff --git a/resources/xerces2-j-src/org/apache/xerces/util/XMLSymbols.java b/resources/xerces2-j-src/org/apache/xerces/util/XMLSymbols.java new file mode 100644 index 0000000..96b710a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/util/XMLSymbols.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package org.apache.xerces.util; + +/** + * All internalized xml symbols. They can be compared using "==". + * + * @author Sandy Gao, IBM + * @version $Id$ + */ +public class XMLSymbols { + + // public constructor. + public XMLSymbols(){} + + //========================== + // Commonly used strings + //========================== + + /** + * The empty string. + */ + public final static String EMPTY_STRING = "".intern(); + + //========================== + // Namespace prefixes/uris + //========================== + + /** + * The internalized "xml" prefix. + */ + public final static String PREFIX_XML = "xml".intern(); + + /** + * The internalized "xmlns" prefix. + */ + public final static String PREFIX_XMLNS = "xmlns".intern(); + + //========================== + // DTD symbols + //========================== + + /** Symbol: "ANY". */ + public static final String fANYSymbol = "ANY".intern(); + + /** Symbol: "CDATA". */ + public static final String fCDATASymbol = "CDATA".intern(); + + /** Symbol: "ID". */ + public static final String fIDSymbol = "ID".intern(); + + /** Symbol: "IDREF". */ + public static final String fIDREFSymbol = "IDREF".intern(); + + /** Symbol: "IDREFS". */ + public static final String fIDREFSSymbol = "IDREFS".intern(); + + /** Symbol: "ENTITY". */ + public static final String fENTITYSymbol = "ENTITY".intern(); + + /** Symbol: "ENTITIES". */ + public static final String fENTITIESSymbol = "ENTITIES".intern(); + + /** Symbol: "NMTOKEN". */ + public static final String fNMTOKENSymbol = "NMTOKEN".intern(); + + /** Symbol: "NMTOKENS". */ + public static final String fNMTOKENSSymbol = "NMTOKENS".intern(); + + /** Symbol: "NOTATION". */ + public static final String fNOTATIONSymbol = "NOTATION".intern(); + + /** Symbol: "ENUMERATION". */ + public static final String fENUMERATIONSymbol = "ENUMERATION".intern(); + + /** Symbol: "#IMPLIED. */ + public static final String fIMPLIEDSymbol = "#IMPLIED".intern(); + + /** Symbol: "#REQUIRED". */ + public static final String fREQUIREDSymbol = "#REQUIRED".intern(); + + /** Symbol: "#FIXED". */ + public static final String fFIXEDSymbol = "#FIXED".intern(); + + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xinclude/MultipleScopeNamespaceSupport.java b/resources/xerces2-j-src/org/apache/xerces/xinclude/MultipleScopeNamespaceSupport.java new file mode 100644 index 0000000..4c8300d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xinclude/MultipleScopeNamespaceSupport.java @@ -0,0 +1,195 @@ +/* + * 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. + */ + +package org.apache.xerces.xinclude; + +import java.util.Enumeration; + +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; + +/** + * This implementation of NamespaceContext has the ability to maintain multiple + * scopes of namespace/prefix bindings. This is useful in situations when it is + * not always appropriate for elements to inherit the namespace bindings of their + * ancestors (such as included elements in XInclude). + * + * When searching for a URI to match a prefix, or a prefix to match a URI, it is + * searched for in the current context, then the ancestors of the current context, + * up to the beginning of the current scope. Other scopes are not searched. + * + * @author Peter McCracken, IBM + * + * @version $Id$ + */ +public class MultipleScopeNamespaceSupport extends NamespaceSupport { + + protected int[] fScope = new int[8]; + protected int fCurrentScope; + + /** + * + */ + public MultipleScopeNamespaceSupport() { + super(); + fCurrentScope = 0; + fScope[0] = 0; + } + + /** + * @param context + */ + public MultipleScopeNamespaceSupport(NamespaceContext context) { + super(context); + fCurrentScope = 0; + fScope[0] = 0; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.NamespaceContext#getAllPrefixes() + */ + public Enumeration getAllPrefixes() { + int count = 0; + if (fPrefixes.length < (fNamespace.length / 2)) { + // resize prefix array + String[] prefixes = new String[fNamespaceSize]; + fPrefixes = prefixes; + } + String prefix = null; + boolean unique = true; + for (int i = fContext[fScope[fCurrentScope]]; + i <= (fNamespaceSize - 2); + i += 2) { + prefix = fNamespace[i]; + for (int k = 0; k < count; k++) { + if (fPrefixes[k] == prefix) { + unique = false; + break; + } + } + if (unique) { + fPrefixes[count++] = prefix; + } + unique = true; + } + return new Prefixes(fPrefixes, count); + } + + public int getScopeForContext(int context) { + int scope = fCurrentScope; + while (context < fScope[scope]) { + scope--; + } + return scope; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.NamespaceContext#getPrefix(java.lang.String) + */ + public String getPrefix(String uri) { + return getPrefix(uri, fNamespaceSize, fContext[fScope[fCurrentScope]]); + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.NamespaceContext#getURI(java.lang.String) + */ + public String getURI(String prefix) { + return getURI(prefix, fNamespaceSize, fContext[fScope[fCurrentScope]]); + } + + public String getPrefix(String uri, int context) { + return getPrefix(uri, fContext[context+1], fContext[fScope[getScopeForContext(context)]]); + } + + public String getURI(String prefix, int context) { + return getURI(prefix, fContext[context+1], fContext[fScope[getScopeForContext(context)]]); + } + + public String getPrefix(String uri, int start, int end) { + // this saves us from having a copy of each of these in fNamespace for each scope + if (uri == NamespaceContext.XML_URI) { + return XMLSymbols.PREFIX_XML; + } + if (uri == NamespaceContext.XMLNS_URI) { + return XMLSymbols.PREFIX_XMLNS; + } + + // find uri in current context + for (int i = start; i > end; i -= 2) { + if (fNamespace[i - 1] == uri) { + if (getURI(fNamespace[i - 2]) == uri) + return fNamespace[i - 2]; + } + } + + // uri not found + return null; + } + + public String getURI(String prefix, int start, int end) { + // this saves us from having a copy of each of these in fNamespace for each scope + if (prefix == XMLSymbols.PREFIX_XML) { + return NamespaceContext.XML_URI; + } + if (prefix == XMLSymbols.PREFIX_XMLNS) { + return NamespaceContext.XMLNS_URI; + } + + // find prefix in current context + for (int i = start; i > end; i -= 2) { + if (fNamespace[i - 2] == prefix) { + return fNamespace[i - 1]; + } + } + + // prefix not found + return null; + } + + /** + * Only resets the current scope -- all namespaces defined in lower scopes + * remain valid after a call to reset. + */ + public void reset() { + fCurrentContext = fScope[fCurrentScope]; + fNamespaceSize = fContext[fCurrentContext]; + } + + /** + * Begins a new scope. None of the previous namespace bindings will be used, + * until the new scope is popped with popScope() + */ + public void pushScope() { + if (fCurrentScope + 1 == fScope.length) { + int[] contextarray = new int[fScope.length * 2]; + System.arraycopy(fScope, 0, contextarray, 0, fScope.length); + fScope = contextarray; + } + pushContext(); + fScope[++fCurrentScope] = fCurrentContext; + } + + /** + * Pops the current scope. The namespace bindings from the new current scope + * are then used for searching for namespaces and prefixes. + */ + public void popScope() { + fCurrentContext = fScope[fCurrentScope--]; + popContext(); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xinclude/ObjectFactory.java b/resources/xerces2-j-src/org/apache/xerces/xinclude/ObjectFactory.java new file mode 100644 index 0000000..2c82e1d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xinclude/ObjectFactory.java @@ -0,0 +1,543 @@ +/* + * 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. + */ + +package org.apache.xerces.xinclude; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; + +/** + * This class is duplicated for each JAXP subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of the JAXP + * API. + *

        + * This code is designed to implement the JAXP 1.1 spec pluggability + * feature and is designed to run on JDK version 1.1 and + * later, and to compile on JDK 1.2 and onward. + * The code also runs both as part of an unbundled jar file and + * when bundled as part of the JDK. + *

        + * + * @version $Id$ + */ +final class ObjectFactory { + + // + // Constants + // + + // name of default properties file to look for in JDK's jre/lib directory + private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties"; + + /** Set to true for debugging */ + private static final boolean DEBUG = isDebugEnabled(); + + /** + * Default columns per line. + */ + private static final int DEFAULT_LINE_LENGTH = 80; + + /** cache the contents of the xerces.properties file. + * Until an attempt has been made to read this file, this will + * be null; if the file does not exist or we encounter some other error + * during the read, this will be empty. + */ + private static Properties fXercesProperties = null; + + /*** + * Cache the time stamp of the xerces.properties file so + * that we know if it's been modified and can invalidate + * the cache when necessary. + */ + private static long fLastModified = -1; + + // + // static methods + // + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *

          + *
        1. query the system property using System.getProperty + *
        2. read META-INF/services/factoryId file + *
        3. use fallback classname + *
        + * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, String fallbackClassName) + throws ConfigurationError { + return createObject(factoryId, null, fallbackClassName); + } // createObject(String,String):Object + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *
          + *
        1. query the system property using System.getProperty + *
        2. read $java.home/lib/propertiesFilename file + *
        3. read META-INF/services/factoryId file + *
        4. use fallback classname + *
        + * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param propertiesFilename The filename in the $java.home/lib directory + * of the properties file. If none specified, + * ${java.home}/lib/xerces.properties will be used. + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, + String propertiesFilename, + String fallbackClassName) + throws ConfigurationError + { + if (DEBUG) debugPrintln("debug is on"); + + ClassLoader cl = findClassLoader(); + + // Use the system property first + try { + String systemProp = SecuritySupport.getSystemProperty(factoryId); + if (systemProp != null && systemProp.length() > 0) { + if (DEBUG) debugPrintln("found system property, value=" + systemProp); + return newInstance(systemProp, cl, true); + } + } catch (SecurityException se) { + // Ignore and continue w/ next location + } + + // Try to read from propertiesFilename, or $java.home/lib/xerces.properties + String factoryClassName = null; + // no properties file name specified; use $JAVA_HOME/lib/xerces.properties: + if (propertiesFilename == null) { + File propertiesFile = null; + boolean propertiesFileExists = false; + try { + String javah = SecuritySupport.getSystemProperty("java.home"); + propertiesFilename = javah + File.separator + + "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME; + propertiesFile = new File(propertiesFilename); + propertiesFileExists = SecuritySupport.getFileExists(propertiesFile); + } catch (SecurityException e) { + // try again... + fLastModified = -1; + fXercesProperties = null; + } + + synchronized (ObjectFactory.class) { + boolean loadProperties = false; + FileInputStream fis = null; + try { + // file existed last time + if(fLastModified >= 0) { + if(propertiesFileExists && + (fLastModified < (fLastModified = SecuritySupport.getLastModified(propertiesFile)))) { + loadProperties = true; + } else { + // file has stopped existing... + if(!propertiesFileExists) { + fLastModified = -1; + fXercesProperties = null; + } // else, file wasn't modified! + } + } else { + // file has started to exist: + if(propertiesFileExists) { + loadProperties = true; + fLastModified = SecuritySupport.getLastModified(propertiesFile); + } // else, nothing's changed + } + if(loadProperties) { + // must never have attempted to read xerces.properties before (or it's outdeated) + fXercesProperties = new Properties(); + fis = SecuritySupport.getFileInputStream(propertiesFile); + fXercesProperties.load(fis); + } + } catch (Exception x) { + fXercesProperties = null; + fLastModified = -1; + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if(fXercesProperties != null) { + factoryClassName = fXercesProperties.getProperty(factoryId); + } + } else { + FileInputStream fis = null; + try { + fis = SecuritySupport.getFileInputStream(new File(propertiesFilename)); + Properties props = new Properties(); + props.load(fis); + factoryClassName = props.getProperty(factoryId); + } catch (Exception x) { + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if (factoryClassName != null) { + if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName); + return newInstance(factoryClassName, cl, true); + } + + // Try Jar Service Provider Mechanism + Object provider = findJarServiceProvider(factoryId); + if (provider != null) { + return provider; + } + + if (fallbackClassName == null) { + throw new ConfigurationError( + "Provider for " + factoryId + " cannot be found", null); + } + + if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); + return newInstance(fallbackClassName, cl, true); + } // createObject(String,String,String):Object + + // + // Private static methods + // + + /** Returns true if debug has been enabled. */ + private static boolean isDebugEnabled() { + try { + String val = SecuritySupport.getSystemProperty("xerces.debug"); + // Allow simply setting the prop to turn on debug + return (val != null && (!"false".equals(val))); + } + catch (SecurityException se) {} + return false; + } // isDebugEnabled() + + /** Prints a message to standard error if debugging is enabled. */ + private static void debugPrintln(String msg) { + if (DEBUG) { + System.err.println("XERCES: " + msg); + } + } // debugPrintln(String) + + /** + * Figure out which ClassLoader to use. For JDK 1.2 and later use + * the context ClassLoader. + */ + static ClassLoader findClassLoader() + throws ConfigurationError + { + // Figure out which ClassLoader to use for loading the provider + // class. If there is a Context ClassLoader then use it. + ClassLoader context = SecuritySupport.getContextClassLoader(); + ClassLoader system = SecuritySupport.getSystemClassLoader(); + + ClassLoader chain = system; + while (true) { + if (context == chain) { + // Assert: we are on JDK 1.1 or we have no Context ClassLoader + // or any Context ClassLoader in chain of system classloader + // (including extension ClassLoader) so extend to widest + // ClassLoader (always look in system ClassLoader if Xerces + // is in boot/extension/system classpath and in current + // ClassLoader otherwise); normal classloaders delegate + // back to system ClassLoader first so this widening doesn't + // change the fact that context ClassLoader will be consulted + ClassLoader current = ObjectFactory.class.getClassLoader(); + + chain = system; + while (true) { + if (current == chain) { + // Assert: Current ClassLoader in chain of + // boot/extension/system ClassLoaders + return system; + } + if (chain == null) { + break; + } + chain = SecuritySupport.getParentClassLoader(chain); + } + + // Assert: Current ClassLoader not in chain of + // boot/extension/system ClassLoaders + return current; + } + + if (chain == null) { + // boot ClassLoader reached + break; + } + + // Check for any extension ClassLoaders in chain up to + // boot ClassLoader + chain = SecuritySupport.getParentClassLoader(chain); + }; + + // Assert: Context ClassLoader not in chain of + // boot/extension/system ClassLoaders + return context; + } // findClassLoader():ClassLoader + + /** + * Create an instance of a class using the specified ClassLoader + */ + static Object newInstance(String className, ClassLoader cl, + boolean doFallback) + throws ConfigurationError + { + // assert(className != null); + try{ + Class providerClass = findProviderClass(className, cl, doFallback); + Object instance = providerClass.newInstance(); + if (DEBUG) debugPrintln("created new instance of " + providerClass + + " using ClassLoader: " + cl); + return instance; + } catch (ClassNotFoundException x) { + throw new ConfigurationError( + "Provider " + className + " not found", x); + } catch (Exception x) { + throw new ConfigurationError( + "Provider " + className + " could not be instantiated: " + x, + x); + } + } + + /** + * Find a Class using the specified ClassLoader + */ + static Class findProviderClass(String className, ClassLoader cl, + boolean doFallback) + throws ClassNotFoundException, ConfigurationError + { + //throw security exception if the calling thread is not allowed to access the package + //restrict the access to package as specified in java.security policy + SecurityManager security = System.getSecurityManager(); + if (security != null) { + final int lastDot = className.lastIndexOf('.'); + String packageName = className; + if (lastDot != -1) packageName = className.substring(0, lastDot); + security.checkPackageAccess(packageName); + } + Class providerClass; + if (cl == null) { + // XXX Use the bootstrap ClassLoader. There is no way to + // load a class using the bootstrap ClassLoader that works + // in both JDK 1.1 and Java 2. However, this should still + // work b/c the following should be true: + // + // (cl == null) iff current ClassLoader == null + // + // Thus Class.forName(String) will use the current + // ClassLoader which will be the bootstrap ClassLoader. + providerClass = Class.forName(className); + } else { + try { + providerClass = cl.loadClass(className); + } catch (ClassNotFoundException x) { + if (doFallback) { + // Fall back to current classloader + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (current == null) { + providerClass = Class.forName(className); + } else if (cl != current) { + cl = current; + providerClass = cl.loadClass(className); + } else { + throw x; + } + } else { + throw x; + } + } + } + + return providerClass; + } + + /* + * Try to find provider using Jar Service Provider Mechanism + * + * @return instance of provider class if found or null + */ + private static Object findJarServiceProvider(String factoryId) + throws ConfigurationError + { + String serviceId = "META-INF/services/" + factoryId; + InputStream is = null; + + // First try the Context ClassLoader + ClassLoader cl = findClassLoader(); + + is = SecuritySupport.getResourceAsStream(cl, serviceId); + + // If no provider found then try the current ClassLoader + if (is == null) { + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (cl != current) { + cl = current; + is = SecuritySupport.getResourceAsStream(cl, serviceId); + } + } + + if (is == null) { + // No provider found + return null; + } + + if (DEBUG) debugPrintln("found jar resource=" + serviceId + + " using ClassLoader: " + cl); + + // Read the service provider name in UTF-8 as specified in + // the jar spec. Unfortunately this fails in Microsoft + // VJ++, which does not implement the UTF-8 + // encoding. Theoretically, we should simply let it fail in + // that case, since the JVM is obviously broken if it + // doesn't support such a basic standard. But since there + // are still some users attempting to use VJ++ for + // development, we have dropped in a fallback which makes a + // second attempt using the platform's default encoding. In + // VJ++ this is apparently ASCII, which is a subset of + // UTF-8... and since the strings we'll be reading here are + // also primarily limited to the 7-bit ASCII range (at + // least, in English versions), this should work well + // enough to keep us on the air until we're ready to + // officially decommit from VJ++. [Edited comment from + // jkesselm] + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); + } catch (java.io.UnsupportedEncodingException e) { + rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); + } + + String factoryClassName = null; + try { + // XXX Does not handle all possible input as specified by the + // Jar Service Provider specification + factoryClassName = rd.readLine(); + } catch (IOException x) { + // No provider found + return null; + } + finally { + try { + // try to close the reader. + rd.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + + if (factoryClassName != null && + ! "".equals(factoryClassName)) { + if (DEBUG) debugPrintln("found in resource, value=" + + factoryClassName); + + // Note: here we do not want to fall back to the current + // ClassLoader because we want to avoid the case where the + // resource file was found using one ClassLoader and the + // provider class was instantiated using a different one. + return newInstance(factoryClassName, cl, false); + } + + // No provider found + return null; + } + + // + // Classes + // + + /** + * A configuration error. + */ + static final class ConfigurationError + extends Error { + + /** Serialization version. */ + static final long serialVersionUID = 5061904944269807898L; + + // + // Data + // + + /** Exception. */ + private Exception exception; + + // + // Constructors + // + + /** + * Construct a new instance with the specified detail string and + * exception. + */ + ConfigurationError(String msg, Exception x) { + super(msg); + this.exception = x; + } // (String,Exception) + + // + // methods + // + + /** Returns the exception associated to this error. */ + Exception getException() { + return exception; + } // getException():Exception + + } // class ConfigurationError + +} // class ObjectFactory diff --git a/resources/xerces2-j-src/org/apache/xerces/xinclude/SecuritySupport.java b/resources/xerces2-j-src/org/apache/xerces/xinclude/SecuritySupport.java new file mode 100644 index 0000000..3f76678 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xinclude/SecuritySupport.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.xerces.xinclude; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * This class is duplicated for each subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of any API. + * + * @xerces.internal + * + * @version $Id$ + */ +final class SecuritySupport { + + static ClassLoader getContextClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (SecurityException ex) { } + return cl; + } + }); + } + + static ClassLoader getSystemClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (SecurityException ex) {} + return cl; + } + }); + } + + static ClassLoader getParentClassLoader(final ClassLoader cl) { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader parent = null; + try { + parent = cl.getParent(); + } catch (SecurityException ex) {} + + // eliminate loops in case of the boot + // ClassLoader returning itself as a parent + return (parent == cl) ? null : parent; + } + }); + } + + static String getSystemProperty(final String propName) { + return (String) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(propName); + } + }); + } + + static FileInputStream getFileInputStream(final File file) + throws FileNotFoundException + { + try { + return (FileInputStream) + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws FileNotFoundException { + return new FileInputStream(file); + } + }); + } catch (PrivilegedActionException e) { + throw (FileNotFoundException)e.getException(); + } + } + + static InputStream getResourceAsStream(final ClassLoader cl, + final String name) + { + return (InputStream) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + InputStream ris; + if (cl == null) { + ris = ClassLoader.getSystemResourceAsStream(name); + } else { + ris = cl.getResourceAsStream(name); + } + return ris; + } + }); + } + + static boolean getFileExists(final File f) { + return ((Boolean) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return f.exists() ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + } + + static long getLastModified(final File f) { + return ((Long) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return new Long(f.lastModified()); + } + })).longValue(); + } + + private SecuritySupport () {} +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xinclude/XInclude11TextReader.java b/resources/xerces2-j-src/org/apache/xerces/xinclude/XInclude11TextReader.java new file mode 100644 index 0000000..87e23c4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xinclude/XInclude11TextReader.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.xerces.xinclude; + +import java.io.IOException; + +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * This class is used for reading resources requested in <include> elements in + * XML 1.1 entities, when the parse attribute of the <include> element is "text". + * Using this class will open the location, detect the encoding, and discard the + * byte order mark, if applicable. + * + * @author Michael Glavassevich, IBM + * + * @version $Id$ + * + * @see XIncludeHandler + */ +public class XInclude11TextReader + extends XIncludeTextReader { + + /** + * Construct the XIncludeReader using the XMLInputSource and XIncludeHandler. + * + * @param source The XMLInputSource to use. + * @param handler The XIncludeHandler to use. + * @param bufferSize The size of this text reader's buffer. + */ + public XInclude11TextReader(XMLInputSource source, XIncludeHandler handler, int bufferSize) + throws IOException { + super(source, handler, bufferSize); + } + + /** + * Returns true if the specified character is a valid XML character + * as per the rules of XML 1.1. + * + * @param ch The character to check. + */ + protected boolean isValid(int ch) { + return XML11Char.isXML11Valid(ch); + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeHandler.java b/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeHandler.java new file mode 100644 index 0000000..26b635b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeHandler.java @@ -0,0 +1,3102 @@ +/* + * 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. + */ + +package org.apache.xerces.xinclude; + +import java.io.CharConversionException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Stack; +import java.util.StringTokenizer; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.io.MalformedByteSequenceException; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.AugmentationsImpl; +import org.apache.xerces.util.HTTPInputSource; +import org.apache.xerces.util.IntStack; +import org.apache.xerces.util.ParserConfigurationSettings; +import org.apache.xerces.util.SecurityManager; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.URI; +import org.apache.xerces.util.XMLAttributesImpl; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLLocatorWrapper; +import org.apache.xerces.util.XMLResourceIdentifierImpl; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.util.URI.MalformedURIException; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.NamespaceContext; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLComponent; +import org.apache.xerces.xni.parser.XMLComponentManager; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLDTDFilter; +import org.apache.xerces.xni.parser.XMLDTDSource; +import org.apache.xerces.xni.parser.XMLDocumentFilter; +import org.apache.xerces.xni.parser.XMLDocumentSource; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.apache.xerces.xpointer.XPointerHandler; +import org.apache.xerces.xpointer.XPointerProcessor; + +/** + *

        + * This is a pipeline component which performs XInclude handling, according to the + * W3C specification for XML Inclusions. + *

        + *

        + * This component analyzes each event in the pipeline, looking for <include> + * elements. An <include> element is one which has a namespace of + * http://www.w3.org/2001/XInclude and a localname of include. + * When it finds an <include> element, it attempts to include the file specified + * in the href attribute of the element. If inclusion succeeds, all + * children of the <include> element are ignored (with the exception of + * checking for invalid children as outlined in the specification). If the inclusion + * fails, the <fallback> child of the <include> element is processed. + *

        + *

        + * See the XInclude specification for + * more information on how XInclude is to be used. + *

        + *

        + * This component requires the following features and properties from the + * component manager that uses it: + *

          + *
        • http://xml.org/sax/features/allow-dtd-events-after-endDTD
        • + *
        • http://apache.org/xml/properties/internal/error-reporter
        • + *
        • http://apache.org/xml/properties/internal/entity-resolver
        • + *
        + * Optional property: + *
          + *
        • http://apache.org/xml/properties/input-buffer-size
        • + *
        + * + * Furthermore, the NamespaceContext used in the pipeline is required + * to be an instance of XIncludeNamespaceSupport. + *

        + *

        + * Currently, this implementation has only partial support for the XInclude specification. + * Specifically, it is missing support for XPointer document fragments. Thus, only whole + * documents can be included using this component in the pipeline. + *

        + * + * @author Peter McCracken, IBM + * @author Michael Glavassevich, IBM + * + * @version $Id$ + * + * @see XIncludeNamespaceSupport + */ +public class XIncludeHandler + implements XMLComponent, XMLDocumentFilter, XMLDTDFilter { + + public final static String XINCLUDE_DEFAULT_CONFIGURATION = + "org.apache.xerces.parsers.XIncludeParserConfiguration"; + public final static String HTTP_ACCEPT = "Accept"; + public final static String HTTP_ACCEPT_LANGUAGE = "Accept-Language"; + public final static String XPOINTER = "xpointer"; + + public final static String XINCLUDE_NS_URI = + "http://www.w3.org/2001/XInclude".intern(); + public final static String XINCLUDE_INCLUDE = "include".intern(); + public final static String XINCLUDE_FALLBACK = "fallback".intern(); + + public final static String XINCLUDE_PARSE_XML = "xml".intern(); + public final static String XINCLUDE_PARSE_TEXT = "text".intern(); + + public final static String XINCLUDE_ATTR_HREF = "href".intern(); + public final static String XINCLUDE_ATTR_PARSE = "parse".intern(); + public final static String XINCLUDE_ATTR_ENCODING = "encoding".intern(); + public final static String XINCLUDE_ATTR_ACCEPT = "accept".intern(); + public final static String XINCLUDE_ATTR_ACCEPT_LANGUAGE = "accept-language".intern(); + + // Top Level Information Items have [included] property in infoset + public final static String XINCLUDE_INCLUDED = "[included]".intern(); + + /** The identifier for the Augmentation that contains the current base URI */ + public final static String CURRENT_BASE_URI = "currentBaseURI"; + + // used for adding [base URI] attributes + private final static String XINCLUDE_BASE = "base".intern(); + private final static QName XML_BASE_QNAME = + new QName( + XMLSymbols.PREFIX_XML, + XINCLUDE_BASE, + (XMLSymbols.PREFIX_XML + ":" + XINCLUDE_BASE).intern(), + NamespaceContext.XML_URI); + + // used for adding [language] attributes + private final static String XINCLUDE_LANG = "lang".intern(); + private final static QName XML_LANG_QNAME = + new QName( + XMLSymbols.PREFIX_XML, + XINCLUDE_LANG, + (XMLSymbols.PREFIX_XML + ":" + XINCLUDE_LANG).intern(), + NamespaceContext.XML_URI); + + private final static QName NEW_NS_ATTR_QNAME = + new QName( + XMLSymbols.PREFIX_XMLNS, + "", + XMLSymbols.PREFIX_XMLNS + ":", + NamespaceContext.XMLNS_URI); + + // Processing States + private final static int STATE_NORMAL_PROCESSING = 1; + // we go into this state after a successful include (thus we ignore the children + // of the include) or after a fallback + private final static int STATE_IGNORE = 2; + // we go into this state after a failed include. If we don't encounter a fallback + // before we reach the end include tag, it's a fatal error + private final static int STATE_EXPECT_FALLBACK = 3; + + // recognized features and properties + + /** Feature identifier: validation. */ + protected static final String VALIDATION = + Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; + + /** Feature identifier: schema validation. */ + protected static final String SCHEMA_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; + + /** Feature identifier: dynamic validation. */ + protected static final String DYNAMIC_VALIDATION = + Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; + + /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */ + protected static final String ALLOW_UE_AND_NOTATION_EVENTS = + Constants.SAX_FEATURE_PREFIX + + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE; + + /** Feature identifier: fixup base URIs. */ + protected static final String XINCLUDE_FIXUP_BASE_URIS = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE; + + /** Feature identifier: fixup language. */ + protected static final String XINCLUDE_FIXUP_LANGUAGE = + Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE; + + /** Property identifier: JAXP schema language. */ + protected static final String JAXP_SCHEMA_LANGUAGE = + Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE; + + /** Property identifier: symbol table. */ + protected static final String SYMBOL_TABLE = + Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; + + /** Property identifier: error reporter. */ + protected static final String ERROR_REPORTER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; + + /** Property identifier: entity resolver. */ + protected static final String ENTITY_RESOLVER = + Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; + + /** property identifier: security manager. */ + protected static final String SECURITY_MANAGER = + Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; + + /** property identifier: buffer size. */ + protected static final String BUFFER_SIZE = + Constants.XERCES_PROPERTY_PREFIX + Constants.BUFFER_SIZE_PROPERTY; + + protected static final String PARSER_SETTINGS = + Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; + + /** Recognized features. */ + private static final String[] RECOGNIZED_FEATURES = + { ALLOW_UE_AND_NOTATION_EVENTS, XINCLUDE_FIXUP_BASE_URIS, XINCLUDE_FIXUP_LANGUAGE }; + + /** Feature defaults. */ + private static final Boolean[] FEATURE_DEFAULTS = { Boolean.TRUE, Boolean.TRUE, Boolean.TRUE }; + + /** Recognized properties. */ + private static final String[] RECOGNIZED_PROPERTIES = + { ERROR_REPORTER, ENTITY_RESOLVER, SECURITY_MANAGER, BUFFER_SIZE }; + + /** Property defaults. */ + private static final Object[] PROPERTY_DEFAULTS = { null, null, null, new Integer(XMLEntityManager.DEFAULT_BUFFER_SIZE) }; + + // instance variables + + // for XMLDocumentFilter + protected XMLDocumentHandler fDocumentHandler; + protected XMLDocumentSource fDocumentSource; + + // for XMLDTDFilter + protected XMLDTDHandler fDTDHandler; + protected XMLDTDSource fDTDSource; + + // for XIncludeHandler + protected XIncludeHandler fParentXIncludeHandler; + + // for buffer size in XIncludeTextReader + protected int fBufferSize = XMLEntityManager.DEFAULT_BUFFER_SIZE; + + // It "feels wrong" to store this value here. However, + // calculating it can be time consuming, so we cache it. + // It's never going to change in the lifetime of this XIncludeHandler + protected String fParentRelativeURI; + + // we cache the child parser configuration, so we don't have to re-create + // the objects when the parser is re-used + protected XMLParserConfiguration fChildConfig; + + // The cached child parser configuration, may contain a + // XInclude or XPointer Handler. Cache both these + protected XMLParserConfiguration fXIncludeChildConfig; + protected XMLParserConfiguration fXPointerChildConfig; + + // The XPointerProcessor + protected XPointerProcessor fXPtrProcessor = null; + + protected XMLLocator fDocLocation; + protected XMLLocatorWrapper fXIncludeLocator = new XMLLocatorWrapper(); + protected XIncludeMessageFormatter fXIncludeMessageFormatter = new XIncludeMessageFormatter(); + protected XIncludeNamespaceSupport fNamespaceContext; + protected SymbolTable fSymbolTable; + protected XMLErrorReporter fErrorReporter; + protected XMLEntityResolver fEntityResolver; + protected SecurityManager fSecurityManager; + + // these are needed for text include processing + protected XIncludeTextReader fXInclude10TextReader; + protected XIncludeTextReader fXInclude11TextReader; + + // these are needed for XML Base processing + protected final XMLResourceIdentifier fCurrentBaseURI; + protected final IntStack fBaseURIScope; + protected final Stack fBaseURI; + protected final Stack fLiteralSystemID; + protected final Stack fExpandedSystemID; + + // these are needed for Language Fixup + protected final IntStack fLanguageScope; + protected final Stack fLanguageStack; + protected String fCurrentLanguage; + + protected String fHrefFromParent; + + // used for passing features on to child XIncludeHandler objects + protected ParserConfigurationSettings fSettings; + + // The current element depth. We start at depth 0 (before we've reached any elements). + // The first element is at depth 1. + private int fDepth; + + // The current element depth of the result infoset. + private int fResultDepth; + + // this value must be at least 1 + private static final int INITIAL_SIZE = 8; + + // Used to ensure that fallbacks are always children of include elements, + // and that include elements are never children of other include elements. + // An index contains true if the ancestor of the current element which resides + // at that depth was an include element. + private boolean[] fSawInclude = new boolean[INITIAL_SIZE]; + + // Ensures that only one fallback element can be at a single depth. + // An index contains true if we have seen any fallback elements at that depth, + // and it is only reset to false when the end tag of the parent is encountered. + private boolean[] fSawFallback = new boolean[INITIAL_SIZE]; + + // The state of the processor at each given depth. + private int[] fState = new int[INITIAL_SIZE]; + + // buffering the necessary DTD events + private final ArrayList fNotations; + private final ArrayList fUnparsedEntities; + + // flags which control whether base URI or language fixup is performed. + private boolean fFixupBaseURIs = true; + private boolean fFixupLanguage = true; + + // for SAX compatibility. + // Has the value of the ALLOW_UE_AND_NOTATION_EVENTS feature + private boolean fSendUEAndNotationEvents; + + // track the version of the document being parsed + private boolean fIsXML11; + + // track whether a DTD is being parsed + private boolean fInDTD; + + // tracks whether content has been reported on the child pipeline + boolean fHasIncludeReportedContent; + + // track whether the root element of the result infoset has been processed + private boolean fSeenRootElement; + + // track whether the child config needs its features refreshed + private boolean fNeedCopyFeatures = true; + + // Constructors + + public XIncludeHandler() { + fDepth = 0; + + fSawFallback[fDepth] = false; + fSawInclude[fDepth] = false; + fState[fDepth] = STATE_NORMAL_PROCESSING; + fNotations = new ArrayList(); + fUnparsedEntities = new ArrayList(); + + fBaseURIScope = new IntStack(); + fBaseURI = new Stack(); + fLiteralSystemID = new Stack(); + fExpandedSystemID = new Stack(); + fCurrentBaseURI = new XMLResourceIdentifierImpl(); + + fLanguageScope = new IntStack(); + fLanguageStack = new Stack(); + fCurrentLanguage = null; + } + + // XMLComponent methods + + public void reset(XMLComponentManager componentManager) + throws XNIException { + fNamespaceContext = null; + fDepth = 0; + fResultDepth = isRootDocument() ? 0 : fParentXIncludeHandler.getResultDepth(); + fNotations.clear(); + fUnparsedEntities.clear(); + fParentRelativeURI = null; + fIsXML11 = false; + fInDTD = false; + fSeenRootElement = false; + + fBaseURIScope.clear(); + fBaseURI.clear(); + fLiteralSystemID.clear(); + fExpandedSystemID.clear(); + fLanguageScope.clear(); + fLanguageStack.clear(); + + // REVISIT: Find a better method for maintaining + // the state of the XInclude processor. These arrays + // can potentially grow quite large. Cleaning them + // out on reset may be very time consuming. -- mrglavas + // + // clear the previous settings from the arrays + for (int i = 0; i < fState.length; ++i) { + fState[i] = STATE_NORMAL_PROCESSING; + } + for (int i = 0; i < fSawFallback.length; ++i) { + fSawFallback[i] = false; + } + for (int i = 0; i < fSawInclude.length; ++i) { + fSawInclude[i] = false; + } + + try { + if (!componentManager.getFeature(PARSER_SETTINGS)) { + // if parser settings have not changed return. + return; + } + } + catch (XMLConfigurationException e) {} + + // parser settings changed. Need to refresh features on child config. + fNeedCopyFeatures = true; + + try { + fSendUEAndNotationEvents = + componentManager.getFeature(ALLOW_UE_AND_NOTATION_EVENTS); + if (fChildConfig != null) { + fChildConfig.setFeature( + ALLOW_UE_AND_NOTATION_EVENTS, + fSendUEAndNotationEvents); + } + } + catch (XMLConfigurationException e) { + } + + try { + fFixupBaseURIs = + componentManager.getFeature(XINCLUDE_FIXUP_BASE_URIS); + if (fChildConfig != null) { + fChildConfig.setFeature( + XINCLUDE_FIXUP_BASE_URIS, + fFixupBaseURIs); + } + } + catch (XMLConfigurationException e) { + fFixupBaseURIs = true; + } + + try { + fFixupLanguage = + componentManager.getFeature(XINCLUDE_FIXUP_LANGUAGE); + if (fChildConfig != null) { + fChildConfig.setFeature( + XINCLUDE_FIXUP_LANGUAGE, + fFixupLanguage); + } + } + catch (XMLConfigurationException e) { + fFixupLanguage = true; + } + + // Get symbol table. + try { + SymbolTable value = + (SymbolTable)componentManager.getProperty(SYMBOL_TABLE); + if (value != null) { + fSymbolTable = value; + if (fChildConfig != null) { + fChildConfig.setProperty(SYMBOL_TABLE, value); + } + } + } + catch (XMLConfigurationException e) { + fSymbolTable = null; + } + + // Get error reporter. + try { + XMLErrorReporter value = + (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER); + if (value != null) { + setErrorReporter(value); + if (fChildConfig != null) { + fChildConfig.setProperty(ERROR_REPORTER, value); + } + } + } + catch (XMLConfigurationException e) { + fErrorReporter = null; + } + + // Get entity resolver. + try { + XMLEntityResolver value = + (XMLEntityResolver)componentManager.getProperty( + ENTITY_RESOLVER); + + if (value != null) { + fEntityResolver = value; + if (fChildConfig != null) { + fChildConfig.setProperty(ENTITY_RESOLVER, value); + } + } + } + catch (XMLConfigurationException e) { + fEntityResolver = null; + } + + // Get security manager. + try { + SecurityManager value = + (SecurityManager)componentManager.getProperty( + SECURITY_MANAGER); + + if (value != null) { + fSecurityManager = value; + if (fChildConfig != null) { + fChildConfig.setProperty(SECURITY_MANAGER, value); + } + } + } + catch (XMLConfigurationException e) { + fSecurityManager = null; + } + + // Get buffer size. + try { + Integer value = + (Integer)componentManager.getProperty( + BUFFER_SIZE); + + if (value != null && value.intValue() > 0) { + fBufferSize = value.intValue(); + if (fChildConfig != null) { + fChildConfig.setProperty(BUFFER_SIZE, value); + } + } + else { + fBufferSize = ((Integer)getPropertyDefault(BUFFER_SIZE)).intValue(); + } + } + catch (XMLConfigurationException e) { + fBufferSize = ((Integer)getPropertyDefault(BUFFER_SIZE)).intValue(); + } + + // Reset XML 1.0 text reader. + if (fXInclude10TextReader != null) { + fXInclude10TextReader.setBufferSize(fBufferSize); + } + // Reset XML 1.1 text reader. + if (fXInclude11TextReader != null) { + fXInclude11TextReader.setBufferSize(fBufferSize); + } + + fSettings = new ParserConfigurationSettings(); + copyFeatures(componentManager, fSettings); + + // We don't want a schema validator on the new pipeline, + // so if it was enabled, we set the feature to false. + try { + if (componentManager.getFeature(SCHEMA_VALIDATION)) { + fSettings.setFeature(SCHEMA_VALIDATION, false); + // If the value of the JAXP 1.2 schema language property + // is http://www.w3.org/2001/XMLSchema we're only validating + // against XML schema so we disable validation on the new pipeline. + if (Constants.NS_XMLSCHEMA.equals(componentManager.getProperty(JAXP_SCHEMA_LANGUAGE))) { + fSettings.setFeature(VALIDATION, false); + } + // If the validation feature was also enabled we turn on + // dynamic validation, so that DTD validation is performed + // on the included documents only if they have a DOCTYPE. + // This is consistent with the behaviour on the main pipeline. + else if (componentManager.getFeature(VALIDATION)) { + fSettings.setFeature(DYNAMIC_VALIDATION, true); + } + } + } + catch (XMLConfigurationException e) {} + + // Don't reset fChildConfig -- we don't want it to share the same components. + // It will be reset when it is actually used to parse something. + } // reset(XMLComponentManager) + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures() { + return (String[])(RECOGNIZED_FEATURES.clone()); + } // getRecognizedFeatures():String[] + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

        + * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException { + if (featureId.equals(ALLOW_UE_AND_NOTATION_EVENTS)) { + fSendUEAndNotationEvents = state; + } + if (fSettings != null) { + fNeedCopyFeatures = true; + fSettings.setFeature(featureId, state); + } + } // setFeature(String,boolean) + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties() { + return (String[])(RECOGNIZED_PROPERTIES.clone()); + } // getRecognizedProperties():String[] + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

        + * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws SAXNotRecognizedException The component should not throw + * this exception. + * @throws SAXNotSupportedException The component should not throw + * this exception. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + if (propertyId.equals(SYMBOL_TABLE)) { + fSymbolTable = (SymbolTable)value; + if (fChildConfig != null) { + fChildConfig.setProperty(propertyId, value); + } + return; + } + if (propertyId.equals(ERROR_REPORTER)) { + setErrorReporter((XMLErrorReporter)value); + if (fChildConfig != null) { + fChildConfig.setProperty(propertyId, value); + } + return; + } + if (propertyId.equals(ENTITY_RESOLVER)) { + fEntityResolver = (XMLEntityResolver)value; + if (fChildConfig != null) { + fChildConfig.setProperty(propertyId, value); + } + return; + } + if (propertyId.equals(SECURITY_MANAGER)) { + fSecurityManager = (SecurityManager)value; + if (fChildConfig != null) { + fChildConfig.setProperty(propertyId, value); + } + return; + } + if (propertyId.equals(BUFFER_SIZE)) { + Integer bufferSize = (Integer) value; + if (fChildConfig != null) { + fChildConfig.setProperty(propertyId, value); + } + if (bufferSize != null && bufferSize.intValue() > 0) { + fBufferSize = bufferSize.intValue(); + // Reset XML 1.0 text reader. + if (fXInclude10TextReader != null) { + fXInclude10TextReader.setBufferSize(fBufferSize); + } + // Reset XML 1.1 text reader. + if (fXInclude11TextReader != null) { + fXInclude11TextReader.setBufferSize(fBufferSize); + } + } + return; + } + + } // setProperty(String,Object) + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId) { + for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { + if (RECOGNIZED_FEATURES[i].equals(featureId)) { + return FEATURE_DEFAULTS[i]; + } + } + return null; + } // getFeatureDefault(String):Boolean + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId) { + for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { + if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { + return PROPERTY_DEFAULTS[i]; + } + } + return null; + } // getPropertyDefault(String):Object + + public void setDocumentHandler(XMLDocumentHandler handler) { + if (fDocumentHandler != handler) { + fDocumentHandler = handler; + if (fXIncludeChildConfig != null) { + fXIncludeChildConfig.setDocumentHandler(handler); + } + if (fXPointerChildConfig != null) { + fXPointerChildConfig.setDocumentHandler(handler); + } + } + } + + public XMLDocumentHandler getDocumentHandler() { + return fDocumentHandler; + } + + // XMLDocumentHandler methods + + /** + * Event sent at the start of the document. + * + * A fatal error will occur here, if it is detected that this document has been processed + * before. + * + * This event is only passed on to the document handler if this is the root document. + */ + public void startDocument( + XMLLocator locator, + String encoding, + NamespaceContext namespaceContext, + Augmentations augs) + throws XNIException { + + // we do this to ensure that the proper location is reported in errors + // otherwise, the locator from the root document would always be used + fErrorReporter.setDocumentLocator(locator); + + if (!(namespaceContext instanceof XIncludeNamespaceSupport)) { + reportFatalError("IncompatibleNamespaceContext"); + } + fNamespaceContext = (XIncludeNamespaceSupport)namespaceContext; + fDocLocation = locator; + fXIncludeLocator.setLocator(fDocLocation); + + // initialize the current base URI + setupCurrentBaseURI(locator); + saveBaseURI(); + if (augs == null) { + augs = new AugmentationsImpl(); + } + augs.putItem(CURRENT_BASE_URI, fCurrentBaseURI); + + // abort here if we detect a recursive include + if (!isRootDocument()) { + fParentXIncludeHandler.fHasIncludeReportedContent = true; + if (fParentXIncludeHandler.searchForRecursiveIncludes( + fCurrentBaseURI.getExpandedSystemId())) { + reportFatalError( + "RecursiveInclude", + new Object[] { fCurrentBaseURI.getExpandedSystemId()}); + } + } + + // initialize the current language + fCurrentLanguage = XMLSymbols.EMPTY_STRING; + saveLanguage(fCurrentLanguage); + + if (isRootDocument() && fDocumentHandler != null) { + fDocumentHandler.startDocument( + fXIncludeLocator, + encoding, + namespaceContext, + augs); + } + } + + public void xmlDecl( + String version, + String encoding, + String standalone, + Augmentations augs) + throws XNIException { + fIsXML11 = "1.1".equals(version); + if (isRootDocument() && fDocumentHandler != null) { + fDocumentHandler.xmlDecl(version, encoding, standalone, augs); + } + } + + public void doctypeDecl( + String rootElement, + String publicId, + String systemId, + Augmentations augs) + throws XNIException { + if (isRootDocument() && fDocumentHandler != null) { + fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); + } + } + + public void comment(XMLString text, Augmentations augs) + throws XNIException { + if (!fInDTD) { + if (fDocumentHandler != null + && getState() == STATE_NORMAL_PROCESSING) { + fDepth++; + augs = modifyAugmentations(augs); + fDocumentHandler.comment(text, augs); + fDepth--; + } + } + else if (fDTDHandler != null) { + fDTDHandler.comment(text, augs); + } + } + + public void processingInstruction( + String target, + XMLString data, + Augmentations augs) + throws XNIException { + if (!fInDTD) { + if (fDocumentHandler != null + && getState() == STATE_NORMAL_PROCESSING) { + // we need to change the depth like this so that modifyAugmentations() works + fDepth++; + augs = modifyAugmentations(augs); + fDocumentHandler.processingInstruction(target, data, augs); + fDepth--; + } + } + else if (fDTDHandler != null) { + fDTDHandler.processingInstruction(target, data, augs); + } + } + + public void startElement( + QName element, + XMLAttributes attributes, + Augmentations augs) + throws XNIException { + fDepth++; + int lastState = getState(fDepth - 1); + // If the last two states were fallback then this must be a descendant of an include + // child which isn't a fallback. The specification says we should ignore such elements + // and their children. + if (lastState == STATE_EXPECT_FALLBACK && getState(fDepth - 2) == STATE_EXPECT_FALLBACK) { + setState(STATE_IGNORE); + } + else { + setState(lastState); + } + + // we process the xml:base and xml:lang attributes regardless + // of what type of element it is. + processXMLBaseAttributes(attributes); + if (fFixupLanguage) { + processXMLLangAttributes(attributes); + } + + if (isIncludeElement(element)) { + boolean success = this.handleIncludeElement(attributes); + if (success) { + setState(STATE_IGNORE); + } + else { + setState(STATE_EXPECT_FALLBACK); + } + } + else if (isFallbackElement(element)) { + this.handleFallbackElement(); + } + else if (hasXIncludeNamespace(element)) { + if (getSawInclude(fDepth - 1)) { + reportFatalError( + "IncludeChild", + new Object[] { element.rawname }); + } + if (getSawFallback(fDepth - 1)) { + reportFatalError( + "FallbackChild", + new Object[] { element.rawname }); + } + if (getState() == STATE_NORMAL_PROCESSING) { + if (fResultDepth++ == 0) { + checkMultipleRootElements(); + } + if (fDocumentHandler != null) { + augs = modifyAugmentations(augs); + attributes = processAttributes(attributes); + fDocumentHandler.startElement(element, attributes, augs); + } + } + } + else if (getState() == STATE_NORMAL_PROCESSING) { + if (fResultDepth++ == 0) { + checkMultipleRootElements(); + } + if (fDocumentHandler != null) { + augs = modifyAugmentations(augs); + attributes = processAttributes(attributes); + fDocumentHandler.startElement(element, attributes, augs); + } + } + } + + public void emptyElement( + QName element, + XMLAttributes attributes, + Augmentations augs) + throws XNIException { + fDepth++; + int lastState = getState(fDepth - 1); + // If the last two states were fallback then this must be a descendant of an include + // child which isn't a fallback. The specification says we should ignore such elements + // and their children. + if (lastState == STATE_EXPECT_FALLBACK && getState(fDepth - 2) == STATE_EXPECT_FALLBACK) { + setState(STATE_IGNORE); + } + else { + setState(lastState); + } + + // we process the xml:base and xml:lang attributes regardless + // of what type of element it is. + processXMLBaseAttributes(attributes); + if (fFixupLanguage) { + processXMLLangAttributes(attributes); + } + + if (isIncludeElement(element)) { + boolean success = this.handleIncludeElement(attributes); + if (success) { + setState(STATE_IGNORE); + } + else { + reportFatalError("NoFallback"); + } + } + else if (isFallbackElement(element)) { + this.handleFallbackElement(); + } + else if (hasXIncludeNamespace(element)) { + if (getSawInclude(fDepth - 1)) { + reportFatalError( + "IncludeChild", + new Object[] { element.rawname }); + } + if (getSawFallback(fDepth - 1)) { + reportFatalError( + "FallbackChild", + new Object[] { element.rawname }); + } + if (getState() == STATE_NORMAL_PROCESSING) { + if (fResultDepth == 0) { + checkMultipleRootElements(); + } + if (fDocumentHandler != null) { + augs = modifyAugmentations(augs); + attributes = processAttributes(attributes); + fDocumentHandler.emptyElement(element, attributes, augs); + } + } + } + else if (getState() == STATE_NORMAL_PROCESSING) { + if (fResultDepth == 0) { + checkMultipleRootElements(); + } + if (fDocumentHandler != null) { + augs = modifyAugmentations(augs); + attributes = processAttributes(attributes); + fDocumentHandler.emptyElement(element, attributes, augs); + } + } + // reset the out of scope stack elements + setSawFallback(fDepth + 1, false); + setSawInclude(fDepth, false); + + // check if an xml:base has gone out of scope + if (fBaseURIScope.size() > 0 && fDepth == fBaseURIScope.peek()) { + // pop the values from the stack + restoreBaseURI(); + } + fDepth--; + } + + public void endElement(QName element, Augmentations augs) + throws XNIException { + + if (isIncludeElement(element)) { + // if we're ending an include element, and we were expecting a fallback + // we check to see if the children of this include element contained a fallback + if (getState() == STATE_EXPECT_FALLBACK + && !getSawFallback(fDepth + 1)) { + reportFatalError("NoFallback"); + } + } + if (isFallbackElement(element)) { + // the state would have been set to normal processing if we were expecting the fallback element + // now that we're done processing it, we should ignore all the other children of the include element + if (getState() == STATE_NORMAL_PROCESSING) { + setState(STATE_IGNORE); + } + } + else if (getState() == STATE_NORMAL_PROCESSING) { + --fResultDepth; + if (fDocumentHandler != null) { + fDocumentHandler.endElement(element, augs); + } + } + + // reset the out of scope stack elements + setSawFallback(fDepth + 1, false); + setSawInclude(fDepth, false); + + // check if an xml:base has gone out of scope + if (fBaseURIScope.size() > 0 && fDepth == fBaseURIScope.peek()) { + // pop the values from the stack + restoreBaseURI(); + } + + // check if an xml:lang has gone out of scope + if (fLanguageScope.size() > 0 && fDepth == fLanguageScope.peek()) { + // pop the language from the stack + fCurrentLanguage = restoreLanguage(); + } + + fDepth--; + } + + public void startGeneralEntity( + String name, + XMLResourceIdentifier resId, + String encoding, + Augmentations augs) + throws XNIException { + if (getState() == STATE_NORMAL_PROCESSING) { + if (fResultDepth == 0) { + if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) { + reportFatalError("UnexpandedEntityReferenceIllegal"); + } + } + else if (fDocumentHandler != null) { + fDocumentHandler.startGeneralEntity(name, resId, encoding, augs); + } + } + } + + public void textDecl(String version, String encoding, Augmentations augs) + throws XNIException { + if (fDocumentHandler != null + && getState() == STATE_NORMAL_PROCESSING) { + fDocumentHandler.textDecl(version, encoding, augs); + } + } + + public void endGeneralEntity(String name, Augmentations augs) + throws XNIException { + if (fDocumentHandler != null + && getState() == STATE_NORMAL_PROCESSING + && fResultDepth != 0) { + fDocumentHandler.endGeneralEntity(name, augs); + } + } + + public void characters(XMLString text, Augmentations augs) + throws XNIException { + if (getState() == STATE_NORMAL_PROCESSING) { + if (fResultDepth == 0) { + checkWhitespace(text); + } + else if (fDocumentHandler != null) { + // we need to change the depth like this so that modifyAugmentations() works + fDepth++; + augs = modifyAugmentations(augs); + fDocumentHandler.characters(text, augs); + fDepth--; + } + } + } + + public void ignorableWhitespace(XMLString text, Augmentations augs) + throws XNIException { + if (fDocumentHandler != null + && getState() == STATE_NORMAL_PROCESSING + && fResultDepth != 0) { + fDocumentHandler.ignorableWhitespace(text, augs); + } + } + + public void startCDATA(Augmentations augs) throws XNIException { + if (fDocumentHandler != null + && getState() == STATE_NORMAL_PROCESSING + && fResultDepth != 0) { + fDocumentHandler.startCDATA(augs); + } + } + + public void endCDATA(Augmentations augs) throws XNIException { + if (fDocumentHandler != null + && getState() == STATE_NORMAL_PROCESSING + && fResultDepth != 0) { + fDocumentHandler.endCDATA(augs); + } + } + + public void endDocument(Augmentations augs) throws XNIException { + if (isRootDocument()) { + if (!fSeenRootElement) { + reportFatalError("RootElementRequired"); + } + if (fDocumentHandler != null) { + fDocumentHandler.endDocument(augs); + } + } + } + + public void setDocumentSource(XMLDocumentSource source) { + fDocumentSource = source; + } + + public XMLDocumentSource getDocumentSource() { + return fDocumentSource; + } + + // DTDHandler methods + // We are only interested in the notation and unparsed entity declarations, + // the rest we just pass on + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#attributeDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, org.apache.xerces.xni.XMLString, org.apache.xerces.xni.XMLString, org.apache.xerces.xni.Augmentations) + */ + public void attributeDecl( + String elementName, + String attributeName, + String type, + String[] enumeration, + String defaultType, + XMLString defaultValue, + XMLString nonNormalizedDefaultValue, + Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.attributeDecl( + elementName, + attributeName, + type, + enumeration, + defaultType, + defaultValue, + nonNormalizedDefaultValue, + augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#elementDecl(java.lang.String, java.lang.String, org.apache.xerces.xni.Augmentations) + */ + public void elementDecl( + String name, + String contentModel, + Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.elementDecl(name, contentModel, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#endAttlist(org.apache.xerces.xni.Augmentations) + */ + public void endAttlist(Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endAttlist(augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#endConditional(org.apache.xerces.xni.Augmentations) + */ + public void endConditional(Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endConditional(augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#endDTD(org.apache.xerces.xni.Augmentations) + */ + public void endDTD(Augmentations augmentations) throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endDTD(augmentations); + } + fInDTD = false; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#endExternalSubset(org.apache.xerces.xni.Augmentations) + */ + public void endExternalSubset(Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endExternalSubset(augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#endParameterEntity(java.lang.String, org.apache.xerces.xni.Augmentations) + */ + public void endParameterEntity(String name, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.endParameterEntity(name, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#externalEntityDecl(java.lang.String, org.apache.xerces.xni.XMLResourceIdentifier, org.apache.xerces.xni.Augmentations) + */ + public void externalEntityDecl( + String name, + XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.externalEntityDecl(name, identifier, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#getDTDSource() + */ + public XMLDTDSource getDTDSource() { + return fDTDSource; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#ignoredCharacters(org.apache.xerces.xni.XMLString, org.apache.xerces.xni.Augmentations) + */ + public void ignoredCharacters(XMLString text, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.ignoredCharacters(text, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#internalEntityDecl(java.lang.String, org.apache.xerces.xni.XMLString, org.apache.xerces.xni.XMLString, org.apache.xerces.xni.Augmentations) + */ + public void internalEntityDecl( + String name, + XMLString text, + XMLString nonNormalizedText, + Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.internalEntityDecl( + name, + text, + nonNormalizedText, + augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#notationDecl(java.lang.String, org.apache.xerces.xni.XMLResourceIdentifier, org.apache.xerces.xni.Augmentations) + */ + public void notationDecl( + String name, + XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException { + this.addNotation(name, identifier, augmentations); + if (fDTDHandler != null) { + fDTDHandler.notationDecl(name, identifier, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#setDTDSource(org.apache.xerces.xni.parser.XMLDTDSource) + */ + public void setDTDSource(XMLDTDSource source) { + fDTDSource = source; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#startAttlist(java.lang.String, org.apache.xerces.xni.Augmentations) + */ + public void startAttlist(String elementName, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startAttlist(elementName, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#startConditional(short, org.apache.xerces.xni.Augmentations) + */ + public void startConditional(short type, Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startConditional(type, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#startDTD(org.apache.xerces.xni.XMLLocator, org.apache.xerces.xni.Augmentations) + */ + public void startDTD(XMLLocator locator, Augmentations augmentations) + throws XNIException { + fInDTD = true; + if (fDTDHandler != null) { + fDTDHandler.startDTD(locator, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#startExternalSubset(org.apache.xerces.xni.XMLResourceIdentifier, org.apache.xerces.xni.Augmentations) + */ + public void startExternalSubset( + XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startExternalSubset(identifier, augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#startParameterEntity(java.lang.String, org.apache.xerces.xni.XMLResourceIdentifier, java.lang.String, org.apache.xerces.xni.Augmentations) + */ + public void startParameterEntity( + String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augmentations) + throws XNIException { + if (fDTDHandler != null) { + fDTDHandler.startParameterEntity( + name, + identifier, + encoding, + augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.XMLDTDHandler#unparsedEntityDecl(java.lang.String, org.apache.xerces.xni.XMLResourceIdentifier, java.lang.String, org.apache.xerces.xni.Augmentations) + */ + public void unparsedEntityDecl( + String name, + XMLResourceIdentifier identifier, + String notation, + Augmentations augmentations) + throws XNIException { + this.addUnparsedEntity(name, identifier, notation, augmentations); + if (fDTDHandler != null) { + fDTDHandler.unparsedEntityDecl( + name, + identifier, + notation, + augmentations); + } + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.parser.XMLDTDSource#getDTDHandler() + */ + public XMLDTDHandler getDTDHandler() { + return fDTDHandler; + } + + /* (non-Javadoc) + * @see org.apache.xerces.xni.parser.XMLDTDSource#setDTDHandler(org.apache.xerces.xni.XMLDTDHandler) + */ + public void setDTDHandler(XMLDTDHandler handler) { + fDTDHandler = handler; + } + + // XIncludeHandler methods + + private void setErrorReporter(XMLErrorReporter reporter) { + fErrorReporter = reporter; + if (fErrorReporter != null) { + fErrorReporter.putMessageFormatter( + XIncludeMessageFormatter.XINCLUDE_DOMAIN, fXIncludeMessageFormatter); + // this ensures the proper location is displayed in error messages + if (fDocLocation != null) { + fErrorReporter.setDocumentLocator(fDocLocation); + } + } + } + + protected void handleFallbackElement() { + if (!getSawInclude(fDepth - 1)) { + if (getState() == STATE_IGNORE) { + return; + } + reportFatalError("FallbackParent"); + } + + setSawInclude(fDepth, false); + fNamespaceContext.setContextInvalid(); + + if (getSawFallback(fDepth)) { + reportFatalError("MultipleFallbacks"); + } + else { + setSawFallback(fDepth, true); + } + + // Either the state is STATE_EXPECT_FALLBACK or it's STATE_IGNORE. + // If we're ignoring, we want to stay ignoring. But if we're expecting this fallback element, + // we want to signal that we should process the children. + if (getState() == STATE_EXPECT_FALLBACK) { + setState(STATE_NORMAL_PROCESSING); + } + } + + protected boolean handleIncludeElement(XMLAttributes attributes) + throws XNIException { + if (getSawInclude(fDepth - 1)) { + reportFatalError("IncludeChild", new Object[] { XINCLUDE_INCLUDE }); + } + if (getState() == STATE_IGNORE) { + return true; + } + setSawInclude(fDepth, true); + fNamespaceContext.setContextInvalid(); + + // TODO: does Java use IURIs by default? + // [Definition: An internationalized URI reference, or IURI, is a URI reference that directly uses [Unicode] characters.] + // TODO: figure out what section 4.1.1 of the XInclude spec is talking about + // has to do with disallowed ASCII character escaping + // this ties in with the above IURI section, but I suspect Java already does it + + String href = attributes.getValue(XINCLUDE_ATTR_HREF); + String parse = attributes.getValue(XINCLUDE_ATTR_PARSE); + String xpointer = attributes.getValue(XPOINTER); + String accept = attributes.getValue(XINCLUDE_ATTR_ACCEPT); + String acceptLanguage = attributes.getValue(XINCLUDE_ATTR_ACCEPT_LANGUAGE); + + if (parse == null) { + parse = XINCLUDE_PARSE_XML; + } + if (href == null) { + href = XMLSymbols.EMPTY_STRING; + } + if (href.length() == 0 && XINCLUDE_PARSE_XML.equals(parse)) { + if (xpointer == null) { + reportFatalError("XpointerMissing"); + } + else { + // When parse="xml" and an xpointer is specified treat + // all absences of the href attribute as a resource error. + Locale locale = (fErrorReporter != null) ? fErrorReporter.getLocale() : null; + String reason = fXIncludeMessageFormatter.formatMessage(locale, "XPointerStreamability", null); + reportResourceError("XMLResourceError", new Object[] { href, reason }); + return false; + } + } + + URI hrefURI = null; + + // Check whether href is correct and perform escaping as per section 4.1.1 of the XInclude spec. + // Report fatal error if the href value contains a fragment identifier or if the value after + // escaping is a syntactically invalid URI or IRI. + try { + hrefURI = new URI(href, true); + if (hrefURI.getFragment() != null) { + reportFatalError("HrefFragmentIdentifierIllegal", new Object[] {href}); + } + } + catch (URI.MalformedURIException exc) { + String newHref = escapeHref(href); + if (href != newHref) { + href = newHref; + try { + hrefURI = new URI(href, true); + if (hrefURI.getFragment() != null) { + reportFatalError("HrefFragmentIdentifierIllegal", new Object[] {href}); + } + } + catch (URI.MalformedURIException exc2) { + reportFatalError("HrefSyntacticallyInvalid", new Object[] {href}); + } + } + else { + reportFatalError("HrefSyntacticallyInvalid", new Object[] {href}); + } + } + + // Verify that if an accept and/or an accept-language attribute exist + // that the value(s) don't contain disallowed characters. + if (accept != null && !isValidInHTTPHeader(accept)) { + reportFatalError("AcceptMalformed", null); + accept = null; + } + if (acceptLanguage != null && !isValidInHTTPHeader(acceptLanguage)) { + reportFatalError("AcceptLanguageMalformed", null); + acceptLanguage = null; + } + + XMLInputSource includedSource = null; + if (fEntityResolver != null) { + try { + XMLResourceIdentifier resourceIdentifier = + new XMLResourceIdentifierImpl( + null, + href, + fCurrentBaseURI.getExpandedSystemId(), + XMLEntityManager.expandSystemId( + href, + fCurrentBaseURI.getExpandedSystemId(), + false)); + + includedSource = + fEntityResolver.resolveEntity(resourceIdentifier); + + if (includedSource != null && + !(includedSource instanceof HTTPInputSource) && + (accept != null || acceptLanguage != null) && + includedSource.getCharacterStream() == null && + includedSource.getByteStream() == null) { + + includedSource = createInputSource(includedSource.getPublicId(), includedSource.getSystemId(), + includedSource.getBaseSystemId(), accept, acceptLanguage); + } + } + catch (IOException e) { + reportResourceError( + "XMLResourceError", + new Object[] { href, e.getMessage()}, e); + return false; + } + } + + if (includedSource == null) { + // setup an HTTPInputSource if either of the content negotation attributes were specified. + if (accept != null || acceptLanguage != null) { + includedSource = createInputSource(null, href, fCurrentBaseURI.getExpandedSystemId(), accept, acceptLanguage); + } + else { + includedSource = new XMLInputSource(null, href, fCurrentBaseURI.getExpandedSystemId()); + } + } + + if (parse.equals(XINCLUDE_PARSE_XML)) { + // Instead of always creating a new configuration, the first one can be reused + if ((xpointer != null && fXPointerChildConfig == null) + || (xpointer == null && fXIncludeChildConfig == null) ) { + + String parserName = XINCLUDE_DEFAULT_CONFIGURATION; + if (xpointer != null) + parserName = "org.apache.xerces.parsers.XPointerParserConfiguration"; + + fChildConfig = + (XMLParserConfiguration)ObjectFactory.newInstance( + parserName, + ObjectFactory.findClassLoader(), + true); + + // use the same symbol table, error reporter, entity resolver, security manager and buffer size. + if (fSymbolTable != null) fChildConfig.setProperty(SYMBOL_TABLE, fSymbolTable); + if (fErrorReporter != null) fChildConfig.setProperty(ERROR_REPORTER, fErrorReporter); + if (fEntityResolver != null) fChildConfig.setProperty(ENTITY_RESOLVER, fEntityResolver); + fChildConfig.setProperty(SECURITY_MANAGER, fSecurityManager); + fChildConfig.setProperty(BUFFER_SIZE, new Integer(fBufferSize)); + + // features must be copied to child configuration + fNeedCopyFeatures = true; + + // use the same namespace context + fChildConfig.setProperty( + Constants.XERCES_PROPERTY_PREFIX + + Constants.NAMESPACE_CONTEXT_PROPERTY, + fNamespaceContext); + + fChildConfig.setFeature( + XINCLUDE_FIXUP_BASE_URIS, + fFixupBaseURIs); + + fChildConfig.setFeature( + XINCLUDE_FIXUP_LANGUAGE, + fFixupLanguage); + + + // If the xpointer attribute is present + if (xpointer != null ) { + + XPointerHandler newHandler = + (XPointerHandler)fChildConfig.getProperty( + Constants.XERCES_PROPERTY_PREFIX + + Constants.XPOINTER_HANDLER_PROPERTY); + + fXPtrProcessor = newHandler; + + // ??? + ((XPointerHandler)fXPtrProcessor).setProperty( + Constants.XERCES_PROPERTY_PREFIX + + Constants.NAMESPACE_CONTEXT_PROPERTY, + fNamespaceContext); + + ((XPointerHandler)fXPtrProcessor).setProperty(XINCLUDE_FIXUP_BASE_URIS, + fFixupBaseURIs ? Boolean.TRUE : Boolean.FALSE); + + ((XPointerHandler)fXPtrProcessor).setProperty( + XINCLUDE_FIXUP_LANGUAGE, + fFixupLanguage ? Boolean.TRUE : Boolean.FALSE); + + if (fErrorReporter != null) + ((XPointerHandler)fXPtrProcessor).setProperty(ERROR_REPORTER, fErrorReporter); + // ??? + + newHandler.setParent(this); + newHandler.setHref(href); + newHandler.setXIncludeLocator(fXIncludeLocator); + newHandler.setDocumentHandler(this.getDocumentHandler()); + fXPointerChildConfig = fChildConfig; + } else { + XIncludeHandler newHandler = + (XIncludeHandler)fChildConfig.getProperty( + Constants.XERCES_PROPERTY_PREFIX + + Constants.XINCLUDE_HANDLER_PROPERTY); + + newHandler.setParent(this); + newHandler.setHref(href); + newHandler.setXIncludeLocator(fXIncludeLocator); + newHandler.setDocumentHandler(this.getDocumentHandler()); + fXIncludeChildConfig = fChildConfig; + } + } + + // If an xpointer attribute is present + if (xpointer != null ) { + fChildConfig = fXPointerChildConfig; + + // Parse the XPointer expression + try { + ((XPointerProcessor)fXPtrProcessor).parseXPointer(xpointer); + + } catch (XNIException ex) { + // report the XPointer error as a resource error + reportResourceError( + "XMLResourceError", + new Object[] { href, ex.getMessage()}); + return false; + } + } else { + fChildConfig = fXIncludeChildConfig; + } + + // set all features on parserConfig to match this parser configuration + if (fNeedCopyFeatures) { + copyFeatures(fSettings, fChildConfig); + } + fNeedCopyFeatures = false; + + try { + fHasIncludeReportedContent = false; + fNamespaceContext.pushScope(); + + fChildConfig.parse(includedSource); + // necessary to make sure proper location is reported to the application and in errors + fXIncludeLocator.setLocator(fDocLocation); + if (fErrorReporter != null) { + fErrorReporter.setDocumentLocator(fDocLocation); + } + + // If the xpointer attribute is present + if (xpointer != null ) { + // and it was not resolved + if (!((XPointerProcessor)fXPtrProcessor).isXPointerResolved()) { + Locale locale = (fErrorReporter != null) ? fErrorReporter.getLocale() : null; + String reason = fXIncludeMessageFormatter.formatMessage(locale, "XPointerResolutionUnsuccessful", null); + reportResourceError("XMLResourceError", new Object[] {href, reason}); + // use the fallback + return false; + } + } + } + catch (XNIException e) { + // necessary to make sure proper location is reported to the application and in errors + fXIncludeLocator.setLocator(fDocLocation); + if (fErrorReporter != null) { + fErrorReporter.setDocumentLocator(fDocLocation); + } + reportFatalError("XMLParseError", new Object[] { href }); + } + catch (IOException e) { + // necessary to make sure proper location is reported to the application and in errors + fXIncludeLocator.setLocator(fDocLocation); + if (fErrorReporter != null) { + fErrorReporter.setDocumentLocator(fDocLocation); + } + // If the start document event has been seen on the child pipeline it + // means the resource was successfully opened and we started reporting + // document events. If an IOException is thrown after the start document + // event we had a failure midstream and cannot recover. + if (fHasIncludeReportedContent) { + throw new XNIException(e); + } + // In other circumstances an IOException indicates that we had trouble + // accessing or opening the file, not that it was an invalid XML file. So we + // send a resource error, not a fatal error. + reportResourceError( + "XMLResourceError", + new Object[] { href, e.getMessage()}, e); + return false; + } + finally { + fNamespaceContext.popScope(); + } + } + else if (parse.equals(XINCLUDE_PARSE_TEXT)) { + // we only care about encoding for parse="text" + String encoding = attributes.getValue(XINCLUDE_ATTR_ENCODING); + includedSource.setEncoding(encoding); + XIncludeTextReader textReader = null; + + try { + fHasIncludeReportedContent = false; + + // Setup the appropriate text reader. + if (!fIsXML11) { + if (fXInclude10TextReader == null) { + fXInclude10TextReader = new XIncludeTextReader(includedSource, this, fBufferSize); + } + else { + fXInclude10TextReader.setInputSource(includedSource); + } + textReader = fXInclude10TextReader; + } + else { + if (fXInclude11TextReader == null) { + fXInclude11TextReader = new XInclude11TextReader(includedSource, this, fBufferSize); + } + else { + fXInclude11TextReader.setInputSource(includedSource); + } + textReader = fXInclude11TextReader; + } + textReader.setErrorReporter(fErrorReporter); + textReader.parse(); + } + // encoding errors + catch (MalformedByteSequenceException ex) { + fErrorReporter.reportError(ex.getDomain(), ex.getKey(), + ex.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, ex); + } + catch (CharConversionException e) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR, e); + } + catch (IOException e) { + // If a characters event has already been sent down the pipeline it + // means the resource was successfully opened and that this IOException + // is from a failure midstream from which we cannot recover. + if (fHasIncludeReportedContent) { + throw new XNIException(e); + } + reportResourceError( + "TextResourceError", + new Object[] { href, e.getMessage()}, e); + return false; + } + finally { + if (textReader != null) { + try { + textReader.close(); + } + catch (IOException e) { + reportResourceError( + "TextResourceError", + new Object[] { href, e.getMessage()}, e); + return false; + } + } + } + } + else { + reportFatalError("InvalidParseValue", new Object[] { parse }); + } + return true; + } + + /** + * Returns true if the element has the namespace "http://www.w3.org/2001/XInclude" + * @param element the element to check + * @return true if the element has the namespace "http://www.w3.org/2001/XInclude" + */ + protected boolean hasXIncludeNamespace(QName element) { + // REVISIT: The namespace of this element should be bound + // already. Why are we looking it up from the namespace + // context? -- mrglavas + return element.uri == XINCLUDE_NS_URI + || fNamespaceContext.getURI(element.prefix) == XINCLUDE_NS_URI; + } + + /** + * Checks if the element is an <include> element. The element must have + * the XInclude namespace, and a local name of "include". + * + * @param element the element to check + * @return true if the element is an <include> element + * @see #hasXIncludeNamespace(QName) + */ + protected boolean isIncludeElement(QName element) { + return element.localpart.equals(XINCLUDE_INCLUDE) && + hasXIncludeNamespace(element); + } + + /** + * Checks if the element is an <fallback> element. The element must have + * the XInclude namespace, and a local name of "fallback". + * + * @param element the element to check + * @return true if the element is an <fallback; element + * @see #hasXIncludeNamespace(QName) + */ + protected boolean isFallbackElement(QName element) { + return element.localpart.equals(XINCLUDE_FALLBACK) && + hasXIncludeNamespace(element); + } + + /** + * Returns true if the current [base URI] is the same as the [base URI] that + * was in effect on the include parent. This method should only be called + * when the current element is a top level included element, i.e. the direct child + * of a fallback element, or the root elements in an included document. + * The "include parent" is the element which, in the result infoset, will be the + * direct parent of the current element. + * @return true if the [base URIs] are the same string + */ + protected boolean sameBaseURIAsIncludeParent() { + String parentBaseURI = getIncludeParentBaseURI(); + String baseURI = fCurrentBaseURI.getExpandedSystemId(); + // REVISIT: should we use File#sameFile() ? + // I think the benefit of using it is that it resolves host names + // instead of just doing a string comparison. + // TODO: [base URI] is still an open issue with the working group. + // They're deciding if xml:base should be added if the [base URI] is different in terms + // of resolving relative references, or if it should be added if they are different at all. + // Revisit this after a final decision has been made. + // The decision also affects whether we output the file name of the URI, or just the path. + return parentBaseURI != null && parentBaseURI.equals(baseURI); + } + + /** + * Returns true if the current [language] is equivalent to the [language] that + * was in effect on the include parent, taking case-insensitivity into account + * as per [RFC 3066]. This method should only be called when the + * current element is a top level included element, i.e. the direct child + * of a fallback element, or the root elements in an included document. + * The "include parent" is the element which, in the result infoset, will be the + * direct parent of the current element. + * + * @return true if the [language] properties have the same value + * taking case-insensitivity into account as per [RFC 3066]. + */ + protected boolean sameLanguageAsIncludeParent() { + String parentLanguage = getIncludeParentLanguage(); + return parentLanguage != null && parentLanguage.equalsIgnoreCase(fCurrentLanguage); + } + + protected void setupCurrentBaseURI(XMLLocator locator) { + fCurrentBaseURI.setBaseSystemId(locator.getBaseSystemId()); + + if (locator.getLiteralSystemId() != null) { + fCurrentBaseURI.setLiteralSystemId(locator.getLiteralSystemId()); + } + else { + fCurrentBaseURI.setLiteralSystemId(fHrefFromParent); + } + + String expandedSystemId = locator.getExpandedSystemId(); + if (expandedSystemId == null) { + // attempt to expand it ourselves + try { + expandedSystemId = + XMLEntityManager.expandSystemId( + fCurrentBaseURI.getLiteralSystemId(), + fCurrentBaseURI.getBaseSystemId(), + false); + if (expandedSystemId == null) { + expandedSystemId = fCurrentBaseURI.getLiteralSystemId(); + } + } + catch (MalformedURIException e) { + reportFatalError("ExpandedSystemId"); + } + } + fCurrentBaseURI.setExpandedSystemId(expandedSystemId); + } + + /** + * Checks if the file indicated by the given system id has already been + * included in the current stack. + * @param includedSysId the system id to check for inclusion + * @return true if the source has already been included + */ + protected boolean searchForRecursiveIncludes(String includedSysId) { + if (includedSysId.equals(fCurrentBaseURI.getExpandedSystemId())) { + return true; + } + else if (fParentXIncludeHandler == null) { + return false; + } + else { + return fParentXIncludeHandler.searchForRecursiveIncludes(includedSysId); + } + } + + /** + * Returns true if the current element is a top level included item. This means + * it's either the child of a fallback element, or the top level item in an + * included document + * @return true if the current element is a top level included item + */ + protected boolean isTopLevelIncludedItem() { + return isTopLevelIncludedItemViaInclude() + || isTopLevelIncludedItemViaFallback(); + } + + protected boolean isTopLevelIncludedItemViaInclude() { + return fDepth == 1 && !isRootDocument(); + } + + protected boolean isTopLevelIncludedItemViaFallback() { + // Technically, this doesn't check if the parent was a fallback, it also + // would return true if any of the parent's sibling elements were fallbacks. + // However, this doesn't matter, since we will always be ignoring elements + // whose parent's siblings were fallbacks. + return getSawFallback(fDepth - 1); + } + + /** + * Processes the XMLAttributes object of startElement() calls. Performs the following tasks: + *

          + *
        • If the element is a top level included item whose [base URI] is different from the + * [base URI] of the include parent, then an xml:base attribute is added to specify the + * true [base URI] + *
        • For all namespace prefixes which are in-scope in an included item, but not in scope + * in the include parent, a xmlns:prefix attribute is added + *
        • For all attributes with a type of ENTITY, ENTITIES or NOTATIONS, the notations and + * unparsed entities are processed as described in the spec, sections 4.5.1 and 4.5.2 + *
        + * @param attributes + * @return the processed XMLAttributes + */ + protected XMLAttributes processAttributes(XMLAttributes attributes) { + if (isTopLevelIncludedItem()) { + // Modify attributes to fix the base URI (spec 4.5.5). + // We only do it to top level included elements, which have a different + // base URI than their include parent. + if (fFixupBaseURIs && !sameBaseURIAsIncludeParent()) { + if (attributes == null) { + attributes = new XMLAttributesImpl(); + } + + // This causes errors with schema validation, if the schema doesn't + // specify that these elements can have an xml:base attribute + String uri = null; + try { + uri = this.getRelativeBaseURI(); + } + catch (MalformedURIException e) { + // this shouldn't ever happen, since by definition, we had to traverse + // the same URIs to even get to this place + uri = fCurrentBaseURI.getExpandedSystemId(); + } + int index = + attributes.addAttribute( + XML_BASE_QNAME, + XMLSymbols.fCDATASymbol, + uri); + attributes.setSpecified(index, true); + } + + // Modify attributes to perform language-fixup (spec 4.5.6). + // We only do it to top level included elements, which have a different + // [language] than their include parent. + if (fFixupLanguage && !sameLanguageAsIncludeParent()) { + if (attributes == null) { + attributes = new XMLAttributesImpl(); + } + int index = + attributes.addAttribute( + XML_LANG_QNAME, + XMLSymbols.fCDATASymbol, + fCurrentLanguage); + attributes.setSpecified(index, true); + } + + // Modify attributes of included items to do namespace-fixup. (spec 4.5.4) + Enumeration inscopeNS = fNamespaceContext.getAllPrefixes(); + while (inscopeNS.hasMoreElements()) { + String prefix = (String)inscopeNS.nextElement(); + String parentURI = + fNamespaceContext.getURIFromIncludeParent(prefix); + String uri = fNamespaceContext.getURI(prefix); + if (parentURI != uri && attributes != null) { + if (prefix == XMLSymbols.EMPTY_STRING) { + if (attributes + .getValue( + NamespaceContext.XMLNS_URI, + XMLSymbols.PREFIX_XMLNS) + == null) { + if (attributes == null) { + attributes = new XMLAttributesImpl(); + } + + QName ns = (QName)NEW_NS_ATTR_QNAME.clone(); + ns.prefix = null; + ns.localpart = XMLSymbols.PREFIX_XMLNS; + ns.rawname = XMLSymbols.PREFIX_XMLNS; + int index = + attributes.addAttribute( + ns, + XMLSymbols.fCDATASymbol, + uri != null ? uri : XMLSymbols.EMPTY_STRING); + attributes.setSpecified(index, true); + // Need to re-declare this prefix in the current context + // in order for the SAX parser to report the appropriate + // start and end prefix mapping events. -- mrglavas + fNamespaceContext.declarePrefix(prefix, uri); + } + } + else if ( + attributes.getValue(NamespaceContext.XMLNS_URI, prefix) + == null) { + if (attributes == null) { + attributes = new XMLAttributesImpl(); + } + + QName ns = (QName)NEW_NS_ATTR_QNAME.clone(); + ns.localpart = prefix; + ns.rawname += prefix; + ns.rawname = (fSymbolTable != null) ? + fSymbolTable.addSymbol(ns.rawname) : + ns.rawname.intern(); + int index = + attributes.addAttribute( + ns, + XMLSymbols.fCDATASymbol, + uri != null ? uri : XMLSymbols.EMPTY_STRING); + attributes.setSpecified(index, true); + // Need to re-declare this prefix in the current context + // in order for the SAX parser to report the appropriate + // start and end prefix mapping events. -- mrglavas + fNamespaceContext.declarePrefix(prefix, uri); + } + } + } + } + + if (attributes != null) { + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + String type = attributes.getType(i); + String value = attributes.getValue(i); + if (type == XMLSymbols.fENTITYSymbol) { + this.checkUnparsedEntity(value); + } + if (type == XMLSymbols.fENTITIESSymbol) { + // 4.5.1 - Unparsed Entities + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) { + String entName = st.nextToken(); + this.checkUnparsedEntity(entName); + } + } + else if (type == XMLSymbols.fNOTATIONSymbol) { + // 4.5.2 - Notations + this.checkNotation(value); + } + /* We actually don't need to do anything for 4.5.3, because at this stage the + * value of the attribute is just a string. It will be taken care of later + * in the pipeline, when the IDREFs are actually resolved against IDs. + * + * if (type == XMLSymbols.fIDREFSymbol || type == XMLSymbols.fIDREFSSymbol) { } + */ + } + } + + return attributes; + } + + /** + * Returns a URI, relative to the include parent's base URI, of the current + * [base URI]. For instance, if the current [base URI] was "dir1/dir2/file.xml" + * and the include parent's [base URI] was "dir/", this would return "dir2/file.xml". + * @return the relative URI + */ + protected String getRelativeBaseURI() throws MalformedURIException { + int includeParentDepth = getIncludeParentDepth(); + String relativeURI = this.getRelativeURI(includeParentDepth); + if (isRootDocument()) { + return relativeURI; + } + else { + if (relativeURI.length() == 0) { + relativeURI = fCurrentBaseURI.getLiteralSystemId(); + } + + if (includeParentDepth == 0) { + if (fParentRelativeURI == null) { + fParentRelativeURI = + fParentXIncludeHandler.getRelativeBaseURI(); + } + if (fParentRelativeURI.length() == 0) { + return relativeURI; + } + + URI base = new URI(fParentRelativeURI, true); + URI uri = new URI(base, relativeURI); + + /** Check whether the scheme components are equal. */ + final String baseScheme = base.getScheme(); + final String literalScheme = uri.getScheme(); + if (!isEqual(baseScheme, literalScheme)) { + return relativeURI; + } + + /** Check whether the authority components are equal. */ + final String baseAuthority = base.getAuthority(); + final String literalAuthority = uri.getAuthority(); + if (!isEqual(baseAuthority, literalAuthority)) { + return uri.getSchemeSpecificPart(); + } + + /** + * The scheme and authority components are equal, + * return the path and the possible query and/or + * fragment which follow. + */ + final String literalPath = uri.getPath(); + final String literalQuery = uri.getQueryString(); + final String literalFragment = uri.getFragment(); + if (literalQuery != null || literalFragment != null) { + StringBuffer buffer = new StringBuffer(); + if (literalPath != null) { + buffer.append(literalPath); + } + if (literalQuery != null) { + buffer.append('?'); + buffer.append(literalQuery); + } + if (literalFragment != null) { + buffer.append('#'); + buffer.append(literalFragment); + } + return buffer.toString(); + } + return literalPath; + } + else { + return relativeURI; + } + } + } + + /** + * Returns the [base URI] of the include parent. + * @return the base URI of the include parent. + */ + private String getIncludeParentBaseURI() { + int depth = getIncludeParentDepth(); + if (!isRootDocument() && depth == 0) { + return fParentXIncludeHandler.getIncludeParentBaseURI(); + } + else { + return this.getBaseURI(depth); + } + } + + /** + * Returns the [language] of the include parent. + * + * @return the language property of the include parent. + */ + private String getIncludeParentLanguage() { + int depth = getIncludeParentDepth(); + if (!isRootDocument() && depth == 0) { + return fParentXIncludeHandler.getIncludeParentLanguage(); + } + else { + return getLanguage(depth); + } + } + + /** + * Returns the depth of the include parent. Here, the include parent is + * calculated as the last non-include or non-fallback element. It is assumed + * this method is called when the current element is a top level included item. + * Returning 0 indicates that the top level element in this document + * was an include element. + * @return the depth of the top level include element + */ + private int getIncludeParentDepth() { + // We don't start at fDepth, since it is either the top level included item, + // or an include element, when this method is called. + for (int i = fDepth - 1; i >= 0; i--) { + // This technically might not always return the first non-include/fallback + // element that it comes to, since sawFallback() returns true if a fallback + // was ever encountered at that depth. However, if a fallback was encountered + // at that depth, and it wasn't the direct descendant of the current element + // then we can't be in a situation where we're calling this method (because + // we'll always be in STATE_IGNORE) + if (!getSawInclude(i) && !getSawFallback(i)) { + return i; + } + } + // shouldn't get here, since depth 0 should never have an include element or + // a fallback element + return 0; + } + + /** + * Returns the current element depth of the result infoset. + */ + private int getResultDepth() { + return fResultDepth; + } + + /** + * Modify the augmentations. Add an [included] infoset item, if the current + * element is a top level included item. + * @param augs the Augmentations to modify. + * @return the modified Augmentations + */ + protected Augmentations modifyAugmentations(Augmentations augs) { + return modifyAugmentations(augs, false); + } + + /** + * Modify the augmentations. Add an [included] infoset item, if force + * is true, or if the current element is a top level included item. + * @param augs the Augmentations to modify. + * @param force whether to force modification + * @return the modified Augmentations + */ + protected Augmentations modifyAugmentations( + Augmentations augs, + boolean force) { + if (force || isTopLevelIncludedItem()) { + if (augs == null) { + augs = new AugmentationsImpl(); + } + augs.putItem(XINCLUDE_INCLUDED, Boolean.TRUE); + } + return augs; + } + + protected int getState(int depth) { + return fState[depth]; + } + + protected int getState() { + return fState[fDepth]; + } + + protected void setState(int state) { + if (fDepth >= fState.length) { + int[] newarray = new int[fDepth * 2]; + System.arraycopy(fState, 0, newarray, 0, fState.length); + fState = newarray; + } + fState[fDepth] = state; + } + + /** + * Records that an <fallback> was encountered at the specified depth, + * as an ancestor of the current element, or as a sibling of an ancestor of the + * current element. + * + * @param depth + * @param val + */ + protected void setSawFallback(int depth, boolean val) { + if (depth >= fSawFallback.length) { + boolean[] newarray = new boolean[depth * 2]; + System.arraycopy(fSawFallback, 0, newarray, 0, fSawFallback.length); + fSawFallback = newarray; + } + fSawFallback[depth] = val; + } + + /** + * Returns whether an <fallback> was encountered at the specified depth, + * as an ancestor of the current element, or as a sibling of an ancestor of the + * current element. + * + * @param depth + */ + protected boolean getSawFallback(int depth) { + if (depth >= fSawFallback.length) { + return false; + } + return fSawFallback[depth]; + } + + /** + * Records that an <include> was encountered at the specified depth, + * as an ancestor of the current item. + * + * @param depth + * @param val + */ + protected void setSawInclude(int depth, boolean val) { + if (depth >= fSawInclude.length) { + boolean[] newarray = new boolean[depth * 2]; + System.arraycopy(fSawInclude, 0, newarray, 0, fSawInclude.length); + fSawInclude = newarray; + } + fSawInclude[depth] = val; + } + + /** + * Return whether an <include> was encountered at the specified depth, + * as an ancestor of the current item. + * + * @param depth + * @return true if an include was seen at the given depth, false otherwise + */ + protected boolean getSawInclude(int depth) { + if (depth >= fSawInclude.length) { + return false; + } + return fSawInclude[depth]; + } + + protected void reportResourceError(String key) { + this.reportResourceError(key, null); + } + + protected void reportResourceError(String key, Object[] args) { + this.reportResourceError(key, args, null); + } + + protected void reportResourceError(String key, Object[] args, Exception exception) { + this.reportError(key, args, XMLErrorReporter.SEVERITY_WARNING, exception); + } + + protected void reportFatalError(String key) { + this.reportFatalError(key, null); + } + + protected void reportFatalError(String key, Object[] args) { + this.reportFatalError(key, args, null); + } + + protected void reportFatalError(String key, Object[] args, Exception exception) { + this.reportError(key, args, XMLErrorReporter.SEVERITY_FATAL_ERROR, exception); + } + + private void reportError(String key, Object[] args, short severity, Exception exception) { + if (fErrorReporter != null) { + fErrorReporter.reportError( + XIncludeMessageFormatter.XINCLUDE_DOMAIN, + key, + args, + severity, + exception); + } + // we won't worry about when error reporter is null, since there should always be + // at least the default error reporter + } + + /** + * Set the parent of this XIncludeHandler in the tree + * @param parent + */ + protected void setParent(XIncludeHandler parent) { + fParentXIncludeHandler = parent; + } + + protected void setHref(String href) { + fHrefFromParent = href; + } + + protected void setXIncludeLocator(XMLLocatorWrapper locator) { + fXIncludeLocator = locator; + } + + // used to know whether to pass declarations to the document handler + protected boolean isRootDocument() { + return fParentXIncludeHandler == null; + } + + /** + * Caches an unparsed entity. + * @param name the name of the unparsed entity + * @param identifier the location of the unparsed entity + * @param augmentations any Augmentations that were on the original unparsed entity declaration + */ + protected void addUnparsedEntity( + String name, + XMLResourceIdentifier identifier, + String notation, + Augmentations augmentations) { + UnparsedEntity ent = new UnparsedEntity(); + ent.name = name; + ent.systemId = identifier.getLiteralSystemId(); + ent.publicId = identifier.getPublicId(); + ent.baseURI = identifier.getBaseSystemId(); + ent.expandedSystemId = identifier.getExpandedSystemId(); + ent.notation = notation; + ent.augmentations = augmentations; + fUnparsedEntities.add(ent); + } + + /** + * Caches a notation. + * @param name the name of the notation + * @param identifier the location of the notation + * @param augmentations any Augmentations that were on the original notation declaration + */ + protected void addNotation( + String name, + XMLResourceIdentifier identifier, + Augmentations augmentations) { + Notation not = new Notation(); + not.name = name; + not.systemId = identifier.getLiteralSystemId(); + not.publicId = identifier.getPublicId(); + not.baseURI = identifier.getBaseSystemId(); + not.expandedSystemId = identifier.getExpandedSystemId(); + not.augmentations = augmentations; + fNotations.add(not); + } + + /** + * Checks if an UnparsedEntity with the given name was declared in the DTD of the document + * for the current pipeline. If so, then the notation for the UnparsedEntity is checked. + * If that turns out okay, then the UnparsedEntity is passed to the root pipeline to + * be checked for conflicts, and sent to the root DTDHandler. + * + * @param entName the name of the UnparsedEntity to check + */ + protected void checkUnparsedEntity(String entName) { + UnparsedEntity ent = new UnparsedEntity(); + ent.name = entName; + int index = fUnparsedEntities.indexOf(ent); + if (index != -1) { + ent = (UnparsedEntity)fUnparsedEntities.get(index); + // first check the notation of the unparsed entity + checkNotation(ent.notation); + checkAndSendUnparsedEntity(ent); + } + } + + /** + * Checks if a Notation with the given name was declared in the DTD of the document + * for the current pipeline. If so, that Notation is passed to the root pipeline to + * be checked for conflicts, and sent to the root DTDHandler + * + * @param notName the name of the Notation to check + */ + protected void checkNotation(String notName) { + Notation not = new Notation(); + not.name = notName; + int index = fNotations.indexOf(not); + if (index != -1) { + not = (Notation)fNotations.get(index); + checkAndSendNotation(not); + } + } + + /** + * The purpose of this method is to check if an UnparsedEntity conflicts with a previously + * declared entity in the current pipeline stack. If there is no conflict, the + * UnparsedEntity is sent by the root pipeline. + * + * @param ent the UnparsedEntity to check for conflicts + */ + protected void checkAndSendUnparsedEntity(UnparsedEntity ent) { + if (isRootDocument()) { + int index = fUnparsedEntities.indexOf(ent); + if (index == -1) { + // There is no unparsed entity with the same name that we have sent. + // Calling unparsedEntityDecl() will add the entity to our local store, + // and also send the unparsed entity to the DTDHandler + XMLResourceIdentifier id = + new XMLResourceIdentifierImpl( + ent.publicId, + ent.systemId, + ent.baseURI, + ent.expandedSystemId); + addUnparsedEntity( + ent.name, + id, + ent.notation, + ent.augmentations); + if (fSendUEAndNotationEvents && fDTDHandler != null) { + fDTDHandler.unparsedEntityDecl( + ent.name, + id, + ent.notation, + ent.augmentations); + } + } + else { + UnparsedEntity localEntity = + (UnparsedEntity)fUnparsedEntities.get(index); + if (!ent.isDuplicate(localEntity)) { + reportFatalError( + "NonDuplicateUnparsedEntity", + new Object[] { ent.name }); + } + } + } + else { + fParentXIncludeHandler.checkAndSendUnparsedEntity(ent); + } + } + + /** + * The purpose of this method is to check if a Notation conflicts with a previously + * declared notation in the current pipeline stack. If there is no conflict, the + * Notation is sent by the root pipeline. + * + * @param not the Notation to check for conflicts + */ + protected void checkAndSendNotation(Notation not) { + if (isRootDocument()) { + int index = fNotations.indexOf(not); + if (index == -1) { + // There is no notation with the same name that we have sent. + XMLResourceIdentifier id = + new XMLResourceIdentifierImpl( + not.publicId, + not.systemId, + not.baseURI, + not.expandedSystemId); + addNotation(not.name, id, not.augmentations); + if (fSendUEAndNotationEvents && fDTDHandler != null) { + fDTDHandler.notationDecl(not.name, id, not.augmentations); + } + } + else { + Notation localNotation = (Notation)fNotations.get(index); + if (!not.isDuplicate(localNotation)) { + reportFatalError( + "NonDuplicateNotation", + new Object[] { not.name }); + } + } + } + else { + fParentXIncludeHandler.checkAndSendNotation(not); + } + } + + /** + * Checks whether the string only contains white space characters. + * + * @param value the text to check + */ + private void checkWhitespace(XMLString value) { + int end = value.offset + value.length; + for (int i = value.offset; i < end; ++i) { + if (!XMLChar.isSpace(value.ch[i])) { + reportFatalError("ContentIllegalAtTopLevel"); + return; + } + } + } + + /** + * Checks whether the root element has already been processed. + */ + private void checkMultipleRootElements() { + if (getRootElementProcessed()) { + reportFatalError("MultipleRootElements"); + } + setRootElementProcessed(true); + } + + /** + * Sets whether the root element has been processed. + */ + private void setRootElementProcessed(boolean seenRoot) { + if (isRootDocument()) { + fSeenRootElement = seenRoot; + return; + } + fParentXIncludeHandler.setRootElementProcessed(seenRoot); + } + + /** + * Returns whether the root element has been processed. + */ + private boolean getRootElementProcessed() { + return isRootDocument() ? fSeenRootElement : fParentXIncludeHandler.getRootElementProcessed(); + } + + // It would be nice if we didn't have to repeat code like this, but there's no interface that has + // setFeature() and addRecognizedFeatures() that the objects have in common. + protected void copyFeatures( + XMLComponentManager from, + ParserConfigurationSettings to) { + Enumeration features = Constants.getXercesFeatures(); + copyFeatures1(features, Constants.XERCES_FEATURE_PREFIX, from, to); + features = Constants.getSAXFeatures(); + copyFeatures1(features, Constants.SAX_FEATURE_PREFIX, from, to); + } + + protected void copyFeatures( + XMLComponentManager from, + XMLParserConfiguration to) { + Enumeration features = Constants.getXercesFeatures(); + copyFeatures1(features, Constants.XERCES_FEATURE_PREFIX, from, to); + features = Constants.getSAXFeatures(); + copyFeatures1(features, Constants.SAX_FEATURE_PREFIX, from, to); + } + + private void copyFeatures1( + Enumeration features, + String featurePrefix, + XMLComponentManager from, + ParserConfigurationSettings to) { + while (features.hasMoreElements()) { + String featureId = featurePrefix + (String)features.nextElement(); + + to.addRecognizedFeatures(new String[] { featureId }); + + try { + to.setFeature(featureId, from.getFeature(featureId)); + } + catch (XMLConfigurationException e) { + // componentManager doesn't support this feature, + // so we won't worry about it + } + } + } + + private void copyFeatures1( + Enumeration features, + String featurePrefix, + XMLComponentManager from, + XMLParserConfiguration to) { + while (features.hasMoreElements()) { + String featureId = featurePrefix + (String)features.nextElement(); + boolean value = from.getFeature(featureId); + + try { + to.setFeature(featureId, value); + } + catch (XMLConfigurationException e) { + // componentManager doesn't support this feature, + // so we won't worry about it + } + } + } + + // This is a storage class to hold information about the notations. + // We're not using XMLNotationDecl because we don't want to lose the augmentations. + protected static class Notation { + public String name; + public String systemId; + public String baseURI; + public String publicId; + public String expandedSystemId; + public Augmentations augmentations; + + // equals() returns true if two Notations have the same name. + // Useful for searching Vectors for notations with the same name + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj instanceof Notation) { + Notation other = (Notation)obj; + return name.equals(other.name); + } + return false; + } + + // from 4.5.2 + // Notation items with the same [name], [system identifier], + // [public identifier], and [declaration base URI] are considered + // to be duplicate. An application may also be able to detect that + // notations are duplicate through other means. For instance, the URI + // resulting from combining the system identifier and the declaration + // base URI is the same. + public boolean isDuplicate(Object obj) { + if (obj != null && obj instanceof Notation) { + Notation other = (Notation)obj; + return name.equals(other.name) + && isEqual(publicId, other.publicId) + && isEqual(expandedSystemId, other.expandedSystemId); + } + return false; + } + + private boolean isEqual(String one, String two) { + return (one == two || (one != null && one.equals(two))); + } + } + + // This is a storage class to hold information about the unparsed entities. + // We're not using XMLEntityDecl because we don't want to lose the augmentations. + protected static class UnparsedEntity { + public String name; + public String systemId; + public String baseURI; + public String publicId; + public String expandedSystemId; + public String notation; + public Augmentations augmentations; + + // equals() returns true if two UnparsedEntities have the same name. + // Useful for searching Vectors for entities with the same name + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj instanceof UnparsedEntity) { + UnparsedEntity other = (UnparsedEntity)obj; + return name.equals(other.name); + } + return false; + } + + // from 4.5.1: + // Unparsed entity items with the same [name], [system identifier], + // [public identifier], [declaration base URI], [notation name], and + // [notation] are considered to be duplicate. An application may also + // be able to detect that unparsed entities are duplicate through other + // means. For instance, the URI resulting from combining the system + // identifier and the declaration base URI is the same. + public boolean isDuplicate(Object obj) { + if (obj != null && obj instanceof UnparsedEntity) { + UnparsedEntity other = (UnparsedEntity)obj; + return name.equals(other.name) + && isEqual(publicId, other.publicId) + && isEqual(expandedSystemId, other.expandedSystemId) + && isEqual(notation, other.notation); + } + return false; + } + + private boolean isEqual(String one, String two) { + return (one == two || (one != null && one.equals(two))); + } + } + + // The following methods are used for XML Base processing + + /** + * Saves the current base URI to the top of the stack. + */ + protected void saveBaseURI() { + fBaseURIScope.push(fDepth); + fBaseURI.push(fCurrentBaseURI.getBaseSystemId()); + fLiteralSystemID.push(fCurrentBaseURI.getLiteralSystemId()); + fExpandedSystemID.push(fCurrentBaseURI.getExpandedSystemId()); + } + + /** + * Discards the URIs at the top of the stack, and restores the ones beneath it. + */ + protected void restoreBaseURI() { + fBaseURI.pop(); + fLiteralSystemID.pop(); + fExpandedSystemID.pop(); + fBaseURIScope.pop(); + fCurrentBaseURI.setBaseSystemId((String)fBaseURI.peek()); + fCurrentBaseURI.setLiteralSystemId((String)fLiteralSystemID.peek()); + fCurrentBaseURI.setExpandedSystemId((String)fExpandedSystemID.peek()); + } + + // The following methods are used for language processing + + /** + * Saves the given language on the top of the stack. + * + * @param language the language to push onto the stack. + */ + protected void saveLanguage(String language) { + fLanguageScope.push(fDepth); + fLanguageStack.push(language); + } + + /** + * Discards the language at the top of the stack, and returns the one beneath it. + */ + public String restoreLanguage() { + fLanguageStack.pop(); + fLanguageScope.pop(); + return (String) fLanguageStack.peek(); + } + + /** + * Gets the base URI that was in use at that depth + * @param depth + * @return the base URI + */ + public String getBaseURI(int depth) { + int scope = scopeOfBaseURI(depth); + return (String)fExpandedSystemID.elementAt(scope); + } + + /** + * Gets the language that was in use at that depth. + * @param depth + * @return the language + */ + public String getLanguage(int depth) { + int scope = scopeOfLanguage(depth); + return (String)fLanguageStack.elementAt(scope); + } + + /** + * Returns a relative URI, which when resolved against the base URI at the + * specified depth, will create the current base URI. + * This is accomplished by merged the literal system IDs. + * @param depth the depth at which to start creating the relative URI + * @return a relative URI to convert the base URI at the given depth to the current + * base URI + */ + public String getRelativeURI(int depth) throws MalformedURIException { + // The literal system id at the location given by "start" is *in focus* at + // the given depth. So we need to adjust it to the next scope, so that we + // only process out of focus literal system ids + int start = scopeOfBaseURI(depth) + 1; + if (start == fBaseURIScope.size()) { + // If that is the last system id, then we don't need a relative URI + return ""; + } + URI uri = new URI("file", (String)fLiteralSystemID.elementAt(start)); + for (int i = start + 1; i < fBaseURIScope.size(); i++) { + uri = new URI(uri, (String)fLiteralSystemID.elementAt(i)); + } + return uri.getPath(); + } + + // We need to find two consecutive elements in the scope stack, + // such that the first is lower than 'depth' (or equal), and the + // second is higher. + private int scopeOfBaseURI(int depth) { + for (int i = fBaseURIScope.size() - 1; i >= 0; i--) { + if (fBaseURIScope.elementAt(i) <= depth) + return i; + } + // we should never get here, because 0 was put on the stack in startDocument() + return -1; + } + + private int scopeOfLanguage(int depth) { + for (int i = fLanguageScope.size() - 1; i >= 0; i--) { + if (fLanguageScope.elementAt(i) <= depth) + return i; + } + // we should never get here, because 0 was put on the stack in startDocument() + return -1; + } + + /** + * Search for a xml:base attribute, and if one is found, put the new base URI into + * effect. + */ + protected void processXMLBaseAttributes(XMLAttributes attributes) { + String baseURIValue = + attributes.getValue(NamespaceContext.XML_URI, "base"); + if (baseURIValue != null) { + try { + String expandedValue = + XMLEntityManager.expandSystemId( + baseURIValue, + fCurrentBaseURI.getExpandedSystemId(), + false); + fCurrentBaseURI.setLiteralSystemId(baseURIValue); + fCurrentBaseURI.setBaseSystemId( + fCurrentBaseURI.getExpandedSystemId()); + fCurrentBaseURI.setExpandedSystemId(expandedValue); + + // push the new values on the stack + saveBaseURI(); + } + catch (MalformedURIException e) { + // REVISIT: throw error here + } + } + } + + /** + * Search for a xml:lang attribute, and if one is found, put the new + * [language] into effect. + */ + protected void processXMLLangAttributes(XMLAttributes attributes) { + String language = attributes.getValue(NamespaceContext.XML_URI, "lang"); + if (language != null) { + fCurrentLanguage = language; + saveLanguage(fCurrentLanguage); + } + } + + /** + * Returns true if the given string + * would be valid in an HTTP header. + * + * @param value string to check + * @return true if the given string + * would be valid in an HTTP header + */ + private boolean isValidInHTTPHeader (String value) { + char ch; + for (int i = value.length() - 1; i >= 0; --i) { + ch = value.charAt(i); + if (ch < 0x20 || ch > 0x7E) { + return false; + } + } + return true; + } + + /** + * Returns a new XMLInputSource from the given parameters. + */ + private XMLInputSource createInputSource(String publicId, + String systemId, String baseSystemId, + String accept, String acceptLanguage) { + + HTTPInputSource httpSource = new HTTPInputSource(publicId, systemId, baseSystemId); + if (accept != null && accept.length() > 0) { + httpSource.setHTTPRequestProperty(XIncludeHandler.HTTP_ACCEPT, accept); + } + if (acceptLanguage != null && acceptLanguage.length() > 0) { + httpSource.setHTTPRequestProperty(XIncludeHandler.HTTP_ACCEPT_LANGUAGE, acceptLanguage); + } + return httpSource; + } + + private boolean isEqual(String one, String two) { + return (one == two || (one != null && one.equals(two))); + } + + // which ASCII characters need to be escaped + private static final boolean gNeedEscaping[] = new boolean[128]; + // the first hex character if a character needs to be escaped + private static final char gAfterEscaping1[] = new char[128]; + // the second hex character if a character needs to be escaped + private static final char gAfterEscaping2[] = new char[128]; + private static final char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + // initialize the above 3 arrays + static { + char[] escChs = {' ', '<', '>', '"', '{', '}', '|', '\\', '^', '`'}; + int len = escChs.length; + char ch; + for (int i = 0; i < len; i++) { + ch = escChs[i]; + gNeedEscaping[ch] = true; + gAfterEscaping1[ch] = gHexChs[ch >> 4]; + gAfterEscaping2[ch] = gHexChs[ch & 0xf]; + } + } + + // + // Escape an href value according to (4.1.1): + // + // To convert the value of the href attribute to an IRI reference, the following characters must be escaped: + // space #x20 + // the delimiters < #x3C, > #x3E and " #x22 + // the unwise characters { #x7B, } #x7D, | #x7C, \ #x5C, ^ #x5E and ` #x60 + // + // To convert an IRI reference to a URI reference, the following characters must also be escaped: + // the Unicode plane 0 characters #xA0 - #xD7FF, #xF900-#xFDCF, #xFDF0-#xFFEF + // the Unicode plane 1-14 characters #x10000-#x1FFFD ... #xE0000-#xEFFFD + // + private String escapeHref(String href) { + int len = href.length(); + int ch; + StringBuffer buffer = new StringBuffer(len*3); + + // for each character in the href + int i = 0; + for (; i < len; i++) { + ch = href.charAt(i); + // if it's not an ASCII character (excluding 0x7F), break here, and use UTF-8 encoding + if (ch > 0x7E) { + break; + } + // abort: href does not allow this character + if (ch < 0x20) { + return href; + } + if (gNeedEscaping[ch]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[ch]); + buffer.append(gAfterEscaping2[ch]); + } + else { + buffer.append((char)ch); + } + } + + // we saw some non-ascii character + if (i < len) { + // check if remainder of href contains any illegal characters before proceeding + for (int j = i; j < len; ++j) { + ch = href.charAt(j); + if ((ch >= 0x20 && ch <= 0x7E) || + (ch >= 0xA0 && ch <= 0xD7FF) || + (ch >= 0xF900 && ch <= 0xFDCF) || + (ch >= 0xFDF0 && ch <= 0xFFEF)) { + continue; + } + if (XMLChar.isHighSurrogate(ch) && ++j < len) { + int ch2 = href.charAt(j); + if (XMLChar.isLowSurrogate(ch2)) { + ch2 = XMLChar.supplemental((char)ch, (char)ch2); + if (ch2 < 0xF0000 && (ch2 & 0xFFFF) <= 0xFFFD) { + continue; + } + } + } + // abort: href does not allow this character + return href; + } + + // get UTF-8 bytes for the remaining sub-string + byte[] bytes = null; + byte b; + try { + bytes = href.substring(i).getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException e) { + // should never happen + return href; + } + len = bytes.length; + + // for each byte + for (i = 0; i < len; i++) { + b = bytes[i]; + // for non-ASCII character: make it positive, then escape + if (b < 0) { + ch = b + 256; + buffer.append('%'); + buffer.append(gHexChs[ch >> 4]); + buffer.append(gHexChs[ch & 0xf]); + } + else if (gNeedEscaping[b]) { + buffer.append('%'); + buffer.append(gAfterEscaping1[b]); + buffer.append(gAfterEscaping2[b]); + } + else { + buffer.append((char)b); + } + } + } + + // If escaping happened, create a new string; + // otherwise, return the original one. + if (buffer.length() != len) { + return buffer.toString(); + } + else { + return href; + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeMessageFormatter.java b/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeMessageFormatter.java new file mode 100644 index 0000000..ad50d3d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeMessageFormatter.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.xerces.xinclude; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.xerces.util.MessageFormatter; + +// TODO: fix error messages in XIncludeMessages.properties +/** + * XIncludeMessageFormatter provides error messages for the XInclude 1.0 Candidate Recommendation + * + * @author Peter McCracken, IBM + * + * @version $Id$ + */ +public class XIncludeMessageFormatter implements MessageFormatter { + + public static final String XINCLUDE_DOMAIN = "http://www.w3.org/TR/xinclude"; + + // private objects to cache the locale and resource bundle + private Locale fLocale = null; + private ResourceBundle fResourceBundle = null; + + /** + * Formats a message with the specified arguments using the given + * locale information. + * + * @param locale The locale of the message. + * @param key The message key. + * @param arguments The message replacement text arguments. The order + * of the arguments must match that of the placeholders + * in the actual message. + * + * @return Returns the formatted message. + * + * @throws MissingResourceException Thrown if the message with the + * specified key cannot be found. + */ + public String formatMessage(Locale locale, String key, Object[] arguments) + throws MissingResourceException { + + if (locale == null) { + locale = Locale.getDefault(); + } + if (locale != fLocale) { + fResourceBundle = ResourceBundle.getBundle("org.apache.xerces.impl.msg.XIncludeMessages", locale); + // memorize the most-recent locale + fLocale = locale; + } + + String msg = fResourceBundle.getString(key); + if (arguments != null) { + try { + msg = java.text.MessageFormat.format(msg, arguments); + } catch (Exception e) { + msg = fResourceBundle.getString("FormatFailed"); + msg += " " + fResourceBundle.getString(key); + } + } + + if (msg == null) { + msg = fResourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(msg, "org.apache.xerces.impl.msg.XIncludeMessages", key); + } + + return msg; + } +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeNamespaceSupport.java b/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeNamespaceSupport.java new file mode 100644 index 0000000..3beee4e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeNamespaceSupport.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.xerces.xinclude; + +import org.apache.xerces.xni.NamespaceContext; + +/** + * This is an implementation of NamespaceContext which is intended to be used for + * XInclude processing. It enables each context to be marked as invalid, if necessary, + * to indicate that the namespaces recorded on those contexts won't be apparent in the + * resulting infoset. + * + * @author Peter McCracken, IBM + * + * @version $Id$ + */ +public class XIncludeNamespaceSupport extends MultipleScopeNamespaceSupport { + + /** + * This stores whether or not the context at the matching depth was valid. + */ + private boolean[] fValidContext = new boolean[8]; + + /** + * + */ + public XIncludeNamespaceSupport() { + super(); + } + + /** + * @param context + */ + public XIncludeNamespaceSupport(NamespaceContext context) { + super(context); + } + + /** + * Pushes a new context onto the stack. + */ + public void pushContext() { + super.pushContext(); + if (fCurrentContext + 1 == fValidContext.length) { + boolean[] contextarray = new boolean[fValidContext.length * 2]; + System.arraycopy(fValidContext, 0, contextarray, 0, fValidContext.length); + fValidContext = contextarray; + } + + fValidContext[fCurrentContext] = true; + } + + /** + * This method is used to set a context invalid for XInclude namespace processing. + * Any context defined by an <include> or <fallback> element is not + * valid for processing the include parent's [in-scope namespaces]. Thus, contexts + * defined by these elements are set to invalid by the XInclude processor using + * this method. + */ + public void setContextInvalid() { + fValidContext[fCurrentContext] = false; + } + + /** + * This returns the namespace URI which was associated with the given pretext, in + * the context that existed at the include parent of the current element. The + * include parent is the last element, before the current one, which was not set + * to an invalid context using setContextInvalid() + * + * @param prefix the prefix of the desired URI + * @return the URI corresponding to the prefix in the context of the include parent + */ + public String getURIFromIncludeParent(String prefix) { + int lastValidContext = fCurrentContext - 1; + while (lastValidContext > 0 && !fValidContext[lastValidContext]) { + lastValidContext--; + } + return getURI(prefix, lastValidContext); + } +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeTextReader.java b/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeTextReader.java new file mode 100644 index 0000000..7431904 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xinclude/XIncludeTextReader.java @@ -0,0 +1,548 @@ +/* + * 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. + */ + +package org.apache.xerces.xinclude; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.impl.io.ASCIIReader; +import org.apache.xerces.impl.io.Latin1Reader; +import org.apache.xerces.impl.io.UTF16Reader; +import org.apache.xerces.impl.io.UTF8Reader; +import org.apache.xerces.impl.msg.XMLMessageFormatter; +import org.apache.xerces.util.EncodingMap; +import org.apache.xerces.util.HTTPInputSource; +import org.apache.xerces.util.MessageFormatter; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * This class is used for reading resources requested in <include> elements, + * when the parse attribute of the <include> element is "text". Using this + * class will open the location, detect the encoding, and discard the byte order + * mark, if applicable. + * + * REVISIT: + * Much of the code in this class is taken from XMLEntityManager. It would be nice + * if this code could be shared in some way. However, since XMLEntityManager is used + * for reading files as XML, and this needs to read files as text, there would need + * to be some refactoring done. + * + * @author Michael Glavassevich, IBM + * @author Peter McCracken, IBM + * @author Ankit Pasricha, IBM + * @author Arun Yadav, Sun Microsystems Inc. + * + * @version $Id$ + * + * @see XIncludeHandler + */ +public class XIncludeTextReader { + + private Reader fReader; + private final XIncludeHandler fHandler; + private XMLInputSource fSource; + private XMLErrorReporter fErrorReporter; + private XMLString fTempString = new XMLString(); + + /** + * Construct the XIncludeReader using the XMLInputSource and XIncludeHandler. + * + * @param source The XMLInputSource to use. + * @param handler The XIncludeHandler to use. + * @param bufferSize The size of this text reader's buffer. + */ + public XIncludeTextReader(XMLInputSource source, XIncludeHandler handler, int bufferSize) + throws IOException { + fHandler = handler; + fSource = source; + fTempString = new XMLString(new char[bufferSize + 1], 0, 0); + } + + /** + * Sets the XMLErrorReporter used for reporting errors while + * reading the text include. + * + * @param errorReporter the XMLErrorReporter to be used for + * reporting errors. + */ + public void setErrorReporter(XMLErrorReporter errorReporter) { + fErrorReporter = errorReporter; + } + + /** + * Return the Reader for given XMLInputSource. + * + * @param source The XMLInputSource to use. + */ + protected Reader getReader(XMLInputSource source) throws IOException { + if (source.getCharacterStream() != null) { + return source.getCharacterStream(); + } + else { + InputStream stream = null; + + String encoding = source.getEncoding(); + if (encoding == null) { + encoding = "UTF-8"; + } + if (source.getByteStream() != null) { + stream = source.getByteStream(); + // Wrap the InputStream so that it is possible to rewind it. + if (!(stream instanceof BufferedInputStream)) { + stream = new BufferedInputStream(stream, fTempString.ch.length); + } + } + else { + String expandedSystemId = XMLEntityManager.expandSystemId(source.getSystemId(), source.getBaseSystemId(), false); + + URL url = new URL(expandedSystemId); + URLConnection urlCon = url.openConnection(); + + // If this is an HTTP connection attach any request properties to the request. + if (urlCon instanceof HttpURLConnection && source instanceof HTTPInputSource) { + final HttpURLConnection urlConnection = (HttpURLConnection) urlCon; + final HTTPInputSource httpInputSource = (HTTPInputSource) source; + + // set request properties + Iterator propIter = httpInputSource.getHTTPRequestProperties(); + while (propIter.hasNext()) { + Map.Entry entry = (Map.Entry) propIter.next(); + urlConnection.setRequestProperty((String) entry.getKey(), (String) entry.getValue()); + } + + // set preference for redirection + boolean followRedirects = httpInputSource.getFollowHTTPRedirects(); + if (!followRedirects) { + urlConnection.setInstanceFollowRedirects(followRedirects); + } + } + + // Wrap the InputStream so that it is possible to rewind it. + stream = new BufferedInputStream(urlCon.getInputStream()); + + // content type will be string like "text/xml; charset=UTF-8" or "text/xml" + final String rawContentType = urlCon.getContentType(); + + // text/xml and application/xml offer only one optional parameter + final int index = (rawContentType != null) ? rawContentType.indexOf(';') : -1; + + final String contentType; + String charset = null; + if (index != -1) { + // this should be something like "text/xml" + contentType = rawContentType.substring(0, index).trim(); + + // this should be something like "charset=UTF-8", but we want to + // strip it down to just "UTF-8" + charset = rawContentType.substring(index + 1).trim(); + if (charset.startsWith("charset=")) { + // 8 is the length of "charset=" + charset = charset.substring(8).trim(); + // strip quotes, if present + if ((charset.charAt(0) == '"' + && charset.charAt(charset.length() - 1) == '"') + || (charset.charAt(0) == '\'' + && charset.charAt(charset.length() - 1) + == '\'')) { + charset = + charset.substring(1, charset.length() - 1); + } + } + else { + charset = null; + } + } + else { + contentType = (rawContentType != null) ? rawContentType.trim() : ""; + } + + String detectedEncoding = null; + /** The encoding of such a resource is determined by: + 1 external encoding information, if available, otherwise + -- the most common type of external information is the "charset" parameter of a MIME package + 2 if the media type of the resource is text/xml, application/xml, or matches the conventions text/*+xml or application/*+xml as described in XML Media Types [IETF RFC 3023], the encoding is recognized as specified in XML 1.0, otherwise + 3 the value of the encoding attribute if one exists, otherwise + 4 UTF-8. + **/ + if (contentType.equals("text/xml")) { + if (charset != null) { + detectedEncoding = charset; + } + else { + // see RFC2376 or 3023, section 3.1 + detectedEncoding = "US-ASCII"; + } + } + else if (contentType.equals("application/xml")) { + if (charset != null) { + detectedEncoding = charset; + } + else { + // see RFC2376 or 3023, section 3.2 + detectedEncoding = getEncodingName(stream); + } + } + else if (contentType.endsWith("+xml")) { + detectedEncoding = getEncodingName(stream); + } + + if (detectedEncoding != null) { + encoding = detectedEncoding; + } + // else 3 or 4. + } + + encoding = encoding.toUpperCase(Locale.ENGLISH); + + // eat the Byte Order Mark + encoding = consumeBOM(stream, encoding); + + // If the document is UTF-8, UTF-16, US-ASCII or ISO-8859-1 use + // the Xerces readers for these encodings. For US-ASCII and ISO-8859-1 + // consult the encoding map since these encodings have many aliases. + if (encoding.equals("UTF-8")) { + return createUTF8Reader(stream); + } + else if (encoding.equals("UTF-16BE")) { + return createUTF16Reader(stream, true); + } + else if (encoding.equals("UTF-16LE")) { + return createUTF16Reader(stream, false); + } + + // Try to use a Java reader. + String javaEncoding = EncodingMap.getIANA2JavaMapping(encoding); + + // If the specified encoding wasn't a recognized IANA encoding throw an IOException. + // The XIncludeHandler will report this as a ResourceError and then will + // attempt to include a fallback if there is one. + if (javaEncoding == null) { + MessageFormatter aFormatter = + fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN); + Locale aLocale = fErrorReporter.getLocale(); + throw new IOException( aFormatter.formatMessage( aLocale, + "EncodingDeclInvalid", + new Object[] {encoding} ) ); + } + else if (javaEncoding.equals("ASCII")) { + return createASCIIReader(stream); + } + else if (javaEncoding.equals("ISO8859_1")) { + return createLatin1Reader(stream); + } + return new InputStreamReader(stream, javaEncoding); + } + } + + /** Create a new UTF-8 reader from the InputStream. **/ + private Reader createUTF8Reader(InputStream stream) { + return new UTF8Reader(stream, + fTempString.ch.length, + fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), + fErrorReporter.getLocale()); + } + + /** Create a new UTF-16 reader from the InputStream. **/ + private Reader createUTF16Reader(InputStream stream, boolean isBigEndian) { + return new UTF16Reader(stream, + (fTempString.ch.length << 1), + isBigEndian, + fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), + fErrorReporter.getLocale()); + } + + /** Create a new ASCII reader from the InputStream. **/ + private Reader createASCIIReader(InputStream stream) { + return new ASCIIReader(stream, + fTempString.ch.length, + fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), + fErrorReporter.getLocale()); + } + + /** Create a new ISO-8859-1 reader from the InputStream. **/ + private Reader createLatin1Reader(InputStream stream) { + return new Latin1Reader(stream, fTempString.ch.length); + } + + /** + * XMLEntityManager cares about endian-ness, since it creates its own optimized + * readers. Since we're just using generic Java readers for now, we're not caring + * about endian-ness. If this changes, even more code needs to be copied from + * XMLEntity manager. -- PJM + */ + protected String getEncodingName(InputStream stream) throws IOException { + final byte[] b4 = new byte[4]; + String encoding = null; + + // this has the potential to throw an exception + // it will be fixed when we ensure the stream is rewindable (see note above) + stream.mark(4); + int count = stream.read(b4, 0, 4); + stream.reset(); + if (count == 4) { + encoding = getEncodingName(b4); + } + + return encoding; + } + + /** + * Removes the byte order mark from the stream, if + * it exists and returns the encoding name. + * + * @param stream + * @param encoding + * @throws IOException + */ + protected String consumeBOM(InputStream stream, String encoding) + throws IOException { + + byte[] b = new byte[3]; + int count = 0; + stream.mark(3); + if (encoding.equals("UTF-8")) { + count = stream.read(b, 0, 3); + if (count == 3) { + final int b0 = b[0] & 0xFF; + final int b1 = b[1] & 0xFF; + final int b2 = b[2] & 0xFF; + if (b0 != 0xEF || b1 != 0xBB || b2 != 0xBF) { + // First three bytes are not BOM, so reset. + stream.reset(); + } + } + else { + stream.reset(); + } + } + else if (encoding.startsWith("UTF-16")) { + count = stream.read(b, 0, 2); + if (count == 2) { + final int b0 = b[0] & 0xFF; + final int b1 = b[1] & 0xFF; + if (b0 == 0xFE && b1 == 0xFF) { + return "UTF-16BE"; + } + else if (b0 == 0xFF && b1 == 0xFE) { + return "UTF-16LE"; + } + } + // First two bytes are not BOM, so reset. + stream.reset(); + } + // We could do UTF-32, but since the getEncodingName() doesn't support that + // we won't support it here. + // To implement UTF-32, look for: 00 00 FE FF for big-endian + // or FF FE 00 00 for little-endian + return encoding; + } + + /** + * REVISIT: This code is taken from org.apache.xerces.impl.XMLEntityManager. + * Is there any way we can share the code, without having it implemented twice? + * I think we should make it public and static in XMLEntityManager. --PJM + * + * Returns the IANA encoding name that is auto-detected from + * the bytes specified, with the endian-ness of that encoding where appropriate. + * + * @param b4 The first four bytes of the input. + * @return the encoding name, or null if no encoding could be detected + */ + protected String getEncodingName(byte[] b4) { + + // UTF-16, with BOM + int b0 = b4[0] & 0xFF; + int b1 = b4[1] & 0xFF; + if (b0 == 0xFE && b1 == 0xFF) { + // UTF-16, big-endian + return "UTF-16BE"; + } + if (b0 == 0xFF && b1 == 0xFE) { + // UTF-16, little-endian + return "UTF-16LE"; + } + + // UTF-8 with a BOM + int b2 = b4[2] & 0xFF; + if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { + return "UTF-8"; + } + + // other encodings + int b3 = b4[3] & 0xFF; + if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { + // UCS-4, big endian (1234) + return "ISO-10646-UCS-4"; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { + // UCS-4, little endian (4321) + return "ISO-10646-UCS-4"; + } + if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { + // UCS-4, unusual octet order (2143) + return "ISO-10646-UCS-4"; + } + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { + // UCS-4, unusual octect order (3412) + return "ISO-10646-UCS-4"; + } + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { + // UTF-16, big-endian, no BOM + // (or could turn out to be UCS-2... + return "UTF-16BE"; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { + // UTF-16, little-endian, no BOM + // (or could turn out to be UCS-2... + return "UTF-16LE"; + } + if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { + // EBCDIC + // a la xerces1, return CP037 instead of EBCDIC here + return "CP037"; + } + + // this signals us to use the value from the encoding attribute + return null; + + } // getEncodingName(byte[]):Object[] + + /** + * Read the input stream as text, and pass the text on to the XIncludeHandler + * using calls to characters(). This will read all of the text it can from the + * resource. + * + * @throws IOException + */ + public void parse() throws IOException { + fReader = getReader(fSource); + fSource = null; + int readSize = fReader.read(fTempString.ch, 0, fTempString.ch.length - 1); + fHandler.fHasIncludeReportedContent = true; + while (readSize != -1) { + for (int i = 0; i < readSize; ++i) { + char ch = fTempString.ch[i]; + if (!isValid(ch)) { + if (XMLChar.isHighSurrogate(ch)) { + int ch2; + // retrieve next character + if (++i < readSize) { + ch2 = fTempString.ch[i]; + } + // handle rare boundary case + else { + ch2 = fReader.read(); + if (ch2 != -1) { + fTempString.ch[readSize++] = (char) ch2; + } + } + if (XMLChar.isLowSurrogate(ch2)) { + // convert surrogates to a supplemental character + int sup = XMLChar.supplemental(ch, (char)ch2); + if (!isValid(sup)) { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "InvalidCharInContent", + new Object[] { Integer.toString(sup, 16) }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + else { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "InvalidCharInContent", + new Object[] { Integer.toString(ch2, 16) }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + else { + fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, + "InvalidCharInContent", + new Object[] { Integer.toString(ch, 16) }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + } + if (fHandler != null && readSize > 0) { + fTempString.offset = 0; + fTempString.length = readSize; + fHandler.characters( + fTempString, + fHandler.modifyAugmentations(null, true)); + } + readSize = fReader.read(fTempString.ch, 0, fTempString.ch.length - 1); + } + + } + + /** + * Sets the input source on this text reader. + * + * @param source The XMLInputSource to use. + */ + public void setInputSource(XMLInputSource source) { + fSource = source; + } + + /** + * Closes the stream. Call this after parse(), or when there is no longer any need + * for this object. + * + * @throws IOException + */ + public void close() throws IOException { + if (fReader != null) { + fReader.close(); + fReader = null; + } + } + + /** + * Returns true if the specified character is a valid XML character + * as per the rules of XML 1.0. + * + * @param ch The character to check. + */ + protected boolean isValid(int ch) { + return XMLChar.isValid(ch); + } + + /** + * Sets the buffer size property for the reader which decides the chunk sizes that are parsed + * by the reader at a time and passed to the handler + * + * @param bufferSize The size of the buffer desired + */ + protected void setBufferSize(int bufferSize) { + if (fTempString.ch.length != ++bufferSize) { + fTempString.ch = new char[bufferSize]; + } + } + +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/Augmentations.java b/resources/xerces2-j-src/org/apache/xerces/xni/Augmentations.java new file mode 100644 index 0000000..a55d343 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/Augmentations.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +import java.util.Enumeration; + +/** + * The Augmentations interface defines a table of additional data that may + * be passed along the document pipeline. The information can contain extra + * arguments or infoset augmentations, for example PSVI. This additional + * information is identified by a String key. + *

        + * Note: + * Methods that receive Augmentations are required to copy the information + * if it is to be saved for use beyond the scope of the method. + * The Augmentations content is volatile, and maybe modified by any method in + * any component in the pipeline. Therefore, methods passed this structure + * should not save any reference to the structure. + * + * @author Elena Litani, IBM + * @version $Id$ + */ + +public interface Augmentations { + + + /** + * Add additional information identified by a key to the Augmentations structure. + * + * @param key Identifier, can't be null + * @param item Additional information + * + * @return the previous value of the specified key in the Augmentations structure, + * or null if it did not have one. + */ + public Object putItem (String key, Object item); + + + /** + * Get information identified by a key from the Augmentations structure + * + * @param key Identifier, can't be null + * + * @return the value to which the key is mapped in the Augmentations structure; + * null if the key is not mapped to any value. + */ + public Object getItem(String key); + + + /** + * Remove additional info from the Augmentations structure + * + * @param key Identifier, can't be null + * @return the previous value of the specified key in the Augmentations structure, + * or null if it did not have one. + */ + public Object removeItem (String key); + + + /** + * Returns an enumeration of the keys in the Augmentations structure + * + */ + public Enumeration keys (); + + + /** + * Remove all objects from the Augmentations structure. + */ + public void removeAllItems (); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/NamespaceContext.java b/resources/xerces2-j-src/org/apache/xerces/xni/NamespaceContext.java new file mode 100644 index 0000000..18aa750 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/NamespaceContext.java @@ -0,0 +1,176 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +import java.util.Enumeration; + +/** + * Represents an interface to query namespace information. + *

        + * The prefix and namespace must be identical references for equal strings, thus + * each string should be internalized (@see String.intern()) + * or added to the SymbolTable + * + * @see + * org.apache.xerces.util.SymbolTable + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface NamespaceContext { + + // + // Constants + // + + /** + * The XML Namespace ("http://www.w3.org/XML/1998/namespace"). This is + * the Namespace URI that is automatically mapped to the "xml" prefix. + */ + public final static String XML_URI = "http://www.w3.org/XML/1998/namespace".intern(); + + /** + * XML Information Set REC + * all namespace attributes (including those named xmlns, + * whose [prefix] property has no value) have a namespace URI of http://www.w3.org/2000/xmlns/ + */ + public final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/".intern(); + + // + // NamespaceContext methods + // + + /** + * Start a new Namespace context. + *

        + * A new context should be pushed at the beginning + * of each XML element: the new context will automatically inherit + * the declarations of its parent context, but it will also keep + * track of which declarations were made within this context. + *

        + * + * @see #popContext + */ + public void pushContext(); + + /** + * Revert to the previous Namespace context. + *

        + * The context should be popped at the end of each + * XML element. After popping the context, all Namespace prefix + * mappings that were previously in force are restored. + *

        + * Users must not attempt to declare additional Namespace + * prefixes after popping a context, unless you push another + * context first. + * + * @see #pushContext + */ + public void popContext(); + + /** + * Declare a Namespace prefix. + *

        + * This method declares a prefix in the current Namespace + * context; the prefix will remain in force until this context + * is popped, unless it is shadowed in a descendant context. + *

        + * Note that to declare a default Namespace, use the empty string. + * The prefixes "xml" and "xmlns" can't be rebound. + *

        + * Note that you must not declare a prefix after + * you've pushed and popped another Namespace. + * + * @param prefix The prefix to declare, or null for the empty + * string. + * @param uri The Namespace URI to associate with the prefix. + * + * @return true if the prefix was legal, false otherwise + * + * @see #getURI + * @see #getDeclaredPrefixAt + */ + public boolean declarePrefix(String prefix, String uri); + + + /** + * Look up a prefix and get the currently-mapped Namespace URI. + *

        + * This method looks up the prefix in the current context. If no mapping + * is found, this methods will continue lookup in the parent context(s). + * Use the empty string ("") for the default Namespace. + * + * @param prefix The prefix to look up. + * + * @return The associated Namespace URI, or null if the prefix + * is undeclared in this context. + */ + public String getURI(String prefix); + + /** + * Look up a namespace URI and get one of the mapped prefix. + *

        + * This method looks up the namespace URI in the current context. + * If more than one prefix is currently mapped to the same URI, + * this method will make an arbitrary selection + * If no mapping is found, this methods will continue lookup in the + * parent context(s). + * + * @param uri The namespace URI to look up. + * + * @return One of the associated prefixes, or null if the uri + * does not map to any prefix. + * + * @see #getPrefix + */ + public String getPrefix(String uri); + + /** + * Return a count of locally declared prefixes, including + * the default prefix if bound. + */ + public int getDeclaredPrefixCount(); + + /** + * Returns the prefix at the specified index in the current context. + */ + public String getDeclaredPrefixAt(int index); + + /** + * Return an enumeration of all prefixes whose declarations are active + * in the current context. This includes declarations from parent contexts + * that have not been overridden. + * @return Enumeration + */ + public Enumeration getAllPrefixes(); + + /** + * Reset this Namespace support object for reuse. + * + *

        It is necessary to invoke this method before reusing the + * Namespace support object for a new session.

        + * + *

        Note that implementations of this method need to ensure that + * the declaration of the prefixes "xmlns" and "xml" are available.

        + */ + public void reset(); + + + +} // interface NamespaceContext diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/QName.java b/resources/xerces2-j-src/org/apache/xerces/xni/QName.java new file mode 100644 index 0000000..26e8431 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/QName.java @@ -0,0 +1,194 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +/** + * A structure that holds the components of an XML Namespaces qualified + * name. + *

        + * To be used correctly, the strings must be identical references for + * equal strings. Within the parser, these values are considered symbols + * and should always be retrieved from the SymbolTable. + * + * @see org.apache.xerces.util.SymbolTable + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class QName + implements Cloneable { + + // + // Data + // + + /** + * The qname prefix. For example, the prefix for the qname "a:foo" + * is "a". + */ + public String prefix; + + /** + * The qname localpart. For example, the localpart for the qname "a:foo" + * is "foo". + */ + public String localpart; + + /** + * The qname rawname. For example, the rawname for the qname "a:foo" + * is "a:foo". + */ + public String rawname; + + /** + * The URI to which the qname prefix is bound. This binding must be + * performed by a XML Namespaces aware processor. + */ + public String uri; + + // + // Constructors + // + + /** Default constructor. */ + public QName() { + clear(); + } // () + + /** Constructs a QName with the specified values. */ + public QName(String prefix, String localpart, String rawname, String uri) { + setValues(prefix, localpart, rawname, uri); + } // (String,String,String,String) + + /** Constructs a copy of the specified QName. */ + public QName(QName qname) { + setValues(qname); + } // (QName) + + // + // Public methods + // + + /** + * Convenience method to set the values of the qname components. + * + * @param qname The qualified name to be copied. + */ + public void setValues(QName qname) { + prefix = qname.prefix; + localpart = qname.localpart; + rawname = qname.rawname; + uri = qname.uri; + } // setValues(QName) + + /** + * Convenience method to set the values of the qname components. + * + * @param prefix The qname prefix. (e.g. "a") + * @param localpart The qname localpart. (e.g. "foo") + * @param rawname The qname rawname. (e.g. "a:foo") + * @param uri The URI binding. (e.g. "http://foo.com/mybinding") + */ + public void setValues(String prefix, String localpart, String rawname, + String uri) { + this.prefix = prefix; + this.localpart = localpart; + this.rawname = rawname; + this.uri = uri; + } // setValues(String,String,String,String) + + /** Clears the values of the qname components. */ + public void clear() { + prefix = null; + localpart = null; + rawname = null; + uri = null; + } // clear() + + // + // Cloneable methods + // + + /** Returns a clone of this object. */ + public Object clone() { + return new QName(this); + } // clone():Object + + // + // Object methods + // + + /** Returns the hashcode for this object. */ + public int hashCode() { + if (uri != null) { + return uri.hashCode() + + ((localpart != null) ? localpart.hashCode() : 0); + } + return (rawname != null) ? rawname.hashCode() : 0; + } // hashCode():int + + /** Returns true if the two objects are equal. */ + public boolean equals(Object object) { + if (object instanceof QName) { + QName qname = (QName)object; + if (qname.uri != null) { + return uri == qname.uri && localpart == qname.localpart; + } + else if (uri == null) { + return rawname == qname.rawname; + } + // fall through and return not equal + } + return false; + } // equals(Object):boolean + + /** Returns a string representation of this object. */ + public String toString() { + + StringBuffer str = new StringBuffer(); + boolean comma = false; + if (prefix != null) { + str.append("prefix=\"").append(prefix).append('"'); + comma = true; + } + if (localpart != null) { + if (comma) { + str.append(','); + } + str.append("localpart=\"").append(localpart).append('"'); + comma = true; + } + if (rawname != null) { + if (comma) { + str.append(','); + } + str.append("rawname=\"").append(rawname).append('"'); + comma = true; + } + if (uri != null) { + if (comma) { + str.append(','); + } + str.append("uri=\"").append(uri).append('"'); + } + return str.toString(); + + } // toString():String + +} // class QName diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XMLAttributes.java b/resources/xerces2-j-src/org/apache/xerces/xni/XMLAttributes.java new file mode 100644 index 0000000..be378d1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XMLAttributes.java @@ -0,0 +1,389 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +/** + * The XMLAttributes interface defines a collection of attributes for + * an element. In the parser, the document source would scan the entire + * start element and collect the attributes. The attributes are + * communicated to the document handler in the startElement method. + *

        + * The attributes are read-write so that subsequent stages in the document + * pipeline can modify the values or change the attributes that are + * propagated to the next stage. + * + * @see XMLDocumentHandler#startElement + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLAttributes { + + // + // XMLAttributes methods + // + + /** + * Adds an attribute. The attribute's non-normalized value of the + * attribute will have the same value as the attribute value until + * set using the setNonNormalizedValue method. Also, + * the added attribute will be marked as specified in the XML instance + * document unless set otherwise using the setSpecified + * method. + *

        + * Note: If an attribute of the same name already + * exists, the old values for the attribute are replaced by the new + * values. + * + * @param attrName The attribute name. + * @param attrType The attribute type. The type name is determined by + * the type specified for this attribute in the DTD. + * For example: "CDATA", "ID", "NMTOKEN", etc. However, + * attributes of type enumeration will have the type + * value specified as the pipe ('|') separated list of + * the enumeration values prefixed by an open + * parenthesis and suffixed by a close parenthesis. + * For example: "(true|false)". + * @param attrValue The attribute value. + * + * @return Returns the attribute index. + * + * @see #setNonNormalizedValue + * @see #setSpecified + */ + public int addAttribute(QName attrName, String attrType, String attrValue); + + /** + * Removes all of the attributes. This method will also remove all + * entities associated to the attributes. + */ + public void removeAllAttributes(); + + /** + * Removes the attribute at the specified index. + *

        + * Note: This operation changes the indexes of all + * attributes following the attribute at the specified index. + * + * @param attrIndex The attribute index. + */ + public void removeAttributeAt(int attrIndex); + + /** + * Returns the number of attributes in the list. + *

        + * Once you know the number of attributes, you can iterate + * through the list. + * + * @see #getURI(int) + * @see #getLocalName(int) + * @see #getQName(int) + * @see #getType(int) + * @see #getValue(int) + */ + public int getLength(); + + /** + * Look up the index of an attribute by XML 1.0 qualified name. + * + * @param qName The qualified (prefixed) name. + * + * @return The index of the attribute, or -1 if it does not + * appear in the list. + */ + public int getIndex(String qName); + + /** + * Look up the index of an attribute by Namespace name. + * + * @param uri The Namespace URI, or the empty string if + * the name has no Namespace URI. + * @param localPart The attribute's local name. + * + * @return The index of the attribute, or -1 if it does not + * appear in the list. + */ + public int getIndex(String uri, String localPart); + + /** + * Sets the name of the attribute at the specified index. + * + * @param attrIndex The attribute index. + * @param attrName The new attribute name. + */ + public void setName(int attrIndex, QName attrName); + + /** + * Sets the fields in the given QName structure with the values + * of the attribute name at the specified index. + * + * @param attrIndex The attribute index. + * @param attrName The attribute name structure to fill in. + */ + public void getName(int attrIndex, QName attrName); + + /** + * Returns the prefix of the attribute at the specified index. + * + * @param index The index of the attribute. + */ + public String getPrefix(int index); + + /** + * Look up an attribute's Namespace URI by index. + * + * @param index The attribute index (zero-based). + * + * @return The Namespace URI, or the empty string if none + * is available, or null if the index is out of + * range. + * + * @see #getLength + */ + public String getURI(int index); + + /** + * Look up an attribute's local name by index. + * + * @param index The attribute index (zero-based). + * + * @return The local name, or the empty string if Namespace + * processing is not being performed, or null + * if the index is out of range. + * + * @see #getLength + */ + public String getLocalName(int index); + + /** + * Look up an attribute's XML 1.0 qualified name by index. + * + * @param index The attribute index (zero-based). + * + * @return The XML 1.0 qualified name, or the empty string + * if none is available, or null if the index + * is out of range. + * + * @see #getLength + */ + public String getQName(int index); + + /** + * Sets the type of the attribute at the specified index. + * + * @param attrIndex The attribute index. + * @param attrType The attribute type. The type name is determined by + * the type specified for this attribute in the DTD. + * For example: "CDATA", "ID", "NMTOKEN", etc. However, + * attributes of type enumeration will have the type + * value specified as the pipe ('|') separated list of + * the enumeration values prefixed by an open + * parenthesis and suffixed by a close parenthesis. + * For example: "(true|false)". + */ + public void setType(int attrIndex, String attrType); + + /** + * Look up an attribute's type by index. + *

        + * The attribute type is one of the strings "CDATA", "ID", + * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", + * or "NOTATION" (always in upper case). + *

        + * If the parser has not read a declaration for the attribute, + * or if the parser does not report attribute types, then it must + * return the value "CDATA" as stated in the XML 1.0 Recommendation + * (clause 3.3.3, "Attribute-Value Normalization"). + *

        + * For an enumerated attribute that is not a notation, the + * parser will report the type as "NMTOKEN". + * + * @param index The attribute index (zero-based). + * + * @return The attribute's type as a string, or null if the + * index is out of range. + * + * @see #getLength + */ + public String getType(int index); + + /** + * Look up an attribute's type by XML 1.0 qualified name. + *

        + * See {@link #getType(int) getType(int)} for a description + * of the possible types. + * + * @param qName The XML 1.0 qualified name. + * + * @return The attribute type as a string, or null if the + * attribute is not in the list or if qualified names + * are not available. + */ + public String getType(String qName); + + /** + * Look up an attribute's type by Namespace name. + *

        + * See {@link #getType(int) getType(int)} for a description + * of the possible types. + * + * @param uri The Namespace URI, or the empty String if the + * name has no Namespace URI. + * @param localName The local name of the attribute. + * + * @return The attribute type as a string, or null if the + * attribute is not in the list or if Namespace + * processing is not being performed. + */ + public String getType(String uri, String localName); + + /** + * Sets the value of the attribute at the specified index. This + * method will overwrite the non-normalized value of the attribute. + * + * @param attrIndex The attribute index. + * @param attrValue The new attribute value. + * + * @see #setNonNormalizedValue + */ + public void setValue(int attrIndex, String attrValue); + + /** + * Look up an attribute's value by index. + *

        + * If the attribute value is a list of tokens (IDREFS, + * ENTITIES, or NMTOKENS), the tokens will be concatenated + * into a single string with each token separated by a + * single space. + * + * @param index The attribute index (zero-based). + * + * @return The attribute's value as a string, or null if the + * index is out of range. + * + * @see #getLength + */ + public String getValue(int index); + + /** + * Look up an attribute's value by XML 1.0 qualified name. + *

        + * See {@link #getValue(int) getValue(int)} for a description + * of the possible values. + * + * @param qName The XML 1.0 qualified name. + * + * @return The attribute value as a string, or null if the + * attribute is not in the list or if qualified names + * are not available. + */ + public String getValue(String qName); + + /** + * Look up an attribute's value by Namespace name. + *

        + * See {@link #getValue(int) getValue(int)} for a description + * of the possible values. + * + * @param uri The Namespace URI, or the empty String if the + * name has no Namespace URI. + * @param localName The local name of the attribute. + * + * @return The attribute value as a string, or null if the + * attribute is not in the list. + */ + public String getValue(String uri, String localName); + + /** + * Sets the non-normalized value of the attribute at the specified + * index. + * + * @param attrIndex The attribute index. + * @param attrValue The new non-normalized attribute value. + */ + public void setNonNormalizedValue(int attrIndex, String attrValue); + + /** + * Returns the non-normalized value of the attribute at the specified + * index. If no non-normalized value is set, this method will return + * the same value as the getValue(int) method. + * + * @param attrIndex The attribute index. + */ + public String getNonNormalizedValue(int attrIndex); + + /** + * Sets whether an attribute is specified in the instance document + * or not. + * + * @param attrIndex The attribute index. + * @param specified True if the attribute is specified in the instance + * document. + */ + public void setSpecified(int attrIndex, boolean specified); + + /** + * Returns true if the attribute is specified in the instance document. + * + * @param attrIndex The attribute index. + */ + public boolean isSpecified(int attrIndex); + + + /** + * Look up an augmentation by attribute's index. + * + * @param attributeIndex The attribute index. + * @return Augmentations + */ + public Augmentations getAugmentations (int attributeIndex); + + /** + * Look up an augmentation by namespace name. + * + * @param uri The Namespace URI, or the empty string if + * the name has no Namespace URI. + * @param localPart + * @return Augmentations + */ + public Augmentations getAugmentations (String uri, String localPart); + + + /** + * Look up an augmentation by XML 1.0 qualified name. + *

        + * + * @param qName The XML 1.0 qualified name. + * + * @return Augmentations + * + */ + public Augmentations getAugmentations(String qName); + + + /** + * Sets the augmentations of the attribute at the specified index. + * + * @param attrIndex The attribute index. + * @param augs The augmentations. + */ + public void setAugmentations(int attrIndex, Augmentations augs); + + +} // interface XMLAttributes diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XMLDTDContentModelHandler.java b/resources/xerces2-j-src/org/apache/xerces/xni/XMLDTDContentModelHandler.java new file mode 100644 index 0000000..111d043 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XMLDTDContentModelHandler.java @@ -0,0 +1,271 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +import org.apache.xerces.xni.parser.XMLDTDContentModelSource; + +/** + * The DTD content model handler interface defines callback methods + * to report information items in DTD content models of an element + * declaration. Parser components interested in DTD content model + * information implement this interface and are registered as the DTD + * content model handler on the DTD content model source. + * + * @see XMLDTDHandler + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDTDContentModelHandler { + + // + // Constants + // + + // separators + + /** + * A choice separator for children and mixed content models. This + * separator is used to specify that the allowed child is one of a + * collection. + *

        + * For example: + *

        +     * <!ELEMENT elem (foo|bar)>
        +     * <!ELEMENT elem (foo|bar+)>
        +     * <!ELEMENT elem (foo|bar|baz)>
        +     * <!ELEMENT elem (#PCDATA|foo|bar)*>
        +     * 
        + * + * @see #SEPARATOR_SEQUENCE + */ + public static final short SEPARATOR_CHOICE = 0; + + /** + * A sequence separator for children content models. This separator + * is used to specify that the allowed children must follow in the + * specified sequence. + *

        + *

        +     * <!ELEMENT elem (foo,bar)>
        +     * <!ELEMENT elem (foo,bar*)>
        +     * <!ELEMENT elem (foo,bar,baz)>
        +     * 
        + * + * @see #SEPARATOR_CHOICE + */ + public static final short SEPARATOR_SEQUENCE = 1; + + // occurrence counts + + /** + * This occurrence count limits the element, choice, or sequence in a + * children content model to zero or one. In other words, the child + * is optional. + *

        + * For example: + *

        +     * <!ELEMENT elem (foo?)>
        +     * 
        + * + * @see #OCCURS_ZERO_OR_MORE + * @see #OCCURS_ONE_OR_MORE + */ + public static final short OCCURS_ZERO_OR_ONE = 2; + + /** + * This occurrence count limits the element, choice, or sequence in a + * children content model to zero or more. In other words, the child + * may appear an arbitrary number of times, or not at all. This + * occurrence count is also used for mixed content models. + *

        + * For example: + *

        +     * <!ELEMENT elem (foo*)>
        +     * <!ELEMENT elem (#PCDATA|foo|bar)*>
        +     * 
        + * + * @see #OCCURS_ZERO_OR_ONE + * @see #OCCURS_ONE_OR_MORE + */ + public static final short OCCURS_ZERO_OR_MORE = 3; + + /** + * This occurrence count limits the element, choice, or sequence in a + * children content model to one or more. In other words, the child + * may appear an arbitrary number of times, but must appear at least + * once. + *

        + * For example: + *

        +     * <!ELEMENT elem (foo+)>
        +     * 
        + * + * @see #OCCURS_ZERO_OR_ONE + * @see #OCCURS_ZERO_OR_MORE + */ + public static final short OCCURS_ONE_OR_MORE = 4; + + // + // XMLDTDContentModelHandler methods + // + + /** + * The start of a content model. Depending on the type of the content + * model, specific methods may be called between the call to the + * startContentModel method and the call to the endContentModel method. + * + * @param elementName The name of the element. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startContentModel(String elementName, Augmentations augmentations) + throws XNIException; + + /** + * A content model of ANY. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #empty + * @see #startGroup + */ + public void any(Augmentations augmentations) throws XNIException; + + /** + * A content model of EMPTY. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @see #any + * @see #startGroup + */ + public void empty(Augmentations augmentations) throws XNIException; + + /** + * A start of either a mixed or children content model. A mixed + * content model will immediately be followed by a call to the + * pcdata() method. A children content model will + * contain additional groups and/or elements. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #any + * @see #empty + */ + public void startGroup(Augmentations augmentations) throws XNIException; + + /** + * The appearance of "#PCDATA" within a group signifying a + * mixed content model. This method will be the first called + * following the content model's startGroup(). + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #startGroup + */ + public void pcdata(Augmentations augmentations) throws XNIException; + + /** + * A referenced element in a mixed or children content model. + * + * @param elementName The name of the referenced element. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void element(String elementName, Augmentations augmentations) + throws XNIException; + + /** + * The separator between choices or sequences of a mixed or children + * content model. + * + * @param separator The type of children separator. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #SEPARATOR_CHOICE + * @see #SEPARATOR_SEQUENCE + */ + public void separator(short separator, Augmentations augmentations) + throws XNIException; + + /** + * The occurrence count for a child in a children content model or + * for the mixed content model group. + * + * @param occurrence The occurrence count for the last element + * or group. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #OCCURS_ZERO_OR_ONE + * @see #OCCURS_ZERO_OR_MORE + * @see #OCCURS_ONE_OR_MORE + */ + public void occurrence(short occurrence, Augmentations augmentations) + throws XNIException; + + /** + * The end of a group for mixed or children content models. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endGroup(Augmentations augmentations) throws XNIException; + + /** + * The end of a content model. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endContentModel(Augmentations augmentations) throws XNIException; + + // set content model source + public void setDTDContentModelSource(XMLDTDContentModelSource source); + + // get content model source + public XMLDTDContentModelSource getDTDContentModelSource(); + +} // interface XMLDTDContentModelHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XMLDTDHandler.java b/resources/xerces2-j-src/org/apache/xerces/xni/XMLDTDHandler.java new file mode 100644 index 0000000..59cec6e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XMLDTDHandler.java @@ -0,0 +1,376 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +import org.apache.xerces.xni.parser.XMLDTDSource; + +/** + * The DTD handler interface defines callback methods to report + * information items in the DTD of an XML document. Parser components + * interested in DTD information implement this interface and are + * registered as the DTD handler on the DTD source. + * + * @see XMLDTDContentModelHandler + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDTDHandler { + + // + // Constants + // + + /** + * Conditional section: INCLUDE. + * + * @see #CONDITIONAL_IGNORE + */ + public static final short CONDITIONAL_INCLUDE = 0; + + /** + * Conditional section: IGNORE. + * + * @see #CONDITIONAL_INCLUDE + */ + public static final short CONDITIONAL_IGNORE = 1; + + // + // XMLDTDHandler methods + // + + /** + * The start of the DTD. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing of + * the document DTD. However, it is strongly + * recommended that a locator be supplied that can + * at least report the base system identifier of the + * DTD. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDTD(XMLLocator locator, Augmentations augmentations) + throws XNIException; + + /** + * This method notifies of the start of a parameter entity. The parameter + * entity name start with a '%' character. + * + * @param name The name of the parameter entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal parameter entities). + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startParameterEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augmentations) throws XNIException; + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

        + * Note: This method is only called for external + * parameter entities referenced in the DTD. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, + Augmentations augmentations) throws XNIException; + + /** + * This method notifies the end of a parameter entity. Parameter entity + * names begin with a '%' character. + * + * @param name The name of the parameter entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endParameterEntity(String name, Augmentations augmentations) + throws XNIException; + + /** + * The start of the DTD external subset. + * + * @param identifier The resource identifier. + * @param augmentations + * Additional information that may include infoset + * augmentations. + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startExternalSubset(XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException; + + /** + * The end of the DTD external subset. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endExternalSubset(Augmentations augmentations) + throws XNIException; + + /** + * A comment. + * + * @param text The text in the comment. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augmentations) + throws XNIException; + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, + Augmentations augmentations) + throws XNIException; + + /** + * An element declaration. + * + * @param name The name of the element. + * @param contentModel The element content model. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void elementDecl(String name, String contentModel, + Augmentations augmentations) + throws XNIException; + + /** + * The start of an attribute list. + * + * @param elementName The name of the element that this attribute + * list is associated with. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startAttlist(String elementName, + Augmentations augmentations) throws XNIException; + + /** + * An attribute declaration. + * + * @param elementName The name of the element that this attribute + * is associated with. + * @param attributeName The name of the attribute. + * @param type The attribute type. This value will be one of + * the following: "CDATA", "ENTITY", "ENTITIES", + * "ENUMERATION", "ID", "IDREF", "IDREFS", + * "NMTOKEN", "NMTOKENS", or "NOTATION". + * @param enumeration If the type has the value "ENUMERATION" or + * "NOTATION", this array holds the allowed attribute + * values; otherwise, this array is null. + * @param defaultType The attribute default type. This value will be + * one of the following: "#FIXED", "#IMPLIED", + * "#REQUIRED", or null. + * @param defaultValue The attribute default value, or null if no + * default value is specified. + * @param nonNormalizedDefaultValue The attribute default value with no normalization + * performed, or null if no default value is specified. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void attributeDecl(String elementName, String attributeName, + String type, String[] enumeration, + String defaultType, XMLString defaultValue, + XMLString nonNormalizedDefaultValue, Augmentations augmentations) + throws XNIException; + + /** + * The end of an attribute list. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endAttlist(Augmentations augmentations) throws XNIException; + + /** + * An internal entity declaration. + * + * @param name The name of the entity. Parameter entity names start with + * '%', whereas the name of a general entity is just the + * entity name. + * @param text The value of the entity. + * @param nonNormalizedText The non-normalized value of the entity. This + * value contains the same sequence of characters that was in + * the internal entity declaration, without any entity + * references expanded. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void internalEntityDecl(String name, XMLString text, + XMLString nonNormalizedText, + Augmentations augmentations) + throws XNIException; + + /** + * An external entity declaration. + * + * @param name The name of the entity. Parameter entity names start + * with '%', whereas the name of a general entity is just + * the entity name. + * @param identifier An object containing all location information + * pertinent to this external entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void externalEntityDecl(String name, + XMLResourceIdentifier identifier, + Augmentations augmentations) + throws XNIException; + + /** + * An unparsed entity declaration. + * + * @param name The name of the entity. + * @param identifier An object containing all location information + * pertinent to this unparsed entity declaration. + * @param notation The name of the notation. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void unparsedEntityDecl(String name, + XMLResourceIdentifier identifier, + String notation, Augmentations augmentations) + throws XNIException; + + /** + * A notation declaration + * + * @param name The name of the notation. + * @param identifier An object containing all location information + * pertinent to this notation. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void notationDecl(String name, XMLResourceIdentifier identifier, + Augmentations augmentations) throws XNIException; + + /** + * The start of a conditional section. + * + * @param type The type of the conditional section. This value will + * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + * + * @see #CONDITIONAL_INCLUDE + * @see #CONDITIONAL_IGNORE + */ + public void startConditional(short type, Augmentations augmentations) + throws XNIException; + + /** + * Characters within an IGNORE conditional section. + * + * @param text The ignored text. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignoredCharacters(XMLString text, Augmentations augmentations) + throws XNIException; + + /** + * The end of a conditional section. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endConditional(Augmentations augmentations) throws XNIException; + + /** + * The end of the DTD. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDTD(Augmentations augmentations) throws XNIException; + + // set the source of this handler + public void setDTDSource(XMLDTDSource source); + + // return the source from which this handler derives its events + public XMLDTDSource getDTDSource(); + +} // interface XMLDTDHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XMLDocumentFragmentHandler.java b/resources/xerces2-j-src/org/apache/xerces/xni/XMLDocumentFragmentHandler.java new file mode 100644 index 0000000..20f1632 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XMLDocumentFragmentHandler.java @@ -0,0 +1,257 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +/** + * This handler interface contains methods necessary to receive + * information about document elements and content. + *

        + * Note: Some of these methods overlap methods + * found in the XMLDocumentHandler interface. + * + * @see XMLDocumentHandler + * + * @author Andy Clark, IBM + * @version $Id$ + */ +public interface XMLDocumentFragmentHandler { + + // + // XMLDocumentFragmentHandler methods + // + + /** + * The start of the document fragment. + * + * @param locator The document locator, or null if the + * document location cannot be reported + * during the parsing of this fragment. + * However, it is strongly + * recommended that a locator be supplied + * that can at least report the base + * system identifier. + * @param namespaceContext The namespace context in effect at the + * start of this document fragment. This + * object only represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startDocumentFragment(XMLLocator locator, + NamespaceContext namespaceContext, + Augmentations augmentations) + throws XNIException; + + /** + * This method notifies the start of a general entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augmentations) throws XNIException; + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

        + * Note: This method will never be called for the + * document entity; it is only called for external general entities + * referenced in document content. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, + Augmentations augmentations) throws XNIException; + + /** + * This method notifies the end of a general entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augmentations) + throws XNIException; + + /** + * A comment. + * + * @param text The text in the comment. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augmentations) + throws XNIException; + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, + Augmentations augmentations) + throws XNIException; + + /** + * The start of an element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, + Augmentations augmentations) throws XNIException; + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, + Augmentations augmentations) throws XNIException; + + /** + * Character content. + * + * @param text The content. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augmentations) + throws XNIException; + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, + Augmentations augmentations) + throws XNIException; + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augmentations) + throws XNIException; + + /** + * The start of a CDATA section. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augmentations) throws XNIException; + + /** + * The end of a CDATA section. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augmentations) throws XNIException; + + /** + * The end of the document fragment. + * + * @param augmentations Additional information that may include infoset + * augmentations. + * + * @throws XNIException Thrown by handler to signal an error. + */ + public void endDocumentFragment(Augmentations augmentations) + throws XNIException; + +} // interface XMLDocumentFragmentHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XMLDocumentHandler.java b/resources/xerces2-j-src/org/apache/xerces/xni/XMLDocumentHandler.java new file mode 100644 index 0000000..e52e9f1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XMLDocumentHandler.java @@ -0,0 +1,294 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +import org.apache.xerces.xni.parser.XMLDocumentSource; + +/** + * The document handler interface defines callback methods to report + * information items in XML documents. Parser components interested in + * document information implement this interface and are registered + * as the document handler on the document source. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDocumentHandler { + + // + // XMLDocumentHandler methods + // + + /** + * The start of the document. + * + * @param locator The document locator, or null if the document + * location cannot be reported during the parsing + * of this document. However, it is strongly + * recommended that a locator be supplied that can + * at least report the system identifier of the + * document. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param namespaceContext + * The namespace context in effect at the + * start of this document. + * This object represents the current context. + * Implementors of this class are responsible + * for copying the namespace bindings from the + * the current context (and its parent contexts) + * if that information is important. + * + * @param augs Additional information that may include infoset augmentations + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startDocument(XMLLocator locator, String encoding, + NamespaceContext namespaceContext, + Augmentations augs) + throws XNIException; + + /** + * Notifies of the presence of an XMLDecl line in the document. If + * present, this method will be called immediately following the + * startDocument call. + * + * @param version The XML version. + * @param encoding The IANA encoding name of the document, or null if + * not specified. + * @param standalone The standalone value, or null if not specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) + throws XNIException; + + /** + * Notifies of the presence of the DOCTYPE line in the document. + * + * @param rootElement + * The name of the root element. + * @param publicId The public identifier if an external DTD or null + * if the external DTD is specified using SYSTEM. + * @param systemId The system identifier if an external DTD, null + * otherwise. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) + throws XNIException; + + /** + * A comment. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException; + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, Augmentations augs) + throws XNIException; + + /** + * The start of an element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException; + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) + throws XNIException; + + /** + * This method notifies the start of a general entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the general entity. + * @param identifier The resource identifier. + * @param encoding The auto-detected IANA encoding name of the entity + * stream. This value will be null in those situations + * where the entity encoding is not auto-detected (e.g. + * internal entities or a document entity that is + * parsed from a java.io.Reader). + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException Thrown by handler to signal an error. + */ + public void startGeneralEntity(String name, + XMLResourceIdentifier identifier, + String encoding, + Augmentations augs) throws XNIException; + + /** + * Notifies of the presence of a TextDecl line in an entity. If present, + * this method will be called immediately following the startEntity call. + *

        + * Note: This method will never be called for the + * document entity; it is only called for external general entities + * referenced in document content. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param version The XML version, or null if not specified. + * @param encoding The IANA encoding name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void textDecl(String version, String encoding, Augmentations augs) throws XNIException; + + /** + * This method notifies the end of a general entity. + *

        + * Note: This method is not called for entity references + * appearing as part of attribute values. + * + * @param name The name of the entity. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endGeneralEntity(String name, Augmentations augs) throws XNIException; + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) throws XNIException; + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException; + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) throws XNIException; + + /** + * The start of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException; + + /** + * The end of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException; + + /** + * The end of the document. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endDocument(Augmentations augs) throws XNIException; + + + /** Sets the document source. */ + public void setDocumentSource(XMLDocumentSource source); + + + /** Returns the document source. */ + public XMLDocumentSource getDocumentSource(); + +} // interface XMLDocumentHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XMLLocator.java b/resources/xerces2-j-src/org/apache/xerces/xni/XMLLocator.java new file mode 100644 index 0000000..4caf223 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XMLLocator.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +/** + * Location information. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLLocator { + + // + // XMLLocator methods + // + + /** Returns the public identifier. */ + public String getPublicId(); + + /** Returns the literal system identifier. */ + public String getLiteralSystemId(); + + /** Returns the base system identifier. */ + public String getBaseSystemId(); + + /** Returns the expanded system identifier. */ + public String getExpandedSystemId(); + + /** Returns the line number, or -1 if no line number is available. */ + public int getLineNumber(); + + /** Returns the column number, or -1 if no column number is available. */ + public int getColumnNumber(); + + /** Returns the character offset, or -1 if no character offset is available. */ + public int getCharacterOffset(); + + /** + * Returns the encoding of the current entity. + * Note that, for a given entity, this value can only be + * considered final once the encoding declaration has been read (or once it + * has been determined that there is no such declaration) since, no encoding + * having been specified on the XMLInputSource, the parser + * will make an initial "guess" which could be in error. + */ + public String getEncoding(); + + /** + * Returns the XML version of the current entity. This will normally be the + * value from the XML or text declaration or defaulted by the parser. Note that + * that this value may be different than the version of the processing rules + * applied to the current entity. For instance, an XML 1.1 document may refer to + * XML 1.0 entities. In such a case the rules of XML 1.1 are applied to the entire + * document. Also note that, for a given entity, this value can only be considered + * final once the XML or text declaration has been read or once it has been + * determined that there is no such declaration. + */ + public String getXMLVersion(); + + +} // interface XMLLocator diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XMLResourceIdentifier.java b/resources/xerces2-j-src/org/apache/xerces/xni/XMLResourceIdentifier.java new file mode 100644 index 0000000..621452d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XMLResourceIdentifier.java @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +/** + *

        This represents the basic physical description of the location of any + * XML resource (a Schema grammar, a DTD, a general entity etc.)

        + * + * @author Neil Graham, IBM + * @version $Id$ + */ + +public interface XMLResourceIdentifier { + + /** Sets the public identifier. */ + public void setPublicId(String publicId); + + /** Returns the public identifier. */ + public String getPublicId(); + + /** Sets the expanded system identifier. */ + public void setExpandedSystemId(String systemId); + + /** Returns the expanded system identifier. */ + public String getExpandedSystemId(); + + /** Sets the literal system identifier. */ + public void setLiteralSystemId(String systemId); + + /** Returns the literal system identifier. */ + public String getLiteralSystemId(); + + /** Sets the base URI against which the literal SystemId is to be + resolved.*/ + public void setBaseSystemId(String systemId); + + /**

        Returns the base URI against which the literal SystemId is to be + resolved.

        */ + public String getBaseSystemId(); + + /** Sets the namespace of the resource. */ + public void setNamespace(String namespace); + + /** Returns the namespace of the resource. */ + public String getNamespace(); + +} // XMLResourceIdentifier diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XMLString.java b/resources/xerces2-j-src/org/apache/xerces/xni/XMLString.java new file mode 100644 index 0000000..bfa8661 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XMLString.java @@ -0,0 +1,189 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +/** + * This class is used as a structure to pass text contained in the underlying + * character buffer of the scanner. The offset and length fields allow the + * buffer to be re-used without creating new character arrays. + *

        + * Note: Methods that are passed an XMLString structure + * should consider the contents read-only and not make any modifications + * to the contents of the buffer. The method receiving this structure + * should also not modify the offset and length if this structure (or + * the values of this structure) are passed to another method. + *

        + * Note: Methods that are passed an XMLString structure + * are required to copy the information out of the buffer if it is to be + * saved for use beyond the scope of the method. The contents of the + * structure are volatile and the contents of the character buffer cannot + * be assured once the method that is passed this structure returns. + * Therefore, methods passed this structure should not save any reference + * to the structure or the character array contained in the structure. + * + * @author Eric Ye, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XMLString { + + // + // Data + // + + /** The character array. */ + public char[] ch; + + /** The offset into the character array. */ + public int offset; + + /** The length of characters from the offset. */ + public int length; + + // + // Constructors + // + + /** Default constructor. */ + public XMLString() { + } // () + + /** + * Constructs an XMLString structure preset with the specified + * values. + * + * @param ch The character array. + * @param offset The offset into the character array. + * @param length The length of characters from the offset. + */ + public XMLString(char[] ch, int offset, int length) { + setValues(ch, offset, length); + } // (char[],int,int) + + /** + * Constructs an XMLString structure with copies of the values in + * the given structure. + *

        + * Note: This does not copy the character array; + * only the reference to the array is copied. + * + * @param string The XMLString to copy. + */ + public XMLString(XMLString string) { + setValues(string); + } // (XMLString) + + // + // Public methods + // + + /** + * Initializes the contents of the XMLString structure with the + * specified values. + * + * @param ch The character array. + * @param offset The offset into the character array. + * @param length The length of characters from the offset. + */ + public void setValues(char[] ch, int offset, int length) { + this.ch = ch; + this.offset = offset; + this.length = length; + } // setValues(char[],int,int) + + /** + * Initializes the contents of the XMLString structure with copies + * of the given string structure. + *

        + * Note: This does not copy the character array; + * only the reference to the array is copied. + * + * @param s + */ + public void setValues(XMLString s) { + setValues(s.ch, s.offset, s.length); + } // setValues(XMLString) + + /** Resets all of the values to their defaults. */ + public void clear() { + this.ch = null; + this.offset = 0; + this.length = -1; + } // clear() + + /** + * Returns true if the contents of this XMLString structure and + * the specified array are equal. + * + * @param ch The character array. + * @param offset The offset into the character array. + * @param length The length of characters from the offset. + */ + public boolean equals(char[] ch, int offset, int length) { + if (ch == null) { + return false; + } + if (this.length != length) { + return false; + } + + for (int i=0; i 0 ? new String(ch, offset, length) : ""; + } // toString():String + +} // class XMLString diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/XNIException.java b/resources/xerces2-j-src/org/apache/xerces/xni/XNIException.java new file mode 100644 index 0000000..31008a2 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/XNIException.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package org.apache.xerces.xni; + +/** + * This exception is the base exception of all XNI exceptions. It + * can be constructed with an error message or used to wrap another + * exception object. + *

        + * Note: By extending the Java + * RuntimeException, XNI handlers and components are + * not required to catch XNI exceptions but may explicitly catch + * them, if so desired. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XNIException + extends RuntimeException { + + /** Serialization version. */ + static final long serialVersionUID = 9019819772686063775L; + + // + // Data + // + + /** The wrapped exception. */ + private Exception fException = this; + + // + // Constructors + // + + /** + * Constructs an XNI exception with a message. + * + * @param message The exception message. + */ + public XNIException(String message) { + super(message); + } // (String) + + /** + * Constructs an XNI exception with a wrapped exception. + * + * @param exception The wrapped exception. + */ + public XNIException(Exception exception) { + super(exception.getMessage()); + fException = exception; + } // (Exception) + + /** + * Constructs an XNI exception with a message and wrapped exception. + * + * @param message The exception message. + * @param exception The wrapped exception. + */ + public XNIException(String message, Exception exception) { + super(message); + fException = exception; + } // (Exception,String) + + // + // Public methods + // + + /** Returns the wrapped exception. */ + public Exception getException() { + return fException != this ? fException : null; + } // getException():Exception + + /** + * Initializes the cause of this XNIException. + * The value must be an instance of Exception or + * null. + * + * @param throwable the cause + * @return this exception + * + * @throws IllegalStateException if a cause has already been set + * @throws IllegalArgumentException if the cause is this exception + * @throws ClassCastException if the cause is not assignable to Exception + */ + public synchronized Throwable initCause(Throwable throwable) { + if (fException != this) { + // TODO: Add error message. + throw new IllegalStateException(); + } + if (throwable == this) { + // TODO: Add error message. + throw new IllegalArgumentException(); + } + fException = (Exception) throwable; + return this; + } // initCause(Throwable):Throwable + + /** Returns the cause of this XNIException. */ + public Throwable getCause() { + return getException(); + } // getCause():Throwable + +} // class XNIException diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/grammars/Grammar.java b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/Grammar.java new file mode 100644 index 0000000..da9d979 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/Grammar.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.grammars; + +/** + * A generic grammar for use in validating XML documents. The Grammar + * object stores the validation information in a compiled form. Specific + * subclasses extend this class and "populate" the grammar by compiling + * the specific syntax (DTD, Schema, etc) into the data structures used + * by this object. + *

        + * Note: The Grammar object is not useful as a generic + * grammar access or query object. In other words, you cannot round-trip + * specific grammar syntaxes with the compiled grammar information in + * the Grammar object. You can create equivalent validation + * rules in your choice of grammar syntax but there is no guarantee that + * the input and output will be the same. + * + *

        Right now, this class is largely a shell; eventually, + * it will be enriched by having more expressive methods added.

        + * will be moved from dtd.Grammar here. + * + * @author Jeffrey Rodriguez, IBM + * @author Eric Ye, IBM + * @author Andy Clark, IBM + * @author Neil Graham, IBM + * + * @version $Id$ + */ + +public interface Grammar { + + /** + * get the XMLGrammarDescription associated with this + * object + */ + public XMLGrammarDescription getGrammarDescription (); +} // interface Grammar + diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLDTDDescription.java b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLDTDDescription.java new file mode 100644 index 0000000..9bda5e4 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLDTDDescription.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.grammars; + +/** + * All information specific to DTD grammars. + * + * @author Sandy Gao, IBM + * @version $Id$ + */ +public interface XMLDTDDescription extends XMLGrammarDescription { + + /** + * Return the root name of this DTD. + * + * @return the root name. null if the name is unknown. + */ + public String getRootName(); + +} // interface XMLDTDDescription diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarDescription.java b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarDescription.java new file mode 100644 index 0000000..279466f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarDescription.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.grammars; + +import org.apache.xerces.xni.XMLResourceIdentifier; + +/** + *

        This interface describes basic attributes of XML grammars--their + * physical location and their type.

        + * + * @author Neil Graham, IBM + * @version $Id$ + */ +public interface XMLGrammarDescription extends XMLResourceIdentifier { + + // initial set of grammar constants that some configurations will recognize;user + // components which create and/or recognize other types of grammars may + // certainly use their own constants in place of these (so long as + // their Grammar objects implement this interface). + + /** + * The grammar type constant for XML Schema grammars. When getGrammarType() + * method returns this constant, the object should be an instance of + * the XMLSchemaDescription interface. + */ + public static final String XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; + + /** + * The grammar type constant for DTD grammars. When getGrammarType() + * method returns this constant, the object should be an instance of + * the XMLDTDDescription interface. + */ + public static final String XML_DTD = "http://www.w3.org/TR/REC-xml"; + + /** + * Return the type of this grammar. + * + * @return the type of this grammar + */ + public String getGrammarType(); + +} // interface XMLGrammarDescription diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarLoader.java b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarLoader.java new file mode 100644 index 0000000..1379b93 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarLoader.java @@ -0,0 +1,146 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.grammars; + +import java.io.IOException; +import java.util.Locale; + +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; + +/** + * The intention of this interface is to provide a generic means + * by which Grammar objects may be created without parsing instance + * documents. Implementations of this interface will know how to load + * specific types of grammars (e.g., DTD's or schemas); a wrapper + * will be provided for user applications to interact with these implementations. + * + * @author Neil Graham, IBM + * @version $Id$ + */ + +public interface XMLGrammarLoader { + + /** + * Returns a list of feature identifiers that are recognized by + * this XMLGrammarLoader. This method may return null if no features + * are recognized. + */ + public String[] getRecognizedFeatures(); + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * + * @throws XMLConfigurationException Thrown on configuration error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException; + + /** + * Sets the state of a feature. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws XMLConfigurationException Thrown when a feature is not + * recognized or cannot be set. + */ + public void setFeature(String featureId, + boolean state) throws XMLConfigurationException; + + /** + * Returns a list of property identifiers that are recognized by + * this XMLGrammarLoader. This method may return null if no properties + * are recognized. + */ + public String[] getRecognizedProperties(); + + /** + * Returns the state of a property. + * + * @param propertyId The property identifier. + * + * @throws XMLConfigurationException Thrown on configuration error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException; + + /** + * Sets the state of a property. + * + * @param propertyId The property identifier. + * @param state The state of the property. + * + * @throws XMLConfigurationException Thrown when a property is not + * recognized or cannot be set. + */ + public void setProperty(String propertyId, + Object state) throws XMLConfigurationException; + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale); + + /** Return the Locale the XMLGrammarLoader is using. */ + public Locale getLocale(); + + /** + * Sets the error handler. + * + * @param errorHandler The error handler. + */ + public void setErrorHandler(XMLErrorHandler errorHandler); + + /** Returns the registered error handler. */ + public XMLErrorHandler getErrorHandler(); + + /** + * Sets the entity resolver. + * + * @param entityResolver The new entity resolver. + */ + public void setEntityResolver(XMLEntityResolver entityResolver); + + /** Returns the registered entity resolver. */ + public XMLEntityResolver getEntityResolver(); + + /** + * Returns a Grammar object by parsing the contents of the + * entity pointed to by source. + * + * @param source the location of the entity which forms + * the starting point of the grammar to be constructed. + * @throws IOException When a problem is encountered reading the entity + * XNIException When a condition arises (such as a FatalError) that requires parsing + * of the entity be terminated. + */ + public Grammar loadGrammar(XMLInputSource source) + throws IOException, XNIException; +} // XMLGrammarLoader + diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarPool.java b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarPool.java new file mode 100644 index 0000000..2cdeefa --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLGrammarPool.java @@ -0,0 +1,104 @@ +/* + * 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. + */ +package org.apache.xerces.xni.grammars; + +/** + *

        This interface specifies how the parser and the application + * interact with respect to Grammar objects that the application + * possesses--either by having precompiled them or by having stored them + * from a previous validation of an instance document. It makes no + * assumptions about the kind of Grammar involved, or about how the + * application's storage mechanism works.

        + * + *

        The interaction works as follows: + *

          + *
        • When a validator considers a document, it is expected to request + * grammars of the type it can handle from this object using the + * retrieveInitialGrammarSet method.
        • + *
        • If it requires a grammar + * not in this set, it will request it from this Object using the + * retrieveGrammar method.
        • + *
        • After successfully validating an + * instance, the validator should make any new grammars it has compiled + * available to this object using the cacheGrammars + * method; for ease of implementation it may make other Grammars it holds references to as well (i.e., + * it may return some grammars that were retrieved from the GrammarPool in earlier operations).

        + * + * @author Neil Graham, IBM + * @version $Id$ + */ + +public interface XMLGrammarPool { + + //

        we are trying to make this XMLGrammarPool work for all kinds of + // grammars, so we have a parameter "grammarType" for each of the + // methods.

        + + /** + *

        retrieve the initial known set of grammars. this method is + * called by a validator before the validation starts. the application + * can provide an initial set of grammars available to the current + * validation attempt.

        + * @param grammarType the type of the grammar, from the + * org.apache.xerces.xni.grammars.Grammar interface. + * @return the set of grammars the validator may put in its "bucket" + */ + public Grammar[] retrieveInitialGrammarSet(String grammarType); + + /** + *

        return the final set of grammars that the validator ended up + * with. + * This method is called after the + * validation finishes. The application may then choose to cache some + * of the returned grammars.

        + * @param grammarType the type of the grammars being returned; + * @param grammars an array containing the set of grammars being + * returned; order is not significant. + */ + public void cacheGrammars(String grammarType, Grammar[] grammars); + + /** + *

        This method requests that the application retrieve a grammar + * corresponding to the given GrammarIdentifier from its cache. + * If it cannot do so it must return null; the parser will then + * call the EntityResolver. An application must not call its + * EntityResolver itself from this method; this may result in infinite + * recursions. + * @param desc The description of the Grammar being requested. + * @return the Grammar corresponding to this description or null if + * no such Grammar is known. + */ + public Grammar retrieveGrammar(XMLGrammarDescription desc); + + /** + * Causes the XMLGrammarPool not to store any grammars when + * the cacheGrammars(String, Grammar[[]) method is called. + */ + public void lockPool(); + + /** + * Allows the XMLGrammarPool to store grammars when its cacheGrammars(String, Grammar[]) + * method is called. This is the default state of the object. + */ + public void unlockPool(); + + /** + * Removes all grammars from the pool. + */ + public void clear(); +} // XMLGrammarPool + diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLSchemaDescription.java b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLSchemaDescription.java new file mode 100644 index 0000000..b8220a6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XMLSchemaDescription.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.grammars; + +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; + +/** + * All information specific to XML Schema grammars. + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public interface XMLSchemaDescription extends XMLGrammarDescription { + + // used to indicate what triggered the call + /** + * Indicate that the current schema document is <include>d by another + * schema document. + */ + public final static short CONTEXT_INCLUDE = 0; + /** + * Indicate that the current schema document is <redefine>d by another + * schema document. + */ + public final static short CONTEXT_REDEFINE = 1; + /** + * Indicate that the current schema document is <import>ed by another + * schema document. + */ + public final static short CONTEXT_IMPORT = 2; + /** + * Indicate that the current schema document is being preparsed. + */ + public final static short CONTEXT_PREPARSE = 3; + /** + * Indicate that the parse of the current schema document is triggered + * by xsi:schemaLocation/noNamespaceSchemaLocation attribute(s) in the + * instance document. This value is only used if we don't defer the loading + * of schema documents. + */ + public final static short CONTEXT_INSTANCE = 4; + /** + * Indicate that the parse of the current schema document is triggered by + * the occurrence of an element whose namespace is the target namespace + * of this schema document. This value is only used if we do defer the + * loading of schema documents until a component from that namespace is + * referenced from the instance. + */ + public final static short CONTEXT_ELEMENT = 5; + /** + * Indicate that the parse of the current schema document is triggered by + * the occurrence of an attribute whose namespace is the target namespace + * of this schema document. This value is only used if we do defer the + * loading of schema documents until a component from that namespace is + * referenced from the instance. + */ + public final static short CONTEXT_ATTRIBUTE = 6; + /** + * Indicate that the parse of the current schema document is triggered by + * the occurrence of an "xsi:type" attribute, whose value (a QName) has + * the target namespace of this schema document as its namespace. + * This value is only used if we do defer the loading of schema documents + * until a component from that namespace is referenced from the instance. + */ + public final static short CONTEXT_XSITYPE = 7; + + /** + * Get the context. The returned value is one of the pre-defined + * CONTEXT_xxx constants. + * + * @return the value indicating the context + */ + public short getContextType(); + + /** + * If the context is "include" or "redefine", then return the target + * namespace of the enclosing schema document; otherwise, the expected + * target namespace of this document. + * + * @return the expected/enclosing target namespace + */ + public String getTargetNamespace(); + + /** + * For import and references from the instance document, it's possible to + * have multiple hints for one namespace. So this method returns an array, + * which contains all location hints. + * + * @return an array of all location hints associated to the expected + * target namespace + */ + public String[] getLocationHints(); + + /** + * If a call is triggered by an element/attribute/xsi:type in the instance, + * this call returns the name of such triggering component: the name of + * the element/attribute, or the value of the xsi:type. + * + * @return the name of the triggering component + */ + public QName getTriggeringComponent(); + + /** + * If a call is triggered by an attribute or xsi:type, then this method + * returns the enclosing element of such element. + * + * @return the name of the enclosing element + */ + public QName getEnclosingElementName(); + + /** + * If a call is triggered by an element/attribute/xsi:type in the instance, + * this call returns all attributes of such an element (or enclosing element). + * + * @return all attributes of the triggering/enclosing element + */ + public XMLAttributes getAttributes(); + +} // XSDDescription diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XSGrammar.java b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XSGrammar.java new file mode 100644 index 0000000..5a932c7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/grammars/XSGrammar.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.grammars; + +import org.apache.xerces.xs.XSModel; + +/** + * Representing a schema grammar. It contains declaration/definitions from + * a certain namespace. When a grammar is preparsed, and its grammar type is + * XML Schema, it can be casted to this interface. Objects of this interface + * can be converted to XSModel, from which further information about components + * in this grammar can be obtained. + * + * @author Sandy Gao, IBM + * + * @version $Id$ + */ +public interface XSGrammar extends Grammar { + + /** + * Return an XSModel that represents components in this schema + * grammar and any schema grammars that are imported by this grammar + * directly or indirectly. + * + * @return an XSModel representing this schema grammar + */ + public XSModel toXSModel(); + + /** + * Return an XSModel that represents components in this schema + * grammar and the grammars in the grammarsparameter, + * any schema grammars that are imported by them directly or indirectly. + * + * @return an XSModel representing these schema grammars + */ + public XSModel toXSModel(XSGrammar[] grammars); + +} // interface XSGrammar diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLComponent.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLComponent.java new file mode 100644 index 0000000..c6afd1f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLComponent.java @@ -0,0 +1,126 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XNIException; + +/** + * The component interface defines methods that must be implemented + * by components in a parser configuration. The component methods allow + * the component manager to initialize the component state and notify + * the component when feature and property values change. + * + * @see XMLComponentManager + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLComponent { + + // + // XMLComponent methods + // + + /** + * Resets the component. The component can query the component manager + * about any features and properties that affect the operation of the + * component. + * + * @param componentManager The component manager. + * + * @throws XNIException Thrown by component on initialization error. + */ + public void reset(XMLComponentManager componentManager) + throws XMLConfigurationException; + + /** + * Returns a list of feature identifiers that are recognized by + * this component. This method may return null if no features + * are recognized by this component. + */ + public String[] getRecognizedFeatures(); + + /** + * Sets the state of a feature. This method is called by the component + * manager any time after reset when a feature changes state. + *

        + * Note: Components should silently ignore features + * that do not affect the operation of the component. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException; + + /** + * Returns a list of property identifiers that are recognized by + * this component. This method may return null if no properties + * are recognized by this component. + */ + public String[] getRecognizedProperties(); + + /** + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

        + * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException; + + /** + * Returns the default state for a feature, or null if this + * component does not want to report a default value for this + * feature. + * + * @param featureId The feature identifier. + * + * @since Xerces 2.2.0 + */ + public Boolean getFeatureDefault(String featureId); + + /** + * Returns the default state for a property, or null if this + * component does not want to report a default value for this + * property. + * + * @param propertyId The property identifier. + * + * @since Xerces 2.2.0 + */ + public Object getPropertyDefault(String propertyId); + +} // interface XMLComponent diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLComponentManager.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLComponentManager.java new file mode 100644 index 0000000..483e606 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLComponentManager.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +/** + * The component manager manages a parser configuration and the components + * that make up that configuration. The manager notifies each component + * before parsing to allow the components to initialize their state; and + * also any time that a parser feature or property changes. + *

        + * The methods of the component manager allow components to query features + * and properties that affect the operation of the component. + * + * @see XMLComponent + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLComponentManager { + + // + // XMLComponentManager methods + // + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * + * @throws XMLConfigurationException Thrown on configuration error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException; + + /** + * Returns the value of a property. + * + * @param propertyId The property identifier. + * + * @throws XMLConfigurationException Thrown on configuration error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException; + +} // interface XMLComponentManager diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLConfigurationException.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLConfigurationException.java new file mode 100644 index 0000000..7e12b32 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLConfigurationException.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XNIException; + +/** + * An XNI parser configuration exception. This exception class extends + * XNIException in order to differentiate between general + * parsing errors and configuration errors. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XMLConfigurationException + extends XNIException { + + /** Serialization version. */ + static final long serialVersionUID = -5437427404547669188L; + + // + // Constants + // + + /** Exception type: identifier not recognized. */ + public static final short NOT_RECOGNIZED = 0; + + /** Exception type: identifier not supported. */ + public static final short NOT_SUPPORTED = 1; + + // + // Data + // + + /** Exception type. */ + protected short fType; + + /** Identifier. */ + protected String fIdentifier; + + // + // Constructors + // + + /** + * Constructs a configuration exception with the specified type + * and feature/property identifier. + * + * @param type The type of the exception. + * @param identifier The feature or property identifier. + * + * @see #NOT_RECOGNIZED + * @see #NOT_SUPPORTED + */ + public XMLConfigurationException(short type, String identifier) { + super(identifier); + fType = type; + fIdentifier = identifier; + } // (short,String) + + /** + * Constructs a configuration exception with the specified type, + * feature/property identifier, and error message + * + * @param type The type of the exception. + * @param identifier The feature or property identifier. + * @param message The error message. + * + * @see #NOT_RECOGNIZED + * @see #NOT_SUPPORTED + */ + public XMLConfigurationException(short type, String identifier, + String message) { + super(message); + fType = type; + fIdentifier = identifier; + } // (short,String,String) + + // + // Public methods + // + + /** + * Returns the exception type. + * + * @see #NOT_RECOGNIZED + * @see #NOT_SUPPORTED + */ + public short getType() { + return fType; + } // getType():short + + /** Returns the feature or property identifier. */ + public String getIdentifier() { + return fIdentifier; + } // getIdentifier():String + +} // class XMLConfigurationException diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDContentModelFilter.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDContentModelFilter.java new file mode 100644 index 0000000..3f05c97 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDContentModelFilter.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XMLDTDContentModelHandler; + +/** + * Defines a DTD content model filter that acts as both a receiver and + * an emitter of DTD content model events. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDTDContentModelFilter + extends XMLDTDContentModelHandler, XMLDTDContentModelSource { + +} // interface XMLDTDContentModelFilter diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDContentModelSource.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDContentModelSource.java new file mode 100644 index 0000000..9dea2c5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDContentModelSource.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XMLDTDContentModelHandler; + +/** + * Defines a DTD content model source. In other words, any object that + * implements this interface is able to emit DTD content model "events" + * to the registered DTD content model handler. These events could be + * produced by parsing an XML document's internal or external subset, + * could be generated from some other source, or could be created + * programmatically. This interface does not say how the events + * are created, only that the implementor is able to emit them. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDTDContentModelSource { + + // + // XMLDTDContentModelSource methods + // + + /** Sets the DTD content model handler. */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler handler); + + /** Returns the DTD content model handler. */ + public XMLDTDContentModelHandler getDTDContentModelHandler( ); + +} // interface XMLDTDContentModelSource diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDFilter.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDFilter.java new file mode 100644 index 0000000..b53ae66 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDFilter.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XMLDTDHandler; + +/** + * Defines a DTD filter that acts as both a receiver and an emitter + * of DTD events. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDTDFilter + extends XMLDTDHandler, XMLDTDSource { + +} // interface XMLDTDFilter diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDScanner.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDScanner.java new file mode 100644 index 0000000..fbd077b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDScanner.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import java.io.IOException; + +import org.apache.xerces.xni.XNIException; + +/** + * This interface defines a generic DTD scanner. This interface + * allows a scanner to be used interchangably in existing parser + * configurations. + *

        + * If the parser configuration uses a DTD scanner that implements + * this interface, components should be able to query the scanner + * instance from the component manager using the following property + * identifier: + *

        + * "http://apache.org/xml/properties/internal/dtd-scanner" + *
        + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDTDScanner + extends XMLDTDSource, XMLDTDContentModelSource { + + // + // XMLDTDScanner methods + // + + /** + * Sets the input source. + * + * @param inputSource The input source or null. + * + * @throws IOException Thrown on i/o error. + */ + public void setInputSource(XMLInputSource inputSource) throws IOException; + + /** + * Scans the internal subset of the document. + * + * @param complete True if the scanner should scan the document + * completely, pushing all events to the registered + * document handler. A value of false indicates that + * that the scanner should only scan the next portion + * of the document and return. A scanner instance is + * permitted to completely scan a document if it does + * not support this "pull" scanning model. + * @param standalone True if the document was specified as standalone. + * This value is important for verifying certain + * well-formedness constraints. + * @param hasExternalSubset True if the document has an external DTD. + * This allows the scanner to properly notify + * the handler of the end of the DTD in the + * absence of an external subset. + * + * @return True if there is more to scan, false otherwise. + */ + public boolean scanDTDInternalSubset(boolean complete, boolean standalone, + boolean hasExternalSubset) + throws IOException, XNIException; + + /** + * Scans the external subset of the document. + * + * @param complete True if the scanner should scan the document + * completely, pushing all events to the registered + * document handler. A value of false indicates that + * that the scanner should only scan the next portion + * of the document and return. A scanner instance is + * permitted to completely scan a document if it does + * not support this "pull" scanning model. + * + * @return True if there is more to scan, false otherwise. + */ + public boolean scanDTDExternalSubset(boolean complete) + throws IOException, XNIException; + +} // interface XMLDTDScanner diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDSource.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDSource.java new file mode 100644 index 0000000..f2c0ec6 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDTDSource.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XMLDTDHandler; + +/** + * Defines a DTD source. In other words, any object that implements + * this interface is able to emit DTD "events" to the registered + * DTD handler. These events could be produced by parsing an XML + * document's internal or external subset, could be generated from + * some other source, or could be created programmatically. This + * interface does not say how the events are created, only + * that the implementor is able to emit them. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDTDSource { + + // + // XMLDTDSource methods + // + + /** Sets the DTD handler. */ + public void setDTDHandler(XMLDTDHandler handler); + + /** Returns the DTD handler. */ + public XMLDTDHandler getDTDHandler(); + +} // interface XMLDTDSource diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentFilter.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentFilter.java new file mode 100644 index 0000000..59e2d02 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentFilter.java @@ -0,0 +1,34 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XMLDocumentHandler; + +/** + * Defines a document filter that acts as both a receiver and an emitter + * of document events. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDocumentFilter + extends XMLDocumentHandler, XMLDocumentSource { + + +} // interface XMLDocumentFilter diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentScanner.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentScanner.java new file mode 100644 index 0000000..77e26fe --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentScanner.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import java.io.IOException; + +import org.apache.xerces.xni.XNIException; + +/** + * This interface defines a generic document scanner. This interface + * allows a scanner to be used interchangably in existing parser + * configurations. + *

        + * If the parser configuration uses a document scanner that implements + * this interface, components should be able to query the scanner + * instance from the component manager using the following property + * identifier: + *

        + * "http://apache.org/xml/properties/internal/document-scanner" + *
        + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDocumentScanner + extends XMLDocumentSource { + + // + // XMLDocumentScanner methods + // + + /** + * Sets the input source. + * + * @param inputSource The input source. + * + * @throws IOException Thrown on i/o error. + */ + public void setInputSource(XMLInputSource inputSource) throws IOException; + + /** + * Scans a document. + * + * @param complete True if the scanner should scan the document + * completely, pushing all events to the registered + * document handler. A value of false indicates that + * that the scanner should only scan the next portion + * of the document and return. A scanner instance is + * permitted to completely scan a document if it does + * not support this "pull" scanning model. + * + * @return True if there is more to scan, false otherwise. + */ + public boolean scanDocument(boolean complete) + throws IOException, XNIException; + +} // interface XMLDocumentScanner diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentSource.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentSource.java new file mode 100644 index 0000000..b2ac37d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLDocumentSource.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XMLDocumentHandler; + +/** + * Defines a document source. In other words, any object that implements + * this interface is able to emit document "events" to the registered + * document handler. These events could be produced by parsing an XML + * document, could be generated from some other source, or could be + * created programmatically. This interface does not say how + * the events are created, only that the implementor is able to emit + * them. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLDocumentSource { + + // + // XMLDocumentSource methods + // + + /** Sets the document handler. */ + public void setDocumentHandler(XMLDocumentHandler handler); + + /** Returns the document handler */ + public XMLDocumentHandler getDocumentHandler(); + +} // interface XMLDocumentSource diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLEntityResolver.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLEntityResolver.java new file mode 100644 index 0000000..4d7ec83 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLEntityResolver.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import java.io.IOException; + +import org.apache.xerces.xni.XMLResourceIdentifier; +import org.apache.xerces.xni.XNIException; + +/** + * This interface is used to resolve external parsed entities. The + * application can register an object that implements this interface + * with the parser configuration in order to intercept entities and + * resolve them explicitly. If the registered entity resolver cannot + * resolve the entity, it should return null so that the + * parser will try to resolve the entity using a default mechanism. + * + * @see XMLParserConfiguration + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLEntityResolver { + + // + // XMLEntityResolver methods + // + + /** + * Resolves an external parsed entity. If the entity cannot be + * resolved, this method should return null. + * + * @param resourceIdentifier location of the XML resource to resolve + * + * @throws XNIException Thrown on general error. + * @throws IOException Thrown if resolved entity stream cannot be + * opened or some other i/o error occurs. + * @see org.apache.xerces.xni.XMLResourceIdentifier + */ + public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) + throws XNIException, IOException; + +} // interface XMLEntityResolver diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLErrorHandler.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLErrorHandler.java new file mode 100644 index 0000000..5efa2a0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLErrorHandler.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XNIException; + +/** + * An interface for handling errors. If the application is interested + * in error notifications, then it can register an error handler object + * that implements this interface with the parser configuration. + * + * @see XMLParserConfiguration + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLErrorHandler { + + // + // XMLErrorHandler methods + // + + /** + * Reports a warning. Warnings are non-fatal and can be safely ignored + * by most applications. + * + * @param domain The domain of the warning. The domain can be any + * string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevant specification or + * document pertaining to this warning. + * @param key The warning key. This key can be any string and + * is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + public void warning(String domain, String key, + XMLParseException exception) throws XNIException; + + /** + * Reports an error. Errors are non-fatal and usually signify that the + * document is invalid with respect to its grammar(s). + * + * @param domain The domain of the error. The domain can be any + * string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevant specification or + * document pertaining to this error. + * @param key The error key. This key can be any string and + * is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + public void error(String domain, String key, + XMLParseException exception) throws XNIException; + + /** + * Report a fatal error. Fatal errors usually occur when the document + * is not well-formed and signifies that the parser cannot continue + * normal operation. + *

        + * Note: The error handler should always + * throw an XNIException from this method. This exception + * can either be the same exception that is passed as a parameter to + * the method or a new XNI exception object. If the registered error + * handler fails to throw an exception, the continuing operation of + * the parser is undetermined. + * + * @param domain The domain of the fatal error. The domain can be + * any string but is suggested to be a valid URI. The + * domain can be used to conveniently specify a web + * site location of the relevant specification or + * document pertaining to this fatal error. + * @param key The fatal error key. This key can be any string + * and is implementation dependent. + * @param exception Exception. + * + * @throws XNIException Thrown to signal that the parser should stop + * parsing the document. + */ + public void fatalError(String domain, String key, + XMLParseException exception) throws XNIException; + +} // interface XMLErrorHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLInputSource.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLInputSource.java new file mode 100644 index 0000000..da7a3b0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLInputSource.java @@ -0,0 +1,252 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import java.io.InputStream; +import java.io.Reader; + +import org.apache.xerces.xni.XMLResourceIdentifier; + +/** + * This class represents an input source for an XML document. The + * basic properties of an input source are the following: + *

          + *
        • public identifier
        • + *
        • system identifier
        • + *
        • byte stream or character stream
        • + *
        • + *
        + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XMLInputSource { + + // + // Data + // + + /** Public identifier. */ + protected String fPublicId; + + /** System identifier. */ + protected String fSystemId; + + /** Base system identifier. */ + protected String fBaseSystemId; + + /** Byte stream. */ + protected InputStream fByteStream; + + /** Character stream. */ + protected Reader fCharStream; + + /** Encoding. */ + protected String fEncoding; + + // + // Constructors + // + + /** + * Constructs an input source from just the public and system + * identifiers, leaving resolution of the entity and opening of + * the input stream up to the caller. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + */ + public XMLInputSource(String publicId, String systemId, + String baseSystemId) { + fPublicId = publicId; + fSystemId = systemId; + fBaseSystemId = baseSystemId; + } // (String,String,String) + + /** + * Constructs an input source from a XMLResourceIdentifier + * object, leaving resolution of the entity and opening of + * the input stream up to the caller. + * + * @param resourceIdentifier the XMLResourceIdentifier containing the information + */ + public XMLInputSource(XMLResourceIdentifier resourceIdentifier) { + + fPublicId = resourceIdentifier.getPublicId(); + fSystemId = resourceIdentifier.getLiteralSystemId(); + fBaseSystemId = resourceIdentifier.getBaseSystemId(); + } // (XMLResourceIdentifier) + + /** + * Constructs an input source from a byte stream. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + * @param byteStream The byte stream. + * @param encoding The encoding of the byte stream, if known. + */ + public XMLInputSource(String publicId, String systemId, + String baseSystemId, InputStream byteStream, + String encoding) { + fPublicId = publicId; + fSystemId = systemId; + fBaseSystemId = baseSystemId; + fByteStream = byteStream; + fEncoding = encoding; + } // (String,String,String,InputStream,String) + + /** + * Constructs an input source from a character stream. + * + * @param publicId The public identifier, if known. + * @param systemId The system identifier. This value should + * always be set, if possible, and can be + * relative or absolute. If the system identifier + * is relative, then the base system identifier + * should be set. + * @param baseSystemId The base system identifier. This value should + * always be set to the fully expanded URI of the + * base system identifier, if possible. + * @param charStream The character stream. + * @param encoding The original encoding of the byte stream + * used by the reader, if known. + */ + public XMLInputSource(String publicId, String systemId, + String baseSystemId, Reader charStream, + String encoding) { + fPublicId = publicId; + fSystemId = systemId; + fBaseSystemId = baseSystemId; + fCharStream = charStream; + fEncoding = encoding; + } // (String,String,String,Reader,String) + + // + // Public methods + // + + /** + * Sets the public identifier. + * + * @param publicId The new public identifier. + */ + public void setPublicId(String publicId) { + fPublicId = publicId; + } // setPublicId(String) + + /** Returns the public identifier. */ + public String getPublicId() { + return fPublicId; + } // getPublicId():String + + /** + * Sets the system identifier. + * + * @param systemId The new system identifier. + */ + public void setSystemId(String systemId) { + fSystemId = systemId; + } // setSystemId(String) + + /** Returns the system identifier. */ + public String getSystemId() { + return fSystemId; + } // getSystemId():String + + /** + * Sets the base system identifier. + * + * @param baseSystemId The new base system identifier. + */ + public void setBaseSystemId(String baseSystemId) { + fBaseSystemId = baseSystemId; + } // setBaseSystemId(String) + + /** Returns the base system identifier. */ + public String getBaseSystemId() { + return fBaseSystemId; + } // getBaseSystemId():String + + /** + * Sets the byte stream. If the byte stream is not already opened + * when this object is instantiated, then the code that opens the + * stream should also set the byte stream on this object. Also, if + * the encoding is auto-detected, then the encoding should also be + * set on this object. + * + * @param byteStream The new byte stream. + */ + public void setByteStream(InputStream byteStream) { + fByteStream = byteStream; + } // setByteStream(InputSource) + + /** Returns the byte stream. */ + public InputStream getByteStream() { + return fByteStream; + } // getByteStream():InputStream + + /** + * Sets the character stream. If the character stream is not already + * opened when this object is instantiated, then the code that opens + * the stream should also set the character stream on this object. + * Also, the encoding of the byte stream used by the reader should + * also be set on this object, if known. + * + * @param charStream The new character stream. + * + * @see #setEncoding + */ + public void setCharacterStream(Reader charStream) { + fCharStream = charStream; + } // setCharacterStream(Reader) + + /** Returns the character stream. */ + public Reader getCharacterStream() { + return fCharStream; + } // getCharacterStream():Reader + + /** + * Sets the encoding of the stream. + * + * @param encoding The new encoding. + */ + public void setEncoding(String encoding) { + fEncoding = encoding; + } // setEncoding(String) + + /** Returns the encoding of the stream, or null if not known. */ + public String getEncoding() { + return fEncoding; + } // getEncoding():String + +} // class XMLInputSource diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLParseException.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLParseException.java new file mode 100644 index 0000000..1610fc5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLParseException.java @@ -0,0 +1,179 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import org.apache.xerces.xni.XMLLocator; +import org.apache.xerces.xni.XNIException; + +/** + * A parsing exception. This exception is different from the standard + * XNI exception in that it stores the location in the document (or + * its entities) where the exception occurred. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public class XMLParseException + extends XNIException { + + /** Serialization version. */ + static final long serialVersionUID = 1732959359448549967L; + + // + // Data + // + + /** Public identifier. */ + protected String fPublicId; + + /** literal System identifier. */ + protected String fLiteralSystemId; + + /** expanded System identifier. */ + protected String fExpandedSystemId; + + /** Base system identifier. */ + protected String fBaseSystemId; + + /** Line number. */ + protected int fLineNumber = -1; + + /** Column number. */ + protected int fColumnNumber = -1; + + /** Character offset. */ + protected int fCharacterOffset = -1; + + // + // Constructors + // + + /** Constructs a parse exception. */ + public XMLParseException(XMLLocator locator, String message) { + super(message); + if (locator != null) { + fPublicId = locator.getPublicId(); + fLiteralSystemId = locator.getLiteralSystemId(); + fExpandedSystemId = locator.getExpandedSystemId(); + fBaseSystemId = locator.getBaseSystemId(); + fLineNumber = locator.getLineNumber(); + fColumnNumber = locator.getColumnNumber(); + fCharacterOffset = locator.getCharacterOffset(); + } + } // (XMLLocator,String) + + /** Constructs a parse exception. */ + public XMLParseException(XMLLocator locator, + String message, Exception exception) { + super(message, exception); + if (locator != null) { + fPublicId = locator.getPublicId(); + fLiteralSystemId = locator.getLiteralSystemId(); + fExpandedSystemId = locator.getExpandedSystemId(); + fBaseSystemId = locator.getBaseSystemId(); + fLineNumber = locator.getLineNumber(); + fColumnNumber = locator.getColumnNumber(); + fCharacterOffset = locator.getCharacterOffset(); + } + } // (XMLLocator,String,Exception) + + // + // Public methods + // + + /** Returns the public identifier. */ + public String getPublicId() { + return fPublicId; + } // getPublicId():String + + /** Returns the expanded system identifier. */ + public String getExpandedSystemId() { + return fExpandedSystemId; + } // getExpandedSystemId():String + + /** Returns the literal system identifier. */ + public String getLiteralSystemId() { + return fLiteralSystemId; + } // getLiteralSystemId():String + + /** Returns the base system identifier. */ + public String getBaseSystemId() { + return fBaseSystemId; + } // getBaseSystemId():String + + /** Returns the line number. */ + public int getLineNumber() { + return fLineNumber; + } // getLineNumber():int + + /** Returns the row number. */ + public int getColumnNumber() { + return fColumnNumber; + } // getRowNumber():int + + /** Returns the character offset. */ + public int getCharacterOffset() { + return fCharacterOffset; + } // getCharacterOffset():int + + // + // Object methods + // + + /** Returns a string representation of this object. */ + public String toString() { + + StringBuffer str = new StringBuffer(); + if (fPublicId != null) { + str.append(fPublicId); + } + str.append(':'); + if (fLiteralSystemId != null) { + str.append(fLiteralSystemId); + } + str.append(':'); + if (fExpandedSystemId != null) { + str.append(fExpandedSystemId); + } + str.append(':'); + if (fBaseSystemId != null) { + str.append(fBaseSystemId); + } + str.append(':'); + str.append(fLineNumber); + str.append(':'); + str.append(fColumnNumber); + str.append(':'); + str.append(fCharacterOffset); + str.append(':'); + String message = getMessage(); + if (message == null) { + Exception exception = getException(); + if (exception != null) { + message = exception.getMessage(); + } + } + if (message != null) { + str.append(message); + } + return str.toString(); + + } // toString():String + +} // XMLParseException diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLParserConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLParserConfiguration.java new file mode 100644 index 0000000..964d138 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLParserConfiguration.java @@ -0,0 +1,251 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import java.io.IOException; +import java.util.Locale; + +import org.apache.xerces.xni.XMLDTDContentModelHandler; +import org.apache.xerces.xni.XMLDTDHandler; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XNIException; + +/** + * Represents a parser configuration. The parser configuration maintains + * a table of recognized features and properties, assembles components + * for the parsing pipeline, and is responsible for initiating parsing + * of an XML document. + *

        + * By separating the configuration of a parser from the specific parser + * instance, applications can create new configurations and re-use the + * existing parser components and external API generators (e.g. the + * DOMParser and SAXParser). + *

        + * The internals of any specific parser configuration instance are hidden. + * Therefore, each configuration may implement the parsing mechanism any + * way necessary. However, the parser configuration should follow these + * guidelines: + *

          + *
        • + * Call the reset method on each component before parsing. + * This is only required if the configuration is re-using existing + * components that conform to the XMLComponent interface. + * If the configuration uses all custom parts, then it is free to + * implement everything as it sees fit as long as it follows the + * other guidelines. + *
        • + *
        • + * Call the setFeature and setProperty method + * on each component during parsing to propagate features and properties + * that have changed. This is only required if the configuration is + * re-using existing components that conform to the XMLComponent + * interface. If the configuration uses all custom parts, then it is free + * to implement everything as it sees fit as long as it follows the other + * guidelines. + *
        • + *
        • + * Pass the same unique String references for all symbols that are + * propagated to the registered handlers. Symbols include, but may not + * be limited to, the names of elements and attributes (including their + * uri, prefix, and localpart). This is suggested but not an absolute + * must. However, the standard parser components may require access to + * the same symbol table for creation of unique symbol references to be + * propagated in the XNI pipeline. + *
        • + *
        + * + * @author Arnaud Le Hors, IBM + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLParserConfiguration + extends XMLComponentManager { + + // + // XMLParserConfiguration methods + // + + // parsing + + /** + * Parse an XML document. + *

        + * The parser can use this method to instruct this configuration + * to begin parsing an XML document from any valid input source + * (a character stream, a byte stream, or a URI). + *

        + * Parsers may not invoke this method while a parse is in progress. + * Once a parse is complete, the parser may then parse another XML + * document. + *

        + * This method is synchronous: it will not return until parsing + * has ended. If a client application wants to terminate + * parsing early, it should throw an exception. + *

        + * When this method returns, all characters streams and byte streams + * opened by the parser are closed. + * + * @param inputSource The input source for the top-level of the + * XML document. + * + * @exception XNIException Any XNI exception, possibly wrapping + * another exception. + * @exception IOException An IO exception from the parser, possibly + * from a byte stream or character stream + * supplied by the parser. + */ + public void parse(XMLInputSource inputSource) + throws XNIException, IOException; + + // generic configuration + + /** + * Allows a parser to add parser specific features to be recognized + * and managed by the parser configuration. + * + * @param featureIds An array of the additional feature identifiers + * to be recognized. + */ + public void addRecognizedFeatures(String[] featureIds); + + /** + * Sets the state of a feature. This method is called by the parser + * and gets propagated to components in this parser configuration. + * + * @param featureId The feature identifier. + * @param state The state of the feature. + * + * @throws XMLConfigurationException Thrown if there is a configuration + * error. + */ + public void setFeature(String featureId, boolean state) + throws XMLConfigurationException; + + /** + * Returns the state of a feature. + * + * @param featureId The feature identifier. + * + * @throws XMLConfigurationException Thrown if there is a configuration + * error. + */ + public boolean getFeature(String featureId) + throws XMLConfigurationException; + + /** + * Allows a parser to add parser specific properties to be recognized + * and managed by the parser configuration. + * + * @param propertyIds An array of the additional property identifiers + * to be recognized. + */ + public void addRecognizedProperties(String[] propertyIds); + + /** + * Sets the value of a property. This method is called by the parser + * and gets propagated to components in this parser configuration. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws XMLConfigurationException Thrown if there is a configuration + * error. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException; + + /** + * Returns the value of a property. + * + * @param propertyId The property identifier. + * + * @throws XMLConfigurationException Thrown if there is a configuration + * error. + */ + public Object getProperty(String propertyId) + throws XMLConfigurationException; + + // handlers + + /** + * Sets the error handler. + * + * @param errorHandler The error resolver. + */ + public void setErrorHandler(XMLErrorHandler errorHandler); + + /** Returns the registered error handler. */ + public XMLErrorHandler getErrorHandler(); + + /** + * Sets the document handler to receive information about the document. + * + * @param documentHandler The document handler. + */ + public void setDocumentHandler(XMLDocumentHandler documentHandler); + + /** Returns the registered document handler. */ + public XMLDocumentHandler getDocumentHandler(); + + /** + * Sets the DTD handler. + * + * @param dtdHandler The DTD handler. + */ + public void setDTDHandler(XMLDTDHandler dtdHandler); + + /** Returns the registered DTD handler. */ + public XMLDTDHandler getDTDHandler(); + + /** + * Sets the DTD content model handler. + * + * @param dtdContentModelHandler The DTD content model handler. + */ + public void setDTDContentModelHandler(XMLDTDContentModelHandler dtdContentModelHandler); + + /** Returns the registered DTD content model handler. */ + public XMLDTDContentModelHandler getDTDContentModelHandler(); + + // other settings + + /** + * Sets the entity resolver. + * + * @param entityResolver The new entity resolver. + */ + public void setEntityResolver(XMLEntityResolver entityResolver); + + /** Returns the registered entity resolver. */ + public XMLEntityResolver getEntityResolver(); + + /** + * Set the locale to use for messages. + * + * @param locale The locale object to use for localization of messages. + * + * @exception XNIException Thrown if the parser does not support the + * specified locale. + */ + public void setLocale(Locale locale) throws XNIException; + + /** Returns the locale. */ + public Locale getLocale(); + +} // interface XMLParserConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLPullParserConfiguration.java b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLPullParserConfiguration.java new file mode 100644 index 0000000..fdb2452 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xni/parser/XMLPullParserConfiguration.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package org.apache.xerces.xni.parser; + +import java.io.IOException; + +import org.apache.xerces.xni.XNIException; + +/** + * Represents a parser configuration that can be used as the + * configuration for a "pull" parser. A pull parser allows the + * application to drive the parser instead of having document + * information events "pushed" to the registered handlers. + *

        + * A pull parser using this type of configuration first calls + * the setInputSource method. After the input + * source is set, the pull parser repeatedly calls the + * parse(boolean):boolean method. This method + * returns a value of true if there is more to parse in the + * document. + *

        + * Calling the parse(XMLInputSource) is equivalent + * to setting the input source and calling the + * parse(boolean):boolean method with a "complete" + * value of true. + * + * @author Andy Clark, IBM + * + * @version $Id$ + */ +public interface XMLPullParserConfiguration + extends XMLParserConfiguration { + + // + // XMLPullParserConfiguration methods + // + + // parsing + + /** + * Sets the input source for the document to parse. + * + * @param inputSource The document's input source. + * + * @exception XMLConfigurationException Thrown if there is a + * configuration error when initializing the + * parser. + * @exception IOException Thrown on I/O error. + * + * @see #parse(boolean) + */ + public void setInputSource(XMLInputSource inputSource) + throws XMLConfigurationException, IOException; + + /** + * Parses the document in a pull parsing fashion. + * + * @param complete True if the pull parser should parse the + * remaining document completely. + * + * @return True if there is more document to parse. + * + * @exception XNIException Any XNI exception, possibly wrapping + * another exception. + * @exception IOException An IO exception from the parser, possibly + * from a byte stream or character stream + * supplied by the parser. + * + * @see #setInputSource + */ + public boolean parse(boolean complete) throws XNIException, IOException; + + /** + * If the application decides to terminate parsing before the xml document + * is fully parsed, the application should call this method to free any + * resource allocated during parsing. For example, close all opened streams. + */ + public void cleanup(); + +} // interface XMLPullParserConfiguration diff --git a/resources/xerces2-j-src/org/apache/xerces/xpointer/ElementSchemePointer.java b/resources/xerces2-j-src/org/apache/xerces/xpointer/ElementSchemePointer.java new file mode 100644 index 0000000..45ad17d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xpointer/ElementSchemePointer.java @@ -0,0 +1,877 @@ +/* + * 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. + */ + +package org.apache.xerces.xpointer; + +import java.util.HashMap; + +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLErrorHandler; + +/** + *

        + * Implements the XPointerPart interface for element() scheme specific processing. + *

        + * + * @xerces.internal + * + * @version $Id$ + */ +final class ElementSchemePointer implements XPointerPart { + + // Fields + + // The Scheme Name i.e element + private String fSchemeName; + + // The scheme Data + private String fSchemeData; + + // The scheme Data & child sequence + private String fShortHandPointerName; + + // Should we attempt to resolve the ChildSequence from the + // current element position. If a ShortHand Pointer is present + // attempt to resolve relative to the short hand pointer. + private boolean fIsResolveElement = false; + + // Has the element been found + private boolean fIsElementFound = false; + + // Was only an empty element found + private boolean fWasOnlyEmptyElementFound = false; + + // If a shorthand pointer is present and resolved + boolean fIsShortHand = false; + + // The depth at which the element was found + int fFoundDepth = 0; + + // The XPointer element child sequence + private int fChildSequence[]; + + // The current child position + private int fCurrentChildPosition = 1; + + // The current child depth + private int fCurrentChildDepth = 0; + + // The current element's child sequence + private int fCurrentChildSequence[];; + + // Stores if the Fragment was resolved by the pointer + private boolean fIsFragmentResolved = false; + + // Stores if the Fragment was resolved by the pointer + private ShortHandPointer fShortHandPointer; + + // The XPointer Error reporter + protected XMLErrorReporter fErrorReporter; + + // The XPointer Error Handler + protected XMLErrorHandler fErrorHandler; + + // + private SymbolTable fSymbolTable; + + // ************************************************************************ + // Constructors + // ************************************************************************ + public ElementSchemePointer() { + } + + public ElementSchemePointer(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + } + + public ElementSchemePointer(SymbolTable symbolTable, + XMLErrorReporter errorReporter) { + fSymbolTable = symbolTable; + fErrorReporter = errorReporter; + } + + // ************************************************************************ + // XPointerPart implementation + // ************************************************************************ + + /** + * Parses the XPointer expression and tokenizes it into Strings + * delimited by whitespace. + * + * @see org.apache.xerces.xpointer.XPointerProcessor#parseXPointer(java.lang.String) + */ + public void parseXPointer(String xpointer) throws XNIException { + + // + init(); + + // tokens + final Tokens tokens = new Tokens(fSymbolTable); + + // scanner + Scanner scanner = new Scanner(fSymbolTable) { + protected void addToken(Tokens tokens, int token) + throws XNIException { + if (token == Tokens.XPTRTOKEN_ELEM_CHILD + || token == Tokens.XPTRTOKEN_ELEM_NCNAME) { + super.addToken(tokens, token); + return; + } + reportError("InvalidElementSchemeToken", new Object[] { tokens + .getTokenString(token) }); + } + }; + + // scan the element() XPointer expression + int length = xpointer.length(); + boolean success = scanner.scanExpr(fSymbolTable, tokens, xpointer, 0, + length); + + if (!success) { + reportError("InvalidElementSchemeXPointer", + new Object[] { xpointer }); + } + + // Initialize a temp arrays to the size of token count which should + // be atleast twice the size of child sequence, to hold the ChildSequence. + int tmpChildSequence[] = new int[tokens.getTokenCount() / 2 + 1]; + + // the element depth + int i = 0; + + // Traverse the scanned tokens + while (tokens.hasMore()) { + int token = tokens.nextToken(); + + switch (token) { + case Tokens.XPTRTOKEN_ELEM_NCNAME: { + // Note: Only a single ShortHand pointer can be present + + // The shortHand name + token = tokens.nextToken(); + fShortHandPointerName = tokens.getTokenString(token); + + // Create a new ShortHandPointer + fShortHandPointer = new ShortHandPointer(fSymbolTable); + fShortHandPointer.setSchemeName(fShortHandPointerName); + + break; + } + case Tokens.XPTRTOKEN_ELEM_CHILD: { + tmpChildSequence[i] = tokens.nextToken(); + i++; + + break; + } + default: + reportError("InvalidElementSchemeXPointer", + new Object[] { xpointer }); + } + } + + // Initialize the arrays to the number of elements in the ChildSequence. + fChildSequence = new int[i]; + fCurrentChildSequence = new int[i]; + System.arraycopy(tmpChildSequence, 0, fChildSequence, 0, i); + + } + + /** + * Returns the scheme name i.e element + * @see org.apache.xerces.xpointer.XPointerPart#getSchemeName() + */ + public String getSchemeName() { + return fSchemeName; + } + + /** + * Returns the scheme data + * + * @see org.apache.xerces.xpointer.XPointerPart#getSchemeData() + */ + public String getSchemeData() { + return fSchemeData; + } + + /** + * Sets the scheme name + * + * @see org.apache.xerces.xpointer.XPointerPart#setSchemeName(java.lang.String) + */ + public void setSchemeName(String schemeName) { + fSchemeName = schemeName; + + } + + /** + * Sets the scheme data + * + * @see org.apache.xerces.xpointer.XPointerPart#setSchemeData(java.lang.String) + */ + public void setSchemeData(String schemeData) { + fSchemeData = schemeData; + } + + /** + * Responsible for resolving the element() scheme XPointer. If a ShortHand + * Pointer is present and it is successfully resolved and if a child + * sequence is present, the child sequence is resolved relative to it. + * + * @see org.apache.xerces.xpointer.XPointerProcessor#resolveXPointer(org.apache.xerces.xni.QName, org.apache.xerces.xni.XMLAttributes, org.apache.xerces.xni.Augmentations, int event) + */ + public boolean resolveXPointer(QName element, XMLAttributes attributes, + Augmentations augs, int event) throws XNIException { + + boolean isShortHandPointerResolved = false; + + // if a ChildSequence exisits, resolve child elements + + // if an element name exists + if (fShortHandPointerName != null) { + // resolve ShortHand Pointer + isShortHandPointerResolved = fShortHandPointer.resolveXPointer( + element, attributes, augs, event); + if (isShortHandPointerResolved) { + fIsResolveElement = true; + fIsShortHand = true; + } else { + fIsResolveElement = false; + } + } else { + fIsResolveElement = true; + } + + // Added here to skip the ShortHand pointer corresponding to + // an element if one exisits and start searching from its child + if (fChildSequence.length > 0) { + fIsFragmentResolved = matchChildSequence(element, event); + } else if (isShortHandPointerResolved && fChildSequence.length <= 0) { + // if only a resolved shorthand pointer exists + fIsFragmentResolved = isShortHandPointerResolved; + } else { + fIsFragmentResolved = false; + } + + return fIsFragmentResolved; + } + + /** + * Matches the current element position in the document tree with the + * element position specified in the element XPointer scheme. + * + * @param event + * @return boolean - true if the current element position in the document + * tree matches theelement position specified in the element XPointer + * scheme. + */ + protected boolean matchChildSequence(QName element, int event) + throws XNIException { + + // need to resize fCurrentChildSequence + if (fCurrentChildDepth >= fCurrentChildSequence.length) { + int tmpCurrentChildSequence[] = new int[fCurrentChildSequence.length]; + System.arraycopy(fCurrentChildSequence, 0, tmpCurrentChildSequence, + 0, fCurrentChildSequence.length); + + // Increase the size by a factor of 2 (?) + fCurrentChildSequence = new int[fCurrentChildDepth * 2]; + System.arraycopy(tmpCurrentChildSequence, 0, fCurrentChildSequence, + 0, tmpCurrentChildSequence.length); + } + + // + if (fIsResolveElement) { + // start + if (event == XPointerPart.EVENT_ELEMENT_START) { + fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition; + fCurrentChildDepth++; + + // reset the current child position + fCurrentChildPosition = 1; + + //if (!fSchemeNameFound) { + if ((fCurrentChildDepth <= fFoundDepth) || (fFoundDepth == 0)) { + if (checkMatch()) { + fIsElementFound = true; + fFoundDepth = fCurrentChildDepth; + } else { + fIsElementFound = false; + fFoundDepth = 0; + } + } + + } else if (event == XPointerPart.EVENT_ELEMENT_END) { + if (fCurrentChildDepth == fFoundDepth) { + fIsElementFound = true; + } else if (((fCurrentChildDepth < fFoundDepth) && (fFoundDepth != 0)) + || ((fCurrentChildDepth > fFoundDepth) // or empty element found + && (fFoundDepth == 0))) { + fIsElementFound = false; + } + + // reset array position of last child + fCurrentChildSequence[fCurrentChildDepth] = 0; + + fCurrentChildDepth--; + fCurrentChildPosition = fCurrentChildSequence[fCurrentChildDepth] + 1; + + } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) { + + fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition; + fCurrentChildPosition++; + + // Donot check for empty elements if the empty element is + // a child of a found parent element + if (checkMatch()) { + if (!fIsElementFound) { + fWasOnlyEmptyElementFound = true; + } else { + fWasOnlyEmptyElementFound = false; + } + fIsElementFound = true; + } else { + fIsElementFound = false; + fWasOnlyEmptyElementFound = false; + } + } + } + + return fIsElementFound; + } + + /** + * Matches the current position of the element being visited by checking + * its position and previous elements against the element XPointer expression. + * If a match is found it return true else false. + * + * @return boolean + */ + protected boolean checkMatch() { + // If the number of elements in the ChildSequence is greater than the + // current child depth, there is not point in checking further + if (!fIsShortHand) { + // If a shorthand pointer is not present traverse the children + // and compare + if (fChildSequence.length <= fCurrentChildDepth + 1) { + + for (int i = 0; i < fChildSequence.length; i++) { + if (fChildSequence[i] != fCurrentChildSequence[i]) { + return false; + } + } + } else { + return false; + } + } else { + // If a shorthand pointer is present traverse the children + // ignoring the first element of the CurrenChildSequence which + // contains the ShortHand pointer element and compare + if (fChildSequence.length <= fCurrentChildDepth + 1) { + + for (int i = 0; i < fChildSequence.length; i++) { + // ensure fCurrentChildSequence is large enough + if (fCurrentChildSequence.length < i + 2) { + return false; + } + + // ignore the first element of fCurrentChildSequence + if (fChildSequence[i] != fCurrentChildSequence[i + 1]) { + return false; + } + } + } else { + return false; + } + + } + + return true; + } + + /** + * Returns true if the node matches or is a child of a matching element() + * scheme XPointer. + * + * @see org.apache.xerces.xpointer.XPointerProcessor#isFragmentResolved() + */ + public boolean isFragmentResolved() throws XNIException { + // Return true if the Fragment was resolved and the current Node depth + // is greater than or equal to the depth at which the element was found + return fIsFragmentResolved ; + } + + /** + * Returns true if the XPointer expression resolves to a non-element child + * of the current resource fragment. + * + * @see org.apache.xerces.xpointer.XPointerPart#isChildFragmentResolved() + * + */ + public boolean isChildFragmentResolved() { + // if only a shorthand pointer was present + if (fIsShortHand && fShortHandPointer != null && fChildSequence.length <= 0) { + return fShortHandPointer.isChildFragmentResolved(); + } else { + return fWasOnlyEmptyElementFound ? !fWasOnlyEmptyElementFound + : (fIsFragmentResolved && (fCurrentChildDepth >= fFoundDepth)); + } + } + + /** + * Reports an XPointer error + */ + protected void reportError(String key, Object[] arguments) + throws XNIException { + /*fErrorReporter.reportError(XPointerMessageFormatter.XPOINTER_DOMAIN, + key, arguments, XMLErrorReporter.SEVERITY_ERROR); + */ + throw new XNIException((fErrorReporter + .getMessageFormatter(XPointerMessageFormatter.XPOINTER_DOMAIN)) + .formatMessage(fErrorReporter.getLocale(), key, arguments)); + } + + /** + * Initializes error handling objects + */ + protected void initErrorReporter() { + if (fErrorReporter == null) { + fErrorReporter = new XMLErrorReporter(); + } + if (fErrorHandler == null) { + fErrorHandler = new XPointerErrorHandler(); + } + fErrorReporter.putMessageFormatter( + XPointerMessageFormatter.XPOINTER_DOMAIN, + new XPointerMessageFormatter()); + } + + /** + * Initializes the element scheme processor + */ + protected void init() { + fSchemeName = null; + fSchemeData = null; + fShortHandPointerName = null; + fIsResolveElement = false; + fIsElementFound = false; + fWasOnlyEmptyElementFound = false; + fFoundDepth = 0; + fCurrentChildPosition = 1; + fCurrentChildDepth = 0; + fIsFragmentResolved = false; + fShortHandPointer = null; + + initErrorReporter(); + } + + // ************************************************************************ + // element() Scheme expression scanner + // ************************************************************************ + + /** + * List of XPointer Framework tokens. + * + * @xerces.internal + * + * @author Neil Delima, IBM + * @version $Id$ + * + */ + private final class Tokens { + + /** + * XPointer element() scheme + * [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence + * [2] ChildSequence ::= ('/' [1-9] [0-9]*)+ + */ + private static final int XPTRTOKEN_ELEM_NCNAME = 0; + + private static final int XPTRTOKEN_ELEM_CHILD = 1; + + // Token names + private final String[] fgTokenNames = { "XPTRTOKEN_ELEM_NCNAME", + "XPTRTOKEN_ELEM_CHILD" }; + + // Token count + private static final int INITIAL_TOKEN_COUNT = 1 << 8; + + private int[] fTokens = new int[INITIAL_TOKEN_COUNT]; + + private int fTokenCount = 0; + + // Current token position + private int fCurrentTokenIndex; + + private SymbolTable fSymbolTable; + + private HashMap fTokenNames = new HashMap(); + + /** + * Constructor + * + * @param symbolTable SymbolTable + */ + private Tokens(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + + fTokenNames.put(new Integer(XPTRTOKEN_ELEM_NCNAME), + "XPTRTOKEN_ELEM_NCNAME"); + fTokenNames.put(new Integer(XPTRTOKEN_ELEM_CHILD), + "XPTRTOKEN_ELEM_CHILD"); + } + + /* + * Returns the token String + * @param token The index of the token + * @return String The token string + */ + private String getTokenString(int token) { + return (String) fTokenNames.get(new Integer(token)); + } + + /** + * Returns the token String + * @param token The index of the token + * @return String The token string + */ + private Integer getToken(int token) { + return (Integer) fTokenNames.get(new Integer(token)); + } + + /** + * Add the specified string as a token + * + * @param token The token string + */ + private void addToken(String tokenStr) { + Integer tokenInt = (Integer) fTokenNames.get(tokenStr); + if (tokenInt == null) { + tokenInt = new Integer(fTokenNames.size()); + fTokenNames.put(tokenInt, tokenStr); + } + addToken(tokenInt.intValue()); + } + + /** + * Add the specified int token + * + * @param token The int specifying the token + */ + private void addToken(int token) { + try { + fTokens[fTokenCount] = token; + } catch (ArrayIndexOutOfBoundsException ex) { + int[] oldList = fTokens; + fTokens = new int[fTokenCount << 1]; + System.arraycopy(oldList, 0, fTokens, 0, fTokenCount); + fTokens[fTokenCount] = token; + } + fTokenCount++; + } + + /** + * Resets the current position to the head of the token list. + */ + private void rewind() { + fCurrentTokenIndex = 0; + } + + /** + * Returns true if the {@link #getNextToken()} method + * returns a valid token. + */ + private boolean hasMore() { + return fCurrentTokenIndex < fTokenCount; + } + + /** + * Obtains the token at the current position, then advance + * the current position by one. + * + * If there's no such next token, this method throws + * new XNIException("InvalidXPointerExpression");. + */ + private int nextToken() throws XNIException { + if (fCurrentTokenIndex == fTokenCount) + reportError("XPointerElementSchemeProcessingError", null); + return fTokens[fCurrentTokenIndex++]; + } + + /** + * Obtains the token at the current position, without advancing + * the current position. + * + * If there's no such next token, this method throws + * new XNIException("InvalidXPointerExpression");. + */ + private int peekToken() throws XNIException { + if (fCurrentTokenIndex == fTokenCount) + reportError("XPointerElementSchemeProcessingError", null); + return fTokens[fCurrentTokenIndex]; + } + + /** + * Obtains the token at the current position as a String. + * + * If there's no current token or if the current token + * is not a string token, this method throws + * If there's no such next token, this method throws + * new XNIException("InvalidXPointerExpression");. + */ + private String nextTokenAsString() throws XNIException { + String s = getTokenString(nextToken()); + if (s == null) + reportError("XPointerElementSchemeProcessingError", null); + return s; + } + + /** + * Returns the number of tokens. + * + */ + private int getTokenCount() { + return fTokenCount; + } + } + + /** + * + * The XPointer expression scanner. Scans the XPointer framework expression. + * + * @xerces.internal + * + * @version $Id$ + */ + private class Scanner { + + /** + * 7-bit ASCII subset + * + * 0 1 2 3 4 5 6 7 8 9 A B C D E F + * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0 + * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2 + * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3 + * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4 + * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5 + * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6 + * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7 + */ + private static final byte CHARTYPE_INVALID = 0, // invalid XML characters, control characters and 7F + CHARTYPE_OTHER = 1, // A valid XML character (possibly invalid NCNameChar) that does not fall in one of the other categories + CHARTYPE_MINUS = 2, // '-' (0x2D) + CHARTYPE_PERIOD = 3, // '.' (0x2E) + CHARTYPE_SLASH = 4, // '/' (0x2F) + CHARTYPE_DIGIT = 5, // '0'-'9' (0x30 to 0x39) + CHARTYPE_LETTER = 6, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A) + CHARTYPE_UNDERSCORE = 7, // '_' (0x5F) + CHARTYPE_NONASCII = 8; // Non-ASCII Unicode codepoint (>= 0x80) + + private final byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, + 7, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1 }; + + /** + * Symbol literals + */ + + // + // Data + // + /** Symbol table. */ + private SymbolTable fSymbolTable; + + // + // Constructors + // + + /** + * Constructs an XPath expression scanner. + * + * @param symbolTable SymbolTable + */ + private Scanner(SymbolTable symbolTable) { + // save pool and tokens + fSymbolTable = symbolTable; + + } // (SymbolTable) + + /** + * Scans the XPointer Expression + * + */ + private boolean scanExpr(SymbolTable symbolTable, Tokens tokens, + String data, int currentOffset, int endOffset) + throws XNIException { + + int ch; + int nameOffset; + String nameHandle = null; + + while (true) { + if (currentOffset == endOffset) { + break; + } + + ch = data.charAt(currentOffset); + byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII + : fASCIICharMap[ch]; + + // + // [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence + // [2] ChildSequence ::= ('/' [1-9] [0-9]*)+ + // + + switch (chartype) { + + case CHARTYPE_SLASH: + // if last character is '/', break and report an error + if (++currentOffset == endOffset) { + return false; + } + + addToken(tokens, Tokens.XPTRTOKEN_ELEM_CHILD); + ch = data.charAt(currentOffset); + + // ChildSequence ::= ('/' [1-9] [0-9]*)+ + int child = 0; + while (ch >= '0' && ch <= '9') { + child = (child * 10) + (ch - '0'); + if (++currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + } + + // An invalid child sequence character + if (child == 0) { + reportError("InvalidChildSequenceCharacter", + new Object[] { new Character((char) ch) }); + return false; + } + + tokens.addToken(child); + + break; + + case CHARTYPE_DIGIT: + case CHARTYPE_LETTER: + case CHARTYPE_MINUS: + case CHARTYPE_NONASCII: + case CHARTYPE_OTHER: + case CHARTYPE_PERIOD: + case CHARTYPE_UNDERSCORE: + // Scan the ShortHand Pointer NCName + nameOffset = currentOffset; + currentOffset = scanNCName(data, endOffset, currentOffset); + + if (currentOffset == nameOffset) { + //return false; + reportError("InvalidNCNameInElementSchemeData", + new Object[] { data }); + return false; + } + + if (currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } else { + ch = -1; + } + + nameHandle = symbolTable.addSymbol(data.substring( + nameOffset, currentOffset)); + addToken(tokens, Tokens.XPTRTOKEN_ELEM_NCNAME); + tokens.addToken(nameHandle); + + break; + } + } + return true; + } + + /** + * Scans a NCName. + * From Namespaces in XML + * [5] NCName ::= (Letter | '_') (NCNameChar)* + * [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender + * + * @param data A String containing the XPointer expression + * @param endOffset The int XPointer expression length + * @param currentOffset An int representing the current position of the XPointer expression pointer + */ + private int scanNCName(String data, int endOffset, int currentOffset) { + int ch = data.charAt(currentOffset); + if (ch >= 0x80) { + if (!XMLChar.isNameStart(ch)) { + return currentOffset; + } + } else { + byte chartype = fASCIICharMap[ch]; + if (chartype != CHARTYPE_LETTER + && chartype != CHARTYPE_UNDERSCORE) { + return currentOffset; + } + } + while (++currentOffset < endOffset) { + ch = data.charAt(currentOffset); + if (ch >= 0x80) { + if (!XMLChar.isName(ch)) { + break; + } + } else { + byte chartype = fASCIICharMap[ch]; + if (chartype != CHARTYPE_LETTER + && chartype != CHARTYPE_DIGIT + && chartype != CHARTYPE_PERIOD + && chartype != CHARTYPE_MINUS + && chartype != CHARTYPE_UNDERSCORE) { + break; + } + } + } + return currentOffset; + } + + // + // Protected methods + // + + /** + * This method adds the specified token to the token list. By + * default, this method allows all tokens. However, subclasses + * of the XPathExprScanner can override this method in order + * to disallow certain tokens from being used in the scanned + * XPath expression. This is a convenient way of allowing only + * a subset of XPath. + */ + protected void addToken(Tokens tokens, int token) throws XNIException { + tokens.addToken(token); + } // addToken(int) + + } // class Scanner + +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xpointer/ShortHandPointer.java b/resources/xerces2-j-src/org/apache/xerces/xpointer/ShortHandPointer.java new file mode 100644 index 0000000..47b01ac --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xpointer/ShortHandPointer.java @@ -0,0 +1,294 @@ +/* + * 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. + */ + +package org.apache.xerces.xpointer; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.dv.XSSimpleType; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xs.AttributePSVI; +import org.apache.xerces.xs.XSTypeDefinition; + +/** + *

        + * Implements the XPointerPart interface and handles processing of + * ShortHand Pointers. It identifies at most one element in the + * resource's information set; specifically, the first one (if any) + * in document order that has a matching NCName as an identifier. + *

        + * + * @version $Id$ + */ +final class ShortHandPointer implements XPointerPart { + + // The name of the ShortHand pointer + private String fShortHandPointer; + + // The name of the ShortHand pointer + private boolean fIsFragmentResolved = false; + + // SymbolTable + private SymbolTable fSymbolTable; + + // + // Constructors + // + public ShortHandPointer() { + } + + public ShortHandPointer(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + } + + /** + * The XPointerProcessor takes care of this. Simply set the ShortHand Pointer here. + * + * @see org.apache.xerces.xpointer.XPointerPart#parseXPointer(java.lang.String) + */ + public void parseXPointer(String part) throws XNIException { + fShortHandPointer = part; + // reset fIsFragmentResolved + fIsFragmentResolved = false; + } + + /** + * Resolves the XPointer ShortHand pointer based on the rules defined in + * Section 3.2 of the XPointer Framework Recommendation. + * Note that in the current implementation only supports DTD determined ID's. + * + * @see org.apache.xerces.xpointer.XPointerPart#resolveXPointer(org.apache.xerces.xni.QName, org.apache.xerces.xni.XMLAttributes, org.apache.xerces.xni.Augmentations, int event) + */ + int fMatchingChildCount = 0; + public boolean resolveXPointer(QName element, XMLAttributes attributes, + Augmentations augs, int event) throws XNIException { + + // reset fIsFragmentResolved + if (fMatchingChildCount == 0) { + fIsFragmentResolved = false; + } + + // On startElement or emptyElement, if no matching elements or parent + // elements were found, check for a matching idenfitier. + if (event == XPointerPart.EVENT_ELEMENT_START) { + if (fMatchingChildCount == 0) { + fIsFragmentResolved = hasMatchingIdentifier(element, attributes, augs, + event); + } + if (fIsFragmentResolved) { + fMatchingChildCount++; + } + } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) { + if (fMatchingChildCount == 0) { + fIsFragmentResolved = hasMatchingIdentifier(element, attributes, augs, + event); + } + } + else { + // On endElement, decrease the matching child count if the child or + // its parent was resolved. + if (fIsFragmentResolved) { + fMatchingChildCount--; + } + } + + return fIsFragmentResolved ; + } + + /** + * + * @param element + * @param attributes + * @param augs + * @param event + * @return + * @throws XNIException + */ + private boolean hasMatchingIdentifier(QName element, + XMLAttributes attributes, Augmentations augs, int event) + throws XNIException { + String normalizedValue = null; + + // The identifiers of an element are determined by the + // ShortHand Pointer as follows: + + if (attributes != null) { + for (int i = 0; i < attributes.getLength(); i++) { + + // 1. If an element information item has an attribute information item + // among its [attributes] that is a schema-determined ID, then it is + // identified by the value of that attribute information item's + // [schema normalized value] property; + normalizedValue = getSchemaDeterminedID(attributes, i); + if (normalizedValue != null) { + break; + } + + // 2. If an element information item has an element information item among + // its [children] that is a schema-determined ID, then it is identified by + // the value of that element information item's [schema normalized value] property; + // ??? + normalizedValue = getChildrenSchemaDeterminedID(attributes, i); + if (normalizedValue != null) { + break; + } + + // 3. If an element information item has an attribute information item among + // its [attributes] that is a DTD-determined ID, then it is identified by the + // value of that attribute information item's [normalized value] property. + // An attribute information item is a DTD-determined ID if and only if it has + // a [type definition] property whose value is equal to ID. + normalizedValue = getDTDDeterminedID(attributes, i); + if (normalizedValue != null) { + break; + } + // 4. No externally determined ID's + } + } + + if (normalizedValue != null + && normalizedValue.equals(fShortHandPointer)) { + return true; + } + + return false; + } + + /** + * Rerturns the DTD determine-ID + * + * @param attributes + * @param index + * @return String + * @throws XNIException + */ + public String getDTDDeterminedID(XMLAttributes attributes, int index) + throws XNIException { + + if (attributes.getType(index).equals("ID")) { + return attributes.getValue(index); + } + return null; + } + + /** + * Returns the schema-determined-ID. + * + * + * @param attributes + * @param index + * @return A String containing the schema-determined ID. + * @throws XNIException + */ + public String getSchemaDeterminedID(XMLAttributes attributes, int index) + throws XNIException { + Augmentations augs = attributes.getAugmentations(index); + AttributePSVI attrPSVI = (AttributePSVI) augs + .getItem(Constants.ATTRIBUTE_PSVI); + + if (attrPSVI != null) { + // An element or attribute information item is a schema-determined + // ID if and only if one of the following is true:] + + // 1. It has a [member type definition] or [type definition] property + // whose value in turn has [name] equal to ID and [target namespace] + // equal to http://www.w3.org/2001/XMLSchema; + + // 2. It has a [base type definition] whose value has that [name] and [target namespace]; + + // 3. It has a [base type definition] whose value has a [base type definition] + // whose value has that [name] and [target namespace], and so on following + // the [base type definition] property recursively; + + XSTypeDefinition typeDef = attrPSVI.getMemberTypeDefinition(); + if (typeDef != null) { + typeDef = attrPSVI.getTypeDefinition(); + } + + // + if (typeDef != null && ((XSSimpleType) typeDef).isIDType()) { + return attrPSVI.getSchemaNormalizedValue(); + } + + // 4 & 5 NA + } + + return null; + } + + /** + * Not quite sure how this can be correctly implemented. + * + * @param attributes + * @param index + * @return String - We return null since we currenly do not supprt this. + * @throws XNIException + */ + public String getChildrenSchemaDeterminedID(XMLAttributes attributes, + int index) throws XNIException { + return null; + } + + /** + * + * @see org.apache.xerces.xpointer.XPointerPart#isFragmentResolved() + */ + public boolean isFragmentResolved() { + return fIsFragmentResolved; + } + + /** + * + * @see org.apache.xerces.xpointer.XPointerPart#isChildFragmentResolved() + */ + public boolean isChildFragmentResolved() { + return fIsFragmentResolved && (fMatchingChildCount > 0); + } + + /** + * Returns the name of the ShortHand pointer + * + * @see org.apache.xerces.xpointer.XPointerPart#getSchemeName() + */ + public String getSchemeName() { + return fShortHandPointer; + } + + /** + * @see org.apache.xerces.xpointer.XPointerPart#getSchemeData() + */ + public String getSchemeData() { + return null; + } + + /** + * @see org.apache.xerces.xpointer.XPointerPart#setSchemeName(java.lang.String) + */ + public void setSchemeName(String schemeName) { + fShortHandPointer = schemeName; + } + + /** + * @see org.apache.xerces.xpointer.XPointerPart#setSchemeData(java.lang.String) + */ + public void setSchemeData(String schemeData) { + // NA + } +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerErrorHandler.java b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerErrorHandler.java new file mode 100644 index 0000000..13d4daa --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerErrorHandler.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package org.apache.xerces.xpointer; + +import java.io.PrintWriter; + +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLParseException; + +/** + * The Default XPointer error handler used by the XInclude implementation. + * XPointer error's are thrown so that they may be caught by the XInclude + * implementation and reported as resource errors. + * + * @version $Id$ + */ +final class XPointerErrorHandler implements XMLErrorHandler { + + // + // Data + // + + /** Print writer. */ + protected PrintWriter fOut; + + // + // Constructors + // + + /** + * Constructs an error handler that prints error messages to + * System.err. + */ + public XPointerErrorHandler() { + this(new PrintWriter(System.err)); + } // () + + /** + * Constructs an error handler that prints error messages to the + * specified PrintWriter(PrintWriter) + + // + // ErrorHandler methods + // + + /** Warning. */ + public void warning(String domain, String key, XMLParseException ex) + throws XNIException { + printError("Warning", ex); + } // warning(XMLParseException) + + /** Error. */ + public void error(String domain, String key, XMLParseException ex) + throws XNIException { + printError("Error", ex); + //throw ex; + } // error(XMLParseException) + + /** Fatal error. */ + public void fatalError(String domain, String key, XMLParseException ex) + throws XNIException { + printError("Fatal Error", ex); + throw ex; + } // fatalError(XMLParseException) + + // + // Private methods + // + + /** Prints the error message. */ + private void printError(String type, XMLParseException ex) { + + fOut.print("["); + fOut.print(type); + fOut.print("] "); + String systemId = ex.getExpandedSystemId(); + if (systemId != null) { + int index = systemId.lastIndexOf('/'); + if (index != -1) + systemId = systemId.substring(index + 1); + fOut.print(systemId); + } + fOut.print(':'); + fOut.print(ex.getLineNumber()); + fOut.print(':'); + fOut.print(ex.getColumnNumber()); + fOut.print(": "); + fOut.print(ex.getMessage()); + fOut.println(); + fOut.flush(); + + } // printError(String,SAXParseException) + +} // class DefaultErrorHandler diff --git a/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerHandler.java b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerHandler.java new file mode 100644 index 0000000..98c142c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerHandler.java @@ -0,0 +1,1252 @@ +/* + * 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. + */ + +package org.apache.xerces.xpointer; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLErrorReporter; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xinclude.XIncludeHandler; +import org.apache.xerces.xinclude.XIncludeNamespaceSupport; +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XMLDocumentHandler; +import org.apache.xerces.xni.XMLString; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLConfigurationException; +import org.apache.xerces.xni.parser.XMLErrorHandler; + +/** + *

        + * This is a pipeline component which extends the XIncludeHandler to perform + * XPointer specific processing specified in the W3C XPointerFramework and + * element() Scheme Recommendations. + *

        + * + *

        + * This component analyzes each event in the pipeline, looking for an element + * that matches a PointerPart in the parent XInclude element's xpointer attribute + * value. If the match succeeds, all children are passed by this component. + *

        + * + *

        + * See the XPointer Framework Recommendation for + * more information on the XPointer Framework and ShortHand Pointers. + * See the XPointer element() Scheme Recommendation for + * more information on the XPointer element() Scheme. + *

        + * + * @xerces.internal + * + * @version $Id$ + */ +public final class XPointerHandler extends XIncludeHandler implements + XPointerProcessor { + + // Fields + // An ArrayList of XPointerParts + protected ArrayList fXPointerParts = null; + + // The current XPointerPart + protected XPointerPart fXPointerPart = null; + + // Has the fXPointerPart resolved successfully + protected boolean fFoundMatchingPtrPart = false; + + // The XPointer Error reporter + protected XMLErrorReporter fXPointerErrorReporter; + + // The XPointer Error Handler + protected XMLErrorHandler fErrorHandler; + + // XPointerFramework symbol table + protected SymbolTable fSymbolTable = null; + + // Supported schemes + private final String ELEMENT_SCHEME_NAME = "element"; + + // Has the XPointer resolved the subresource + protected boolean fIsXPointerResolved = false; + + // Fixup xml:base and xml:lang attributes + protected boolean fFixupBase = false; + protected boolean fFixupLang = false; + + // ************************************************************************ + // Constructors + // ************************************************************************ + + /** + * + */ + public XPointerHandler() { + super(); + + fXPointerParts = new ArrayList(); + fSymbolTable = new SymbolTable(); + } + + public XPointerHandler(SymbolTable symbolTable, + XMLErrorHandler errorHandler, XMLErrorReporter errorReporter) { + super(); + + fXPointerParts = new ArrayList(); + fSymbolTable = symbolTable; + fErrorHandler = errorHandler; + fXPointerErrorReporter = errorReporter; + //fErrorReporter = errorReporter; // The XInclude ErrorReporter + } + + public void setDocumentHandler(XMLDocumentHandler handler) { + fDocumentHandler = handler; + } + + // ************************************************************************ + // Implementation of the XPointerProcessor interface. + // ************************************************************************ + + /** + * Parses the XPointer framework expression and delegates scheme specific parsing. + * + * @see org.apache.xerces.xpointer.XPointerProcessor#parseXPointer(java.lang.String) + */ + public void parseXPointer(String xpointer) throws XNIException { + + // Initialize + init(); + + // tokens + final Tokens tokens = new Tokens(fSymbolTable); + + // scanner + Scanner scanner = new Scanner(fSymbolTable) { + protected void addToken(Tokens tokens, int token) + throws XNIException { + if (token == Tokens.XPTRTOKEN_OPEN_PAREN + || token == Tokens.XPTRTOKEN_CLOSE_PAREN + || token == Tokens.XPTRTOKEN_SCHEMENAME + || token == Tokens.XPTRTOKEN_SCHEMEDATA + || token == Tokens.XPTRTOKEN_SHORTHAND) { + super.addToken(tokens, token); + return; + } + reportError("InvalidXPointerToken", new Object[] { tokens + .getTokenString(token) }); + } + }; + + // scan the XPointer expression + int length = xpointer.length(); + boolean success = scanner.scanExpr(fSymbolTable, tokens, xpointer, 0, + length); + + if (!success) + reportError("InvalidXPointerExpression", new Object[] { xpointer }); + + while (tokens.hasMore()) { + int token = tokens.nextToken(); + + switch (token) { + case Tokens.XPTRTOKEN_SHORTHAND: { + + // The shortHand name + token = tokens.nextToken(); + String shortHandPointerName = tokens.getTokenString(token); + + if (shortHandPointerName == null) { + reportError("InvalidXPointerExpression", + new Object[] { xpointer }); + } + + XPointerPart shortHandPointer = new ShortHandPointer( + fSymbolTable); + shortHandPointer.setSchemeName(shortHandPointerName); + fXPointerParts.add(shortHandPointer); + break; + } + case Tokens.XPTRTOKEN_SCHEMENAME: { + + // Retreive the local name and prefix to form the scheme name + token = tokens.nextToken(); + String prefix = tokens.getTokenString(token); + token = tokens.nextToken(); + String localName = tokens.getTokenString(token); + + String schemeName = prefix + localName; + + // The next character should be an open parenthesis + int openParenCount = 0; + int closeParenCount = 0; + + token = tokens.nextToken(); + String openParen = tokens.getTokenString(token); + if (openParen != "XPTRTOKEN_OPEN_PAREN") { + + // can not have more than one ShortHand Pointer + if (token == Tokens.XPTRTOKEN_SHORTHAND) { + reportError("MultipleShortHandPointers", + new Object[] { xpointer }); + } else { + reportError("InvalidXPointerExpression", + new Object[] { xpointer }); + } + } + openParenCount++; + + // followed by zero or more ( and the schemeData + String schemeData = null; + while (tokens.hasMore()) { + token = tokens.nextToken(); + schemeData = tokens.getTokenString(token); + if (schemeData != "XPTRTOKEN_OPEN_PAREN") { + break; + } + openParenCount++; + } + token = tokens.nextToken(); + schemeData = tokens.getTokenString(token); + + // followed by the same number of ) + token = tokens.nextToken(); + String closeParen = tokens.getTokenString(token); + if (closeParen != "XPTRTOKEN_CLOSE_PAREN") { + reportError("SchemeDataNotFollowedByCloseParenthesis", + new Object[] { xpointer }); + } + closeParenCount++; + + while (tokens.hasMore()) { + if (tokens.getTokenString(tokens.peekToken()) != "XPTRTOKEN_OPEN_PAREN") { + break; + } + closeParenCount++; + } + + // check if the number of open parenthesis are equal to the number of close parenthesis + if (openParenCount != closeParenCount) { + reportError("UnbalancedParenthesisInXPointerExpression", + new Object[] { xpointer, + new Integer(openParenCount), + new Integer(closeParenCount) }); + } + + // Perform scheme specific parsing of the pointer part + if (schemeName.equals(ELEMENT_SCHEME_NAME)) { + XPointerPart elementSchemePointer = new ElementSchemePointer( + fSymbolTable, fErrorReporter); + elementSchemePointer.setSchemeName(schemeName); + elementSchemePointer.setSchemeData(schemeData); + + // If an exception occurs while parsing the element() scheme expression + // ignore it and move on to the next pointer part + try { + elementSchemePointer.parseXPointer(schemeData); + fXPointerParts.add(elementSchemePointer); + } catch (XNIException e) { + // Re-throw the XPointer element() scheme syntax error. + throw new XNIException (e); + } + + } else { + // ???? + reportWarning("SchemeUnsupported", + new Object[] { schemeName }); + } + + break; + } + default: + reportError("InvalidXPointerExpression", + new Object[] { xpointer }); + } + } + + } + + /** + * + * @see org.apache.xerces.xpointer.XPointerProcessor#resolveXPointer(org.apache.xerces.xni.QName, org.apache.xerces.xni.XMLAttributes, org.apache.xerces.xni.Augmentations, int event) + */ + public boolean resolveXPointer(QName element, XMLAttributes attributes, + Augmentations augs, int event) throws XNIException { + boolean resolved = false; + + // The result of the first pointer part whose evaluation identifies + // one or more subresources is reported by the XPointer processor as the + // result of the pointer as a whole, and evaluation stops. + // In our implementation, typically the first xpointer scheme that + // matches an element is the document is considered. + // If the pointer part resolved then use it, else search for the fragment + // using next pointer part from lef-right. + if (!fFoundMatchingPtrPart) { + + // for each element, attempt to resolve it against each pointer part + // in the XPointer expression until a matching element is found. + for (int i = 0; i < fXPointerParts.size(); i++) { + + fXPointerPart = (XPointerPart) fXPointerParts.get(i); + + if (fXPointerPart.resolveXPointer(element, attributes, augs, + event)) { + fFoundMatchingPtrPart = true; + resolved = true; + } + } + } else { + if (fXPointerPart.resolveXPointer(element, attributes, augs, event)) { + resolved = true; + } + } + + if (!fIsXPointerResolved) { + fIsXPointerResolved = resolved; + } + + return resolved; + } + + /** + * Returns true if the Node fragment is resolved. + * + * @see org.apache.xerces.xpointer.XPointerProcessor#isFragmentResolved() + */ + public boolean isFragmentResolved() throws XNIException { + boolean resolved = (fXPointerPart != null) ? fXPointerPart.isFragmentResolved() + : false; + + if (!fIsXPointerResolved) { + fIsXPointerResolved = resolved; + } + + return resolved; + } + + /** + * Returns true if the XPointer expression resolves to a non-element child + * of the current resource fragment. + * + * @see org.apache.xerces.xpointer.XPointerPart#isChildFragmentResolved() + * + */ + public boolean isChildFragmentResolved() throws XNIException { + boolean resolved = (fXPointerPart != null) ? fXPointerPart + .isChildFragmentResolved() : false; + return resolved; + } + + /** + * Returns true if the XPointer successfully found a sub-resource . + * + * @see org.apache.xerces.xpointer.XPointerProcessor#isFragmentResolved() + */ + public boolean isXPointerResolved() throws XNIException { + return fIsXPointerResolved; + } + + /** + * Returns the pointer part used to resolve the document fragment. + * + * @return String - The pointer part used to resolve the document fragment. + */ + public XPointerPart getXPointerPart() { + return fXPointerPart; + } + + /** + * Reports XPointer Errors + * + */ + private void reportError(String key, Object[] arguments) + throws XNIException { + /* + fXPointerErrorReporter.reportError( + XPointerMessageFormatter.XPOINTER_DOMAIN, key, arguments, + XMLErrorReporter.SEVERITY_ERROR); + */ + throw new XNIException((fErrorReporter + .getMessageFormatter(XPointerMessageFormatter.XPOINTER_DOMAIN)) + .formatMessage(fErrorReporter.getLocale(), key, arguments)); + } + + /** + * Reports XPointer Warnings + * + */ + private void reportWarning(String key, Object[] arguments) + throws XNIException { + fXPointerErrorReporter.reportError( + XPointerMessageFormatter.XPOINTER_DOMAIN, key, arguments, + XMLErrorReporter.SEVERITY_WARNING); + } + + /** + * Initializes error handling objects + * + */ + protected void initErrorReporter() { + if (fXPointerErrorReporter == null) { + fXPointerErrorReporter = new XMLErrorReporter(); + } + if (fErrorHandler == null) { + fErrorHandler = new XPointerErrorHandler(); + } + /* + fXPointerErrorReporter.setProperty(Constants.XERCES_PROPERTY_PREFIX + + Constants.ERROR_HANDLER_PROPERTY, fErrorHandler); + */ + fXPointerErrorReporter.putMessageFormatter( + XPointerMessageFormatter.XPOINTER_DOMAIN, + new XPointerMessageFormatter()); + } + + /** + * Initializes the XPointer Processor; + */ + protected void init() { + fXPointerParts.clear(); + fXPointerPart = null; + fFoundMatchingPtrPart = false; + fIsXPointerResolved = false; + //fFixupBase = false; + //fFixupLang = false; + + initErrorReporter(); + } + + /** + * Returns an ArrayList of XPointerPart objects + * + * @return An ArrayList of XPointerPart objects. + */ + public ArrayList getPointerParts() { + return fXPointerParts; + } + + /** + * List of XPointer Framework tokens. + * + * @xerces.internal + * + */ + private final class Tokens { + + /** + * XPointer Framework tokens + * [1] Pointer ::= Shorthand | SchemeBased + * [2] Shorthand ::= NCName + * [3] SchemeBased ::= PointerPart (S? PointerPart)* + * [4] PointerPart ::= SchemeName '(' SchemeData ')' + * [5] SchemeName ::= QName + * [6] SchemeData ::= EscapedData* + * [7] EscapedData ::= NormalChar | '^(' | '^)' | '^^' | '(' SchemeData ')' + * [8] NormalChar ::= UnicodeChar - [()^] + * [9] UnicodeChar ::= [#x0-#x10FFFF] + * + */ + private static final int XPTRTOKEN_OPEN_PAREN = 0, + XPTRTOKEN_CLOSE_PAREN = 1, XPTRTOKEN_SHORTHAND = 2, + XPTRTOKEN_SCHEMENAME = 3, XPTRTOKEN_SCHEMEDATA = 4; + + // Token names + private final String[] fgTokenNames = { "XPTRTOKEN_OPEN_PAREN", + "XPTRTOKEN_CLOSE_PAREN", "XPTRTOKEN_SHORTHAND", + "XPTRTOKEN_SCHEMENAME", "XPTRTOKEN_SCHEMEDATA" }; + + // Token count + private static final int INITIAL_TOKEN_COUNT = 1 << 8; + + private int[] fTokens = new int[INITIAL_TOKEN_COUNT]; + + private int fTokenCount = 0; + + // Current token position + private int fCurrentTokenIndex; + + private SymbolTable fSymbolTable; + + private HashMap fTokenNames = new HashMap(); + + /** + * Constructor + * + * @param symbolTable SymbolTable + */ + private Tokens(SymbolTable symbolTable) { + fSymbolTable = symbolTable; + + fTokenNames.put(new Integer(XPTRTOKEN_OPEN_PAREN), + "XPTRTOKEN_OPEN_PAREN"); + fTokenNames.put(new Integer(XPTRTOKEN_CLOSE_PAREN), + "XPTRTOKEN_CLOSE_PAREN"); + fTokenNames.put(new Integer(XPTRTOKEN_SHORTHAND), + "XPTRTOKEN_SHORTHAND"); + fTokenNames.put(new Integer(XPTRTOKEN_SCHEMENAME), + "XPTRTOKEN_SCHEMENAME"); + fTokenNames.put(new Integer(XPTRTOKEN_SCHEMEDATA), + "XPTRTOKEN_SCHEMEDATA"); + } + + /** + * Returns the token String + * @param token The index of the token + * @return String The token string + */ + private String getTokenString(int token) { + return (String) fTokenNames.get(new Integer(token)); + } + + /** + * Add the specified string as a token + * + * @param token The token string + */ + private void addToken(String tokenStr) { + Integer tokenInt = (Integer) fTokenNames.get(tokenStr); + if (tokenInt == null) { + tokenInt = new Integer(fTokenNames.size()); + fTokenNames.put(tokenInt, tokenStr); + } + addToken(tokenInt.intValue()); + } + + /** + * Add the specified int token + * + * @param token The int specifying the token + */ + private void addToken(int token) { + try { + fTokens[fTokenCount] = token; + } catch (ArrayIndexOutOfBoundsException ex) { + int[] oldList = fTokens; + fTokens = new int[fTokenCount << 1]; + System.arraycopy(oldList, 0, fTokens, 0, fTokenCount); + fTokens[fTokenCount] = token; + } + fTokenCount++; + } + + /** + * Resets the current position to the head of the token list. + */ + private void rewind() { + fCurrentTokenIndex = 0; + } + + /** + * Returns true if the {@link #getNextToken()} method + * returns a valid token. + */ + private boolean hasMore() { + return fCurrentTokenIndex < fTokenCount; + } + + /** + * Obtains the token at the current position, then advance + * the current position by one. + * + * throws If there's no such next token, this method throws + * new XNIException("XPointerProcessingError");. + */ + private int nextToken() throws XNIException { + if (fCurrentTokenIndex == fTokenCount) { + reportError("XPointerProcessingError", null); + } + return fTokens[fCurrentTokenIndex++]; + } + + /** + * Obtains the token at the current position, without advancing + * the current position. + * + * If there's no such next token, this method throws + * new XNIException("XPointerProcessingError");. + */ + private int peekToken() throws XNIException { + if (fCurrentTokenIndex == fTokenCount) { + reportError("XPointerProcessingError", null); + } + return fTokens[fCurrentTokenIndex]; + } + + /** + * Obtains the token at the current position as a String. + * + * If there's no current token or if the current token + * is not a string token, this method throws + * If there's no such next token, this method throws + * new XNIException("XPointerProcessingError");. + */ + private String nextTokenAsString() throws XNIException { + String tokenStrint = getTokenString(nextToken()); + if (tokenStrint == null) { + reportError("XPointerProcessingError", null); + } + return tokenStrint; + } + } + + /** + * + * The XPointer expression scanner. Scans the XPointer framework expression. + * + * @xerces.internal + * + */ + private class Scanner { + + /** + * 7-bit ASCII subset + * + * 0 1 2 3 4 5 6 7 8 9 A B C D E F + * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0 + * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2 + * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3 + * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4 + * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5 + * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6 + * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7 + */ + private static final byte CHARTYPE_INVALID = 0, // invalid XML character + CHARTYPE_OTHER = 1, // not special - one of "#%&;?\`{}~" or DEL + CHARTYPE_WHITESPACE = 2, // one of "\t\n\r " (0x09, 0x0A, 0x0D, 0x20) + CHARTYPE_CARRET = 3, // ^ + CHARTYPE_OPEN_PAREN = 4, // '(' (0x28) + CHARTYPE_CLOSE_PAREN = 5, // ')' (0x29) + CHARTYPE_MINUS = 6, // '-' (0x2D) + CHARTYPE_PERIOD = 7, // '.' (0x2E) + CHARTYPE_SLASH = 8, // '/' (0x2F) + CHARTYPE_DIGIT = 9, // '0'-'9' (0x30 to 0x39) + CHARTYPE_COLON = 10, // ':' (0x3A) + CHARTYPE_EQUAL = 11, // '=' (0x3D) + CHARTYPE_LETTER = 12, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A) + CHARTYPE_UNDERSCORE = 13, // '_' (0x5F) + CHARTYPE_NONASCII = 14; // Non-ASCII Unicode codepoint (>= 0x80) + + private final byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 1, 1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 6, 7, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 10, 1, 1, 11, 1, 1, 1, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 1, 1, 1, 3, 13, 1, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 1, 1, 1, 1, 1 }; + + // + // Data + // + /** Symbol table. */ + private SymbolTable fSymbolTable; + + /** + * Constructs an XPointer Framework expression scanner. + * + * @param symbolTable SymbolTable + */ + private Scanner(SymbolTable symbolTable) { + // save pool and tokens + fSymbolTable = symbolTable; + + } // (SymbolTable) + + /** + * Scans the XPointer Expression + * + */ + private boolean scanExpr(SymbolTable symbolTable, Tokens tokens, + String data, int currentOffset, int endOffset) + throws XNIException { + + int ch; + int openParen = 0; + int closeParen = 0; + int nameOffset, dataOffset; + boolean isQName = false; + String name = null; + String prefix = null; + String schemeData = null; + StringBuffer schemeDataBuff = new StringBuffer(); + + while (true) { + + if (currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + + // + while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) { + if (++currentOffset == endOffset) { + break; + } + ch = data.charAt(currentOffset); + } + if (currentOffset == endOffset) { + break; + } + + // + // [1] Pointer ::= Shorthand | SchemeBased + // [2] Shorthand ::= NCName + // [3] SchemeBased ::= PointerPart (S? PointerPart)* + // [4] PointerPart ::= SchemeName '(' SchemeData ')' + // [5] SchemeName ::= QName + // [6] SchemeData ::= EscapedData* + // [7] EscapedData ::= NormalChar | '^(' | '^)' | '^^' | '(' SchemeData ')' + // [8] NormalChar ::= UnicodeChar - [()^] + // [9] UnicodeChar ::= [#x0-#x10FFFF] + // [?] QName ::= (NCName ':')? NCName + // [?] NCName ::= (Letter | '_') (NCNameChar)* + // [?] NCNameChar ::= Letter | Digit | '.' | '-' | '_' (ascii subset of 'NCNameChar') + // [?] Letter ::= [A-Za-z] (ascii subset of 'Letter') + // [?] Digit ::= [0-9] (ascii subset of 'Digit') + // + byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII + : fASCIICharMap[ch]; + + switch (chartype) { + + case CHARTYPE_OPEN_PAREN: // '(' + addToken(tokens, Tokens.XPTRTOKEN_OPEN_PAREN); + openParen++; + ++currentOffset; + break; + + case CHARTYPE_CLOSE_PAREN: // ')' + addToken(tokens, Tokens.XPTRTOKEN_CLOSE_PAREN); + closeParen++; + ++currentOffset; + break; + + case CHARTYPE_CARRET: + case CHARTYPE_COLON: + case CHARTYPE_DIGIT: + case CHARTYPE_EQUAL: + case CHARTYPE_LETTER: + case CHARTYPE_MINUS: + case CHARTYPE_NONASCII: + case CHARTYPE_OTHER: + case CHARTYPE_PERIOD: + case CHARTYPE_SLASH: + case CHARTYPE_UNDERSCORE: + case CHARTYPE_WHITESPACE: + // Scanning SchemeName | Shorthand + if (openParen == 0) { + nameOffset = currentOffset; + currentOffset = scanNCName(data, endOffset, + currentOffset); + + if (currentOffset == nameOffset) { + reportError("InvalidShortHandPointer", + new Object[] { data }); + return false; + } + + if (currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } else { + ch = -1; + } + + name = symbolTable.addSymbol(data.substring(nameOffset, + currentOffset)); + prefix = XMLSymbols.EMPTY_STRING; + + // The name is a QName => a SchemeName + if (ch == ':') { + if (++currentOffset == endOffset) { + return false; + } + + ch = data.charAt(currentOffset); + prefix = name; + nameOffset = currentOffset; + currentOffset = scanNCName(data, endOffset, + currentOffset); + + if (currentOffset == nameOffset) { + return false; + } + + if (currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } else { + ch = -1; + } + + isQName = true; + name = symbolTable.addSymbol(data.substring( + nameOffset, currentOffset)); + } + + // REVISIT: + if (currentOffset != endOffset) { + addToken(tokens, Tokens.XPTRTOKEN_SCHEMENAME); + tokens.addToken(prefix); + tokens.addToken(name); + isQName = false; + } else if (currentOffset == endOffset) { + // NCName => Shorthand + addToken(tokens, Tokens.XPTRTOKEN_SHORTHAND); + tokens.addToken(name); + isQName = false; + } + + // reset open/close paren for the next pointer part + closeParen = 0; + + break; + + } else if (openParen > 0 && closeParen == 0 && name != null) { + // Scanning SchemeData + dataOffset = currentOffset; + currentOffset = scanData(data, schemeDataBuff, + endOffset, currentOffset); + + if (currentOffset == dataOffset) { + reportError("InvalidSchemeDataInXPointer", + new Object[] { data }); + return false; + } + + if (currentOffset < endOffset) { + ch = data.charAt(currentOffset); + } else { + ch = -1; + } + + schemeData = symbolTable.addSymbol(schemeDataBuff + .toString()); + addToken(tokens, Tokens.XPTRTOKEN_SCHEMEDATA); + tokens.addToken(schemeData); + + // reset open/close paren for the next pointer part + openParen = 0; + schemeDataBuff.delete(0, schemeDataBuff.length()); + + } else { + // ex. schemeName() + // Should we throw an exception with a more suitable message instead?? + return false; + } + } + } // end while + return true; + } + + /** + * Scans a NCName. + * From Namespaces in XML + * [5] NCName ::= (Letter | '_') (NCNameChar)* + * [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender + * + * @param data A String containing the XPointer expression + * @param endOffset The int XPointer expression length + * @param currentOffset An int representing the current position of the XPointer expression pointer + */ + private int scanNCName(String data, int endOffset, int currentOffset) { + int ch = data.charAt(currentOffset); + if (ch >= 0x80) { + if (!XMLChar.isNameStart(ch)) { + return currentOffset; + } + } else { + byte chartype = fASCIICharMap[ch]; + if (chartype != CHARTYPE_LETTER + && chartype != CHARTYPE_UNDERSCORE) { + return currentOffset; + } + } + + //while (currentOffset++ < endOffset) { + while (++currentOffset < endOffset) { + ch = data.charAt(currentOffset); + if (ch >= 0x80) { + if (!XMLChar.isName(ch)) { + break; + } + } else { + byte chartype = fASCIICharMap[ch]; + if (chartype != CHARTYPE_LETTER + && chartype != CHARTYPE_DIGIT + && chartype != CHARTYPE_PERIOD + && chartype != CHARTYPE_MINUS + && chartype != CHARTYPE_UNDERSCORE) { + break; + } + } + } + return currentOffset; + } + + /** + * Scans the SchemeData. + * [6] SchemeData ::= EscapedData* + * [7] EscapedData ::= NormalChar | '^(' | '^)' | '^^' | '(' SchemeData ')' + * [8] NormalChar ::= UnicodeChar - [()^] + * [9] UnicodeChar ::= [#x0-#x10FFFF] + * + */ + private int scanData(String data, StringBuffer schemeData, + int endOffset, int currentOffset) { + while (true) { + + if (currentOffset == endOffset) { + break; + } + + int ch = data.charAt(currentOffset); + byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII + : fASCIICharMap[ch]; + + if (chartype == CHARTYPE_OPEN_PAREN) { + schemeData.append(ch); + //schemeData.append(Tokens.XPTRTOKEN_OPEN_PAREN); + currentOffset = scanData(data, schemeData, endOffset, + ++currentOffset); + if (currentOffset == endOffset) { + return currentOffset; + } + + ch = data.charAt(currentOffset); + chartype = (ch >= 0x80) ? CHARTYPE_NONASCII + : fASCIICharMap[ch]; + + if (chartype != CHARTYPE_CLOSE_PAREN) { + return endOffset; + } + schemeData.append((char) ch); + ++currentOffset;// + + } else if (chartype == CHARTYPE_CLOSE_PAREN) { + return currentOffset; + + } else if (chartype == CHARTYPE_CARRET) { + ch = data.charAt(++currentOffset); + chartype = (ch >= 0x80) ? CHARTYPE_NONASCII + : fASCIICharMap[ch]; + + if (chartype != CHARTYPE_CARRET + && chartype != CHARTYPE_OPEN_PAREN + && chartype != CHARTYPE_CLOSE_PAREN) { + break; + } + schemeData.append((char) ch); + ++currentOffset; + + } else { + schemeData.append((char) ch); + ++currentOffset;// + } + } + + return currentOffset; + } + + // + // Protected methods + // + + /** + * This method adds the specified token to the token list. By + * default, this method allows all tokens. However, subclasses + * of the XPathExprScanner can override this method in order + * to disallow certain tokens from being used in the scanned + * XPath expression. This is a convenient way of allowing only + * a subset of XPath. + */ + protected void addToken(Tokens tokens, int token) throws XNIException { + tokens.addToken(token); + } // addToken(int) + + } // class Scanner + + // ************************************************************************ + // Overridden XMLDocumentHandler methods + // ************************************************************************ + /** + * If the comment is a child of a matched element, then pass else return. + * + * @param text The text in the comment. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by application to signal an error. + */ + public void comment(XMLString text, Augmentations augs) throws XNIException { + if (!isChildFragmentResolved()) { + return; + } + super.comment(text, augs); + } + + /** + * A processing instruction. Processing instructions consist of a + * target name and, optionally, text data. The data is only meaningful + * to the application. + *

        + * Typically, a processing instruction's data will contain a series + * of pseudo-attributes. These pseudo-attributes follow the form of + * element attributes but are not parsed or presented + * to the application as anything other than text. The application is + * responsible for parsing the data. + * + * @param target The target. + * @param data The data or null if none specified. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void processingInstruction(String target, XMLString data, + Augmentations augs) throws XNIException { + if (!isChildFragmentResolved()) { + return; + } + super.processingInstruction(target, data, augs); + } + + /** + * The start of an element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + if (!resolveXPointer(element, attributes, augs, + XPointerPart.EVENT_ELEMENT_START)) { + + // xml:base and xml:lang processing + if (fFixupBase) { + processXMLBaseAttributes(attributes); + } + if (fFixupLang) { + processXMLLangAttributes(attributes); + } + + // set the context invalid if the element till an element from the result infoset is included + fNamespaceContext.setContextInvalid(); + + return; + } + super.startElement(element, attributes, augs); + } + + /** + * An empty element. + * + * @param element The name of the element. + * @param attributes The element attributes. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void emptyElement(QName element, XMLAttributes attributes, + Augmentations augs) throws XNIException { + if (!resolveXPointer(element, attributes, augs, + XPointerPart.EVENT_ELEMENT_EMPTY)) { + // xml:base and xml:lang processing + if (fFixupBase) { + processXMLBaseAttributes(attributes); + } + if (fFixupLang) { + processXMLLangAttributes(attributes); + } + // no need to restore restoreBaseURI() for xml:base and xml:lang processing + + // set the context invalid if the element till an element from the result infoset is included + fNamespaceContext.setContextInvalid(); + return; + } + super.emptyElement(element, attributes, augs); + } + + /** + * Character content. + * + * @param text The content. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void characters(XMLString text, Augmentations augs) + throws XNIException { + if (!isChildFragmentResolved()) { + return; + } + super.characters(text, augs); + } + + /** + * Ignorable whitespace. For this method to be called, the document + * source must have some way of determining that the text containing + * only whitespace characters should be considered ignorable. For + * example, the validator can determine if a length of whitespace + * characters in the document are ignorable based on the element + * content model. + * + * @param text The ignorable whitespace. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void ignorableWhitespace(XMLString text, Augmentations augs) + throws XNIException { + if (!isChildFragmentResolved()) { + return; + } + super.ignorableWhitespace(text, augs); + } + + /** + * The end of an element. + * + * @param element The name of the element. + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endElement(QName element, Augmentations augs) + throws XNIException { + if (!resolveXPointer(element, null, augs, + XPointerPart.EVENT_ELEMENT_END)) { + + // no need to restore restoreBaseURI() for xml:base and xml:lang processing + return; + } + super.endElement(element, augs); + } + + /** + * The start of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void startCDATA(Augmentations augs) throws XNIException { + if (!isChildFragmentResolved()) { + return; + } + super.startCDATA(augs); + } + + /** + * The end of a CDATA section. + * + * @param augs Additional information that may include infoset augmentations + * + * @exception XNIException + * Thrown by handler to signal an error. + */ + public void endCDATA(Augmentations augs) throws XNIException { + if (!isChildFragmentResolved()) { + return; + } + super.endCDATA(augs); + } + + // ************************************************************************ + // Overridden XMLComponent methods + // ************************************************************************ + /** + *

        + * Sets the value of a property. This method is called by the component + * manager any time after reset when a property changes value. + *

        + * Note: Components should silently ignore properties + * that do not affect the operation of the component. + * + * @param propertyId The property identifier. + * @param value The value of the property. + * + * @throws XMLConfigurationException Thrown for configuration error. + * In general, components should + * only throw this exception if + * it is really + * a critical error. + */ + public void setProperty(String propertyId, Object value) + throws XMLConfigurationException { + + // Error reporter + if (propertyId == Constants.XERCES_PROPERTY_PREFIX + + Constants.ERROR_REPORTER_PROPERTY) { + if (value != null) { + fXPointerErrorReporter = (XMLErrorReporter) value; + } else { + fXPointerErrorReporter = null; + } + } + + // Error handler + if (propertyId == Constants.XERCES_PROPERTY_PREFIX + + Constants.ERROR_HANDLER_PROPERTY) { + if (value != null) { + fErrorHandler = (XMLErrorHandler) value; + } else { + fErrorHandler = null; + } + } + + // xml:lang + if (propertyId == Constants.XERCES_FEATURE_PREFIX + + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE) { + if (value != null) { + fFixupLang = ((Boolean)value).booleanValue(); + } else { + fFixupLang = false; + } + } + + // xml:base + if (propertyId == Constants.XERCES_FEATURE_PREFIX + + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE) { + if (value != null) { + fFixupBase = ((Boolean)value).booleanValue(); + } else { + fFixupBase = false; + } + } + + // + if (propertyId == Constants.XERCES_PROPERTY_PREFIX + + Constants.NAMESPACE_CONTEXT_PROPERTY) { + fNamespaceContext = (XIncludeNamespaceSupport) value; + } + + super.setProperty(propertyId, value); + } + +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerMessageFormatter.java b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerMessageFormatter.java new file mode 100644 index 0000000..e27d403 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerMessageFormatter.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package org.apache.xerces.xpointer; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.xerces.util.MessageFormatter; + +/** + * XPointerMessageFormatter provides error messages for the XPointer Framework + * and element() Scheme Recommendations. + * + * @xerces.internal + * + * @version $Id$ + */ +final class XPointerMessageFormatter implements MessageFormatter { + + public static final String XPOINTER_DOMAIN = "http://www.w3.org/TR/XPTR"; + + // private objects to cache the locale and resource bundle + private Locale fLocale = null; + + private ResourceBundle fResourceBundle = null; + + /** + * Formats a message with the specified arguments using the given locale + * information. + * + * @param locale + * The locale of the message. + * @param key + * The message key. + * @param arguments + * The message replacement text arguments. The order of the + * arguments must match that of the placeholders in the actual + * message. + * + * @return Returns the formatted message. + * + * @throws MissingResourceException + * Thrown if the message with the specified key cannot be found. + */ + public String formatMessage(Locale locale, String key, Object[] arguments) + throws MissingResourceException { + + if (locale == null) { + locale = Locale.getDefault(); + } + if (locale != fLocale) { + fResourceBundle = ResourceBundle.getBundle("org.apache.xerces.impl.msg.XPointerMessages", locale); + // memorize the most-recent locale + fLocale = locale; + } + + String msg = fResourceBundle.getString(key); + if (arguments != null) { + try { + msg = java.text.MessageFormat.format(msg, arguments); + } catch (Exception e) { + msg = fResourceBundle.getString("FormatFailed"); + msg += " " + fResourceBundle.getString(key); + } + } + + if (msg == null) { + msg = fResourceBundle.getString("BadMessageKey"); + throw new MissingResourceException(msg, + "org.apache.xerces.impl.msg.XPointerMessages", key); + } + + return msg; + } +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerPart.java b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerPart.java new file mode 100644 index 0000000..7fda62c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerPart.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +package org.apache.xerces.xpointer; + +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XNIException; + +/** + *

        + * Used for scheme specific parsing and evaluation of an XPointer expression. + * This interface applies to both ShortHand and SchemeBased XPointer + * expressions. + *

        + * + * @xerces.internal + * + * @version $Id$ + */ +public interface XPointerPart { + + // The start element event + public static final int EVENT_ELEMENT_START = 0; + + // The end element event + public static final int EVENT_ELEMENT_END = 1; + + // The empty element event + public static final int EVENT_ELEMENT_EMPTY = 2; + + /** + * Provides scheme specific parsing of a XPointer expression i.e. + * the PointerPart or ShortHandPointer. + * + * @param part A String representing the PointerPart or ShortHandPointer. + * @throws XNIException Thrown if the PointerPart string does not conform to + * the syntax defined by its scheme. + * + */ + public void parseXPointer(String part) throws XNIException; + + /** + * Evaluates an XML resource with respect to an XPointer expressions + * by checking if it's element and attributes parameters match the + * criteria specified in the xpointer expression. + * + * @param element - The name of the element. + * @param attributes - The element attributes. + * @param augs - Additional information that may include infoset augmentations + * @param event - An integer indicating + * 0 - The start of an element + * 1 - The end of an element + * 2 - An empty element call + * @throws XNIException Thrown to signal an error + * + */ + public boolean resolveXPointer(QName element, XMLAttributes attributes, + Augmentations augs, int event) throws XNIException; + + /** + * Returns true if the XPointer expression resolves to a resource fragment + * specified as input else returns false. + * + * @return True if the xpointer expression matches a fragment in the resource + * else returns false. + * @throws XNIException Thrown to signal an error + * + */ + public boolean isFragmentResolved() throws XNIException; + + /** + * Returns true if the XPointer expression resolves to a non-element child + * of the current resource fragment. + * + * @return True if the XPointer expression resolves to a non-element child + * of the current resource fragment. + * @throws XNIException Thrown to signal an error + * + */ + public boolean isChildFragmentResolved() throws XNIException; + + /** + * Returns a String containing the scheme name of the PointerPart + * or the name of the ShortHand Pointer. + * + * @return A String containing the scheme name of the PointerPart. + * + */ + public String getSchemeName(); + + /** + * Returns a String containing the scheme data of the PointerPart. + * + * @return A String containing the scheme data of the PointerPart. + * + */ + public String getSchemeData(); + + /** + * Sets the scheme name of the PointerPart or the ShortHand Pointer name. + * + * @param schemeName A String containing the scheme name of the PointerPart. + * + */ + public void setSchemeName(String schemeName); + + /** + * Sets the scheme data of the PointerPart. + * + * @param schemeData A String containing the scheme data of the PointerPart. + * + */ + public void setSchemeData(String schemeData); + +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerProcessor.java b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerProcessor.java new file mode 100644 index 0000000..18e9e81 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xpointer/XPointerProcessor.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.xerces.xpointer; + +import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.QName; +import org.apache.xerces.xni.XMLAttributes; +import org.apache.xerces.xni.XNIException; + +/** + *

        + * The XPointerProcessor is responsible for parsing an XPointer + * expression and and providing scheme specific resolution of + * the document fragment pointed to be the pointer. + *

        + * + * @xerces.internal + * + * @version $Id$ + */ +public interface XPointerProcessor { + + // The start element event + public static final int EVENT_ELEMENT_START = 0; + + // The end element event + public static final int EVENT_ELEMENT_END = 1; + + // The empty element event + public static final int EVENT_ELEMENT_EMPTY = 2; + + /** + * Parses an XPointer expression. It performs scheme specific processing + * depending on the pointer parts and sets up a Vector of XPointerParts + * in the order (left-to-right) they appear in the XPointer expression. + * + * @param xpointer A String representing the xpointer expression. + * @throws XNIException Thrown if the xpointer string does not conform to + * the XPointer Framework syntax or the syntax of the pointer part does + * not conform to its definition for its scheme. + */ + public void parseXPointer(String xpointer) throws XNIException; + + /** + * Evaluates an XML resource with respect to an XPointer expressions + * by checking if it's element and attributes parameters match the + * criteria specified in the xpointer expression. + * + * @param element - The name of the element. + * @param attributes - The element attributes. + * @param augs - Additional information that may include infoset augmentations + * @param event - An integer indicating + * 0 - The start of an element + * 1 - The end of an element + * 2 - An empty element call + * @return true if the element was resolved by the xpointer + * @throws XNIException Thrown to signal an error + */ + public boolean resolveXPointer(QName element, XMLAttributes attributes, + Augmentations augs, int event) throws XNIException; + + /** + * Returns true if the XPointer expression resolves to the current resource fragment + * or Node which is part of the input resource being streamed else returns false. + * + * @return True if the xpointer expression matches a node/fragment in the resource + * else returns false. + * @throws XNIException Thrown to signal an error + */ + public boolean isFragmentResolved() throws XNIException; + + /** + * Returns true if the XPointer expression resolves any subresource of the + * input resource. + * + * @return True if the xpointer expression matches a fragment in the resource + * else returns false. + * @throws XNIException Thrown to signal an error + */ + public boolean isXPointerResolved() throws XNIException; + +} \ No newline at end of file diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/AttributePSVI.java b/resources/xerces2-j-src/org/apache/xerces/xs/AttributePSVI.java new file mode 100644 index 0000000..5e2b7da --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/AttributePSVI.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * Represents a PSVI item for one attribute information item. + */ +public interface AttributePSVI extends ItemPSVI { + /** + * [attribute declaration]: An item isomorphic to the declaration + * component itself. + */ + public XSAttributeDeclaration getAttributeDeclaration(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/ElementPSVI.java b/resources/xerces2-j-src/org/apache/xerces/xs/ElementPSVI.java new file mode 100644 index 0000000..af7f279 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/ElementPSVI.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * Represents a PSVI item for one element information item. + */ +public interface ElementPSVI extends ItemPSVI { + /** + * [element declaration]: an item isomorphic to the element declaration + * used to validate this element. + */ + public XSElementDeclaration getElementDeclaration(); + + /** + * [notation]: the notation declaration. + */ + public XSNotationDeclaration getNotation(); + + /** + * [nil]: true if clause 3.2 of Element Locally Valid (Element) (3.3.4) is + * satisfied, otherwise false. + */ + public boolean getNil(); + + /** + * schema information: the schema information property if it is the + * validation root, null otherwise. + */ + public XSModel getSchemaInformation(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/ItemPSVI.java b/resources/xerces2-j-src/org/apache/xerces/xs/ItemPSVI.java new file mode 100644 index 0000000..e855e08 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/ItemPSVI.java @@ -0,0 +1,222 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * Represents an abstract PSVI item for an element or an attribute + * information item. + */ +public interface ItemPSVI { + /** + * Validity value indicating that validation has either not been performed + * or that a strict assessment of validity could not be performed. + */ + public static final short VALIDITY_NOTKNOWN = 0; + /** + * Validity value indicating that validation has been strictly assessed + * and the item in question is invalid according to the rules of schema + * validation. + */ + public static final short VALIDITY_INVALID = 1; + /** + * Validation status indicating that schema validation has been performed + * and the item in question is valid according to the rules of schema + * validation. + */ + public static final short VALIDITY_VALID = 2; + /** + * Validation status indicating that schema validation has been performed + * and the item in question has specifically been skipped. + */ + public static final short VALIDATION_NONE = 0; + /** + * Validation status indicating that schema validation has been performed + * on the item in question under the rules of lax validation. + */ + public static final short VALIDATION_PARTIAL = 1; + /** + * Validation status indicating that full schema validation has been + * performed on the item. + */ + public static final short VALIDATION_FULL = 2; + + /** + * Returns a reference to an immutable instance with the same data + * that this instance of ItemPSVI currently has. + */ + public ItemPSVI constant(); + + /** + * Returns true if this specific instance of + * ItemPSVI is immutable, otherwise false. + */ + public boolean isConstant(); + + /** + * The nearest ancestor element information item with a + * [schema information] property (or this element item + * itself if it has such a property). For more information refer to + * element validation context and attribute validation context . + */ + public String getValidationContext(); + + /** + * [validity]: determines the validity of the schema item + * with respect to the validation being attempted. The value will be one + * of the constants: VALIDITY_NOTKNOWN, + * VALIDITY_INVALID or VALIDITY_VALID. + */ + public short getValidity(); + + /** + * [validation attempted]: determines the extent to which + * the schema item has been validated. The value will be one of the + * constants: VALIDATION_NONE, + * VALIDATION_PARTIAL or VALIDATION_FULL. + */ + public short getValidationAttempted(); + + /** + * [schema error code]: a list of error codes generated from + * the validation attempt or an empty StringList if no + * errors occurred during the validation attempt. + */ + public StringList getErrorCodes(); + + /** + * A list of error messages generated from the validation attempt or + * an empty StringList if no errors occurred during the + * validation attempt. The indices of error messages in this list are + * aligned with those in the [schema error code] list. + */ + public StringList getErrorMessages(); + + /** + * [schema normalized value]: the normalized value of this + * item after validation. + * + * @deprecated Use getSchemaValue().getNormalizedValue() instead + */ + public String getSchemaNormalizedValue(); + + /** + * [schema normalized value]: Binding specific actual value + * or null if the value is in error. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getSchemaValue().getActualValue() instead + */ + public Object getActualNormalizedValue() + throws XSException; + + /** + * The actual value built-in datatype, e.g. + * STRING_DT, SHORT_DT. If the type definition of this + * value is a list type definition, this method returns + * LIST_DT. If the type definition of this value is a list + * type definition whose item type is a union type definition, this + * method returns LISTOFUNION_DT. To query the actual value + * of the list or list of union type definitions use + * itemValueTypes. If the actualNormalizedValue + * is null, this method returns UNAVAILABLE_DT. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getSchemaValue().getActualValueType() instead + */ + public short getActualNormalizedValueType() + throws XSException; + + /** + * In the case the actual value represents a list, i.e. the + * actualNormalizedValueType is LIST_DT, the + * returned array consists of one type kind which represents the itemType + * . For example: + *
         <simpleType name="listtype"> <list 
        +     * itemType="positiveInteger"/> </simpleType> <element 
        +     * name="list" type="listtype"/> ... <list>1 2 3</list> 
        + * + * The schemaNormalizedValue value is "1 2 3", the + * actualNormalizedValueType value is LIST_DT, + * and the itemValueTypes is an array of size 1 with the + * value POSITIVEINTEGER_DT. + *
        If the actual value represents a list type definition whose item + * type is a union type definition, i.e. LISTOFUNION_DT, + * for each actual value in the list the array contains the + * corresponding memberType kind. For example: + *
         <simpleType 
        +     * name='union_type' memberTypes="integer string"/> <simpleType 
        +     * name='listOfUnion'> <list itemType='union_type'/> 
        +     * </simpleType> <element name="list" type="listOfUnion"/> 
        +     * ... <list>1 2 foo</list> 
        + * The + * schemaNormalizedValue value is "1 2 foo", the + * actualNormalizedValueType is LISTOFUNION_DT + * , and the itemValueTypes is an array of size 3 with the + * following values: INTEGER_DT, INTEGER_DT, STRING_DT. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getSchemaValue().getListValueTypes() instead + */ + public ShortList getItemValueTypes() + throws XSException; + + /** + * If this item has a simple type definition or a complex type with simple + * content, then return the value with respect to the simple type. If + * this item doesn't have a simple-typed value, the behavior of this method + * is not specified. + */ + public XSValue getSchemaValue(); + + /** + * [type definition]: an item isomorphic to the type + * definition used to validate the schema item. + */ + public XSTypeDefinition getTypeDefinition(); + + /** + * [member type definition]: if and only if that type + * definition is a simple type definition with {variety} union, or a + * complex type definition whose {content type} is a simple type + * definition with {variety} union, then an item isomorphic to that + * member of the union's {member type definitions} which actually + * validated the schema item's normalized value. + */ + public XSSimpleTypeDefinition getMemberTypeDefinition(); + + /** + * [schema default]: the canonical lexical representation of + * the declaration's {value constraint} value. For more information + * refer to element schema default and attribute schema default. + */ + public String getSchemaDefault(); + + /** + * [schema specified]: if true, the value was specified in + * the schema. If false, the value comes from the infoset. For more + * information refer to element specified and attribute specified. + */ + public boolean getIsSchemaSpecified(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/LSInputList.java b/resources/xerces2-j-src/org/apache/xerces/xs/LSInputList.java new file mode 100644 index 0000000..7d3c7b8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/LSInputList.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import java.util.List; + +import org.w3c.dom.ls.LSInput; + +/** + * The LSInputList interface provides the abstraction of an + * ordered collection of LSInputs, without defining or + * constraining how this collection is implemented. + */ +public interface LSInputList extends List { + /** + * The number of LSInputs in the list. The range of valid + * child object indices is 0 to length-1 inclusive. + */ + public int getLength(); + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The LSInput at the indexth + * position in the LSInputList, or null if + * the index specified is not valid. + */ + public LSInput item(int index); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/PSVIProvider.java b/resources/xerces2-j-src/org/apache/xerces/xs/PSVIProvider.java new file mode 100644 index 0000000..668420e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/PSVIProvider.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface provides access to the post schema validation infoset for an + * API that provides a streaming document infoset, such as SAX, XNI, and + * others. + *

        For implementations that would like to provide access to the PSVI in a + * streaming model, a parser object should also implement the + * PSVIProvider interface. Within the scope of the methods + * handling the start and end of an element, applications may use the + * PSVIProvider to retrieve the PSVI related to the element and + * its attributes. + */ +public interface PSVIProvider { + /** + * Provides the post schema validation item for the current element + * information item. The method must be called by an application while + * in the scope of the methods which report the start and end of an + * element. For example, for SAX the method must be called within the + * scope of the document handler's startElement or + * endElement call. If the method is called outside of the + * specified scope, the return value is undefined. + * @return The post schema validation infoset for the current element. If + * an element information item is valid, then in the + * post-schema-validation infoset the following properties must be + * available for the element information item: The following + * properties are available in the scope of the method that reports + * the start of an element: {element declaration}, {validation + * context}, {notation}. The {schema information} property is + * available for the validation root. The {error codes} property is + * available if any errors occured during validation. The following + * properties are available in the scope of the method that reports + * the end of an element: {nil}, {schema specified}, {normalized + * value},{ member type definition}, {validity}, {validation attempted} + * . If the declaration has a value constraint, the property {schema + * default} is available. The {error codes} property is available if + * any errors occured during validation. Note: some processors may + * choose to provide all the PSVI properties in the scope of the + * method that reports the end of an element. + */ + public ElementPSVI getElementPSVI(); + + /** + * Provides AttributePSVI given the index of an attribute + * information item in the current element's attribute list. The method + * must be called by an application while in the scope of the methods + * which report the start and end of an element at a point where the + * attribute list is available. For example, for SAX the method must be + * called while in the scope of the document handler's + * startElement call. If the method is called outside of + * the specified scope, the return value is undefined. + * @param index The attribute index. + * @return The post schema validation properties of the attribute. + */ + public AttributePSVI getAttributePSVI(int index); + + /** + * Provides AttributePSVI given the namespace name and the + * local name of an attribute information item in the current element's + * attribute list. The method must be called by an application while in + * the scope of the methods which report the start and end of an element + * at a point where the attribute list is available. For example, for + * SAX the method must be called while in the scope of the document + * handler's startElement call. If the method is called + * outside of the specified scope, the return value is undefined. + * @param uri The namespace name of an attribute. + * @param localname The local name of an attribute. + * @return The post schema validation properties of the attribute. + */ + public AttributePSVI getAttributePSVIByName(String uri, + String localname); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/ShortList.java b/resources/xerces2-j-src/org/apache/xerces/xs/ShortList.java new file mode 100644 index 0000000..b26564c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/ShortList.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import java.util.List; + +/** + * The ShortList is an immutable ordered collection of + * unsigned short. + */ +public interface ShortList extends List { + /** + * The number of unsigned shorts in the list. The range of + * valid child object indices is 0 to length-1 inclusive. + */ + public int getLength(); + + /** + * Checks if the unsigned short item is a + * member of this list. + * @param item unsigned short whose presence in this list + * is to be tested. + * @return True if this list contains the unsigned short + * item. + */ + public boolean contains(short item); + + /** + * Returns the indexth item in the collection. The index + * starts at 0. + * @param index index into the collection. + * @return The unsigned short at the indexth + * position in the ShortList. + * @exception XSException + * INDEX_SIZE_ERR: if index is greater than or equal to the + * number of objects in the list. + */ + public short item(int index) + throws XSException; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/StringList.java b/resources/xerces2-j-src/org/apache/xerces/xs/StringList.java new file mode 100644 index 0000000..933cd6e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/StringList.java @@ -0,0 +1,54 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import java.util.List; + +/** + * The StringList is an immutable ordered collection of + * GenericString. + */ +public interface StringList extends List { + /** + * The number of GenericStrings in the list. The range of + * valid child object indices is 0 to length-1 inclusive. + */ + public int getLength(); + + /** + * Checks if the GenericString item is a member + * of this list. + * @param item GenericString whose presence in this list is + * to be tested. + * @return True if this list contains the GenericString + * item. + */ + public boolean contains(String item); + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The GenericString at the indexth + * position in the StringList, or null if + * the index specified is not valid. + */ + public String item(int index); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSAnnotation.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSAnnotation.java new file mode 100644 index 0000000..e49d2e8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSAnnotation.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Annotation schema component. + */ +public interface XSAnnotation extends XSObject { + // TargetType + /** + * The object type is org.w3c.dom.Element. + */ + public static final short W3C_DOM_ELEMENT = 1; + /** + * The object type is org.xml.sax.ContentHandler. + */ + public static final short SAX_CONTENTHANDLER = 2; + /** + * The object type is org.w3c.dom.Document. + */ + public static final short W3C_DOM_DOCUMENT = 3; + + /** + * Write contents of the annotation to the specified object. If the + * specified target is a DOM object, in-scope namespace + * declarations for annotation element are added as + * attribute nodes of the serialized annotation, otherwise + * the corresponding events for all in-scope namespace declarations are + * sent via the specified document handler. + * @param target A target pointer to the annotation target object, i.e. + * org.w3c.dom.Document, org.w3c.dom.Element + * , org.xml.sax.ContentHandler. + * @param targetType A target type. + * @return True if the target is a recognized type and + * supported by this implementation, otherwise false. + */ + public boolean writeAnnotation(Object target, + short targetType); + + /** + * A text representation of the annotation. + */ + public String getAnnotationString(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeDeclaration.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeDeclaration.java new file mode 100644 index 0000000..8247bf1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeDeclaration.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * The interface represents the Attribute Declaration schema component. + */ +public interface XSAttributeDeclaration extends XSObject { + /** + * [type definition]: A simple type definition. + */ + public XSSimpleTypeDefinition getTypeDefinition(); + + /** + * [scope]. One of SCOPE_GLOBAL, SCOPE_LOCAL, or + * SCOPE_ABSENT. If the scope is local, then the + * enclosingCTDefinition is present. + */ + public short getScope(); + + /** + * The complex type definition for locally scoped declarations (see + * scope), otherwise null if no such + * definition exists. + */ + public XSComplexTypeDefinition getEnclosingCTDefinition(); + + /** + * Value constraint: one of VC_NONE, VC_DEFAULT, VC_FIXED. + */ + public short getConstraintType(); + + /** + * Value constraint: The constraint value with respect to the [type + * definition], otherwise null. + * + * @deprecated Use getValueConstraintValue().getNormalizedValue() instead + */ + public String getConstraintValue(); + + /** + * Value Constraint: Binding specific actual constraint value or + * null if the value is in error or there is no value + * constraint. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getActualValue() instead + */ + public Object getActualVC() + throws XSException; + + /** + * The actual constraint value built-in datatype, e.g. + * STRING_DT, SHORT_DT. If the type definition of this + * value is a list type definition, this method returns + * LIST_DT. If the type definition of this value is a list + * type definition whose item type is a union type definition, this + * method returns LISTOFUNION_DT. To query the actual + * constraint value of the list or list of union type definitions use + * itemValueTypes. If the actualValue is + * null, this method returns UNAVAILABLE_DT. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getActualValueType() instead + */ + public short getActualVCType() + throws XSException; + + /** + * In the case the actual constraint value represents a list, i.e. the + * actualValueType is LIST_DT, the returned + * array consists of one type kind which represents the itemType. If the + * actual constraint value represents a list type definition whose item + * type is a union type definition, i.e. LISTOFUNION_DT, + * for each actual constraint value in the list the array contains the + * corresponding memberType kind. For examples, see + * ItemPSVI.itemValueTypes. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getListValueTypes() instead + */ + public ShortList getItemValueTypes() + throws XSException; + + /** + * The actual value of the default or fixed value constraint. + */ + public XSValue getValueConstraintValue(); + + /** + * An annotation if it exists, otherwise null. + * If not null then the first [annotation] from the sequence of annotations. + */ + public XSAnnotation getAnnotation(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeGroupDefinition.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeGroupDefinition.java new file mode 100644 index 0000000..860526e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeGroupDefinition.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Attribute Group Definition schema component. + */ +public interface XSAttributeGroupDefinition extends XSObject { + /** + * A set of [attribute uses] if it exists, otherwise an empty + * XSObjectList. + */ + public XSObjectList getAttributeUses(); + + /** + * A [wildcard] if it exists, otherwise null. + */ + public XSWildcard getAttributeWildcard(); + + /** + * An annotation if it exists, otherwise null. If not null + * then the first [annotation] from the sequence of annotations. + */ + public XSAnnotation getAnnotation(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeUse.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeUse.java new file mode 100644 index 0000000..c3f7c17 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSAttributeUse.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Attribute Use schema component. + */ +public interface XSAttributeUse extends XSObject { + /** + * [required]: determines whether this use of an attribute declaration + * requires an appropriate attribute information item to be present, or + * merely allows it. + */ + public boolean getRequired(); + + /** + * [attribute declaration]: provides the attribute declaration itself, + * which will in turn determine the simple type definition used. + */ + public XSAttributeDeclaration getAttrDeclaration(); + + /** + * Value Constraint: one of default, fixed, or none. + */ + public short getConstraintType(); + + /** + * Value Constraint: The constraint value, otherwise null. + * + * @deprecated Use getValueConstraintValue().getNormalizedValue() instead + */ + public String getConstraintValue(); + + /** + * Value Constraint: Binding specific actual constraint value or + * null if the value is in error or there is no value + * constraint. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getActualValue() instead + */ + public Object getActualVC() + throws XSException; + + /** + * The actual constraint value built-in datatype, e.g. + * STRING_DT, SHORT_DT. If the type definition of this + * value is a list type definition, this method returns + * LIST_DT. If the type definition of this value is a list + * type definition whose item type is a union type definition, this + * method returns LISTOFUNION_DT. To query the actual + * constraint value of the list or list of union type definitions use + * itemValueTypes. If the actualNormalizedValue + * is null, this method returns UNAVAILABLE_DT. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getActualValueType() instead + */ + public short getActualVCType() + throws XSException; + + /** + * In the case the actual constraint value represents a list, i.e. the + * actualValueType is LIST_DT, the returned + * array consists of one type kind which represents the itemType. If the + * actual constraint value represents a list type definition whose item + * type is a union type definition, i.e. LISTOFUNION_DT, + * for each actual constraint value in the list the array contains the + * corresponding memberType kind. For examples, see + * ItemPSVI.itemValueTypes. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getListValueTypes() instead + */ + public ShortList getItemValueTypes() + throws XSException; + + /** + * The actual value of the default or fixed value constraint. + */ + public XSValue getValueConstraintValue(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSComplexTypeDefinition.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSComplexTypeDefinition.java new file mode 100644 index 0000000..975bd4f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSComplexTypeDefinition.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Complex Type Definition schema component. + */ +public interface XSComplexTypeDefinition extends XSTypeDefinition { + // Content Model Types + /** + * Represents an empty content type. A content type with the distinguished + * value empty validates elements with no character or element + * information item children. + */ + public static final short CONTENTTYPE_EMPTY = 0; + /** + * Represents a simple content type. A content type which is simple + * validates elements with character-only children. + */ + public static final short CONTENTTYPE_SIMPLE = 1; + /** + * Represents an element-only content type. An element-only content type + * validates elements with children that conform to the supplied content + * model. + */ + public static final short CONTENTTYPE_ELEMENT = 2; + /** + * Represents a mixed content type. + */ + public static final short CONTENTTYPE_MIXED = 3; + + /** + * [derivation method]: either DERIVATION_EXTENSION, + * DERIVATION_RESTRICTION, or DERIVATION_NONE + * (see XSConstants). + */ + public short getDerivationMethod(); + + /** + * [abstract]: a boolean. Complex types for which abstract is + * true must not be used as the type definition for the validation of + * element information items. + */ + public boolean getAbstract(); + + /** + * A set of attribute uses if it exists, otherwise an empty + * XSObjectList. + */ + public XSObjectList getAttributeUses(); + + /** + * An attribute wildcard if it exists, otherwise null. + */ + public XSWildcard getAttributeWildcard(); + + /** + * [content type]: one of empty (CONTENTTYPE_EMPTY), a simple + * type definition (CONTENTTYPE_SIMPLE), mixed ( + * CONTENTTYPE_MIXED), or element-only ( + * CONTENTTYPE_ELEMENT). + */ + public short getContentType(); + + /** + * A simple type definition corresponding to a simple content model, + * otherwise null. + */ + public XSSimpleTypeDefinition getSimpleType(); + + /** + * A particle for a mixed or element-only content model, otherwise + * null. + */ + public XSParticle getParticle(); + + /** + * [prohibited substitutions]: a subset of {extension, restriction} + * @param restriction Extension or restriction constants (see + * XSConstants). + * @return True if restriction is a prohibited substitution, + * otherwise false. + */ + public boolean isProhibitedSubstitution(short restriction); + + /** + * [prohibited substitutions]: A subset of {extension, restriction} or + * DERIVATION_NONE represented as a bit flag (see + * XSConstants). + */ + public short getProhibitedSubstitutions(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSConstants.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSConstants.java new file mode 100644 index 0000000..4ab421a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSConstants.java @@ -0,0 +1,326 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface defines constants used by this specification. + */ +public interface XSConstants { + // XML Schema Components + /** + * The object describes an attribute declaration. + */ + public static final short ATTRIBUTE_DECLARATION = 1; + /** + * The object describes an element declaration. + */ + public static final short ELEMENT_DECLARATION = 2; + /** + * The object describes a complex type or simple type definition. + */ + public static final short TYPE_DEFINITION = 3; + /** + * The object describes an attribute use definition. + */ + public static final short ATTRIBUTE_USE = 4; + /** + * The object describes an attribute group definition. + */ + public static final short ATTRIBUTE_GROUP = 5; + /** + * The object describes a model group definition. + */ + public static final short MODEL_GROUP_DEFINITION = 6; + /** + * A model group. + */ + public static final short MODEL_GROUP = 7; + /** + * The object describes a particle. + */ + public static final short PARTICLE = 8; + /** + * The object describes a wildcard. + */ + public static final short WILDCARD = 9; + /** + * The object describes an identity constraint definition. + */ + public static final short IDENTITY_CONSTRAINT = 10; + /** + * The object describes a notation declaration. + */ + public static final short NOTATION_DECLARATION = 11; + /** + * The object describes an annotation. + */ + public static final short ANNOTATION = 12; + /** + * The object describes a constraining facet. Note: this object does not + * describe pattern and enumeration facets. + */ + public static final short FACET = 13; + /** + * The object describes enumeration and pattern facets. + */ + public static final short MULTIVALUE_FACET = 14; + + // Derivation constants + /** + * No constraint is available. + */ + public static final short DERIVATION_NONE = 0; + /** + * XSTypeDefinition final set or + * XSElementDeclaration disallowed substitution group. + */ + public static final short DERIVATION_EXTENSION = 1; + /** + * XSTypeDefinition final set or + * XSElementDeclaration disallowed substitution group. + */ + public static final short DERIVATION_RESTRICTION = 2; + /** + * XSTypeDefinition final set. + */ + public static final short DERIVATION_SUBSTITUTION = 4; + /** + * XSTypeDefinition final set. + */ + public static final short DERIVATION_UNION = 8; + /** + * XSTypeDefinition final set. + */ + public static final short DERIVATION_LIST = 16; + + // Scope + /** + * The scope of a declaration within named model groups or attribute + * groups is absent. The scope of such a declaration is + * determined when it is used in the construction of complex type + * definitions. + */ + public static final short SCOPE_ABSENT = 0; + /** + * A scope of global identifies top-level declarations. + */ + public static final short SCOPE_GLOBAL = 1; + /** + * Locally scoped declarations are available for use only + * within the complex type. + */ + public static final short SCOPE_LOCAL = 2; + + // Value Constraint + /** + * Indicates that the component does not have any value constraint. + */ + public static final short VC_NONE = 0; + /** + * Indicates that there is a default value constraint. + */ + public static final short VC_DEFAULT = 1; + /** + * Indicates that there is a fixed value constraint for this attribute. + */ + public static final short VC_FIXED = 2; + + // Built-in types: primitive and derived + /** + * anySimpleType + */ + public static final short ANYSIMPLETYPE_DT = 1; + /** + * string + */ + public static final short STRING_DT = 2; + /** + * boolean + */ + public static final short BOOLEAN_DT = 3; + /** + * decimal + */ + public static final short DECIMAL_DT = 4; + /** + * float + */ + public static final short FLOAT_DT = 5; + /** + * double + */ + public static final short DOUBLE_DT = 6; + /** + * duration + */ + public static final short DURATION_DT = 7; + /** + * dateTime + */ + public static final short DATETIME_DT = 8; + /** + * time + */ + public static final short TIME_DT = 9; + /** + * date + */ + public static final short DATE_DT = 10; + /** + * gYearMonth + */ + public static final short GYEARMONTH_DT = 11; + /** + * gYear + */ + public static final short GYEAR_DT = 12; + /** + * gMonthDay + */ + public static final short GMONTHDAY_DT = 13; + /** + * gDay + */ + public static final short GDAY_DT = 14; + /** + * gMonth + */ + public static final short GMONTH_DT = 15; + /** + * hexBinary + */ + public static final short HEXBINARY_DT = 16; + /** + * base64Binary + */ + public static final short BASE64BINARY_DT = 17; + /** + * anyURI + */ + public static final short ANYURI_DT = 18; + /** + * QName + */ + public static final short QNAME_DT = 19; + /** + * NOTATION + */ + public static final short NOTATION_DT = 20; + /** + * normalizedString + */ + public static final short NORMALIZEDSTRING_DT = 21; + /** + * token + */ + public static final short TOKEN_DT = 22; + /** + * language + */ + public static final short LANGUAGE_DT = 23; + /** + * NMTOKEN + */ + public static final short NMTOKEN_DT = 24; + /** + * Name + */ + public static final short NAME_DT = 25; + /** + * NCName + */ + public static final short NCNAME_DT = 26; + /** + * ID + */ + public static final short ID_DT = 27; + /** + * IDREF + */ + public static final short IDREF_DT = 28; + /** + * ENTITY + */ + public static final short ENTITY_DT = 29; + /** + * integer + */ + public static final short INTEGER_DT = 30; + /** + * nonPositiveInteger + */ + public static final short NONPOSITIVEINTEGER_DT = 31; + /** + * negativeInteger + */ + public static final short NEGATIVEINTEGER_DT = 32; + /** + * long + */ + public static final short LONG_DT = 33; + /** + * int + */ + public static final short INT_DT = 34; + /** + * short + */ + public static final short SHORT_DT = 35; + /** + * byte + */ + public static final short BYTE_DT = 36; + /** + * nonNegativeInteger + */ + public static final short NONNEGATIVEINTEGER_DT = 37; + /** + * unsignedLong + */ + public static final short UNSIGNEDLONG_DT = 38; + /** + * unsignedInt + */ + public static final short UNSIGNEDINT_DT = 39; + /** + * unsignedShort + */ + public static final short UNSIGNEDSHORT_DT = 40; + /** + * unsignedByte + */ + public static final short UNSIGNEDBYTE_DT = 41; + /** + * positiveInteger + */ + public static final short POSITIVEINTEGER_DT = 42; + /** + * The type represents a list type definition whose item type (itemType) + * is a union type definition + */ + public static final short LISTOFUNION_DT = 43; + /** + * The type represents a list type definition. + */ + public static final short LIST_DT = 44; + /** + * The built-in type category is not available. + */ + public static final short UNAVAILABLE_DT = 45; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSElementDeclaration.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSElementDeclaration.java new file mode 100644 index 0000000..1831072 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSElementDeclaration.java @@ -0,0 +1,189 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * The interface represents the Element Declaration schema component. + */ +public interface XSElementDeclaration extends XSTerm { + /** + * [type definition]: either a simple type definition or a complex type + * definition. + */ + public XSTypeDefinition getTypeDefinition(); + + /** + * [scope]. One of SCOPE_GLOBAL, SCOPE_LOCAL, or + * SCOPE_ABSENT. If the scope is local, then the + * enclosingCTDefinition is present. + */ + public short getScope(); + + /** + * The complex type definition for locally scoped declarations (see + * scope), otherwise null if no such + * definition exists. + */ + public XSComplexTypeDefinition getEnclosingCTDefinition(); + + /** + * [Value constraint]: one of VC_NONE, VC_DEFAULT, VC_FIXED. + */ + public short getConstraintType(); + + /** + * [Value constraint]: the constraint value with respect to the [type + * definition], otherwise null. + * + * @deprecated Use getValueConstraintValue().getNormalizedValue() instead + */ + public String getConstraintValue(); + + /** + * Value Constraint: Binding specific actual constraint value or + * null if the value is in error or there is no value + * constraint. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getActualValue() instead + */ + public Object getActualVC() + throws XSException; + + /** + * The actual constraint value built-in datatype, e.g. + * STRING_DT, SHORT_DT. If the type definition of this + * value is a list type definition, this method returns + * LIST_DT. If the type definition of this value is a list + * type definition whose item type is a union type definition, this + * method returns LISTOFUNION_DT. To query the actual + * constraint value of the list or list of union type definitions use + * itemValueTypes. If the actualNormalizedValue + * is null, this method returns UNAVAILABLE_DT. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getActualValueType() instead + */ + public short getActualVCType() + throws XSException; + + /** + * In the case the actual constraint value represents a list, i.e. the + * actualValueType is LIST_DT, the returned + * array consists of one type kind which represents the itemType. If the + * actual constraint value represents a list type definition whose item + * type is a union type definition, i.e. LISTOFUNION_DT, + * for each actual constraint value in the list the array contains the + * corresponding memberType kind. For examples, see + * ItemPSVI.itemValueTypes. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support this + * method. + * + * @deprecated Use getValueConstraintValue().getListValueTypes() instead + */ + public ShortList getItemValueTypes() + throws XSException; + + /** + * The actual value of the default or fixed value constraint. + */ + public XSValue getValueConstraintValue(); + + /** + * If nillable is true, then an element may also be valid if it carries + * the namespace qualified attribute with local name nil + * from namespace http://www.w3.org/2001/XMLSchema-instance + * and value true (xsi:nil) even if it has no text or + * element content despite a content type which would + * otherwise require content. + */ + public boolean getNillable(); + + /** + * identity-constraint definitions: a set of constraint definitions if it + * exists, otherwise an empty XSNamedMap. + */ + public XSNamedMap getIdentityConstraints(); + + /** + * [substitution group affiliation]: a top-level element definition if it + * exists, otherwise null. + */ + public XSElementDeclaration getSubstitutionGroupAffiliation(); + + /** + * Convenience method that checks if exclusion is a + * substitution group exclusion for this element declaration. + * @param exclusion + * DERIVATION_EXTENSION, DERIVATION_RESTRICTION or + * DERIVATION_NONE. Represents final set for the element. + * @return True if exclusion is a part of the substitution + * group exclusion subset. + */ + public boolean isSubstitutionGroupExclusion(short exclusion); + + /** + * [substitution group exclusions]: the returned value is a bit + * combination of the subset of { + * DERIVATION_EXTENSION, DERIVATION_RESTRICTION} or + * DERIVATION_NONE. + */ + public short getSubstitutionGroupExclusions(); + + /** + * Convenience method that checks if disallowed is a + * disallowed substitution for this element declaration. + * @param disallowed { + * DERIVATION_SUBSTITUTION, DERIVATION_EXTENSION, DERIVATION_RESTRICTION + * } or DERIVATION_NONE. Represents a block set for the + * element. + * @return True if disallowed is a part of the substitution + * group exclusion subset. + */ + public boolean isDisallowedSubstitution(short disallowed); + + /** + * [disallowed substitutions]: the returned value is a bit combination of + * the subset of { + * DERIVATION_SUBSTITUTION, DERIVATION_EXTENSION, DERIVATION_RESTRICTION + * } corresponding to substitutions disallowed by this + * XSElementDeclaration or DERIVATION_NONE. + */ + public short getDisallowedSubstitutions(); + + /** + * {abstract} A boolean. + */ + public boolean getAbstract(); + + /** + * An annotation if it exists, otherwise null. If not null + * then the first [annotation] from the sequence of annotations. + */ + public XSAnnotation getAnnotation(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSException.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSException.java new file mode 100644 index 0000000..9e86770 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSException.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * The XML Schema API 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). + *

        Implementations should raise other exceptions under other circumstances. + *

        Some languages and object systems do not support the concept of + * exceptions. For such systems, error conditions may be indicated using + * native error reporting mechanisms. For some bindings, for example, + * methods may return error codes similar to those listed in the + * corresponding method descriptions. + */ +public class XSException extends RuntimeException { + + /** Serialization version. */ + static final long serialVersionUID = 3111893084677917742L; + + public XSException(short code, String message) { + super(message); + this.code = code; + } + public short code; + // ExceptionCode + /** + * If the implementation does not support the requested type of object or + * operation. + */ + public static final short NOT_SUPPORTED_ERR = 1; + /** + * If index or size is negative, or greater than the allowed value + */ + public static final short INDEX_SIZE_ERR = 2; + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSFacet.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSFacet.java new file mode 100644 index 0000000..054b6d8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSFacet.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * Describes a constraining facet. Enumeration and pattern facets are exposed + * via XSMultiValueFacet interface. + */ +public interface XSFacet extends XSObject { + /** + * The name of the facet, e.g. FACET_LENGTH, FACET_TOTALDIGITS + * (see XSSimpleTypeDefinition). + */ + public short getFacetKind(); + + /** + * A value of this facet. + */ + public String getLexicalFacetValue(); + + /** + * If this facet is length, minLength, maxLength, totalDigits, or + * fractionDigits, and if the value can fit in "int", then return the value + * of the facet as an int. If the value can't fit, return -1. Use + * getActualFacetValue() to get the BigInteger representation. For all other + * facets, return 0. + */ + public int getIntFacetValue(); + + /** + * If this facet is minInclusive, maxInclusive, minExclusive, or + * maxExclusive, then return the actual value of the facet. If this facet + * is length, minLength, maxLength, totalDigits, or fractionDigits, then + * return a BigInteger representation of the value. If this facet is + * whiteSpace, then return the String representation of the facet. + */ + public Object getActualFacetValue(); + + /** + * [Facets]: check whether a facet is fixed. + */ + public boolean getFixed(); + + /** + * An annotation if it exists, otherwise null. If not null + * then the first [annotation] from the sequence of annotations. + */ + public XSAnnotation getAnnotation(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSIDCDefinition.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSIDCDefinition.java new file mode 100644 index 0000000..e29a852 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSIDCDefinition.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Identity-constraint Definition schema + * component. + */ +public interface XSIDCDefinition extends XSObject { + // Identity Constraints + /** + * See the definition of key in the identity-constraint + * category. + */ + public static final short IC_KEY = 1; + /** + * See the definition of keyref in the identity-constraint + * category. + */ + public static final short IC_KEYREF = 2; + /** + * See the definition of unique in the identity-constraint + * category. + */ + public static final short IC_UNIQUE = 3; + + /** + * [identity-constraint category]: one of key, keyref or unique. + */ + public short getCategory(); + + /** + * [selector]: a restricted XPath 1.0 expression. + */ + public String getSelectorStr(); + + /** + * [fields]: a non-empty list of restricted XPath 1.0 expressions. + */ + public StringList getFieldStrs(); + + /** + * [referenced key]: required if [identity-constraint category] is keyref, + * null otherwise. An identity-constraint definition with [ + * identity-constraint category] equal to key or unique. + */ + public XSIDCDefinition getRefKey(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSImplementation.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSImplementation.java new file mode 100644 index 0000000..915f7d9 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSImplementation.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import org.w3c.dom.ls.LSInput; + +/** + * This interface allows one to retrieve an instance of XSLoader. + * This interface should be implemented on the same object that implements + * DOMImplementation. + */ +public interface XSImplementation { + /** + * A list containing the versions of XML Schema documents recognized by + * this XSImplemenation. + */ + public StringList getRecognizedVersions(); + + + /** + * Creates a new XSLoader. The newly constructed loader may then be + * configured and used to load XML Schemas. + * @param versions A list containing the versions of XML Schema + * documents which can be loaded by the XSLoader or + * null to permit XML Schema documents of any recognized + * version to be loaded by the XSLoader. + * @return An XML Schema loader. + * @exception XSException + * NOT_SUPPORTED_ERR: Raised if the implementation does not support one + * of the specified versions. + */ + public XSLoader createXSLoader(StringList versions) + throws XSException; + + /** + * Creates an immutable StringList from the given array of Strings. + * @param values the array containing the String values that will be placed in the list. + * @return an immutable StringList from the given array of Strings. + */ + public StringList createStringList(String[] values); + + /** + * Creates an immutable LSInputList from the given array of LSInputs. + * @param values the array containing the LSInput values that will be placed in the list. + * @return an immutable LSInputList from the given array of LSInputs. + */ + public LSInputList createLSInputList(LSInput[] values); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSLoader.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSLoader.java new file mode 100644 index 0000000..f916fcf --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSLoader.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.ls.LSInput; + +/** + * An interface that provides a method to load XML Schema documents. This + * interface uses the DOM Level 3 Core and Load and Save interfaces. + */ +public interface XSLoader { + /** + * The configuration of a document. It maintains a table of recognized + * parameters. Using the configuration, it is possible to change the + * behavior of the load methods. The configuration may support the + * setting of and the retrieval of the following non-boolean parameters + * defined on the DOMConfiguration interface: + * error-handler (DOMErrorHandler) and + * resource-resolver (LSResourceResolver). + *
        The following list of boolean parameters is defined: + *

        + *
        + * "validate"
        + *
        + *
        + *
        true
        + *
        [required] (default) Validate an XML + * Schema during loading. If validation errors are found, the error + * handler is notified.
        + *
        false
        + *
        [optional] Do not + * report errors during the loading of an XML Schema document.
        + *
        + *
        + */ + public DOMConfiguration getConfig(); + + /** + * Parses the content of XML Schema documents specified as the list of URI + * references. If the URI contains a fragment identifier, the behavior + * is not defined by this specification. + * @param uriList The list of URI locations. + * @return An XSModel representing the schema documents. + */ + public XSModel loadURIList(StringList uriList); + + /** + * Parses the content of XML Schema documents specified as a list of + * LSInputs. + * @param is The list of LSInputs from which the XML + * Schema documents are to be read. + * @return An XSModel representing the schema documents. + */ + public XSModel loadInputList(LSInputList is); + + /** + * Parse an XML Schema document from a location identified by a URI + * reference. If the URI contains a fragment identifier, the behavior is + * not defined by this specification. + * @param uri The location of the XML Schema document to be read. + * @return An XSModel representing this schema. + */ + public XSModel loadURI(String uri); + + /** + * Parse an XML Schema document from a resource identified by a + * LSInput . + * @param is The LSInput from which the source + * document is to be read. + * @return An XSModel representing this schema. + */ + public XSModel load(LSInput is); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSModel.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSModel.java new file mode 100644 index 0000000..5888932 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSModel.java @@ -0,0 +1,173 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents an XML Schema. + */ +public interface XSModel { + /** + * Convenience method. Returns a list of all namespaces that belong to + * this schema. The value null is not a valid namespace + * name, but if there are components that do not have a target namespace + * , null is included in this list. + */ + public StringList getNamespaces(); + + /** + * A set of namespace schema information information items (of type + * XSNamespaceItem), one for each namespace name which + * appears as the target namespace of any schema component in the schema + * used for that assessment, and one for absent if any schema component + * in the schema had no target namespace. For more information see + * schema information. + */ + public XSNamespaceItemList getNamespaceItems(); + + /** + * Returns a list of top-level components, i.e. element declarations, + * attribute declarations, etc. Identity-constraint definitions are also + * considered top-level. + * + * @param objectType The type of the declaration, i.e. + * ELEMENT_DECLARATION. Note that + * XSTypeDefinition.SIMPLE_TYPE and + * XSTypeDefinition.COMPLEX_TYPE can also be used as the + * objectType to retrieve only complex types or simple + * types, instead of all types. + * @return A list of top-level definitions of the specified type in + * objectType or an empty XSNamedMap if no + * such definitions exist. + */ + public XSNamedMap getComponents(short objectType); + + /** + * Convenience method. Returns a list of top-level component declarations + * that are defined within the specified namespace, i.e. element + * declarations, attribute declarations, etc. Identity-constraint + * definitions are also considered top-level. + * + * @param objectType The type of the declaration, i.e. + * ELEMENT_DECLARATION. + * @param namespace The namespace to which the declaration belongs or + * null (for components with no target namespace). + * @return A list of top-level definitions of the specified type in + * objectType and defined in the specified + * namespace or an empty XSNamedMap. + */ + public XSNamedMap getComponentsByNamespace(short objectType, + String namespace); + + /** + * [annotations]: a set of annotations if it exists, otherwise an empty + * XSObjectList. + */ + public XSObjectList getAnnotations(); + + /** + * Convenience method. Returns a top-level element declaration. + * @param name The name of the declaration. + * @param namespace The namespace of the declaration, otherwise + * null. + * @return A top-level element declaration or null if such a + * declaration does not exist. + */ + public XSElementDeclaration getElementDeclaration(String name, + String namespace); + + /** + * Convenience method. Returns a top-level attribute declaration. + * @param name The name of the declaration. + * @param namespace The namespace of the declaration, otherwise + * null. + * @return A top-level attribute declaration or null if such + * a declaration does not exist. + */ + public XSAttributeDeclaration getAttributeDeclaration(String name, + String namespace); + + /** + * Convenience method. Returns a top-level simple or complex type + * definition. + * @param name The name of the definition. + * @param namespace The namespace of the declaration, otherwise + * null. + * @return An XSTypeDefinition or null if such + * a definition does not exist. + */ + public XSTypeDefinition getTypeDefinition(String name, + String namespace); + + /** + * Convenience method. Returns a top-level attribute group definition. + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise + * null. + * @return A top-level attribute group definition or null if + * such a definition does not exist. + */ + public XSAttributeGroupDefinition getAttributeGroup(String name, + String namespace); + + /** + * Convenience method. Returns a top-level model group definition. + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise + * null. + * @return A top-level model group definition or null if + * such a definition does not exist. + */ + public XSModelGroupDefinition getModelGroupDefinition(String name, + String namespace); + + /** + * Convenience method. Returns a top-level notation declaration. + * @param name The name of the declaration. + * @param namespace The namespace of the declaration, otherwise + * null. + * @return A top-level notation declaration or null if such + * a declaration does not exist. + */ + public XSNotationDeclaration getNotationDeclaration(String name, + String namespace); + + /** + * Convenience method. Returns an identity-constraint definition. + * @param name The name of the definition. + * @param namespace The namespace of the definition, otherwise + * null. + * @return An identity-constraint definition or null if such + * a declaration does not exist. + */ + public XSIDCDefinition getIDCDefinition(String name, + String namespace); + + /** + * Convenience method. Returns a list containing the members of the + * substitution group for the given XSElementDeclaration + * or an empty XSObjectList if the substitution group + * contains no members. + * @param head The substitution group head. + * @return A list containing the members of the substitution group + * for the given XSElementDeclaration or an empty + * XSObjectList if the substitution group contains + * no members. + */ + public XSObjectList getSubstitutionGroup(XSElementDeclaration head); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSModelGroup.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSModelGroup.java new file mode 100644 index 0000000..22b5ebd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSModelGroup.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Model Group schema component. + */ +public interface XSModelGroup extends XSTerm { + // Content model compositors + /** + * This constant value signifies a sequence operator. + */ + public static final short COMPOSITOR_SEQUENCE = 1; + /** + * This constant value signifies a choice operator. + */ + public static final short COMPOSITOR_CHOICE = 2; + /** + * This content model represents a simplified version of the SGML + * &-Connector and is limited to the top-level of any content model. + * No element in the all content model may appear more than once. + */ + public static final short COMPOSITOR_ALL = 3; + + /** + * [compositor]: one of all, choice or sequence. The valid constant values + * are: + * COMPOSITOR_SEQUENCE, COMPOSITOR_CHOICE, COMPOSITOR_ALL. + */ + public short getCompositor(); + + /** + * A list of [particles] if it exists, otherwise an empty + * XSObjectList. + */ + public XSObjectList getParticles(); + + /** + * An annotation if it exists, otherwise null. If not null + * then the first [annotation] from the sequence of annotations. + */ + public XSAnnotation getAnnotation(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSModelGroupDefinition.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSModelGroupDefinition.java new file mode 100644 index 0000000..42ddab7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSModelGroupDefinition.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Model Group Definition schema component. + */ +public interface XSModelGroupDefinition extends XSObject { + /** + * A model group. + */ + public XSModelGroup getModelGroup(); + + /** + * An annotation if it exists, otherwise null. If not null + * then the first [annotation] from the sequence of annotations. + */ + public XSAnnotation getAnnotation(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSMultiValueFacet.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSMultiValueFacet.java new file mode 100644 index 0000000..de35c92 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSMultiValueFacet.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import org.apache.xerces.xs.datatypes.ObjectList; + +/** + * Describes a multi-value constraining facets: pattern and enumeration. + */ +public interface XSMultiValueFacet extends XSObject { + /** + * The name of the facet, i.e. FACET_ENUMERATION and + * FACET_PATTERN (see XSSimpleTypeDefinition). + */ + public short getFacetKind(); + + /** + * Values of this facet. + */ + public StringList getLexicalFacetValues(); + + /** + * A list of XSValue objects. The actual enumeration values. + */ + public ObjectList getEnumerationValues(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSNamedMap.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSNamedMap.java new file mode 100644 index 0000000..f798d9b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSNamedMap.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import java.util.Map; + +/** + * Objects implementing the XSNamedMap interface are used to + * represent immutable collections of XML Schema components that can be + * accessed by name. Note that XSNamedMap does not inherit from + * XSObjectList. The XSObjects in + * XSNamedMaps are not maintained in any particular order. + */ +public interface XSNamedMap extends Map { + /** + * The number of XSObjects in the XSObjectList. + * The range of valid child object indices is 0 to length-1 + * inclusive. + */ + public int getLength(); + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The XSObject at the indexth + * position in the XSObjectList, or null if + * the index specified is not valid. + */ + public XSObject item(int index); + + /** + * Retrieves an XSObject specified by local name and + * namespace URI. + *
        Per XML Namespaces, applications must use the value null as the + * namespace parameter for methods if they wish to specify + * no namespace. + * @param namespace The namespace URI of the XSObject to + * retrieve, or null if the XSObject has no + * namespace. + * @param localName The local name of the XSObject to + * retrieve. + * @return A XSObject (of any type) with the specified local + * name and namespace URI, or null if they do not + * identify any object in this map. + */ + public XSObject itemByName(String namespace, + String localName); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSNamespaceItem.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSNamespaceItem.java new file mode 100644 index 0000000..0349d6f --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSNamespaceItem.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * The interface represents the namespace schema information information item. + * Each namespace schema information information item corresponds to an XML + * Schema with a unique namespace name. + */ +public interface XSNamespaceItem { + /** + * [schema namespace]: A namespace name or null if absent. + */ + public String getSchemaNamespace(); + + /** + * [schema components]: a list of top-level components, i.e. element + * declarations, attribute declarations, etc. Identity-constraint + * definitions are also considered top-level. + * + * @param objectType The type of the declaration, i.e. + * ELEMENT_DECLARATION. Note that + * XSTypeDefinition.SIMPLE_TYPE and + * XSTypeDefinition.COMPLEX_TYPE can also be used as the + * objectType to retrieve only complex types or simple + * types, instead of all types. + * @return A list of top-level definition of the specified type in + * objectType or an empty XSNamedMap if no + * such definitions exist. + */ + public XSNamedMap getComponents(short objectType); + + /** + * [annotations]: a set of annotations if it exists, otherwise an empty + * XSObjectList. + */ + public XSObjectList getAnnotations(); + + /** + * Convenience method. Returns a top-level element declaration. + * @param name The name of the declaration. + * @return A top-level element declaration or null if such a + * declaration does not exist. + */ + public XSElementDeclaration getElementDeclaration(String name); + + /** + * Convenience method. Returns a top-level attribute declaration. + * @param name The name of the declaration. + * @return A top-level attribute declaration or null if such + * a declaration does not exist. + */ + public XSAttributeDeclaration getAttributeDeclaration(String name); + + /** + * Convenience method. Returns a top-level simple or complex type + * definition. + * @param name The name of the definition. + * @return An XSTypeDefinition or null if such + * a definition does not exist. + */ + public XSTypeDefinition getTypeDefinition(String name); + + /** + * Convenience method. Returns a top-level attribute group definition. + * @param name The name of the definition. + * @return A top-level attribute group definition or null if + * such a definition does not exist. + */ + public XSAttributeGroupDefinition getAttributeGroup(String name); + + /** + * Convenience method. Returns a top-level model group definition. + * @param name The name of the definition. + * @return A top-level model group definition definition or + * null if such a definition does not exist. + */ + public XSModelGroupDefinition getModelGroupDefinition(String name); + + /** + * Convenience method. Returns a top-level notation declaration. + * @param name The name of the declaration. + * @return A top-level notation declaration or null if such + * a declaration does not exist. + */ + public XSNotationDeclaration getNotationDeclaration(String name); + + /** + * Convenience method. Returns an identity-constraint definition. + * @param name The name of the definition. + * @return An identity-constraint definition or null if such + * a declaration does not exist. + */ + public XSIDCDefinition getIDCDefinition(String name); + + /** + * [document location] - a list of location URIs for the documents that + * contributed to the XSModel. + */ + public StringList getDocumentLocations(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSNamespaceItemList.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSNamespaceItemList.java new file mode 100644 index 0000000..f445939 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSNamespaceItemList.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import java.util.List; + +/** + * The XSNamesaceItemList interface provides the abstraction of + * an immutable ordered collection of XSNamespaceItems, without + * defining or constraining how this collection is implemented. + */ +public interface XSNamespaceItemList extends List { + /** + * The number of XSNamespaceItems in the list. The range of + * valid child object indices is 0 to length-1 inclusive. + */ + public int getLength(); + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The XSNamespaceItem at the indexth + * position in the XSNamespaceItemList, or + * null if the index specified is not valid. + */ + public XSNamespaceItem item(int index); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSNotationDeclaration.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSNotationDeclaration.java new file mode 100644 index 0000000..381150b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSNotationDeclaration.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Notation Declaration schema component. + */ +public interface XSNotationDeclaration extends XSObject { + /** + * The URI reference representing the system identifier for the notation + * declaration, if present, null otherwise. + */ + public String getSystemId(); + + /** + * The string representing the public identifier for this notation + * declaration, if present; null otherwise. + */ + public String getPublicId(); + + /** + * An annotation if it exists, otherwise null. If not null + * then the first [annotation] from the sequence of annotations. + */ + public XSAnnotation getAnnotation(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSObject.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSObject.java new file mode 100644 index 0000000..fc981c7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSObject.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * The XSObject is a base object for the XML Schema component + * model. + */ +public interface XSObject { + /** + * The type of this object, i.e. + * ELEMENT_DECLARATION. + */ + public short getType(); + + /** + * The name of type NCName, as defined in XML Namespaces, of + * this declaration specified in the {name} property of the + * component or null if the definition of this component + * does not have a {name} property. For anonymous types, + * the processor must construct and expose an anonymous type name that + * is distinct from the name of every named type and the name of every + * other anonymous type. + */ + public String getName(); + + /** + * The [target namespace] of this object, or null if it is + * unspecified. + */ + public String getNamespace(); + + /** + * A namespace schema information item corresponding to the target + * namespace of the component, if it is globally declared; or + * null otherwise. + */ + public XSNamespaceItem getNamespaceItem(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSObjectList.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSObjectList.java new file mode 100644 index 0000000..9cb3e7d --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSObjectList.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +import java.util.List; + +/** + * The XSObjectList interface provides the abstraction of an + * immutable ordered collection of XSObjects, without defining + * or constraining how this collection is implemented. + */ +public interface XSObjectList extends List { + /** + * The number of XSObjects in the list. The range of valid + * child object indices is 0 to length-1 inclusive. + */ + public int getLength(); + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The XSObject at the indexth + * position in the XSObjectList, or null if + * the index specified is not valid. + */ + public XSObject item(int index); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSParticle.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSParticle.java new file mode 100644 index 0000000..a92b655 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSParticle.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Particle schema component. + */ +public interface XSParticle extends XSObject { + /** + * [min occurs]: determines the minimum number of terms that can occur. + */ + public int getMinOccurs(); + + /** + * [max occurs]: determines the maximum number of terms that can occur. + * To query for the value of unbounded use + * maxOccursUnbounded. When the value of + * maxOccursUnbounded is true, the value of + * maxOccurs is unspecified. + */ + public int getMaxOccurs(); + + /** + * [max occurs]: whether the maxOccurs value is unbounded. + */ + public boolean getMaxOccursUnbounded(); + + /** + * [term]: one of a model group, a wildcard, or an element declaration. + */ + public XSTerm getTerm(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSSimpleTypeDefinition.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSSimpleTypeDefinition.java new file mode 100644 index 0000000..9a8d395 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSSimpleTypeDefinition.java @@ -0,0 +1,244 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Simple Type Definition schema component. This + * interface provides several query operations for facet components. Users + * can either retrieve the defined facets as XML Schema components, using + * the facets and the multiValueFacets attributes; + * or users can separately query a facet's properties using methods such as + * getLexicalFacetValue, isFixedFacet, etc. + */ +public interface XSSimpleTypeDefinition extends XSTypeDefinition { + // Variety definitions + /** + * The variety is absent for the anySimpleType definition. + */ + public static final short VARIETY_ABSENT = 0; + /** + * Atomic type. + */ + public static final short VARIETY_ATOMIC = 1; + /** + * List type. + */ + public static final short VARIETY_LIST = 2; + /** + * Union type. + */ + public static final short VARIETY_UNION = 3; + + // Facets + /** + * No facets defined. + */ + public static final short FACET_NONE = 0; + /** + * 4.3.1 Length + */ + public static final short FACET_LENGTH = 1; + /** + * 4.3.2 minLength. + */ + public static final short FACET_MINLENGTH = 2; + /** + * 4.3.3 maxLength. + */ + public static final short FACET_MAXLENGTH = 4; + /** + * 4.3.4 pattern. + */ + public static final short FACET_PATTERN = 8; + /** + * 4.3.5 whitespace. + */ + public static final short FACET_WHITESPACE = 16; + /** + * 4.3.7 maxInclusive. + */ + public static final short FACET_MAXINCLUSIVE = 32; + /** + * 4.3.9 maxExclusive. + */ + public static final short FACET_MAXEXCLUSIVE = 64; + /** + * 4.3.9 minExclusive. + */ + public static final short FACET_MINEXCLUSIVE = 128; + /** + * 4.3.10 minInclusive. + */ + public static final short FACET_MININCLUSIVE = 256; + /** + * 4.3.11 totalDigits . + */ + public static final short FACET_TOTALDIGITS = 512; + /** + * 4.3.12 fractionDigits. + */ + public static final short FACET_FRACTIONDIGITS = 1024; + /** + * 4.3.5 enumeration. + */ + public static final short FACET_ENUMERATION = 2048; + + /** + * A constant defined for the 'ordered' fundamental facet: not ordered. + */ + public static final short ORDERED_FALSE = 0; + /** + * A constant defined for the 'ordered' fundamental facet: partially + * ordered. + */ + public static final short ORDERED_PARTIAL = 1; + /** + * A constant defined for the 'ordered' fundamental facet: total ordered. + */ + public static final short ORDERED_TOTAL = 2; + /** + * [variety]: one of {atomic, list, union} or absent. + */ + public short getVariety(); + + /** + * If variety is atomic the primitive type definition (a + * built-in primitive datatype definition or the simple ur-type + * definition) is available, otherwise null. + */ + public XSSimpleTypeDefinition getPrimitiveType(); + + /** + * Returns the closest built-in type category this type represents or + * derived from. For example, if this simple type is a built-in derived + * type integer the INTEGER_DV is returned. + */ + public short getBuiltInKind(); + + /** + * If variety is list the item type definition (an atomic or + * union simple type definition) is available, otherwise + * null. + */ + public XSSimpleTypeDefinition getItemType(); + + /** + * If variety is union the list of member type definitions (a + * non-empty sequence of simple type definitions) is available, + * otherwise an empty XSObjectList. + */ + public XSObjectList getMemberTypes(); + + /** + * [facets]: all facets defined on this type. The value is a bit + * combination of FACET_XXX constants of all defined facets. + */ + public short getDefinedFacets(); + + /** + * Convenience method. [Facets]: check whether a facet is defined on this + * type. + * @param facetName The name of the facet. + * @return True if the facet is defined, false otherwise. + */ + public boolean isDefinedFacet(short facetName); + + /** + * [facets]: all defined facets for this type which are fixed. + */ + public short getFixedFacets(); + + /** + * Convenience method. [Facets]: check whether a facet is defined and + * fixed on this type. + * @param facetName The name of the facet. + * @return True if the facet is fixed, false otherwise. + */ + public boolean isFixedFacet(short facetName); + + /** + * Convenience method. Returns a value of a single constraining facet for + * this simple type definition. This method must not be used to retrieve + * values for enumeration and pattern facets. + * @param facetName The name of the facet, i.e. + * FACET_LENGTH, FACET_TOTALDIGITS. + * To retrieve the value for a pattern or + * an enumeration, see enumeration and + * pattern. + * @return A value of the facet specified in facetName for + * this simple type definition or null. + */ + public String getLexicalFacetValue(short facetName); + + /** + * A list of enumeration values if it exists, otherwise an empty + * StringList. + */ + public StringList getLexicalEnumeration(); + + /** + * A list of pattern values if it exists, otherwise an empty + * StringList. + */ + public StringList getLexicalPattern(); + + /** + * Fundamental Facet: ordered. + */ + public short getOrdered(); + + /** + * Fundamental Facet: cardinality. + */ + public boolean getFinite(); + + /** + * Fundamental Facet: bounded. + */ + public boolean getBounded(); + + /** + * Fundamental Facet: numeric. + */ + public boolean getNumeric(); + + /** + * A list of constraining facets if it exists, otherwise an empty + * XSObjectList. Note: This method must not be used to + * retrieve values for enumeration and pattern + * facets. + */ + public XSObjectList getFacets(); + + /** + * A list of enumeration and pattern constraining facets if it exists, + * otherwise an empty XSObjectList. + */ + public XSObjectList getMultiValueFacets(); + + /** + * A constraining facet object. An instance of XSFacet or XSMultiValueFacet. + */ + public XSObject getFacet(int facetType); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSTerm.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSTerm.java new file mode 100644 index 0000000..ece2d20 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSTerm.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * Describes a term that can be one of a model group, a wildcard, or an + * element declaration. Objects implementing + * XSElementDeclaration, XSModelGroup and + * XSWildcard interfaces also implement this interface. + */ +public interface XSTerm extends XSObject { +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSTypeDefinition.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSTypeDefinition.java new file mode 100644 index 0000000..5c021a0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSTypeDefinition.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents a complex or simple type definition. + */ +public interface XSTypeDefinition extends XSObject { + /** + * The object describes a complex type. + */ + public static final short COMPLEX_TYPE = 15; + /** + * The object describes a simple type. + */ + public static final short SIMPLE_TYPE = 16; + /** + * Return whether this type definition is a simple type or complex type. + */ + public short getTypeCategory(); + + /** + * {base type definition}: either a simple type definition or a complex + * type definition. + */ + public XSTypeDefinition getBaseType(); + + /** + * {final}. For a complex type definition it is a subset of {extension, + * restriction}. For a simple type definition it is a subset of + * {extension, list, restriction, union}. + * @param restriction Extension, restriction, list, union constants + * (defined in XSConstants). + * @return True if restriction is in the final set, + * otherwise false. + */ + public boolean isFinal(short restriction); + + /** + * For complex types the returned value is a bit combination of the subset + * of {DERIVATION_EXTENSION, DERIVATION_RESTRICTION} + * corresponding to final set of this type or + * DERIVATION_NONE. For simple types the returned value is + * a bit combination of the subset of { + * DERIVATION_RESTRICTION, DERIVATION_EXTENSION, DERIVATION_UNION, DERIVATION_LIST + * } corresponding to final set of this type or + * DERIVATION_NONE. + */ + public short getFinal(); + + /** + * Convenience attribute. A boolean that specifies if the type definition + * is anonymous. + */ + public boolean getAnonymous(); + + /** + * Convenience method which checks if this type is derived from the given + * ancestorType. + * @param ancestorType An ancestor type definition. + * @param derivationMethod A bit combination representing a subset of { + * DERIVATION_RESTRICTION, DERIVATION_EXTENSION, DERIVATION_UNION, DERIVATION_LIST + * }. + * @return True if this type is derived from ancestorType + * using only derivation methods from the derivationMethod + * . + */ + public boolean derivedFromType(XSTypeDefinition ancestorType, + short derivationMethod); + + /** + * Convenience method which checks if this type is derived from the given + * ancestor type. + * @param namespace An ancestor type namespace. + * @param name An ancestor type name. + * @param derivationMethod A bit combination representing a subset of { + * DERIVATION_RESTRICTION, DERIVATION_EXTENSION, DERIVATION_UNION, DERIVATION_LIST + * }. + * @return True if this type is derived from ancestorType + * using only derivation methods from the derivationMethod + * . + */ + public boolean derivedFrom(String namespace, + String name, + short derivationMethod); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSValue.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSValue.java new file mode 100644 index 0000000..a84fb11 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSValue.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * Represents an actual value of a simple type. + */ +public interface XSValue { + + /** + * The schema normalized value. + */ + public String getNormalizedValue(); + + /** + * The actual value. null if the value is in error. + */ + public Object getActualValue(); + + /** + * The declared simple type definition used to validate this value. + * It can be a union type. + */ + public XSSimpleTypeDefinition getTypeDefinition(); + + /** + * If the declared simple type definition is a union, return the member + * type actually used to validate the value. Otherwise null. + */ + public XSSimpleTypeDefinition getMemberTypeDefinition(); + + /** + * If getTypeDefinition() returns a list type whose item type + * is a union type, then this method returns a list with the same length + * as the value list, for simple types that actually validated + * the corresponding item in the value. + */ + public XSObjectList getMemberTypeDefinitions(); + + /** + * The actual value built-in datatype, e.g. + * STRING_DT, SHORT_DT. If the type definition of this + * value is a list type definition, this method returns + * LIST_DT. If the type definition of this value is a list + * type definition whose item type is a union type definition, this + * method returns LISTOFUNION_DT. To query the actual value + * of the list or list of union type definitions use + * itemValueTypes(). + */ + public short getActualValueType(); + + /** + * In the case the actual value represents a list, i.e. the + * actualNormalizedValueType is LIST_DT, the + * returned array consists of one type kind which represents the itemType + * . For example: + *
         <simpleType name="listtype"> <list 
        +     * itemType="positiveInteger"/> </simpleType> <element 
        +     * name="list" type="listtype"/> ... <list>1 2 3</list> 
        + * + * The schemaNormalizedValue value is "1 2 3", the + * actualNormalizedValueType value is LIST_DT, + * and the itemValueTypes is an array of size 1 with the + * value POSITIVEINTEGER_DT. + *
        If the actual value represents a list type definition whose item + * type is a union type definition, i.e. LISTOFUNION_DT, + * for each actual value in the list the array contains the + * corresponding memberType kind. For example: + *
         <simpleType 
        +     * name='union_type' memberTypes="integer string"/> <simpleType 
        +     * name='listOfUnion'> <list itemType='union_type'/> 
        +     * </simpleType> <element name="list" type="listOfUnion"/> 
        +     * ... <list>1 2 foo</list> 
        + * The + * schemaNormalizedValue value is "1 2 foo", the + * actualNormalizedValueType is LISTOFUNION_DT + * , and the itemValueTypes is an array of size 3 with the + * following values: INTEGER_DT, INTEGER_DT, STRING_DT. + */ + public ShortList getListValueTypes(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/XSWildcard.java b/resources/xerces2-j-src/org/apache/xerces/xs/XSWildcard.java new file mode 100644 index 0000000..5714b51 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/XSWildcard.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.xerces.xs; + +/** + * This interface represents the Wildcard schema component. + */ +public interface XSWildcard extends XSTerm { + // Namespace Constraint + /** + * Namespace Constraint: any namespace is allowed. + */ + public static final short NSCONSTRAINT_ANY = 1; + /** + * Namespace Constraint: namespaces in the list are not allowed. + */ + public static final short NSCONSTRAINT_NOT = 2; + /** + * Namespace Constraint: namespaces in the list are allowed. + */ + public static final short NSCONSTRAINT_LIST = 3; + + // Process contents + /** + * There must be a top-level declaration for the item available, or the + * item must have an xsi:type, and the item must be valid as appropriate. + */ + public static final short PC_STRICT = 1; + /** + * No constraints at all: the item must simply be well-formed XML. + */ + public static final short PC_SKIP = 2; + /** + * If the item, or any items among its [children] is an element + * information item, has a uniquely determined declaration available, it + * must be valid with respect to that definition, that is, validate + * where you can and do not worry when you cannot. + */ + public static final short PC_LAX = 3; + + /** + * Namespace constraint: A constraint type: any, not, list. + */ + public short getConstraintType(); + + /** + * Namespace constraint: For constraintType + * NSCONSTRAINT_LIST, the list contains allowed namespaces. + * For constraintType NSCONSTRAINT_NOT, the + * list contains disallowed namespaces. For constraintType + * NSCONSTRAINT_ANY, the StringList is empty. + */ + public StringList getNsConstraintList(); + + /** + * [process contents]: one of skip, lax or strict. Valid constants values + * are: PC_LAX, PC_SKIP and + * PC_STRICT. + */ + public short getProcessContents(); + + /** + * An annotation if it exists, otherwise null. If not null + * then the first [annotation] from the sequence of annotations. + */ + public XSAnnotation getAnnotation(); + + /** + * A sequence of [annotations] or an empty XSObjectList. + */ + public XSObjectList getAnnotations(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/ByteList.java b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/ByteList.java new file mode 100644 index 0000000..3e5e461 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/ByteList.java @@ -0,0 +1,65 @@ +/* + * 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. + */ +package org.apache.xerces.xs.datatypes; + +import java.util.List; + +import org.apache.xerces.xs.XSException; + +/** + *

        The ByteList is an immutable ordered collection of + * byte.

        + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +public interface ByteList extends List { + + /** + * The number of bytes in the list. The range of + * valid child object indices is 0 to length-1 inclusive. + */ + public int getLength(); + + /** + * Checks if the byte item is a + * member of this list. + * @param item byte whose presence in this list + * is to be tested. + * @return True if this list contains the byte + * item. + */ + public boolean contains(byte item); + + /** + * Returns the indexth item in the collection. The index + * starts at 0. + * @param index index into the collection. + * @return The byte at the indexth + * position in the ByteList. + * @exception XSException + * INDEX_SIZE_ERR: if index is greater than or equal to the + * number of objects in the list or less than zero. + */ + public byte item(int index) throws XSException; + + /** + * Construct and return a byte array for bytes contained in this list. + */ + public byte[] toByteArray(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/ObjectList.java b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/ObjectList.java new file mode 100644 index 0000000..dfc4004 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/ObjectList.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package org.apache.xerces.xs.datatypes; + +import java.util.List; + +/** + *

        The ObjectList is an immutable ordered collection of + * Object.

        + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +public interface ObjectList extends List { + + /** + * The number of Objects in the list. The range of + * valid child object indices is 0 to length-1 inclusive. + */ + public int getLength(); + + /** + * Checks if the Object item is a + * member of this list. + * @param item Object whose presence in this list + * is to be tested. + * @return True if this list contains the Object + * item. + */ + public boolean contains(Object item); + + /** + * Returns the indexth item in the collection or + * null if index is greater than or equal to + * the number of objects in the list. The index starts at 0. + * @param index index into the collection. + * @return The Object at the indexth + * position in the ObjectList, or null if + * the index specified is not valid - greater than or equal to the + * number of items in the list or less than zero. + */ + public Object item(int index); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDateTime.java b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDateTime.java new file mode 100644 index 0000000..4359b4e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDateTime.java @@ -0,0 +1,291 @@ +/* + * 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. + */ +package org.apache.xerces.xs.datatypes; + +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; + +/** + *

        Interface to expose the values for all date-time related types. The following + * table shows the methods defined for various XML Schema 1.0 built-in types. 'X' + * marks whether a particular method is defined for a particular type. Accessing undefined + * methods may return unexpected values. + * + * + *
        + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
        XML Schema Datatype getYears() getMonths() getDays() getHours() getMinutes() getSeconds() getTimeZoneHours() getTimeZoneMinutes() getXMLGregorianCalendar() getDuration() hasTimeZone() normalize() isNormalized() getLexicalValue()
        gYear X-----XXX-XXXX
        gMonth -X----XXX-XXXX
        gDay --X---XXX-XXXX
        gYearMonth XX----XXX-XXXX
        gMonthDay -XX---XXX-XXXX
        date XXX---XXX-XXXX
        time ---XXXXXX-XXXX
        datetime XXXXXXXXX-XXXX
        duration -X---X---X---X
        + *

        + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +public interface XSDateTime { + + /** + * @return years - can be negative for date-time related types; + * + */ + public int getYears(); + + /** + * @return months - can be negative only for duration types; + * For duration types, it returns years*12 + months + */ + public int getMonths(); + + /** + * @return days - cannot be negative; + * + */ + public int getDays(); + + /** + * @return hours - cannot be negative; + * + */ + public int getHours(); + + /** + * @return minutes - cannot be negative; + * + */ + public int getMinutes(); + + /** + * @return seconds - can be negative only for durations; + * For duration types, it returns days*24*3600 + hours*3600 + * + minutes*60 + seconds + */ + public double getSeconds(); + + /** + * @return boolean (true when timezone is specified in the original lexical value) + * + */ + public boolean hasTimeZone(); + + /** + * @return timezone hours (for GMT-xx:xx this will be negative), + * + */ + public int getTimeZoneHours(); + + /** + * @return timezone minutes (for GMT-xx:xx this will be negative), + * + */ + public int getTimeZoneMinutes(); + + /** + * @return the original lexical value + */ + public String getLexicalValue(); + + /** + * @return a new date-time related object with normalized values + * (has no effect on objects already + * normalized) + */ + public XSDateTime normalize(); + + /** + * @return whether a date-time related object is normalized or not + * (value is not useful for types where timezone is not specified) + */ + public boolean isNormalized(); + + /** + * @return an un-normalized XMLGregorianCalendar (if applicable otherwise null) + */ + public XMLGregorianCalendar getXMLGregorianCalendar(); + + /** + * @return a Duration (if applicable otherwise null) + */ + public Duration getDuration(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDecimal.java b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDecimal.java new file mode 100644 index 0000000..fccee8c --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDecimal.java @@ -0,0 +1,65 @@ +/* + * 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. + */ +package org.apache.xerces.xs.datatypes; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + *

        Interface to expose the value of 'decimal' and related datatypes.

        + * + * @author Naela Nissar, IBM + * + * @version $Id$ + */ +public interface XSDecimal { + + /** + * @return the BigDecimal representation of this object + */ + public BigDecimal getBigDecimal(); + + /** + * @return the BigInteger representation of this object + * @exception NumberFormatException if the value cannot be represented as a BigInteger + */ + public BigInteger getBigInteger() throws NumberFormatException; + + /** + * @return the long value representation of this object + * @exception NumberFormatException if the value cannot be represented as a long + */ + public long getLong() throws NumberFormatException; + + /** + * @return the int value representation of this object + * @exception NumberFormatException if the value cannot be represented as a int + */ + public int getInt() throws NumberFormatException; + + /** + * @return the short value representation of this object + * @exception NumberFormatException if the value cannot be represented as a short + */ + public short getShort() throws NumberFormatException; + + /** + * @return the byte value representation of this object + * @exception NumberFormatException if the value cannot be represented as a byte + */ + public byte getByte() throws NumberFormatException; +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDouble.java b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDouble.java new file mode 100644 index 0000000..752aee5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSDouble.java @@ -0,0 +1,33 @@ +/* + * 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. + */ +package org.apache.xerces.xs.datatypes; + +/** + *

        Interface to expose the value of the 'double' datatype.

        + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +public interface XSDouble { + + /** + * @return a double value + */ + public double getValue(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSFloat.java b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSFloat.java new file mode 100644 index 0000000..7715dbd --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSFloat.java @@ -0,0 +1,33 @@ +/* + * 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. + */ +package org.apache.xerces.xs.datatypes; + +/** + *

        Interface to expose value of the float datatype.

        + * + * @author Ankit Pasricha, IBM + * + * @version $Id$ + */ +public interface XSFloat { + + /** + * @return a float value + */ + public float getValue(); + +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSQName.java b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSQName.java new file mode 100644 index 0000000..b40a2fa --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/XSQName.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.xerces.xs.datatypes; + +/** + * Interface to expose QName actual values + * + * @author Ankit Pasricha, IBM + */ +public interface XSQName { + + /** + * @return org.apache.xerces.xni.QName class instance + */ + public org.apache.xerces.xni.QName getXNIQName(); + + /** + * @return javax.xml.namespace.QName class instance + */ + public javax.xml.namespace.QName getJAXPQName(); +} diff --git a/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/package.html b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/package.html new file mode 100644 index 0000000..a343690 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xerces/xs/datatypes/package.html @@ -0,0 +1,306 @@ + + + + + +This package provides interfaces for accessing actual value information through PSVI for XML Schema 1.0 data types. +
        +
        +The table below gives the data type to applicable interface mapping: +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        XML Schema Data TypeInterface/Class
        stringjava.lang.String
        booleanjava.lang.Boolean
        decimalXSDecimal
        floatXSFloat
        doubleXSDouble
        durationXSDateTime
        dateTimeXSDateTime
        dateXSDateTime
        timeXSDateTime
        gYearXSDateTime
        gMonthXSDateTime
        gDayXSDateTime
        gYearMonthXSDateTime
        gMonthDayXSDateTime
        hexBinaryByteList
        base64BinaryByteList
        anyURIjava.lang.String
        QNameXSQName
        NOTATIONXSQName
        normalizedStringjava.lang.String
        tokenjava.lang.String
        languagejava.lang.String
        NMTOKENjava.lang.String
        NMTOKENSObjectList
        Namejava.lang.String
        NCNamejava.lang.String
        IDjava.lang.String
        IDREFjava.lang.String
        IDREFSObjectList
        ENTITYjava.lang.String
        ENTITIESObjectList
        listObjectList
        integerXSDecimal
        positiveIntegerXSDecimal
        negativeIntegerXSDecimal
        nonPositiveIntegerXSDecimal
        nonNegativeIntegerXSDecimal
        unsignedShortXSDecimal
        unsignedLongXSDecimal
        unsignedByteXSDecimal
        unsignedIntXSDecimal
        longXSDecimal
        intXSDecimal
        shortXSDecimal
        byteXSDecimal
        +


        As shown above, the XSDateTime interface provides mapping to a number of decimal/integer data types. The application needs to ensure that appropriate methods for each of these types is invoked. The mapping of these types to defined methods is shown in the table below. Accessing methods that are undefined for a type will give unexpected results. +

        + + +


        +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        XML Schema Data TypeApplicable method in XSDateTime*
        integergetBigInteger()
        positiveIntegergetBigInteger()
        negativeIntegergetBigInteger()
        nonPositiveIntegergetBigInteger()
        nonNegativeIntegergetBigInteger()
        unsignedShortgetInt()
        unsignedLonggetBigInteger()
        unsignedBytegetShort()
        unsignedIntgetLong()
        longgetLong()
        intgetInt()
        shortgetShort()
        bytegetByte()
        +


        * This +shows the base method that can be called. That is, users can call this +method and all methods returning bigger types than the base method +according to the order: byte < short < int < long < +BigInteger < BigDecimal. For example, in the case of unsignedShort, +users can call getInt(), getLong(), getBigInteger() and getBigDecimal() +but NOT getShort() or getByte(). +

        + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/BaseMarkupSerializer.java b/resources/xerces2-j-src/org/apache/xml/serialize/BaseMarkupSerializer.java new file mode 100644 index 0000000..43df5c1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/BaseMarkupSerializer.java @@ -0,0 +1,1850 @@ +/* + * 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. + */ + +// Sep 14, 2000: +// Fixed comments to preserve whitespaces and add a line break +// when indenting. Reported by Gervase Markham +// Sep 14, 2000: +// Fixed serializer to report IO exception directly, instead at +// the end of document processing. +// Reported by Patrick Higgins +// Sep 13, 2000: +// CR in character data will print as �D; +// Aug 25, 2000: +// Fixed processing instruction printing inside element content +// to not escape content. Reported by Mikael Staldal +// +// Aug 25, 2000: +// Added ability to omit comments. +// Contributed by Anupam Bagchi +// Aug 26, 2000: +// Fixed bug in newline handling when preserving spaces. +// Contributed by Mike Dusseault +// Aug 29, 2000: +// Fixed state.unescaped not being set to false when +// entering element state. +// Reported by Lowell Vaughn + +package org.apache.xml.serialize; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.util.Hashtable; +import java.util.Vector; + +import org.apache.xerces.dom.DOMErrorImpl; +import org.apache.xerces.dom.DOMLocatorImpl; +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.util.XMLChar; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSSerializerFilter; +import org.w3c.dom.traversal.NodeFilter; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.DocumentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; + +/** + * Base class for a serializer supporting both DOM and SAX pretty + * serializing of XML/HTML/XHTML documents. Derives classes perform + * the method-specific serializing, this class provides the common + * serializing mechanisms. + *

        + * The serializer must be initialized with the proper writer and + * output format before it can be used by calling {@link #setOutputCharStream} + * or {@link #setOutputByteStream} for the writer and {@link #setOutputFormat} + * for the output format. + *

        + * The serializer can be reused any number of times, but cannot + * be used concurrently by two threads. + *

        + * If an output stream is used, the encoding is taken from the + * output format (defaults to UTF-8). If a writer is + * used, make sure the writer uses the same encoding (if applies) + * as specified in the output format. + *

        + * The serializer supports both DOM and SAX. DOM serializing is done + * by calling {@link #serialize(Document)} and SAX serializing is done by firing + * SAX events and using the serializer as a document handler. + * This also applies to derived class. + *

        + * If an I/O exception occurs while serializing, the serializer + * will not throw an exception directly, but only throw it + * at the end of serializing (either DOM or SAX's {@link + * org.xml.sax.DocumentHandler#endDocument}. + *

        + * For elements that are not specified as whitespace preserving, + * the serializer will potentially break long text lines at space + * boundaries, indent lines, and serialize elements on separate + * lines. Line terminators will be regarded as spaces, and + * spaces at beginning of line will be stripped. + *

        + * When indenting, the serializer is capable of detecting seemingly + * element content, and serializing these elements indented on separate + * lines. An element is serialized indented when it is the first or + * last child of an element, or immediate following or preceding + * another element. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @author Rahul Srivastava + * @author Elena Litani, IBM + * @see Serializer + * @see org.w3c.dom.ls.LSSerializer + */ +public abstract class BaseMarkupSerializer + implements ContentHandler, DocumentHandler, LexicalHandler, + DTDHandler, DeclHandler, DOMSerializer, Serializer +{ + + // DOM L3 implementation + protected short features = 0xFFFFFFFF; + protected DOMErrorHandler fDOMErrorHandler; + protected final DOMErrorImpl fDOMError = new DOMErrorImpl(); + protected LSSerializerFilter fDOMFilter; + + protected EncodingInfo _encodingInfo; + + + /** + * Holds array of all element states that have been entered. + * The array is automatically resized. When leaving an element, + * it's state is not removed but reused when later returning + * to the same nesting level. + */ + private ElementState[] _elementStates; + + + /** + * The index of the next state to place in the array, + * or one plus the index of the current state. When zero, + * we are in no state. + */ + private int _elementStateCount; + + + /** + * Vector holding comments and PIs that come before the root + * element (even after it), see {@link #serializePreRoot}. + */ + private Vector _preRoot; + + + /** + * If the document has been started (header serialized), this + * flag is set to true so it's not started twice. + */ + protected boolean _started; + + + /** + * True if the serializer has been prepared. This flag is set + * to false when the serializer is reset prior to using it, + * and to true after it has been prepared for usage. + */ + private boolean _prepared; + + + /** + * Association between namespace URIs (keys) and prefixes (values). + * Accumulated here prior to starting an element and placing this + * list in the element state. + */ + protected Hashtable _prefixes; + + + /** + * The system identifier of the document type, if known. + */ + protected String _docTypePublicId; + + + /** + * The system identifier of the document type, if known. + */ + protected String _docTypeSystemId; + + + /** + * The output format associated with this serializer. This will never + * be a null reference. If no format was passed to the constructor, + * the default one for this document type will be used. The format + * object is never changed by the serializer. + */ + protected OutputFormat _format; + + + /** + * The printer used for printing text parts. + */ + protected Printer _printer; + + + /** + * True if indenting printer. + */ + protected boolean _indenting; + + /** Temporary buffer to store character data */ + protected final StringBuffer fStrBuffer = new StringBuffer(40); + + /** + * The underlying writer. + */ + private Writer _writer; + + + /** + * The output stream. + */ + private OutputStream _output; + + /** Current node that is being processed */ + protected Node fCurrentNode = null; + + + + //--------------------------------// + // Constructor and initialization // + //--------------------------------// + + + /** + * Protected constructor can only be used by derived class. + * Must initialize the serializer before serializing any document, + * by calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first + */ + protected BaseMarkupSerializer( OutputFormat format ) + { + int i; + + _elementStates = new ElementState[ 10 ]; + for ( i = 0 ; i < _elementStates.length ; ++i ) + _elementStates[ i ] = new ElementState(); + _format = format; + } + + + public DocumentHandler asDocumentHandler() + throws IOException + { + prepare(); + return this; + } + + + public ContentHandler asContentHandler() + throws IOException + { + prepare(); + return this; + } + + + public DOMSerializer asDOMSerializer() + throws IOException + { + prepare(); + return this; + } + + + public void setOutputByteStream( OutputStream output ) + { + if ( output == null ) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, + "ArgumentIsNull", new Object[]{"output"}); + throw new NullPointerException(msg); + } + _output = output; + _writer = null; + reset(); + } + + + public void setOutputCharStream( Writer writer ) + { + if ( writer == null ) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, + "ArgumentIsNull", new Object[]{"writer"}); + throw new NullPointerException(msg); + } + _writer = writer; + _output = null; + reset(); + } + + + public void setOutputFormat( OutputFormat format ) + { + if ( format == null ) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, + "ArgumentIsNull", new Object[]{"format"}); + throw new NullPointerException(msg); + } + _format = format; + reset(); + } + + + public boolean reset() + { + if ( _elementStateCount > 1 ) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, + "ResetInMiddle", null); + throw new IllegalStateException(msg); + } + _prepared = false; + fCurrentNode = null; + fStrBuffer.setLength(0); + return true; + } + + protected void cleanup() { + fCurrentNode = null; + } + + protected void prepare() + throws IOException + { + if ( _prepared ) + return; + + if ( _writer == null && _output == null ) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, + "NoWriterSupplied", null); + throw new IOException(msg); + } + // If the output stream has been set, use it to construct + // the writer. It is possible that the serializer has been + // reused with the same output stream and different encoding. + + _encodingInfo = _format.getEncodingInfo(); + + if ( _output != null ) { + _writer = _encodingInfo.getWriter(_output); + } + + if ( _format.getIndenting() ) { + _indenting = true; + _printer = new IndentPrinter( _writer, _format ); + } else { + _indenting = false; + _printer = new Printer( _writer, _format ); + } + + ElementState state; + + _elementStateCount = 0; + state = _elementStates[ 0 ]; + state.namespaceURI = null; + state.localName = null; + state.rawName = null; + state.preserveSpace = _format.getPreserveSpace(); + state.empty = true; + state.afterElement = false; + state.afterComment = false; + state.doCData = state.inCData = false; + state.prefixes = null; + + _docTypePublicId = _format.getDoctypePublic(); + _docTypeSystemId = _format.getDoctypeSystem(); + _started = false; + _prepared = true; + } + + + + //----------------------------------// + // DOM document serializing methods // + //----------------------------------// + + + /** + * Serializes the DOM element using the previously specified + * writer and output format. Throws an exception only if + * an I/O exception occured while serializing. + * + * @param elem The element to serialize + * @throws IOException An I/O exception occured while + * serializing + */ + public void serialize( Element elem ) + throws IOException + { + reset(); + prepare(); + serializeNode( elem ); + cleanup(); + _printer.flush(); + if ( _printer.getException() != null ) + throw _printer.getException(); + } + + + /** + * Serializes the DOM document fragmnt using the previously specified + * writer and output format. Throws an exception only if + * an I/O exception occured while serializing. + * + * @param frag The document fragment to serialize + * @throws IOException An I/O exception occured while + * serializing + */ + public void serialize( DocumentFragment frag ) + throws IOException + { + reset(); + prepare(); + serializeNode( frag ); + cleanup(); + _printer.flush(); + if ( _printer.getException() != null ) + throw _printer.getException(); + } + + + /** + * Serializes the DOM document using the previously specified + * writer and output format. Throws an exception only if + * an I/O exception occured while serializing. + * + * @param doc The document to serialize + * @throws IOException An I/O exception occured while + * serializing + */ + public void serialize( Document doc ) + throws IOException + { + reset(); + prepare(); + serializeNode( doc ); + serializePreRoot(); + cleanup(); + _printer.flush(); + if ( _printer.getException() != null ) + throw _printer.getException(); + } + + + //------------------------------------------// + // SAX document handler serializing methods // + //------------------------------------------// + + + public void startDocument() + throws SAXException + { + try { + prepare(); + } catch ( IOException except ) { + throw new SAXException( except.toString() ); + } + // Nothing to do here. All the magic happens in startDocument(String) + } + + + public void characters( char[] chars, int start, int length ) + throws SAXException + { + ElementState state; + + try { + state = content(); + + // Check if text should be print as CDATA section or unescaped + // based on elements listed in the output format (the element + // state) or whether we are inside a CDATA section or entity. + + if ( state.inCData || state.doCData ) { + int saveIndent; + + // Print a CDATA section. The text is not escaped, but ']]>' + // appearing in the code must be identified and dealt with. + // The contents of a text node is considered space preserving. + if ( ! state.inCData ) { + _printer.printText( "' ) { + _printer.printText("]]]]>"); + index +=2; + continue; + } + if (!XMLChar.isValid(ch)) { + // check if it is surrogate + if (++index < end) { + surrogates(ch, chars[index], true); + } + else { + fatalError("The character '"+ch+"' is an invalid XML character"); + } + continue; + } + if ( ( ch >= ' ' && _encodingInfo.isPrintable(ch) && ch != 0x7F ) || + ch == '\n' || ch == '\r' || ch == '\t' ) { + _printer.printText(ch); + } + else { + // The character is not printable -- split CDATA section + _printer.printText("]]>&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText("; 0 ; ++i ) + _printer.printText( chars[ i ] ); + } + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public final void processingInstruction( String target, String code ) + throws SAXException + { + try { + processingInstructionIO( target, code ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + public void processingInstructionIO( String target, String code ) + throws IOException + { + int index; + ElementState state; + + state = content(); + + // Create the processing instruction textual representation. + // Make sure we don't have '?>' inside either target or code. + index = target.indexOf( "?>" ); + if ( index >= 0 ) + fStrBuffer.append( "" ); + if ( index >= 0 ) + fStrBuffer.append( code.substring( 0, index ) ); + else + fStrBuffer.append( code ); + } + fStrBuffer.append( "?>" ); + + // If before the root element (or after it), do not print + // the PI directly but place it in the pre-root vector. + if ( isDocumentState() ) { + if ( _preRoot == null ) + _preRoot = new Vector(); + _preRoot.addElement( fStrBuffer.toString() ); + } else { + _printer.indent(); + printText( fStrBuffer.toString(), true, true ); + _printer.unindent(); + if ( _indenting ) + state.afterElement = true; + } + + fStrBuffer.setLength(0); + } + + + public void comment( char[] chars, int start, int length ) + throws SAXException + { + try { + comment( new String( chars, start, length ) ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void comment( String text ) + throws IOException + { + int index; + ElementState state; + + if ( _format.getOmitComments() ) + return; + + state = content(); + // Create the processing comment textual representation. + // Make sure we don't have '-->' inside the comment. + index = text.indexOf( "-->" ); + if ( index >= 0 ) + fStrBuffer.append( "" ); + else + fStrBuffer.append( "" ); + + // If before the root element (or after it), do not print + // the comment directly but place it in the pre-root vector. + if ( isDocumentState() ) { + if ( _preRoot == null ) + _preRoot = new Vector(); + _preRoot.addElement( fStrBuffer.toString() ); + } else { + // Indent this element on a new line if the first + // content of the parent element or immediately + // following an element. + if ( _indenting && ! state.preserveSpace) + _printer.breakLine(); + _printer.indent(); + printText( fStrBuffer.toString(), true, true ); + _printer.unindent(); + if ( _indenting ) + state.afterElement = true; + } + + fStrBuffer.setLength(0); + state.afterComment = true; + state.afterElement = false; + } + + + public void startCDATA() + { + ElementState state; + + state = getElementState(); + state.doCData = true; + } + + + public void endCDATA() + { + ElementState state; + + state = getElementState(); + state.doCData = false; + } + + + public void startNonEscaping() + { + ElementState state; + + state = getElementState(); + state.unescaped = true; + } + + + public void endNonEscaping() + { + ElementState state; + + state = getElementState(); + state.unescaped = false; + } + + + public void startPreserving() + { + ElementState state; + + state = getElementState(); + state.preserveSpace = true; + } + + + public void endPreserving() + { + ElementState state; + + state = getElementState(); + state.preserveSpace = false; + } + + + /** + * Called at the end of the document to wrap it up. + * Will flush the output stream and throw an exception + * if any I/O error occured while serializing. + * + * @throws SAXException An I/O exception occured during + * serializing + */ + public void endDocument() + throws SAXException + { + try { + // Print all the elements accumulated outside of + // the root element. + serializePreRoot(); + // Flush the output, this is necessary for fStrBuffered output. + _printer.flush(); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void startEntity( String name ) + { + // ??? + } + + + public void endEntity( String name ) + { + // ??? + } + + + public void setDocumentLocator( Locator locator ) + { + // Nothing to do + } + + + //-----------------------------------------// + // SAX content handler serializing methods // + //-----------------------------------------// + + + public void skippedEntity ( String name ) + throws SAXException + { + try { + endCDATA(); + content(); + _printer.printText( '&' ); + _printer.printText( name ); + _printer.printText( ';' ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void startPrefixMapping( String prefix, String uri ) + throws SAXException + { + if ( _prefixes == null ) + _prefixes = new Hashtable(); + _prefixes.put( uri, prefix == null ? "" : prefix ); + } + + + public void endPrefixMapping( String prefix ) + throws SAXException + { + } + + + //------------------------------------------// + // SAX DTD/Decl handler serializing methods // + //------------------------------------------// + + + public final void startDTD( String name, String publicId, String systemId ) + throws SAXException + { + try { + _printer.enterDTD(); + _docTypePublicId = publicId; + _docTypeSystemId = systemId; + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void endDTD() + { + // Nothing to do here, all the magic occurs in startDocument(String). + } + + + public void elementDecl( String name, String model ) + throws SAXException + { + try { + _printer.enterDTD(); + _printer.printText( "' ); + if ( _indenting ) + _printer.breakLine(); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void attributeDecl( String eName, String aName, String type, + String valueDefault, String value ) + throws SAXException + { + try { + _printer.enterDTD(); + _printer.printText( "' ); + if ( _indenting ) + _printer.breakLine(); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void internalEntityDecl( String name, String value ) + throws SAXException + { + try { + _printer.enterDTD(); + _printer.printText( "" ); + if ( _indenting ) + _printer.breakLine(); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void externalEntityDecl( String name, String publicId, String systemId ) + throws SAXException + { + try { + _printer.enterDTD(); + unparsedEntityDecl( name, publicId, systemId, null ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void unparsedEntityDecl( String name, String publicId, + String systemId, String notationName ) + throws SAXException + { + try { + _printer.enterDTD(); + if ( publicId == null ) { + _printer.printText( "' ); + if ( _indenting ) + _printer.breakLine(); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void notationDecl( String name, String publicId, String systemId ) + throws SAXException + { + try { + _printer.enterDTD(); + if ( publicId != null ) { + _printer.printText( "' ); + if ( _indenting ) + _printer.breakLine(); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + //------------------------------------------// + // Generic node serializing methods methods // + //------------------------------------------// + + + /** + * Serialize the DOM node. This method is shared across XML, HTML and XHTML + * serializers and the differences are masked out in a separate {@link + * #serializeElement}. + * + * @param node The node to serialize + * @see #serializeElement + * @throws IOException An I/O exception occured while + * serializing + */ + protected void serializeNode( Node node ) + throws IOException + { + fCurrentNode = node; + + // Based on the node type call the suitable SAX handler. + // Only comments entities and documents which are not + // handled by SAX are serialized directly. + switch ( node.getNodeType() ) { + case Node.TEXT_NODE : { + String text; + + text = node.getNodeValue(); + if ( text != null ) { + if (fDOMFilter !=null && + (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_TEXT)!= 0) { + short code = fDOMFilter.acceptNode(node); + switch (code) { + case NodeFilter.FILTER_REJECT: + case NodeFilter.FILTER_SKIP: { + break; + } + default: { + characters(text); + } + } + } + else if ( !_indenting || getElementState().preserveSpace + || (text.replace('\n',' ').trim().length() != 0)) + characters( text ); + + } + break; + } + + case Node.CDATA_SECTION_NODE : { + String text = node.getNodeValue(); + if ((features & DOMSerializerImpl.CDATA) != 0) { + if (text != null) { + if (fDOMFilter != null + && (fDOMFilter.getWhatToShow() + & NodeFilter.SHOW_CDATA_SECTION) + != 0) { + short code = fDOMFilter.acceptNode(node); + switch (code) { + case NodeFilter.FILTER_REJECT : + case NodeFilter.FILTER_SKIP : + { + // skip the CDATA node + return; + } + default : + { + //fall through.. + } + } + } + startCDATA(); + characters(text); + endCDATA(); + } + } else { + // transform into a text node + characters(text); + } + break; + } + case Node.COMMENT_NODE : { + String text; + + if ( ! _format.getOmitComments() ) { + text = node.getNodeValue(); + if ( text != null ) { + + if (fDOMFilter !=null && + (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_COMMENT)!= 0) { + short code = fDOMFilter.acceptNode(node); + switch (code) { + case NodeFilter.FILTER_REJECT: + case NodeFilter.FILTER_SKIP: { + // skip the comment node + return; + } + default: { + // fall through + } + } + } + comment( text ); + } + } + break; + } + + case Node.ENTITY_REFERENCE_NODE : { + Node child; + + endCDATA(); + content(); + + if (((features & DOMSerializerImpl.ENTITIES) != 0) + || (node.getFirstChild() == null)) { + if (fDOMFilter !=null && + (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_ENTITY_REFERENCE)!= 0) { + short code = fDOMFilter.acceptNode(node); + switch (code) { + case NodeFilter.FILTER_REJECT:{ + return; // remove the node + } + case NodeFilter.FILTER_SKIP: { + child = node.getFirstChild(); + while ( child != null ) { + serializeNode( child ); + child = child.getNextSibling(); + } + return; + } + + default: { + // fall through + } + } + } + checkUnboundNamespacePrefixedNode(node); + + _printer.printText("&"); + _printer.printText(node.getNodeName()); + _printer.printText(";"); + } + else { + child = node.getFirstChild(); + while ( child != null ) { + serializeNode( child ); + child = child.getNextSibling(); + } + } + + break; + } + + case Node.PROCESSING_INSTRUCTION_NODE : { + + if (fDOMFilter !=null && + (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_PROCESSING_INSTRUCTION)!= 0) { + short code = fDOMFilter.acceptNode(node); + switch (code) { + case NodeFilter.FILTER_REJECT: + case NodeFilter.FILTER_SKIP: { + return; // skip this node + } + default: { // fall through + } + } + } + processingInstructionIO( node.getNodeName(), node.getNodeValue() ); + break; + } + case Node.ELEMENT_NODE : { + + if (fDOMFilter !=null && + (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_ELEMENT)!= 0) { + short code = fDOMFilter.acceptNode(node); + switch (code) { + case NodeFilter.FILTER_REJECT: { + return; + } + case NodeFilter.FILTER_SKIP: { + Node child = node.getFirstChild(); + while ( child != null ) { + serializeNode( child ); + child = child.getNextSibling(); + } + return; // skip this node + } + + default: { // fall through + } + } + } + serializeElement( (Element) node ); + break; + } + case Node.DOCUMENT_NODE : { + DocumentType docType; + + // If there is a document type, use the SAX events to + // serialize it. + docType = ( (Document) node ).getDoctype(); + if (docType != null) { + // DOM Level 2 (or higher) + try { + String internal; + + _printer.enterDTD(); + _docTypePublicId = docType.getPublicId(); + _docTypeSystemId = docType.getSystemId(); + internal = docType.getInternalSubset(); + if ( internal != null && internal.length() > 0 ) + _printer.printText( internal ); + endDTD(); + } + // DOM Level 1 -- does implementation have methods? + catch (NoSuchMethodError nsme) { + Class docTypeClass = docType.getClass(); + + String docTypePublicId = null; + String docTypeSystemId = null; + try { + java.lang.reflect.Method getPublicId = docTypeClass.getMethod("getPublicId", (Class[]) null); + if (getPublicId.getReturnType().equals(String.class)) { + docTypePublicId = (String)getPublicId.invoke(docType, (Object[]) null); + } + } + catch (Exception e) { + // ignore + } + try { + java.lang.reflect.Method getSystemId = docTypeClass.getMethod("getSystemId", (Class[]) null); + if (getSystemId.getReturnType().equals(String.class)) { + docTypeSystemId = (String)getSystemId.invoke(docType, (Object[]) null); + } + } + catch (Exception e) { + // ignore + } + _printer.enterDTD(); + _docTypePublicId = docTypePublicId; + _docTypeSystemId = docTypeSystemId; + endDTD(); + } + } + // !! Fall through + } + case Node.DOCUMENT_FRAGMENT_NODE : { + Node child; + + // By definition this will happen if the node is a document, + // document fragment, etc. Just serialize its contents. It will + // work well for other nodes that we do not know how to serialize. + child = node.getFirstChild(); + while ( child != null ) { + serializeNode( child ); + child = child.getNextSibling(); + } + break; + } + + default: + break; + } + } + + + /** + * Must be called by a method about to print any type of content. + * If the element was just opened, the opening tag is closed and + * will be matched to a closing tag. Returns the current element + * state with empty and afterElement set to false. + * + * @return The current element state + * @throws IOException An I/O exception occurred while + * serializing + */ + protected ElementState content() + throws IOException + { + ElementState state; + + state = getElementState(); + if ( ! isDocumentState() ) { + // Need to close CData section first + if ( state.inCData && ! state.doCData ) { + _printer.printText( "]]>" ); + state.inCData = false; + } + // If this is the first content in the element, + // change the state to not-empty and close the + // opening element tag. + if ( state.empty ) { + _printer.printText( '>' ); + state.empty = false; + } + // Except for one content type, all of them + // are not last element. That one content + // type will take care of itself. + state.afterElement = false; + // Except for one content type, all of them + // are not last comment. That one content + // type will take care of itself. + state.afterComment = false; + } + return state; + } + + + /** + * Called to print the text contents in the prevailing element format. + * Since this method is capable of printing text as CDATA, it is used + * for that purpose as well. White space handling is determined by the + * current element state. In addition, the output format can dictate + * whether the text is printed as CDATA or unescaped. + * + * @param text The text to print + * @throws IOException An I/O exception occured while + * serializing + */ + protected void characters( String text ) + throws IOException + { + ElementState state; + + state = content(); + // Check if text should be print as CDATA section or unescaped + // based on elements listed in the output format (the element + // state) or whether we are inside a CDATA section or entity. + + if ( state.inCData || state.doCData ) { + // Print a CDATA section. The text is not escaped, but ']]>' + // appearing in the code must be identified and dealt with. + // The contents of a text node is considered space preserving. + if ( ! state.inCData ) { + _printer.printText("'&' + * will return "&amp;". + * + * @param ch Character value + * @return Character entity name, or null + */ + protected abstract String getEntityRef( int ch ); + + + /** + * Called to serializee the DOM element. The element is serialized based on + * the serializer's method (XML, HTML, XHTML). + * + * @param elem The element to serialize + * @throws IOException An I/O exception occured while + * serializing + */ + protected abstract void serializeElement( Element elem ) + throws IOException; + + + /** + * Comments and PIs cannot be serialized before the root element, + * because the root element serializes the document type, which + * generally comes first. Instead such PIs and comments are + * accumulated inside a vector and serialized by calling this + * method. Will be called when the root element is serialized + * and when the document finished serializing. + * + * @throws IOException An I/O exception occured while + * serializing + */ + protected void serializePreRoot() + throws IOException + { + int i; + + if ( _preRoot != null ) { + for ( i = 0 ; i < _preRoot.size() ; ++i ) { + printText( (String) _preRoot.elementAt( i ), true, true ); + if ( _indenting ) + _printer.breakLine(); + } + _preRoot.removeAllElements(); + } + } + + + //---------------------------------------------// + // Text pretty printing and formatting methods // + //---------------------------------------------// + + protected void printCDATAText( String text ) throws IOException { + int length = text.length(); + char ch; + + for ( int index = 0 ; index < length; ++index ) { + ch = text.charAt( index ); + if (ch == ']' + && index + 2 < length + && text.charAt(index + 1) == ']' + && text.charAt(index + 2) == '>') { // check for ']]>' + if (fDOMErrorHandler != null) { + // REVISIT: this means that if DOM Error handler is not registered we don't report any + // fatal errors and might serialize not wellformed document + if ((features & DOMSerializerImpl.SPLITCDATA) == 0) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "EndingCDATA", + null); + if ((features & DOMSerializerImpl.WELLFORMED) != 0) { + // issue fatal error + modifyDOMError(msg, DOMError.SEVERITY_FATAL_ERROR, "wf-invalid-character", fCurrentNode); + fDOMErrorHandler.handleError(fDOMError); + throw new LSException(LSException.SERIALIZE_ERR, msg); + } + // issue error + modifyDOMError(msg, DOMError.SEVERITY_ERROR, "cdata-section-not-splitted", fCurrentNode); + if (!fDOMErrorHandler.handleError(fDOMError)) { + throw new LSException(LSException.SERIALIZE_ERR, msg); + } + } else { + // issue warning + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "SplittingCDATA", + null); + modifyDOMError( + msg, + DOMError.SEVERITY_WARNING, + null, fCurrentNode); + fDOMErrorHandler.handleError(fDOMError); + } + } + // split CDATA section + _printer.printText("]]]]>"); + index += 2; + continue; + } + + if (!XMLChar.isValid(ch)) { + // check if it is surrogate + if (++index = ' ' && _encodingInfo.isPrintable(ch) && ch != 0x7F ) || + ch == '\n' || ch == '\r' || ch == '\t' ) { + _printer.printText(ch); + } + else { + + // The character is not printable -- split CDATA section + _printer.printText("]]>&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";&#x"); + _printer.printText(Integer.toHexString(supplemental)); + _printer.printText("; 0 ) { + char ch = chars[ start ]; + ++start; + if ( ch == '\n' || ch == '\r' || unescaped ) { + _printer.printText( ch ); + } + else { + printEscaped( ch ); + } + } + } else { + // Not preserving spaces: print one part at a time, and + // use spaces between parts to break them into different + // lines. Spaces at beginning of line will be stripped + // by printing mechanism. Line terminator is treated + // no different than other text part. + while ( length-- > 0 ) { + char ch = chars[ start ]; + ++start; + if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) { + _printer.printSpace(); + } + else if ( unescaped ) { + _printer.printText( ch ); + } + else { + printEscaped( ch ); + } + } + } + } + + + protected void printText( String text, boolean preserveSpace, boolean unescaped ) + throws IOException + { + int index; + char ch; + + if ( preserveSpace ) { + // Preserving spaces: the text must print exactly as it is, + // without breaking when spaces appear in the text and without + // consolidating spaces. If a line terminator is used, a line + // break will occur. + for ( index = 0 ; index < text.length() ; ++index ) { + ch = text.charAt( index ); + if ( ch == '\n' || ch == '\r' || unescaped ) + _printer.printText( ch ); + else + printEscaped( ch ); + } + } else { + // Not preserving spaces: print one part at a time, and + // use spaces between parts to break them into different + // lines. Spaces at beginning of line will be stripped + // by printing mechanism. Line terminator is treated + // no different than other text part. + for ( index = 0 ; index < text.length() ; ++index ) { + ch = text.charAt( index ); + if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) { + _printer.printSpace(); + } + else if ( unescaped ) { + _printer.printText( ch ); + } + else { + printEscaped( ch ); + } + } + } + } + + + /** + * Print a document type public or system identifier URL. + * Encapsulates the URL in double quotes, escapes non-printing + * characters and print it equivalent to {@link #printText}. + * + * @param url The document type url to print + */ + protected void printDoctypeURL( String url ) + throws IOException + { + int i; + + _printer.printText( '"' ); + for( i = 0 ; i < url.length() ; ++i ) { + if ( url.charAt( i ) == '"' || url.charAt( i ) < 0x20 || url.charAt( i ) > 0x7F ) { + _printer.printText( '%' ); + _printer.printText( Integer.toHexString( url.charAt( i ) ) ); + } else + _printer.printText( url.charAt( i ) ); + } + _printer.printText( '"' ); + } + + + protected void printEscaped( int ch ) + throws IOException + { + String charRef; + // If there is a suitable entity reference for this + // character, print it. The list of available entity + // references is almost but not identical between + // XML and HTML. + charRef = getEntityRef( ch ); + if ( charRef != null ) { + _printer.printText( '&' ); + _printer.printText( charRef ); + _printer.printText( ';' ); + } else if ( ( ch >= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0x7F ) || + ch == '\n' || ch == '\r' || ch == '\t' ) { + // Non printables are below ASCII space but not tab or line + // terminator, ASCII delete, or above a certain Unicode threshold. + if (ch < 0x10000) { + _printer.printText((char)ch ); + } else { + _printer.printText((char)(((ch-0x10000)>>10)+0xd800)); + _printer.printText((char)(((ch-0x10000)&0x3ff)+0xdc00)); + } + } else { + printHex(ch); + } + } + + /** + * Escapes chars + */ + final void printHex( int ch) throws IOException { + _printer.printText( "&#x" ); + _printer.printText(Integer.toHexString(ch)); + _printer.printText( ';' ); + + } + + + /** + * Escapes a string so it may be printed as text content or attribute + * value. Non printable characters are escaped using character references. + * Where the format specifies a deault entity reference, that reference + * is used (e.g. &lt;). + * + * @param source The string to escape + */ + protected void printEscaped( String source ) + throws IOException + { + for ( int i = 0 ; i < source.length() ; ++i ) { + int ch = source.charAt(i); + if ((ch & 0xfc00) == 0xd800 && i+1 < source.length()) { + int lowch = source.charAt(i+1); + if ((lowch & 0xfc00) == 0xdc00) { + ch = 0x10000 + ((ch-0xd800)<<10) + lowch-0xdc00; + i++; + } + } + printEscaped(ch); + } + } + + + //--------------------------------// + // Element state handling methods // + //--------------------------------// + + + /** + * Return the state of the current element. + * + * @return Current element state + */ + protected ElementState getElementState() + { + return _elementStates[ _elementStateCount ]; + } + + + /** + * Enter a new element state for the specified element. + * Tag name and space preserving is specified, element + * state is initially empty. + * + * @return Current element state, or null + */ + protected ElementState enterElementState( String namespaceURI, String localName, + String rawName, boolean preserveSpace ) + { + ElementState state; + + if ( _elementStateCount + 1 == _elementStates.length ) { + ElementState[] newStates; + + // Need to create a larger array of states. This does not happen + // often, unless the document is really deep. + newStates = new ElementState[ _elementStates.length + 10 ]; + for ( int i = 0 ; i < _elementStates.length ; ++i ) + newStates[ i ] = _elementStates[ i ]; + for ( int i = _elementStates.length ; i < newStates.length ; ++i ) + newStates[ i ] = new ElementState(); + _elementStates = newStates; + } + + ++_elementStateCount; + state = _elementStates[ _elementStateCount ]; + state.namespaceURI = namespaceURI; + state.localName = localName; + state.rawName = rawName; + state.preserveSpace = preserveSpace; + state.empty = true; + state.afterElement = false; + state.afterComment = false; + state.doCData = state.inCData = false; + state.unescaped = false; + state.prefixes = _prefixes; + + _prefixes = null; + return state; + } + + + /** + * Leave the current element state and return to the + * state of the parent element. If this was the root + * element, return to the state of the document. + * + * @return Previous element state + */ + protected ElementState leaveElementState() + { + if ( _elementStateCount > 0 ) { + /*Corrected by David Blondeau (blondeau@intalio.com)*/ + _prefixes = null; + //_prefixes = _elementStates[ _elementStateCount ].prefixes; + -- _elementStateCount; + return _elementStates[ _elementStateCount ]; + } + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "Internal", null); + throw new IllegalStateException(msg); + } + + + /** + * Returns true if in the state of the document. + * Returns true before entering any element and after + * leaving the root element. + * + * @return True if in the state of the document + */ + protected boolean isDocumentState() { + return _elementStateCount == 0; + } + + /** Clears document state. **/ + final void clearDocumentState() { + _elementStateCount = 0; + } + + /** + * Returns the namespace prefix for the specified URI. + * If the URI has been mapped to a prefix, returns the + * prefix, otherwise returns null. + * + * @param namespaceURI The namespace URI + * @return The namespace prefix if known, or null + */ + protected String getPrefix( String namespaceURI ) + { + String prefix; + + if ( _prefixes != null ) { + prefix = (String) _prefixes.get( namespaceURI ); + if ( prefix != null ) + return prefix; + } + if ( _elementStateCount == 0 ) { + return null; + } + for ( int i = _elementStateCount ; i > 0 ; --i ) { + if ( _elementStates[ i ].prefixes != null ) { + prefix = (String) _elementStates[ i ].prefixes.get( namespaceURI ); + if ( prefix != null ) + return prefix; + } + } + return null; + } + + /** + * The method modifies global DOM error object + * + * @param message + * @param severity + * @param type + * @return a DOMError + */ + protected DOMError modifyDOMError(String message, short severity, String type, Node node){ + fDOMError.reset(); + fDOMError.fMessage = message; + fDOMError.fType = type; + fDOMError.fSeverity = severity; + fDOMError.fLocator = new DOMLocatorImpl(-1, -1, -1, node, null); + return fDOMError; + + } + + + protected void fatalError(String message) throws IOException{ + if (fDOMErrorHandler != null) { + modifyDOMError(message, DOMError.SEVERITY_FATAL_ERROR, null, fCurrentNode); + fDOMErrorHandler.handleError(fDOMError); + } + else { + throw new IOException(message); + } + } + + /** + * DOM level 3: + * Check a node to determine if it contains unbound namespace prefixes. + * + * @param node The node to check for unbound namespace prefices + */ + protected void checkUnboundNamespacePrefixedNode (Node node) throws IOException{ + + } +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/DOMSerializer.java b/resources/xerces2-j-src/org/apache/xml/serialize/DOMSerializer.java new file mode 100644 index 0000000..c811cf8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/DOMSerializer.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + + +package org.apache.xml.serialize; + + +import java.io.IOException; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; + + + +/** + * Interface for a DOM serializer implementation. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Scott Boag + * @author Assaf Arkin + */ +public interface DOMSerializer +{ + + + /** + * Serialized the DOM element. Throws an exception only if + * an I/O exception occured while serializing. + * + * @param elem The element to serialize + * @throws IOException An I/O exception occured while + * serializing + */ + public void serialize( Element elem ) + throws IOException; + + + /** + * Serializes the DOM document. Throws an exception only if + * an I/O exception occured while serializing. + * + * @param doc The document to serialize + * @throws IOException An I/O exception occured while + * serializing + */ + public void serialize( Document doc ) + throws IOException; + + + /** + * Serializes the DOM document fragment. Throws an exception + * only if an I/O exception occured while serializing. + * + * @param frag The document fragment to serialize + * @throws IOException An I/O exception occured while + * serializing + */ + public void serialize( DocumentFragment frag ) + throws IOException; + + +} + + + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/DOMSerializerImpl.java b/resources/xerces2-j-src/org/apache/xml/serialize/DOMSerializerImpl.java new file mode 100644 index 0000000..04a0830 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/DOMSerializerImpl.java @@ -0,0 +1,1151 @@ +/* + * 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. + */ + +package org.apache.xml.serialize; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.lang.reflect.Method; +import java.util.ArrayList; + +import org.apache.xerces.dom.CoreDocumentImpl; +import org.apache.xerces.dom.DOMErrorImpl; +import org.apache.xerces.dom.DOMLocatorImpl; +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.dom.DOMNormalizer; +import org.apache.xerces.dom.DOMStringListImpl; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.util.DOMUtil; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.util.XMLChar; +import org.w3c.dom.Attr; +import org.w3c.dom.Comment; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSSerializer; +import org.w3c.dom.ls.LSSerializerFilter; + +/** + * EXPERIMENTAL: Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer by delegating serialization + * calls to XMLSerializer. + * LSSerializer provides an API for serializing (writing) a DOM document out in an + * XML document. The XML data is written to an output stream. + * During serialization of XML data, namespace fixup is done when possible as + * defined in DOM Level 3 Core, Appendix B. + * + * @author Elena Litani, IBM + * @author Gopal Sharma, Sun Microsystems + * @author Arun Yadav, Sun Microsystems + * @version $Id$ + * + * @deprecated Replaced by org.apache.xml.serializer.dom3.LSSerializerImpl in Xerces 2.9.0. + */ +public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { + + // TODO: When DOM Level 3 goes to REC replace method calls using + // reflection for: getXmlEncoding, getInputEncoding and getXmlEncoding + // with regular static calls on the Document object. + + // data + // serializer + private XMLSerializer serializer; + + // XML 1.1 serializer + private XML11Serializer xml11Serializer; + + //Recognized parameters + private DOMStringList fRecognizedParameters; + + /** REVISIT: Currently we handle 3 different configurations, would be nice just have one configuration + * that has different recognized parameters depending if it is used in Core/LS. + */ + protected short features = 0; + + protected final static short NAMESPACES = 0x1<<0; + protected final static short WELLFORMED = 0x1<<1; + protected final static short ENTITIES = 0x1<<2; + protected final static short CDATA = 0x1<<3; + protected final static short SPLITCDATA = 0x1<<4; + protected final static short COMMENTS = 0x1<<5; + protected final static short DISCARDDEFAULT = 0x1<<6; + protected final static short INFOSET = 0x1<<7; + protected final static short XMLDECL = 0x1<<8; + protected final static short NSDECL = 0x1<<9; + protected final static short DOM_ELEMENT_CONTENT_WHITESPACE = 0x1<<10; + protected final static short PRETTY_PRINT = 0x1<<11; + + // well-formness checking + private DOMErrorHandler fErrorHandler = null; + private final DOMErrorImpl fError = new DOMErrorImpl(); + private final DOMLocatorImpl fLocator = new DOMLocatorImpl(); + + /** + * Constructs a new LSSerializer. + * The constructor turns on the namespace support in XMLSerializer and + * initializes the following fields: fNSBinder, fLocalNSBinder, fSymbolTable, + * fEmptySymbol, fXmlSymbol, fXmlnsSymbol, fNamespaceCounter, fFeatures. + */ + public DOMSerializerImpl() { + // set default features + features |= NAMESPACES; + features |= ENTITIES; + features |= COMMENTS; + features |= CDATA; + features |= SPLITCDATA; + features |= WELLFORMED; + features |= NSDECL; + features |= DOM_ELEMENT_CONTENT_WHITESPACE; + features |= DISCARDDEFAULT; + features |= XMLDECL; + + serializer = new XMLSerializer(); + initSerializer(serializer); + } + + + + // + // LSSerializer methods + // + + public DOMConfiguration getDomConfig(){ + return this; + } + + /** DOM L3-EXPERIMENTAL: + * Setter for boolean and object parameters + */ + public void setParameter(String name, Object value) throws DOMException { + if (value instanceof Boolean) { + boolean state = ((Boolean) value).booleanValue(); + if (name.equalsIgnoreCase(Constants.DOM_INFOSET)){ + if (state){ + features &= ~ENTITIES; + features &= ~CDATA; + features |= NAMESPACES; + features |= NSDECL; + features |= WELLFORMED; + features |= COMMENTS; + } + // false does not have any effect + } else if (name.equalsIgnoreCase(Constants.DOM_XMLDECL)) { + features = + (short) (state ? features | XMLDECL : features & ~XMLDECL); + } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) { + features = + (short) (state + ? features | NAMESPACES + : features & ~NAMESPACES); + serializer.fNamespaces = state; + } else if (name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)) { + features = + (short) (state + ? features | SPLITCDATA + : features & ~SPLITCDATA); + } else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)) { + features = + (short) (state + ? features | DISCARDDEFAULT + : features & ~DISCARDDEFAULT); + } else if (name.equalsIgnoreCase(Constants.DOM_WELLFORMED)) { + features = + (short) (state + ? features | WELLFORMED + : features & ~WELLFORMED); + } else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)){ + features = + (short) (state + ? features | ENTITIES + : features & ~ENTITIES); + } + else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)){ + features = + (short) (state + ? features | CDATA + : features & ~CDATA); + } + else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)){ + features = + (short) (state + ? features | COMMENTS + : features & ~COMMENTS); + } else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { + features = + (short) (state + ? features | PRETTY_PRINT + : features & ~PRETTY_PRINT); + } + else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE) + || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) + || name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION) + || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) { + // true is not supported + if (state) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + }else if ( + name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { + //namespace-declaration has effect only if namespaces is true + features = + (short) (state + ? features | NSDECL + : features & ~NSDECL); + serializer.fNamespacePrefixes = state; + } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) + || name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { + // false is not supported + if (!state) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + } else { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } + } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { + if (value == null || value instanceof DOMErrorHandler) { + fErrorHandler = (DOMErrorHandler)value; + } else { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "TYPE_MISMATCH_ERR", + new Object[] { name }); + throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg); + } + } else if ( + name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) + || name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION) + || name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE) + && value != null) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } else { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[] { name }); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + } + + /** DOM L3-EXPERIMENTAL: + * Check if parameter can be set + */ + public boolean canSetParameter(String name, Object state) { + if (state == null){ + return true; + } + + if (state instanceof Boolean){ + boolean value = ((Boolean)state).booleanValue(); + if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES) + || name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA) + || name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT) + || name.equalsIgnoreCase(Constants.DOM_XMLDECL) + || name.equalsIgnoreCase(Constants.DOM_WELLFORMED) + || name.equalsIgnoreCase(Constants.DOM_INFOSET) + || name.equalsIgnoreCase(Constants.DOM_ENTITIES) + || name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS) + || name.equalsIgnoreCase(Constants.DOM_COMMENTS) + || name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT) + || name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)){ + // both values supported + return true; + } + else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE) + || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) + || name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION) + || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) { + // true is not supported + return !value; + } + else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) + || name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { + // false is not supported + return value; + } + } + else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER) && + state == null || state instanceof DOMErrorHandler){ + return true; + } + return false; + } + + /** + * DOM Level 3 Core CR - Experimental. + * + * The list of the parameters supported by this + * DOMConfiguration object and for which at least one value + * can be set by the application. Note that this list can also contain + * parameter names defined outside this specification. + */ + public DOMStringList getParameterNames() { + + if (fRecognizedParameters == null){ + ArrayList parameters = new ArrayList(); + + //Add DOM recognized parameters + //REVISIT: Would have been nice to have a list of + //recognized parameters. + parameters.add(Constants.DOM_NAMESPACES); + parameters.add(Constants.DOM_SPLIT_CDATA); + parameters.add(Constants.DOM_DISCARD_DEFAULT_CONTENT); + parameters.add(Constants.DOM_XMLDECL); + parameters.add(Constants.DOM_CANONICAL_FORM); + parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA); + parameters.add(Constants.DOM_VALIDATE); + parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION); + parameters.add(Constants.DOM_DATATYPE_NORMALIZATION); + parameters.add(Constants.DOM_FORMAT_PRETTY_PRINT); + parameters.add(Constants.DOM_NORMALIZE_CHARACTERS); + parameters.add(Constants.DOM_WELLFORMED); + parameters.add(Constants.DOM_INFOSET); + parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS); + parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE); + parameters.add(Constants.DOM_ENTITIES); + parameters.add(Constants.DOM_CDATA_SECTIONS); + parameters.add(Constants.DOM_COMMENTS); + parameters.add(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS); + parameters.add(Constants.DOM_ERROR_HANDLER); + //parameters.add(Constants.DOM_SCHEMA_LOCATION); + //parameters.add(Constants.DOM_SCHEMA_TYPE); + + //Add recognized xerces features and properties + + fRecognizedParameters = new DOMStringListImpl(parameters); + + } + + return fRecognizedParameters; + } + + /** DOM L3-EXPERIMENTAL: + * Getter for boolean and object parameters + */ + public Object getParameter(String name) throws DOMException { + if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)) { + return ((features & COMMENTS) != 0) ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) { + return (features & NAMESPACES) != 0 ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_XMLDECL)) { + return (features & XMLDECL) != 0 ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) { + return (features & CDATA) != 0 ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)) { + return (features & ENTITIES) != 0 ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)) { + return (features & SPLITCDATA) != 0 ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_WELLFORMED)) { + return (features & WELLFORMED) != 0 ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { + return (features & NSDECL) != 0 ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) || + name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { + return Boolean.TRUE; + }else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)){ + return ((features & DISCARDDEFAULT)!=0)?Boolean.TRUE:Boolean.FALSE; + }else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)){ + return ((features & PRETTY_PRINT)!=0)?Boolean.TRUE:Boolean.FALSE; + }else if (name.equalsIgnoreCase(Constants.DOM_INFOSET)){ + if ((features & ENTITIES) == 0 && + (features & CDATA) == 0 && + (features & NAMESPACES) != 0 && + (features & NSDECL) != 0 && + (features & WELLFORMED) != 0 && + (features & COMMENTS) != 0) { + return Boolean.TRUE; + } + return Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS) + || name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) + || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE) + || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) + || name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION)) { + return Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { + return fErrorHandler; + } else if ( + name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) + || name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION) + || name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE)) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[] { name }); + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); + } else { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[] { name }); + throw new DOMException(DOMException.NOT_FOUND_ERR, msg); + } + } + + + /** + * DOM L3 EXPERIMENTAL: + * Serialize the specified node as described above in the description of + * LSSerializer. The result of serializing the node is + * returned as a string. Writing a Document or Entity node produces a + * serialized form that is well formed XML. Writing other node types + * produces a fragment of text in a form that is not fully defined by + * this document, but that should be useful to a human for debugging or + * diagnostic purposes. + * @param wnode The node to be written. + * @return Returns the serialized data + * @exception DOMException + * DOMSTRING_SIZE_ERR: The resulting string is too long to fit in a + * DOMString. + * @exception LSException + * SERIALIZE_ERR: Unable to serialize the node. DOM applications should + * attach a DOMErrorHandler using the parameter + * "error-handler" to get details on error. + */ + public String writeToString(Node wnode) throws DOMException, LSException { + // determine which serializer to use: + XMLSerializer ser = null; + String ver = _getXmlVersion(wnode); + if (ver != null && ver.equals("1.1")) { + if(xml11Serializer == null) { + xml11Serializer = new XML11Serializer(); + initSerializer(xml11Serializer); + } + // copy setting from "main" serializer to XML 1.1 serializer + copySettings(serializer, xml11Serializer); + ser = xml11Serializer; + } + else { + ser = serializer; + } + + StringWriter destination = new StringWriter(); + try { + prepareForSerialization(ser, wnode); + ser._format.setEncoding("UTF-16"); + ser.setOutputCharStream(destination); + if (wnode.getNodeType() == Node.DOCUMENT_NODE) { + ser.serialize((Document)wnode); + } + else if (wnode.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { + ser.serialize((DocumentFragment)wnode); + } + else if (wnode.getNodeType() == Node.ELEMENT_NODE) { + ser.serialize((Element)wnode); + } + else { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "unable-to-serialize-node", null); + if (ser.fDOMErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl(); + error.fType = "unable-to-serialize-node"; + error.fMessage = msg; + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + ser.fDOMErrorHandler.handleError(error); + } + throw new LSException(LSException.SERIALIZE_ERR, msg); + } + } + catch (LSException lse) { + // Rethrow LSException. + throw lse; + } + catch (RuntimeException e) { + if (e == DOMNormalizer.abort){ + // stopped at user request + return null; + } + throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } + catch (IOException ioe) { + // REVISIT: A generic IOException doesn't provide enough information + // to determine that the serialized document is too large to fit + // into a string. This could have thrown for some other reason. -- mrglavas + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "STRING_TOO_LONG", + new Object[] { ioe.getMessage()}); + throw new DOMException(DOMException.DOMSTRING_SIZE_ERR,msg); + } + finally { + ser.clearDocumentState(); + } + return destination.toString(); + } + + /** + * DOM L3 EXPERIMENTAL: + * The end-of-line sequence of characters to be used in the XML being + * written out. The only permitted values are these: + *

        + *
        null
        + *
        + * Use a default end-of-line sequence. DOM implementations should choose + * the default to match the usual convention for text files in the + * environment being used. Implementations must choose a default + * sequence that matches one of those allowed by 2.11 "End-of-Line + * Handling".
        + *
        CR
        + *
        The carriage-return character (#xD).
        + *
        CR-LF
        + *
        The + * carriage-return and line-feed characters (#xD #xA).
        + *
        LF
        + *
        The line-feed + * character (#xA).
        + *
        + *
        The default value for this attribute is null. + */ + public void setNewLine(String newLine) { + serializer._format.setLineSeparator(newLine); + } + + + /** + * DOM L3 EXPERIMENTAL: + * The end-of-line sequence of characters to be used in the XML being + * written out. The only permitted values are these: + *
        + *
        null
        + *
        + * Use a default end-of-line sequence. DOM implementations should choose + * the default to match the usual convention for text files in the + * environment being used. Implementations must choose a default + * sequence that matches one of those allowed by 2.11 "End-of-Line + * Handling".
        + *
        CR
        + *
        The carriage-return character (#xD).
        + *
        CR-LF
        + *
        The + * carriage-return and line-feed characters (#xD #xA).
        + *
        LF
        + *
        The line-feed + * character (#xA).
        + *
        + *
        The default value for this attribute is null. + */ + public String getNewLine() { + return serializer._format.getLineSeparator(); + } + + + /** + * When the application provides a filter, the serializer will call out + * to the filter before serializing each Node. Attribute nodes are never + * passed to the filter. The filter implementation can choose to remove + * the node from the stream or to terminate the serialization early. + */ + public LSSerializerFilter getFilter(){ + return serializer.fDOMFilter; + } + /** + * When the application provides a filter, the serializer will call out + * to the filter before serializing each Node. Attribute nodes are never + * passed to the filter. The filter implementation can choose to remove + * the node from the stream or to terminate the serialization early. + */ + public void setFilter(LSSerializerFilter filter){ + serializer.fDOMFilter = filter; + } + + // this initializes a newly-created serializer + private void initSerializer(XMLSerializer ser) { + ser.fNSBinder = new NamespaceSupport(); + ser.fLocalNSBinder = new NamespaceSupport(); + ser.fSymbolTable = new SymbolTable(); + } + + // copies all settings that could have been modified + // by calls to LSSerializer methods from one serializer to another. + // IMPORTANT: if new methods are implemented or more settings of + // the serializer are made alterable, this must be + // reflected in this method! + private void copySettings(XMLSerializer src, XMLSerializer dest) { + dest.fDOMErrorHandler = fErrorHandler; + dest._format.setEncoding(src._format.getEncoding()); + dest._format.setLineSeparator(src._format.getLineSeparator()); + dest.fDOMFilter = src.fDOMFilter; + }//copysettings + + /** + * Serialize the specified node as described above in the general + * description of the LSSerializer interface. The output + * is written to the supplied LSOutput. + *
        When writing to a LSOutput, the encoding is found by + * looking at the encoding information that is reachable through the + * LSOutput and the item to be written (or its owner + * document) in this order: + *
          + *
        1. LSOutput.encoding, + *
        2. + *
        3. + * Document.actualEncoding, + *
        4. + *
        5. + * Document.xmlEncoding. + *
        6. + *
        + *
        If no encoding is reachable through the above properties, a + * default encoding of "UTF-8" will be used. + *
        If the specified encoding is not supported an + * "unsupported-encoding" error is raised. + *
        If no output is specified in the LSOutput, a + * "no-output-specified" error is raised. + * @param node The node to serialize. + * @param destination The destination for the serialized DOM. + * @return Returns true if node was + * successfully serialized and false in case the node + * couldn't be serialized. + */ + public boolean write(Node node, LSOutput destination) throws LSException{ + + if (node == null) + return false; + + XMLSerializer ser = null; + String ver = _getXmlVersion(node); + //determine which serializer to use: + if (ver != null && ver.equals("1.1")) { + if (xml11Serializer == null) { + xml11Serializer = new XML11Serializer(); + initSerializer(xml11Serializer); + } + //copy setting from "main" serializer to XML 1.1 serializer + copySettings(serializer, xml11Serializer); + ser = xml11Serializer; + } + else { + ser = serializer; + } + + String encoding = null; + if ((encoding = destination.getEncoding()) == null) { + encoding = _getInputEncoding(node); + if (encoding == null) { + encoding = _getXmlEncoding(node); + if (encoding == null) { + encoding = "UTF-8"; + } + } + } + try { + prepareForSerialization(ser, node); + ser._format.setEncoding(encoding); + OutputStream outputStream = destination.getByteStream(); + Writer writer = destination.getCharacterStream(); + String uri = destination.getSystemId(); + if (writer == null) { + if (outputStream == null) { + if (uri == null) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "no-output-specified", null); + if (ser.fDOMErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl(); + error.fType = "no-output-specified"; + error.fMessage = msg; + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + ser.fDOMErrorHandler.handleError(error); + } + throw new LSException(LSException.SERIALIZE_ERR, msg); + } + else { + ser.setOutputByteStream(XMLEntityManager.createOutputStream(uri)); + } + } + else { + // byte stream was specified + ser.setOutputByteStream(outputStream); + } + } + else { + // character stream is specified + ser.setOutputCharStream(writer); + } + + if (node.getNodeType() == Node.DOCUMENT_NODE) + ser.serialize((Document) node); + else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) + ser.serialize((DocumentFragment) node); + else if (node.getNodeType() == Node.ELEMENT_NODE) + ser.serialize((Element) node); + else + return false; + } + catch( UnsupportedEncodingException ue) { + if (ser.fDOMErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl(); + error.fException = ue; + error.fType = "unsupported-encoding"; + error.fMessage = ue.getMessage(); + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + ser.fDOMErrorHandler.handleError(error); + } + throw new LSException(LSException.SERIALIZE_ERR, + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "unsupported-encoding", null)); + //return false; + } + catch (LSException lse) { + // Rethrow LSException. + throw lse; + } + catch (RuntimeException e) { + if (e == DOMNormalizer.abort){ + // stopped at user request + return false; + } + throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } + catch (Exception e) { + if (ser.fDOMErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl(); + error.fException = e; + error.fMessage = e.getMessage(); + error.fSeverity = DOMError.SEVERITY_ERROR; + ser.fDOMErrorHandler.handleError(error); + + } + throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } + finally { + ser.clearDocumentState(); + } + return true; + + } //write + + /** + * Serialize the specified node as described above in the general + * description of the LSSerializer interface. The output + * is written to the supplied URI. + *
        When writing to a URI, the encoding is found by looking at the + * encoding information that is reachable through the item to be written + * (or its owner document) in this order: + *
          + *
        1. + * Document.inputEncoding, + *
        2. + *
        3. + * Document.xmlEncoding. + *
        4. + *
        + *
        If no encoding is reachable through the above properties, a + * default encoding of "UTF-8" will be used. + *
        If the specified encoding is not supported an + * "unsupported-encoding" error is raised. + * @param node The node to serialize. + * @param URI The URI to write to. + * @return Returns true if node was + * successfully serialized and false in case the node + * couldn't be serialized. + */ + public boolean writeToURI(Node node, String URI) throws LSException{ + if (node == null){ + return false; + } + + XMLSerializer ser = null; + String ver = _getXmlVersion(node); + + if (ver != null && ver.equals("1.1")) { + if (xml11Serializer == null) { + xml11Serializer = new XML11Serializer(); + initSerializer(xml11Serializer); + } + // copy setting from "main" serializer to XML 1.1 serializer + copySettings(serializer, xml11Serializer); + ser = xml11Serializer; + } + else { + ser = serializer; + } + + String encoding = _getInputEncoding(node); + if (encoding == null) { + encoding = _getXmlEncoding(node); + if (encoding == null) { + encoding = "UTF-8"; + } + } + + try { + prepareForSerialization(ser, node); + ser._format.setEncoding(encoding); + ser.setOutputByteStream(XMLEntityManager.createOutputStream(URI)); + + if (node.getNodeType() == Node.DOCUMENT_NODE) + ser.serialize((Document) node); + else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) + ser.serialize((DocumentFragment) node); + else if (node.getNodeType() == Node.ELEMENT_NODE) + ser.serialize((Element) node); + else + return false; + } + catch (LSException lse) { + // Rethrow LSException. + throw lse; + } + catch (RuntimeException e) { + if (e == DOMNormalizer.abort){ + // stopped at user request + return false; + } + throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } + catch (Exception e) { + if (ser.fDOMErrorHandler != null) { + DOMErrorImpl error = new DOMErrorImpl(); + error.fException = e; + error.fMessage = e.getMessage(); + error.fSeverity = DOMError.SEVERITY_ERROR; + ser.fDOMErrorHandler.handleError(error); + } + throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } + finally { + ser.clearDocumentState(); + } + return true; + } //writeURI + + + // + // Private methods + // + + private void prepareForSerialization(XMLSerializer ser, Node node) { + ser.reset(); + ser.features = features; + ser.fDOMErrorHandler = fErrorHandler; + ser.fNamespaces = (features & NAMESPACES) != 0; + ser.fNamespacePrefixes = (features & NSDECL) != 0; + ser._format.setIndenting((features & PRETTY_PRINT) != 0); + ser._format.setOmitComments((features & COMMENTS)==0); + ser._format.setOmitXMLDeclaration((features & XMLDECL) == 0); + + if ((features & WELLFORMED) != 0) { + // REVISIT: this is inefficient implementation of well-formness. Instead, we should check + // well-formness as we serialize the tree + Node next, root; + root = node; + Method versionChanged; + boolean verifyNames = true; + Document document =(node.getNodeType() == Node.DOCUMENT_NODE) + ? (Document) node + : node.getOwnerDocument(); + try { + versionChanged = document.getClass().getMethod("isXMLVersionChanged()", new Class[] {}); + if (versionChanged != null) { + verifyNames = ((Boolean)versionChanged.invoke(document, (Object[]) null)).booleanValue(); + } + } catch (Exception e) { + //no way to test the version... + //ignore the exception + } + if (node.getFirstChild() != null) { + while (node != null) { + verify(node, verifyNames, false); + // Move down to first child + next = node.getFirstChild(); + // No child nodes, so walk tree + while (next == null) { + // Move to sibling if possible. + next = node.getNextSibling(); + if (next == null) { + node = node.getParentNode(); + if (root == node){ + next = null; + break; + } + next = node.getNextSibling(); + } + } + node = next; + } + } + else { + verify(node, verifyNames, false); + } + } + } + + + private void verify (Node node, boolean verifyNames, boolean xml11Version){ + + int type = node.getNodeType(); + fLocator.fRelatedNode = node; + boolean wellformed; + switch (type) { + case Node.DOCUMENT_NODE:{ + break; + } + case Node.DOCUMENT_TYPE_NODE:{ + break; + } + case Node.ELEMENT_NODE:{ + if (verifyNames){ + if((features & NAMESPACES) != 0){ + wellformed = CoreDocumentImpl.isValidQName(node.getPrefix() , node.getLocalName(), xml11Version) ; + } + else{ + wellformed = CoreDocumentImpl.isXMLName(node.getNodeName() , xml11Version); + } + if (!wellformed){ + if (fErrorHandler != null) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Element", node.getNodeName()}); + DOMNormalizer.reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, + "wf-invalid-character-in-node-name"); + } + } + } + + NamedNodeMap attributes = (node.hasAttributes()) ? node.getAttributes() : null; + if (attributes != null) { + for (int i = 0; i < attributes.getLength(); ++i) { + Attr attr = (Attr) attributes.item(i); + fLocator.fRelatedNode = attr; + DOMNormalizer.isAttrValueWF( fErrorHandler, fError, fLocator, + attributes, attr, attr.getValue(), xml11Version); + if (verifyNames) { + wellformed = CoreDocumentImpl.isXMLName( attr.getNodeName(), xml11Version); + if (!wellformed) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[] { "Attr", node.getNodeName()}); + DOMNormalizer.reportDOMError( fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, + "wf-invalid-character-in-node-name"); + } + } + } + + } + + break; + } + + case Node.COMMENT_NODE: { + // only verify well-formness if comments included in the tree + if ((features & COMMENTS) != 0) + DOMNormalizer.isCommentWF(fErrorHandler, fError, fLocator, ((Comment)node).getData(), xml11Version); + break; + } + case Node.ENTITY_REFERENCE_NODE: { + // only if entity is preserved in the tree + if (verifyNames && (features & ENTITIES) != 0){ + CoreDocumentImpl.isXMLName(node.getNodeName() , xml11Version); + } + break; + + } + case Node.CDATA_SECTION_NODE: { + // verify content + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); + // the ]]> string will be checked during serialization + break; + } + case Node.TEXT_NODE:{ + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE:{ + ProcessingInstruction pinode = (ProcessingInstruction)node ; + String target = pinode.getTarget(); + if (verifyNames) { + if (xml11Version) { + wellformed = XML11Char.isXML11ValidName(target); + } else { + wellformed = XMLChar.isValidName(target); + } + + if (!wellformed) { + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[] { "Element", node.getNodeName()}); + DOMNormalizer.reportDOMError( + fErrorHandler, + fError, + fLocator, + msg, + DOMError.SEVERITY_FATAL_ERROR, + "wf-invalid-character-in-node-name"); + } + } + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, pinode.getData(), xml11Version); + break; + } + } + fLocator.fRelatedNode = null; + } + + private String _getXmlVersion(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) ? + (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetXmlVersionMethod.invoke(doc, (Object[]) null); + } + // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } + // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } + // Ignore all other exceptions and errors + catch (Throwable t) {} + } + return null; + } + + private String _getInputEncoding(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) ? + (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetInputEncodingMethod.invoke(doc, (Object[]) null); + } + // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } + // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } + // Ignore all other exceptions and errors + catch (Throwable t) {} + } + return null; + } + + private String _getXmlEncoding(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) ? + (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetXmlEncodingMethod.invoke(doc, (Object[]) null); + } + // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } + // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } + // Ignore all other exceptions and errors + catch (Throwable t) {} + } + return null; + } + + /** + * Holder of DOM Level 3 methods from org.w3c.dom.Document. + */ + static class DocumentMethods { + + // Method: org.w3c.dom.Document.getXmlVersion() + private static java.lang.reflect.Method fgDocumentGetXmlVersionMethod = null; + + // Method: org.w3c.dom.Document.getInputEncoding() + private static java.lang.reflect.Method fgDocumentGetInputEncodingMethod = null; + + // Method: org.w3c.dom.Document.getXmlEncoding() + private static java.lang.reflect.Method fgDocumentGetXmlEncodingMethod = null; + + // Flag indicating whether or not Document methods are available. + private static boolean fgDocumentMethodsAvailable = false; + + private DocumentMethods() {} + + // Attempt to get methods for org.w3c.dom.Document on class initialization. + static { + try { + fgDocumentGetXmlVersionMethod = Document.class.getMethod("getXmlVersion", new Class [] {}); + fgDocumentGetInputEncodingMethod = Document.class.getMethod("getInputEncoding", new Class [] {}); + fgDocumentGetXmlEncodingMethod = Document.class.getMethod("getXmlEncoding", new Class [] {}); + fgDocumentMethodsAvailable = true; + } + // ClassNotFoundException, NoSuchMethodException or SecurityException + // Whatever the case, we cannot retrieve the methods. + catch (Exception exc) { + fgDocumentGetXmlVersionMethod = null; + fgDocumentGetInputEncodingMethod = null; + fgDocumentGetXmlEncodingMethod = null; + fgDocumentMethodsAvailable = false; + } + } + } + +} //DOMSerializerImpl diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/ElementState.java b/resources/xerces2-j-src/org/apache/xml/serialize/ElementState.java new file mode 100644 index 0000000..aff0612 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/ElementState.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + + +package org.apache.xml.serialize; + + +import java.util.Hashtable; + + +/** + * Holds the state of the currently serialized element. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see BaseMarkupSerializer + */ +public class ElementState +{ + + + /** + * The element's raw tag name (local or prefix:local). + */ + public String rawName; + + + /** + * The element's local tag name. + */ + public String localName; + + + /** + * The element's namespace URI. + */ + public String namespaceURI; + + + /** + * True if element is space preserving. + */ + public boolean preserveSpace; + + + /** + * True if element is empty. Turns false immediately + * after serializing the first contents of the element. + */ + public boolean empty; + + + /** + * True if the last serialized node was an element node. + */ + public boolean afterElement; + + + /** + * True if the last serialized node was a comment node. + */ + public boolean afterComment; + + + /** + * True if textual content of current element should be + * serialized as CDATA section. + */ + public boolean doCData; + + + /** + * True if textual content of current element should be + * serialized as raw characters (unescaped). + */ + public boolean unescaped; + + + /** + * True while inside CData and printing text as CData. + */ + public boolean inCData; + + + /** + * Association between namespace URIs (keys) and prefixes (values). + */ + public Hashtable prefixes; + + +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/EncodingInfo.java b/resources/xerces2-j-src/org/apache/xml/serialize/EncodingInfo.java new file mode 100644 index 0000000..9d423a0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/EncodingInfo.java @@ -0,0 +1,273 @@ +/* + * 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. + */ + +package org.apache.xml.serialize; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import org.apache.xerces.util.EncodingMap; + +/** + * This class represents an encoding. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Id$ + */ +public class EncodingInfo { + + // An array to hold the argument for a method of Charset, CharsetEncoder or CharToByteConverter. + private Object [] fArgsForMethod = null; + + // name of encoding as registered with IANA; + // preferably a MIME name, but aliases are fine too. + String ianaName; + String javaName; + int lastPrintable; + + // The CharsetEncoder with which we test unusual characters. + Object fCharsetEncoder = null; + + // The CharToByteConverter with which we test unusual characters. + Object fCharToByteConverter = null; + + // Is the converter null because it can't be instantiated + // for some reason (perhaps we're running with insufficient authority as + // an applet? + boolean fHaveTriedCToB = false; + + // Is the charset encoder usable or available. + boolean fHaveTriedCharsetEncoder = false; + + /** + * Creates new EncodingInfo instance. + */ + public EncodingInfo(String ianaName, String javaName, int lastPrintable) { + this.ianaName = ianaName; + this.javaName = EncodingMap.getIANA2JavaMapping(ianaName); + this.lastPrintable = lastPrintable; + } + + /** + * Returns a MIME charset name of this encoding. + */ + public String getIANAName() { + return this.ianaName; + } + + /** + * Returns a writer for this encoding based on + * an output stream. + * + * @return A suitable writer + * @exception UnsupportedEncodingException There is no convertor + * to support this encoding + */ + public Writer getWriter(OutputStream output) + throws UnsupportedEncodingException { + // this should always be true! + if (javaName != null) + return new OutputStreamWriter(output, javaName); + javaName = EncodingMap.getIANA2JavaMapping(ianaName); + if(javaName == null) + // use UTF-8 as preferred encoding + return new OutputStreamWriter(output, "UTF8"); + return new OutputStreamWriter(output, javaName); + } + + /** + * Checks whether the specified character is printable or not in this encoding. + * + * @param ch a code point (0-0x10ffff) + */ + public boolean isPrintable(char ch) { + if (ch <= this.lastPrintable) { + return true; + } + return isPrintable0(ch); + } + + /** + * Checks whether the specified character is printable or not in this encoding. + * This method accomplishes this using a java.nio.CharsetEncoder. If NIO isn't + * available it will attempt use a sun.io.CharToByteConverter. + * + * @param ch a code point (0-0x10ffff) + */ + private boolean isPrintable0(char ch) { + + // Attempt to get a CharsetEncoder for this encoding. + if (fCharsetEncoder == null && CharsetMethods.fgNIOCharsetAvailable && !fHaveTriedCharsetEncoder) { + if (fArgsForMethod == null) { + fArgsForMethod = new Object [1]; + } + // try and create the CharsetEncoder + try { + fArgsForMethod[0] = javaName; + Object charset = CharsetMethods.fgCharsetForNameMethod.invoke(null, fArgsForMethod); + if (((Boolean) CharsetMethods.fgCharsetCanEncodeMethod.invoke(charset, (Object[]) null)).booleanValue()) { + fCharsetEncoder = CharsetMethods.fgCharsetNewEncoderMethod.invoke(charset, (Object[]) null); + } + // This charset cannot be used for encoding, don't try it again... + else { + fHaveTriedCharsetEncoder = true; + } + } + catch (Exception e) { + // don't try it again... + fHaveTriedCharsetEncoder = true; + } + } + // Attempt to use the CharsetEncoder to determine whether the character is printable. + if (fCharsetEncoder != null) { + try { + fArgsForMethod[0] = new Character(ch); + return ((Boolean) CharsetMethods.fgCharsetEncoderCanEncodeMethod.invoke(fCharsetEncoder, fArgsForMethod)).booleanValue(); + } + catch (Exception e) { + // obviously can't use this charset encoder; possibly a JDK bug + fCharsetEncoder = null; + fHaveTriedCharsetEncoder = false; + } + } + + // As a last resort try to use a sun.io.CharToByteConverter to + // determine whether this character is printable. We will always + // reach here on JDK 1.3 or below. + if (fCharToByteConverter == null) { + if (fHaveTriedCToB || !CharToByteConverterMethods.fgConvertersAvailable) { + // forget it; nothing we can do... + return false; + } + if (fArgsForMethod == null) { + fArgsForMethod = new Object [1]; + } + // try and create the CharToByteConverter + try { + fArgsForMethod[0] = javaName; + fCharToByteConverter = CharToByteConverterMethods.fgGetConverterMethod.invoke(null, fArgsForMethod); + } + catch (Exception e) { + // don't try it again... + fHaveTriedCToB = true; + return false; + } + } + try { + fArgsForMethod[0] = new Character(ch); + return ((Boolean) CharToByteConverterMethods.fgCanConvertMethod.invoke(fCharToByteConverter, fArgsForMethod)).booleanValue(); + } + catch (Exception e) { + // obviously can't use this converter; probably some kind of + // security restriction + fCharToByteConverter = null; + fHaveTriedCToB = false; + return false; + } + } + + // is this an encoding name recognized by this JDK? + // if not, will throw UnsupportedEncodingException + public static void testJavaEncodingName(String name) throws UnsupportedEncodingException { + final byte [] bTest = {(byte)'v', (byte)'a', (byte)'l', (byte)'i', (byte)'d'}; + String s = new String(bTest, name); + } + + /** + * Holder of methods from java.nio.charset.Charset and java.nio.charset.CharsetEncoder. + */ + static class CharsetMethods { + + // Method: java.nio.charset.Charset.forName(java.lang.String) + private static java.lang.reflect.Method fgCharsetForNameMethod = null; + + // Method: java.nio.charset.Charset.canEncode() + private static java.lang.reflect.Method fgCharsetCanEncodeMethod = null; + + // Method: java.nio.charset.Charset.newEncoder() + private static java.lang.reflect.Method fgCharsetNewEncoderMethod = null; + + // Method: java.nio.charset.CharsetEncoder.canEncode(char) + private static java.lang.reflect.Method fgCharsetEncoderCanEncodeMethod = null; + + // Flag indicating whether or not java.nio.charset.* is available. + private static boolean fgNIOCharsetAvailable = false; + + private CharsetMethods() {} + + // Attempt to get methods for Charset and CharsetEncoder on class initialization. + static { + try { + Class charsetClass = Class.forName("java.nio.charset.Charset"); + Class charsetEncoderClass = Class.forName("java.nio.charset.CharsetEncoder"); + fgCharsetForNameMethod = charsetClass.getMethod("forName", new Class [] {String.class}); + fgCharsetCanEncodeMethod = charsetClass.getMethod("canEncode", new Class [] {}); + fgCharsetNewEncoderMethod = charsetClass.getMethod("newEncoder", new Class [] {}); + fgCharsetEncoderCanEncodeMethod = charsetEncoderClass.getMethod("canEncode", new Class [] {Character.TYPE}); + fgNIOCharsetAvailable = true; + } + // ClassNotFoundException, NoSuchMethodException or SecurityException + // Whatever the case, we cannot use java.nio.charset.*. + catch (Exception exc) { + fgCharsetForNameMethod = null; + fgCharsetCanEncodeMethod = null; + fgCharsetEncoderCanEncodeMethod = null; + fgCharsetNewEncoderMethod = null; + fgNIOCharsetAvailable = false; + } + } + } + + /** + * Holder of methods from sun.io.CharToByteConverter. + */ + static class CharToByteConverterMethods { + + // Method: sun.io.CharToByteConverter.getConverter(java.lang.String) + private static java.lang.reflect.Method fgGetConverterMethod = null; + + // Method: sun.io.CharToByteConverter.canConvert(char) + private static java.lang.reflect.Method fgCanConvertMethod = null; + + // Flag indicating whether or not sun.io.CharToByteConverter is available. + private static boolean fgConvertersAvailable = false; + + private CharToByteConverterMethods() {} + + // Attempt to get methods for char to byte converter on class initialization. + static { + try { + Class clazz = Class.forName("sun.io.CharToByteConverter"); + fgGetConverterMethod = clazz.getMethod("getConverter", new Class [] {String.class}); + fgCanConvertMethod = clazz.getMethod("canConvert", new Class [] {Character.TYPE}); + fgConvertersAvailable = true; + } + // ClassNotFoundException, NoSuchMethodException or SecurityException + // Whatever the case, we cannot use sun.io.CharToByteConverter. + catch (Exception exc) { + fgGetConverterMethod = null; + fgCanConvertMethod = null; + fgConvertersAvailable = false; + } + } + } +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/Encodings.java b/resources/xerces2-j-src/org/apache/xml/serialize/Encodings.java new file mode 100644 index 0000000..5d7d406 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/Encodings.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +package org.apache.xml.serialize; + +import java.io.UnsupportedEncodingException; +import java.util.Hashtable; +import java.util.Locale; + +import org.apache.xerces.util.EncodingMap; + +/** + * Provides information about encodings. Depends on the Java runtime + * to provides writers for the different encodings, but can be used + * to override encoding names and provide the last printable character + * for each encoding. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Id$ + * @author Assaf Arkin + */ +public class Encodings +{ + + + /** + * The last printable character for unknown encodings. + */ + static final int DEFAULT_LAST_PRINTABLE = 0x7F; + + // last printable character for Unicode-compatible encodings + static final int LAST_PRINTABLE_UNICODE = 0xffff; + // unicode-compliant encodings; can express plane 0 + static final String[] UNICODE_ENCODINGS = { + "Unicode", "UnicodeBig", "UnicodeLittle", "GB2312", "UTF8", "UTF-16", + }; + // default (Java) encoding if none supplied: + static final String DEFAULT_ENCODING = "UTF8"; + + // note that the size of this Hashtable + // is bounded by the number of encodings recognized by EncodingMap; + // therefore it poses no static mutability risk. + static Hashtable _encodings = new Hashtable(); + + /** + * @param encoding a MIME charset name, or null. + */ + static EncodingInfo getEncodingInfo(String encoding, boolean allowJavaNames) throws UnsupportedEncodingException { + EncodingInfo eInfo = null; + if (encoding == null) { + if((eInfo = (EncodingInfo)_encodings.get(DEFAULT_ENCODING)) != null) + return eInfo; + eInfo = new EncodingInfo(EncodingMap.getJava2IANAMapping(DEFAULT_ENCODING), DEFAULT_ENCODING, LAST_PRINTABLE_UNICODE); + _encodings.put(DEFAULT_ENCODING, eInfo); + return eInfo; + } + // need to convert it to upper case: + encoding = encoding.toUpperCase(Locale.ENGLISH); + String jName = EncodingMap.getIANA2JavaMapping(encoding); + if (jName == null) { + // see if the encoding passed in is a Java encoding name. + if (allowJavaNames) { + EncodingInfo.testJavaEncodingName(encoding); + if ((eInfo = (EncodingInfo)_encodings.get(encoding)) != null) + return eInfo; + // is it known to be unicode-compliant? + int i = 0; + for(; iAssaf Arkin +# +# Character entity references for markup-significant +# +quot 34 +amp 38 +lt 60 +gt 62 +nbsp 160 +# +# Character entity references for ISO 8859-1 characters +# +iexcl 161 +cent 162 +pound 163 +curren 164 +yen 165 +brvbar 166 +sect 167 +uml 168 +copy 169 +ordf 170 +laquo 171 +not 172 +shy 173 +reg 174 +macr 175 +deg 176 +plusmn 177 +sup2 178 +sup3 179 +acute 180 +micro 181 +para 182 +middot 183 +cedil 184 +sup1 185 +ordm 186 +raquo 187 +frac14 188 +frac12 189 +frac34 190 +iquest 191 +Agrave 192 +Aacute 193 +Acirc 194 +Atilde 195 +Auml 196 +Aring 197 +AElig 198 +Ccedil 199 +Egrave 200 +Eacute 201 +Ecirc 202 +Euml 203 +Igrave 204 +Iacute 205 +Icirc 206 +Iuml 207 +ETH 208 +Ntilde 209 +Ograve 210 +Oacute 211 +Ocirc 212 +Otilde 213 +Ouml 214 +times 215 +Oslash 216 +Ugrave 217 +Uacute 218 +Ucirc 219 +Uuml 220 +Yacute 221 +THORN 222 +szlig 223 +agrave 224 +aacute 225 +acirc 226 +atilde 227 +auml 228 +aring 229 +aelig 230 +ccedil 231 +egrave 232 +eacute 233 +ecirc 234 +euml 235 +igrave 236 +iacute 237 +icirc 238 +iuml 239 +eth 240 +ntilde 241 +ograve 242 +oacute 243 +ocirc 244 +otilde 245 +ouml 246 +divide 247 +oslash 248 +ugrave 249 +uacute 250 +ucirc 251 +uuml 252 +yacute 253 +thorn 254 +yuml 255 +# +# Character entity references for symbols, mathematical symbols, and Greek letters +# +# Latin Extended +fnof 402 +# +# Greek +Alpha 913 +Beta 914 +Gamma 915 +Delta 916 +Epsilon 917 +Zeta 918 +Eta 919 +Theta 920 +Iota 921 +Kappa 922 +Lambda 923 +Mu 924 +Nu 925 +Xi 926 +Omicron 927 +Pi 928 +Rho 929 +Sigma 931 +Tau 932 +Upsilon 933 +Phi 934 +Chi 935 +Psi 936 +Omega 937 +alpha 945 +beta 946 +gamma 947 +delta 948 +epsilon 949 +zeta 950 +eta 951 +theta 952 +iota 953 +kappa 954 +lambda 955 +mu 956 +nu 957 +xi 958 +omicron 959 +pi 960 +rho 961 +sigmaf 962 +sigma 963 +tau 964 +upsilon 965 +phi 966 +chi 967 +psi 968 +omega 969 +thetasym 977 +upsih 978 +piv 982 +# +# General Punctuation +bull 8226 +hellip 8230 +prime 8242 +Prime 8243 +oline 8254 +frasl 8260 +# +# Letterlike Symbols +weierp 8472 +image 8465 +real 8476 +trade 8482 +alefsym 8501 +# +# Arrows +larr 8592 +uarr 8593 +rarr 8594 +darr 8595 +harr 8596 +crarr 8629 +lArr 8656 +uArr 8657 +rArr 8658 +dArr 8659 +hArr 8660 +# +# Mathematical Operators +forall 8704 +part 8706 +exist 8707 +empty 8709 +nabla 8711 +isin 8712 +notin 8713 +ni 8715 +prod 8719 +sum 8721 +minus 8722 +lowast 8727 +radic 8730 +prop 8733 +infin 8734 +ang 8736 +and 8743 +or 8744 +cap 8745 +cup 8746 +int 8747 +there4 8756 +sim 8764 +cong 8773 +asymp 8776 +ne 8800 +equiv 8801 +le 8804 +ge 8805 +sub 8834 +sup 8835 +nsub 8836 +sube 8838 +supe 8839 +oplus 8853 +otimes 8855 +perp 8869 +sdot 8901 +# +# Miscellaneous Technical +lceil 8968 +rceil 8969 +lfloor 8970 +rfloor 8971 +lang 9001 +rang 9002 +# +# Geometric Shapes +loz 9674 +# +# Miscellaneous Symbols +spades 9824 +clubs 9827 +hearts 9829 +diams 9830 +# +# Character entity references for internationalization characters +# +# Latin Extended-A +OElig 338 +oelig 339 +#-- Commented out. NN 4.7 does not seem to support these -- +#Scaron 352 +#scaron 353 +Yuml 376 +# +# Spacing Modifier Letters +circ 710 +tilde 732 +# +# General Punctuation +ensp 8194 +emsp 8195 +thinsp 8201 +zwnj 8204 +zwj 8205 +lrm 8206 +rlm 8207 +ndash 8211 +mdash 8212 +lsquo 8216 +rsquo 8217 +sbquo 8218 +ldquo 8220 +rdquo 8221 +bdquo 8222 +dagger 8224 +Dagger 8225 +permil 8240 +lsaquo 8249 +rsaquo 8250 +euro 8364 diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/HTMLSerializer.java b/resources/xerces2-j-src/org/apache/xml/serialize/HTMLSerializer.java new file mode 100644 index 0000000..717fca5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/HTMLSerializer.java @@ -0,0 +1,874 @@ +/* + * 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. + */ + + +// Sep 14, 2000: +// Fixed serializer to report IO exception directly, instead at +// the end of document processing. +// Reported by Patrick Higgins +// Aug 21, 2000: +// Fixed bug in startDocument not calling prepare. +// Reported by Mikael Staldal +// Aug 21, 2000: +// Added ability to omit DOCTYPE declaration. +// Sep 1, 2000: +// If no output format is provided the serializer now defaults +// to ISO-8859-1 encoding. Reported by Mikael Staldal +// + + +package org.apache.xml.serialize; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +import org.apache.xerces.dom.DOMMessageFormatter; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.AttributeList; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + + +/** + * Implements an HTML/XHTML serializer supporting both DOM and SAX + * pretty serializing. HTML/XHTML mode is determined in the + * constructor. For usage instructions see {@link Serializer}. + *

        + * If an output stream is used, the encoding is taken from the + * output format (defaults to UTF-8). If a writer is + * used, make sure the writer uses the same encoding (if applies) + * as specified in the output format. + *

        + * The serializer supports both DOM and SAX. DOM serializing is done + * by calling {@link #serialize} and SAX serializing is done by firing + * SAX events and using the serializer as a document handler. + *

        + * If an I/O exception occurs while serializing, the serializer + * will not throw an exception directly, but only throw it + * at the end of serializing (either DOM or SAX's {@link + * org.xml.sax.DocumentHandler#endDocument}. + *

        + * For elements that are not specified as whitespace preserving, + * the serializer will potentially break long text lines at space + * boundaries, indent lines, and serialize elements on separate + * lines. Line terminators will be regarded as spaces, and + * spaces at beginning of line will be stripped. + *

        + * XHTML is slightly different than HTML: + *

          + *
        • Element/attribute names are lower case and case matters + *
        • Attributes must specify value, even if empty string + *
        • Empty elements must have '/' in empty tag + *
        • Contents of SCRIPT and STYLE elements serialized as CDATA + *
        + * + * @deprecated This class was deprecated in Xerces 2.6.2. It is + * recommended that new applications use JAXP's Transformation API + * for XML (TrAX) for serializing HTML. See the Xerces documentation + * for more information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see Serializer + */ +public class HTMLSerializer + extends BaseMarkupSerializer +{ + + + /** + * True if serializing in XHTML format. + */ + private boolean _xhtml; + + + public static final String XHTMLNamespace = "http://www.w3.org/1999/xhtml"; + + // for users to override XHTMLNamespace if need be. + private String fUserXHTMLNamespace = null; + + + /** + * Constructs a new HTML/XHTML serializer depending on the value of + * xhtml. The serializer cannot be used without calling + * {@link #setOutputCharStream} or {@link #setOutputByteStream} first. + * + * @param xhtml True if XHTML serializing + */ + protected HTMLSerializer( boolean xhtml, OutputFormat format ) + { + super( format ); + _xhtml = xhtml; + } + + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public HTMLSerializer() + { + this( false, new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); + } + + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public HTMLSerializer( OutputFormat format ) + { + this( false, format != null ? format : new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); + } + + + + /** + * Constructs a new serializer that writes to the specified writer + * using the specified output format. If format is null, + * will use a default output format. + * + * @param writer The writer to use + * @param format The output format to use, null for the default + */ + public HTMLSerializer( Writer writer, OutputFormat format ) + { + this( false, format != null ? format : new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); + setOutputCharStream( writer ); + } + + + /** + * Constructs a new serializer that writes to the specified output + * stream using the specified output format. If format + * is null, will use a default output format. + * + * @param output The output stream to use + * @param format The output format to use, null for the default + */ + public HTMLSerializer( OutputStream output, OutputFormat format ) + { + this( false, format != null ? format : new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); + setOutputByteStream( output ); + } + + + public void setOutputFormat( OutputFormat format ) + { + super.setOutputFormat( format != null ? format : new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); + } + + // Set value for alternate XHTML namespace. + public void setXHTMLNamespace(String newNamespace) { + fUserXHTMLNamespace = newNamespace; + } // setXHTMLNamespace(String) + + //-----------------------------------------// + // SAX content handler serializing methods // + //-----------------------------------------// + + + public void startElement( String namespaceURI, String localName, + String rawName, Attributes attrs ) + throws SAXException + { + int i; + boolean preserveSpace; + ElementState state; + String name; + String value; + String htmlName; + boolean addNSAttr = false; + + try { + if ( _printer == null ) + throw new IllegalStateException( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "NoWriterSupplied", null)); + + state = getElementState(); + if ( isDocumentState() ) { + // If this is the root element handle it differently. + // If the first root element in the document, serialize + // the document's DOCTYPE. Space preserving defaults + // to that of the output format. + if ( ! _started ) + startDocument( (localName == null || localName.length() == 0) + ? rawName : localName ); + } else { + // For any other element, if first in parent, then + // close parent's opening tag and use the parnet's + // space preserving. + if ( state.empty ) + _printer.printText( '>' ); + // Indent this element on a new line if the first + // content of the parent element or immediately + // following an element. + if ( _indenting && ! state.preserveSpace && + ( state.empty || state.afterElement ) ) + _printer.breakLine(); + } + preserveSpace = state.preserveSpace; + + // Do not change the current element state yet. + // This only happens in endElement(). + + // As per SAX2, the namespace URI is an empty string if the element has no + // namespace URI, or namespaces is turned off. The check against null protects + // against broken SAX implementations, so I've left it there. - mrglavas + boolean hasNamespaceURI = (namespaceURI != null && namespaceURI.length() != 0); + + // SAX2: rawName (QName) could be empty string if + // namespace-prefixes property is false. + if ( rawName == null || rawName.length() == 0) { + rawName = localName; + if ( hasNamespaceURI ) { + String prefix; + prefix = getPrefix( namespaceURI ); + if ( prefix != null && prefix.length() != 0 ) + rawName = prefix + ":" + localName; + } + addNSAttr = true; + } + if ( !hasNamespaceURI ) + htmlName = rawName; + else { + if ( namespaceURI.equals( XHTMLNamespace ) || + (fUserXHTMLNamespace != null && fUserXHTMLNamespace.equals(namespaceURI)) ) + htmlName = localName; + else + htmlName = null; + } + + // XHTML: element names are lower case, DOM will be different + _printer.printText( '<' ); + if ( _xhtml ) + _printer.printText( rawName.toLowerCase(Locale.ENGLISH) ); + else + _printer.printText( rawName ); + _printer.indent(); + + // For each attribute serialize it's name and value as one part, + // separated with a space so the element can be broken on + // multiple lines. + if ( attrs != null ) { + for ( i = 0 ; i < attrs.getLength() ; ++i ) { + _printer.printSpace(); + name = attrs.getQName( i ).toLowerCase(Locale.ENGLISH); + value = attrs.getValue( i ); + if ( _xhtml || hasNamespaceURI ) { + // XHTML: print empty string for null values. + if ( value == null ) { + _printer.printText( name ); + _printer.printText( "=\"\"" ); + } else { + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + } else { + // HTML: Empty values print as attribute name, no value. + // HTML: URI attributes will print unescaped + if ( value == null ) { + value = ""; + } + if ( !_format.getPreserveEmptyAttributes() && value.length() == 0 ) + _printer.printText( name ); + else if ( HTMLdtd.isURI( rawName, name ) ) { + _printer.printText( name ); + _printer.printText( "=\"" ); + _printer.printText( escapeURI( value ) ); + _printer.printText( '"' ); + } else if ( HTMLdtd.isBoolean( rawName, name ) ) + _printer.printText( name ); + else { + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + } + } + } + if ( htmlName != null && HTMLdtd.isPreserveSpace( htmlName ) ) + preserveSpace = true; + + if ( addNSAttr ) { + Iterator entries = _prefixes.entrySet().iterator(); + while (entries.hasNext()) { + _printer.printSpace(); + Map.Entry entry = (Map.Entry) entries.next(); + value = (String) entry.getKey(); + name = (String) entry.getValue(); + if ( name.length() == 0 ) { + _printer.printText( "xmlns=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + else { + _printer.printText( "xmlns:" ); + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + } + } + + // Now it's time to enter a new element state + // with the tag name and space preserving. + // We still do not change the curent element state. + state = enterElementState( namespaceURI, localName, rawName, preserveSpace ); + + // Prevents line breaks inside A/TD + + if ( htmlName != null && ( htmlName.equalsIgnoreCase( "A" ) || + htmlName.equalsIgnoreCase( "TD" ) ) ) { + state.empty = false; + _printer.printText( '>' ); + } + + // Handle SCRIPT and STYLE specifically by changing the + // state of the current element to CDATA (XHTML) or + // unescaped (HTML). + if ( htmlName != null && ( rawName.equalsIgnoreCase( "SCRIPT" ) || + rawName.equalsIgnoreCase( "STYLE" ) ) ) { + if ( _xhtml ) { + // XHTML: Print contents as CDATA section + state.doCData = true; + } else { + // HTML: Print contents unescaped + state.unescaped = true; + } + } + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void endElement( String namespaceURI, String localName, + String rawName ) + throws SAXException + { + try { + endElementIO( namespaceURI, localName, rawName ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void endElementIO( String namespaceURI, String localName, + String rawName ) + throws IOException + { + ElementState state; + String htmlName; + + // Works much like content() with additions for closing + // an element. Note the different checks for the closed + // element's state and the parent element's state. + _printer.unindent(); + state = getElementState(); + + if ( state.namespaceURI == null || state.namespaceURI.length() == 0 ) + htmlName = state.rawName; + else { + if ( state.namespaceURI.equals( XHTMLNamespace ) || + (fUserXHTMLNamespace != null && fUserXHTMLNamespace.equals(state.namespaceURI)) ) + htmlName = state.localName; + else + htmlName = null; + } + + if ( _xhtml) { + if ( state.empty ) { + _printer.printText( " />" ); + } else { + // Must leave CData section first + if ( state.inCData ) + _printer.printText( "]]>" ); + // XHTML: element names are lower case, DOM will be different + _printer.printText( "' ); + } + } else { + if ( state.empty ) + _printer.printText( '>' ); + // This element is not empty and that last content was + // another element, so print a line break before that + // last element and this element's closing tag. + // [keith] Provided this is not an anchor. + // HTML: some elements do not print closing tag (e.g. LI) + if ( htmlName == null || ! HTMLdtd.isOnlyOpening( htmlName ) ) { + if ( _indenting && ! state.preserveSpace && state.afterElement ) + _printer.breakLine(); + // Must leave CData section first (Illegal in HTML, but still) + if ( state.inCData ) + _printer.printText( "]]>" ); + _printer.printText( "' ); + } + } + // Leave the element state and update that of the parent + // (if we're not root) to not empty and after element. + state = leaveElementState(); + // Temporary hack to prevent line breaks inside A/TD + if ( htmlName == null || ( ! htmlName.equalsIgnoreCase( "A" ) && + ! htmlName.equalsIgnoreCase( "TD" ) ) ) + + state.afterElement = true; + state.empty = false; + if ( isDocumentState() ) + _printer.flush(); + } + + + //------------------------------------------// + // SAX document handler serializing methods // + //------------------------------------------// + + + public void characters( char[] chars, int start, int length ) + throws SAXException + { + ElementState state; + + try { + // HTML: no CDATA section + state = content(); + state.doCData = false; + super.characters( chars, start, length ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void startElement( String tagName, AttributeList attrs ) + throws SAXException + { + int i; + boolean preserveSpace; + ElementState state; + String name; + String value; + + try { + if ( _printer == null ) + throw new IllegalStateException( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "NoWriterSupplied", null)); + + + state = getElementState(); + if ( isDocumentState() ) { + // If this is the root element handle it differently. + // If the first root element in the document, serialize + // the document's DOCTYPE. Space preserving defaults + // to that of the output format. + if ( ! _started ) + startDocument( tagName ); + } else { + // For any other element, if first in parent, then + // close parent's opening tag and use the parnet's + // space preserving. + if ( state.empty ) + _printer.printText( '>' ); + // Indent this element on a new line if the first + // content of the parent element or immediately + // following an element. + if ( _indenting && ! state.preserveSpace && + ( state.empty || state.afterElement ) ) + _printer.breakLine(); + } + preserveSpace = state.preserveSpace; + + // Do not change the current element state yet. + // This only happens in endElement(). + + // XHTML: element names are lower case, DOM will be different + _printer.printText( '<' ); + if ( _xhtml ) + _printer.printText( tagName.toLowerCase(Locale.ENGLISH) ); + else + _printer.printText( tagName ); + _printer.indent(); + + // For each attribute serialize it's name and value as one part, + // separated with a space so the element can be broken on + // multiple lines. + if ( attrs != null ) { + for ( i = 0 ; i < attrs.getLength() ; ++i ) { + _printer.printSpace(); + name = attrs.getName( i ).toLowerCase(Locale.ENGLISH); + value = attrs.getValue( i ); + if ( _xhtml ) { + // XHTML: print empty string for null values. + if ( value == null ) { + _printer.printText( name ); + _printer.printText( "=\"\"" ); + } else { + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + } else { + // HTML: Empty values print as attribute name, no value. + // HTML: URI attributes will print unescaped + if ( value == null ) { + value = ""; + } + if ( !_format.getPreserveEmptyAttributes() && value.length() == 0 ) + _printer.printText( name ); + else if ( HTMLdtd.isURI( tagName, name ) ) { + _printer.printText( name ); + _printer.printText( "=\"" ); + _printer.printText( escapeURI( value ) ); + _printer.printText( '"' ); + } else if ( HTMLdtd.isBoolean( tagName, name ) ) + _printer.printText( name ); + else { + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + } + } + } + if ( HTMLdtd.isPreserveSpace( tagName ) ) + preserveSpace = true; + + // Now it's time to enter a new element state + // with the tag name and space preserving. + // We still do not change the curent element state. + state = enterElementState( null, null, tagName, preserveSpace ); + + // Prevents line breaks inside A/TD + if ( tagName.equalsIgnoreCase( "A" ) || tagName.equalsIgnoreCase( "TD" ) ) { + state.empty = false; + _printer.printText( '>' ); + } + + // Handle SCRIPT and STYLE specifically by changing the + // state of the current element to CDATA (XHTML) or + // unescaped (HTML). + if ( tagName.equalsIgnoreCase( "SCRIPT" ) || + tagName.equalsIgnoreCase( "STYLE" ) ) { + if ( _xhtml ) { + // XHTML: Print contents as CDATA section + state.doCData = true; + } else { + // HTML: Print contents unescaped + state.unescaped = true; + } + } + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void endElement( String tagName ) + throws SAXException + { + endElement( null, null, tagName ); + } + + + //------------------------------------------// + // Generic node serializing methods methods // + //------------------------------------------// + + + /** + * Called to serialize the document's DOCTYPE by the root element. + * The document type declaration must name the root element, + * but the root element is only known when that element is serialized, + * and not at the start of the document. + *

        + * This method will check if it has not been called before ({@link #_started}), + * will serialize the document type declaration, and will serialize all + * pre-root comments and PIs that were accumulated in the document + * (see {@link #serializePreRoot}). Pre-root will be serialized even if + * this is not the first root element of the document. + */ + protected void startDocument( String rootTagName ) + throws IOException + { + // Not supported in HTML/XHTML, but we still have to switch + // out of DTD mode. + _printer.leaveDTD(); + if ( ! _started ) { + // If the public and system identifiers were not specified + // in the output format, use the appropriate ones for HTML + // or XHTML. + if ( _docTypePublicId == null && _docTypeSystemId == null ) { + if ( _xhtml ) { + _docTypePublicId = HTMLdtd.XHTMLPublicId; + _docTypeSystemId = HTMLdtd.XHTMLSystemId; + } else { + _docTypePublicId = HTMLdtd.HTMLPublicId; + _docTypeSystemId = HTMLdtd.HTMLSystemId; + } + } + + if ( ! _format.getOmitDocumentType() ) { + // XHTML: If public identifier and system identifier + // specified, print them, else print just system identifier + // HTML: If public identifier specified, print it with + // system identifier, if specified. + // XHTML requires that all element names are lower case, so the + // root on the DOCTYPE must be 'html'. - mrglavas + if ( _docTypePublicId != null && ( ! _xhtml || _docTypeSystemId != null ) ) { + if (_xhtml) { + _printer.printText( "' ); + _printer.breakLine(); + } else if ( _docTypeSystemId != null ) { + if (_xhtml) { + _printer.printText( "' ); + _printer.breakLine(); + } + } + } + + _started = true; + // Always serialize these, even if not te first root element. + serializePreRoot(); + } + + + /** + * Called to serialize a DOM element. Equivalent to calling {@link + * #startElement}, {@link #endElement} and serializing everything + * inbetween, but better optimized. + */ + protected void serializeElement( Element elem ) + throws IOException + { + Attr attr; + NamedNodeMap attrMap; + int i; + Node child; + ElementState state; + boolean preserveSpace; + String name; + String value; + String tagName; + + tagName = elem.getTagName(); + state = getElementState(); + if ( isDocumentState() ) { + // If this is the root element handle it differently. + // If the first root element in the document, serialize + // the document's DOCTYPE. Space preserving defaults + // to that of the output format. + if ( ! _started ) + startDocument( tagName ); + } else { + // For any other element, if first in parent, then + // close parent's opening tag and use the parnet's + // space preserving. + if ( state.empty ) + _printer.printText( '>' ); + // Indent this element on a new line if the first + // content of the parent element or immediately + // following an element. + if ( _indenting && ! state.preserveSpace && + ( state.empty || state.afterElement ) ) + _printer.breakLine(); + } + preserveSpace = state.preserveSpace; + + // Do not change the current element state yet. + // This only happens in endElement(). + + // XHTML: element names are lower case, DOM will be different + _printer.printText( '<' ); + if ( _xhtml ) + _printer.printText( tagName.toLowerCase(Locale.ENGLISH) ); + else + _printer.printText( tagName ); + _printer.indent(); + + // Lookup the element's attribute, but only print specified + // attributes. (Unspecified attributes are derived from the DTD. + // For each attribute print it's name and value as one part, + // separated with a space so the element can be broken on + // multiple lines. + attrMap = elem.getAttributes(); + if ( attrMap != null ) { + for ( i = 0 ; i < attrMap.getLength() ; ++i ) { + attr = (Attr) attrMap.item( i ); + name = attr.getName().toLowerCase(Locale.ENGLISH); + value = attr.getValue(); + if ( attr.getSpecified() ) { + _printer.printSpace(); + if ( _xhtml ) { + // XHTML: print empty string for null values. + if ( value == null ) { + _printer.printText( name ); + _printer.printText( "=\"\"" ); + } else { + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + } else { + // HTML: Empty values print as attribute name, no value. + // HTML: URI attributes will print unescaped + if ( value == null ) { + value = ""; + } + if ( !_format.getPreserveEmptyAttributes() && value.length() == 0 ) + _printer.printText( name ); + else if ( HTMLdtd.isURI( tagName, name ) ) { + _printer.printText( name ); + _printer.printText( "=\"" ); + _printer.printText( escapeURI( value ) ); + _printer.printText( '"' ); + } else if ( HTMLdtd.isBoolean( tagName, name ) ) + _printer.printText( name ); + else { + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + } + } + } + } + if ( HTMLdtd.isPreserveSpace( tagName ) ) + preserveSpace = true; + + // If element has children, or if element is not an empty tag, + // serialize an opening tag. + if ( elem.hasChildNodes() || ! HTMLdtd.isEmptyTag( tagName ) ) { + // Enter an element state, and serialize the children + // one by one. Finally, end the element. + state = enterElementState( null, null, tagName, preserveSpace ); + + // Prevents line breaks inside A/TD + if ( tagName.equalsIgnoreCase( "A" ) || tagName.equalsIgnoreCase( "TD" ) ) { + state.empty = false; + _printer.printText( '>' ); + } + + // Handle SCRIPT and STYLE specifically by changing the + // state of the current element to CDATA (XHTML) or + // unescaped (HTML). + if ( tagName.equalsIgnoreCase( "SCRIPT" ) || + tagName.equalsIgnoreCase( "STYLE" ) ) { + if ( _xhtml ) { + // XHTML: Print contents as CDATA section + state.doCData = true; + } else { + // HTML: Print contents unescaped + state.unescaped = true; + } + } + child = elem.getFirstChild(); + while ( child != null ) { + serializeNode( child ); + child = child.getNextSibling(); + } + endElementIO( null, null, tagName ); + } else { + _printer.unindent(); + // XHTML: Close empty tag with ' />' so it's XML and HTML compatible. + // HTML: Empty tags are defined as such in DTD no in document. + if ( _xhtml ) + _printer.printText( " />" ); + else + _printer.printText( '>' ); + // After element but parent element is no longer empty. + state.afterElement = true; + state.empty = false; + if ( isDocumentState() ) + _printer.flush(); + } + } + + + + protected void characters( String text ) + throws IOException + { + // HTML: no CDATA section + content(); + super.characters( text ); + } + + + protected String getEntityRef( int ch ) + { + return HTMLdtd.fromChar( ch ); + } + + + protected String escapeURI( String uri ) + { + int index; + + // XXX Apparently Netscape doesn't like if we escape the URI + // using %nn, so we leave it as is, just remove any quotes. + index = uri.indexOf( "\"" ); + if ( index >= 0 ) { + return uri.substring( 0, index ); + } + return uri; + } + +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/HTMLdtd.java b/resources/xerces2-j-src/org/apache/xml/serialize/HTMLdtd.java new file mode 100644 index 0000000..6e26da8 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/HTMLdtd.java @@ -0,0 +1,555 @@ +/* + * 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. + */ + +// Aug 21, 2000: +// Fixed bug in isElement and made HTMLdtd public. +// Contributed by Eric SCHAEFFER" + +package org.apache.xml.serialize; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Hashtable; +import java.util.Locale; + +import org.apache.xerces.dom.DOMMessageFormatter; + +/** + * Utility class for accessing information specific to HTML documents. + * The HTML DTD is expressed as three utility function groups. Two methods + * allow for checking whether an element requires an open tag on printing + * ({@link #isEmptyTag}) or on parsing ({@link #isOptionalClosing}). + *

        + * Two other methods translate character references from name to value and + * from value to name. A small entities resource is loaded into memory the + * first time any of these methods is called for fast and efficient access. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use JAXP's Transformation API for XML (TrAX) for + * serializing HTML. See the Xerces documentation for more information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + */ +public final class HTMLdtd +{ + + /** + * Public identifier for HTML 4.01 (Strict) document type. + */ + public static final String HTMLPublicId = "-//W3C//DTD HTML 4.01//EN"; + + /** + * System identifier for HTML 4.01 (Strict) document type. + */ + public static final String HTMLSystemId = + "http://www.w3.org/TR/html4/strict.dtd"; + + /** + * Public identifier for XHTML 1.0 (Strict) document type. + */ + public static final String XHTMLPublicId = + "-//W3C//DTD XHTML 1.0 Strict//EN"; + + /** + * System identifier for XHTML 1.0 (Strict) document type. + */ + public static final String XHTMLSystemId = + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; + + /** + * Table of reverse character reference mapping. Character codes are held + * as single-character strings, mapped to their reference name. + */ + private static Hashtable _byChar; + + + /** + * Table of entity name to value mapping. Entities are held as strings, + * character references as Character objects. + */ + private static Hashtable _byName; + + + private static Hashtable _boolAttrs; + + + /** + * Holds element definitions. + */ + private static Hashtable _elemDefs; + + + /** + * Locates the HTML entities file that is loaded upon initialization. + * This file is a resource loaded with the default class loader. + */ + private static final String ENTITIES_RESOURCE = "HTMLEntities.res"; + + + /** + * Only opening tag should be printed. + */ + private static final int ONLY_OPENING = 0x0001; + + /** + * Element contains element content only. + */ + private static final int ELEM_CONTENT = 0x0002; + + + /** + * Element preserve spaces. + */ + private static final int PRESERVE = 0x0004; + + + /** + * Optional closing tag. + */ + private static final int OPT_CLOSING = 0x0008; + + + /** + * Element is empty (also means only opening tag) + */ + private static final int EMPTY = 0x0010 | ONLY_OPENING; + + + /** + * Allowed to appear in head. + */ + private static final int ALLOWED_HEAD = 0x0020; + + + /** + * When opened, closes P. + */ + private static final int CLOSE_P = 0x0040; + + + /** + * When opened, closes DD or DT. + */ + private static final int CLOSE_DD_DT = 0x0080; + + + /** + * When opened, closes itself. + */ + private static final int CLOSE_SELF = 0x0100; + + + /** + * When opened, closes another table section. + */ + private static final int CLOSE_TABLE = 0x0200; + + + /** + * When opened, closes TH or TD. + */ + private static final int CLOSE_TH_TD = 0x04000; + + + /** + * Returns true if element is declared to be empty. HTML elements are + * defines as empty in the DTD, not by the document syntax. + * + * @param tagName The element tag name (upper case) + * @return True if element is empty + */ + public static boolean isEmptyTag( String tagName ) + { + return isElement( tagName, EMPTY ); + } + + + /** + * Returns true if element is declared to have element content. + * Whitespaces appearing inside element content will be ignored, + * other text will simply report an error. + * + * @param tagName The element tag name (upper case) + * @return True if element content + */ + public static boolean isElementContent( String tagName ) + { + return isElement( tagName, ELEM_CONTENT ); + } + + + /** + * Returns true if element's textual contents preserves spaces. + * This only applies to PRE and TEXTAREA, all other HTML elements + * do not preserve space. + * + * @param tagName The element tag name (upper case) + * @return True if element's text content preserves spaces + */ + public static boolean isPreserveSpace( String tagName ) + { + return isElement( tagName, PRESERVE ); + } + + + /** + * Returns true if element's closing tag is optional and need not + * exist. An error will not be reported for such elements if they + * are not closed. For example, LI is most often not closed. + * + * @param tagName The element tag name (upper case) + * @return True if closing tag implied + */ + public static boolean isOptionalClosing( String tagName ) + { + return isElement( tagName, OPT_CLOSING ); + } + + + /** + * Returns true if element's closing tag is generally not printed. + * For example, LI should not print the closing tag. + * + * @param tagName The element tag name (upper case) + * @return True if only opening tag should be printed + */ + public static boolean isOnlyOpening( String tagName ) + { + return isElement( tagName, ONLY_OPENING ); + } + + + /** + * Returns true if the opening of one element (tagName) implies + * the closing of another open element (openTag). For example, + * every opening LI will close the previously open LI, + * and every opening BODY will close the previously open HEAD. + * + * @param tagName The newly opened element + * @param openTag The already opened element + * @return True if closing tag closes opening tag + */ + public static boolean isClosing( String tagName, String openTag ) + { + // Several elements are defined as closing the HEAD + if ( openTag.equalsIgnoreCase( "HEAD" ) ) + return ! isElement( tagName, ALLOWED_HEAD ); + // P closes iteself + if ( openTag.equalsIgnoreCase( "P" ) ) + return isElement( tagName, CLOSE_P ); + // DT closes DD, DD closes DT + if ( openTag.equalsIgnoreCase( "DT" ) || openTag.equalsIgnoreCase( "DD" ) ) + return isElement( tagName, CLOSE_DD_DT ); + // LI and OPTION close themselves + if ( openTag.equalsIgnoreCase( "LI" ) || openTag.equalsIgnoreCase( "OPTION" ) ) + return isElement( tagName, CLOSE_SELF ); + // Each of these table sections closes all the others + if ( openTag.equalsIgnoreCase( "THEAD" ) || openTag.equalsIgnoreCase( "TFOOT" ) || + openTag.equalsIgnoreCase( "TBODY" ) || openTag.equalsIgnoreCase( "TR" ) || + openTag.equalsIgnoreCase( "COLGROUP" ) ) + return isElement( tagName, CLOSE_TABLE ); + // TD closes TH and TH closes TD + if ( openTag.equalsIgnoreCase( "TH" ) || openTag.equalsIgnoreCase( "TD" ) ) + return isElement( tagName, CLOSE_TH_TD ); + return false; + } + + + /** + * Returns true if the specified attribute it a URI and should be + * escaped appropriately. In HTML URIs are escaped differently + * than normal attributes. + * + * @param tagName The element's tag name + * @param attrName The attribute's name + */ + public static boolean isURI( String tagName, String attrName ) + { + // Stupid checks. + return ( attrName.equalsIgnoreCase( "href" ) || attrName.equalsIgnoreCase( "src" ) ); + } + + + /** + * Returns true if the specified attribute is a boolean and should be + * printed without the value. This applies to attributes that are true + * if they exist, such as selected (OPTION/INPUT). + * + * @param tagName The element's tag name + * @param attrName The attribute's name + */ + public static boolean isBoolean( String tagName, String attrName ) + { + String[] attrNames; + + attrNames = (String[]) _boolAttrs.get( tagName.toUpperCase(Locale.ENGLISH) ); + if ( attrNames == null ) + return false; + for ( int i = 0 ; i < attrNames.length ; ++i ) + if ( attrNames[ i ].equalsIgnoreCase( attrName ) ) + return true; + return false; + } + + + /** + * Returns the value of an HTML character reference by its name. If the + * reference is not found or was not defined as a character reference, + * returns EOF (-1). + * + * @param name Name of character reference + * @return Character code or EOF (-1) + */ + public static int charFromName( String name ) + { + Object value; + + initialize(); + value = _byName.get( name ); + if ( value != null && value instanceof Integer ) { + return ( (Integer) value ).intValue(); + } + return -1; + } + + + /** + * Returns the name of an HTML character reference based on its character + * value. Only valid for entities defined from character references. If no + * such character value was defined, return null. + * + * @param value Character value of entity + * @return Entity's name or null + */ + public static String fromChar(int value ) + { + if (value > 0xffff) + return null; + + String name; + + initialize(); + name = (String) _byChar.get( new Integer( value ) ); + return name; + } + + + /** + * Initialize upon first access. Will load all the HTML character references + * into a list that is accessible by name or character value and is optimized + * for character substitution. This method may be called any number of times + * but will execute only once. + */ + private static void initialize() + { + InputStream is = null; + BufferedReader reader = null; + int index; + String name; + String value; + int code; + String line; + + // Make sure not to initialize twice. + if ( _byName != null ) + return; + try { + _byName = new Hashtable(); + _byChar = new Hashtable(); + is = HTMLdtd.class.getResourceAsStream( ENTITIES_RESOURCE ); + if ( is == null ) { + throw new RuntimeException( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "ResourceNotFound", new Object[] {ENTITIES_RESOURCE})); + } + reader = new BufferedReader( new InputStreamReader( is, "ASCII" ) ); + line = reader.readLine(); + while ( line != null ) { + if ( line.length() == 0 || line.charAt( 0 ) == '#' ) { + line = reader.readLine(); + continue; + } + index = line.indexOf( ' ' ); + if ( index > 1 ) { + name = line.substring( 0, index ); + ++index; + if ( index < line.length() ) { + value = line.substring( index ); + index = value.indexOf( ' ' ); + if ( index > 0 ) + value = value.substring( 0, index ); + code = Integer.parseInt( value ); + defineEntity( name, (char) code ); + } + } + line = reader.readLine(); + } + is.close(); + } catch ( Exception except ) { + throw new RuntimeException( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "ResourceNotLoaded", new Object[] {ENTITIES_RESOURCE, except.toString()})); + } finally { + if ( is != null ) { + try { + is.close(); + } catch ( Exception except ) { } + } + } + } + + + /** + * Defines a new character reference. The reference's name and value are + * supplied. Nothing happens if the character reference is already defined. + *

        + * Unlike internal entities, character references are a string to single + * character mapping. They are used to map non-ASCII characters both on + * parsing and printing, primarily for HTML documents. '<amp;' is an + * example of a character reference. + * + * @param name The entity's name + * @param value The entity's value + */ + private static void defineEntity( String name, char value ) + { + if ( _byName.get( name ) == null ) { + _byName.put( name, new Integer( value ) ); + _byChar.put( new Integer( value ), name ); + } + } + + + private static void defineElement( String name, int flags ) + { + _elemDefs.put( name, new Integer( flags ) ); + } + + + private static void defineBoolean( String tagName, String attrName ) + { + defineBoolean( tagName, new String[] { attrName } ); + } + + + private static void defineBoolean( String tagName, String[] attrNames ) + { + _boolAttrs.put( tagName, attrNames ); + } + + + private static boolean isElement( String name, int flag ) + { + Integer flags; + + flags = (Integer) _elemDefs.get( name.toUpperCase(Locale.ENGLISH) ); + if ( flags == null ) { + return false; + } + return ( ( flags.intValue() & flag ) == flag ); + } + + + static + { + _elemDefs = new Hashtable(); + defineElement( "ADDRESS", CLOSE_P ); + defineElement( "AREA", EMPTY ); + defineElement( "BASE", EMPTY | ALLOWED_HEAD ); + defineElement( "BASEFONT", EMPTY ); + defineElement( "BLOCKQUOTE", CLOSE_P ); + defineElement( "BODY", OPT_CLOSING ); + defineElement( "BR", EMPTY ); + defineElement( "COL", EMPTY ); + defineElement( "COLGROUP", ELEM_CONTENT | OPT_CLOSING | CLOSE_TABLE ); + defineElement( "DD", OPT_CLOSING | ONLY_OPENING | CLOSE_DD_DT ); + defineElement( "DIV", CLOSE_P ); + defineElement( "DL", ELEM_CONTENT | CLOSE_P ); + defineElement( "DT", OPT_CLOSING | ONLY_OPENING | CLOSE_DD_DT ); + defineElement( "FIELDSET", CLOSE_P ); + defineElement( "FORM", CLOSE_P ); + defineElement( "FRAME", EMPTY | OPT_CLOSING ); + defineElement( "H1", CLOSE_P ); + defineElement( "H2", CLOSE_P ); + defineElement( "H3", CLOSE_P ); + defineElement( "H4", CLOSE_P ); + defineElement( "H5", CLOSE_P ); + defineElement( "H6", CLOSE_P ); + defineElement( "HEAD", ELEM_CONTENT | OPT_CLOSING ); + defineElement( "HR", EMPTY | CLOSE_P ); + defineElement( "HTML", ELEM_CONTENT | OPT_CLOSING ); + defineElement( "IMG", EMPTY ); + defineElement( "INPUT", EMPTY ); + defineElement( "ISINDEX", EMPTY | ALLOWED_HEAD ); + defineElement( "LI", OPT_CLOSING | ONLY_OPENING | CLOSE_SELF ); + defineElement( "LINK", EMPTY | ALLOWED_HEAD ); + defineElement( "MAP", ALLOWED_HEAD ); + defineElement( "META", EMPTY | ALLOWED_HEAD ); + defineElement( "OL", ELEM_CONTENT | CLOSE_P ); + defineElement( "OPTGROUP", ELEM_CONTENT ); + defineElement( "OPTION", OPT_CLOSING | ONLY_OPENING | CLOSE_SELF ); + defineElement( "P", OPT_CLOSING | CLOSE_P | CLOSE_SELF ); + defineElement( "PARAM", EMPTY ); + defineElement( "PRE", PRESERVE | CLOSE_P ); + defineElement( "SCRIPT", ALLOWED_HEAD | PRESERVE ); + defineElement( "NOSCRIPT", ALLOWED_HEAD | PRESERVE ); + defineElement( "SELECT", ELEM_CONTENT ); + defineElement( "STYLE", ALLOWED_HEAD | PRESERVE ); + defineElement( "TABLE", ELEM_CONTENT | CLOSE_P ); + defineElement( "TBODY", ELEM_CONTENT | OPT_CLOSING | CLOSE_TABLE ); + defineElement( "TD", OPT_CLOSING | CLOSE_TH_TD ); + defineElement( "TEXTAREA", PRESERVE ); + defineElement( "TFOOT", ELEM_CONTENT | OPT_CLOSING | CLOSE_TABLE ); + defineElement( "TH", OPT_CLOSING | CLOSE_TH_TD ); + defineElement( "THEAD", ELEM_CONTENT | OPT_CLOSING | CLOSE_TABLE ); + defineElement( "TITLE", ALLOWED_HEAD ); + defineElement( "TR", ELEM_CONTENT | OPT_CLOSING | CLOSE_TABLE ); + defineElement( "UL", ELEM_CONTENT | CLOSE_P ); + + _boolAttrs = new Hashtable(); + defineBoolean( "AREA", "href" ); + defineBoolean( "BUTTON", "disabled" ); + defineBoolean( "DIR", "compact" ); + defineBoolean( "DL", "compact" ); + defineBoolean( "FRAME", "noresize" ); + defineBoolean( "HR", "noshade" ); + defineBoolean( "IMAGE", "ismap" ); + defineBoolean( "INPUT", new String[] { "defaultchecked", "checked", "readonly", "disabled" } ); + defineBoolean( "LINK", "link" ); + defineBoolean( "MENU", "compact" ); + defineBoolean( "OBJECT", "declare" ); + defineBoolean( "OL", "compact" ); + defineBoolean( "OPTGROUP", "disabled" ); + defineBoolean( "OPTION", new String[] { "default-selected", "selected", "disabled" } ); + defineBoolean( "SCRIPT", "defer" ); + defineBoolean( "SELECT", new String[] { "multiple", "disabled" } ); + defineBoolean( "STYLE", "disabled" ); + defineBoolean( "TD", "nowrap" ); + defineBoolean( "TH", "nowrap" ); + defineBoolean( "TEXTAREA", new String[] { "disabled", "readonly" } ); + defineBoolean( "UL", "compact" ); + + initialize(); + } + + + +} + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/IndentPrinter.java b/resources/xerces2-j-src/org/apache/xml/serialize/IndentPrinter.java new file mode 100644 index 0000000..104fac0 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/IndentPrinter.java @@ -0,0 +1,367 @@ +/* + * 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. + */ + + +package org.apache.xml.serialize; + + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; + + +/** + * Extends {@link Printer} and adds support for indentation and line + * wrapping. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + */ +public class IndentPrinter + extends Printer +{ + + + /** + * Holds the currently accumulating text line. This buffer will constantly + * be reused by deleting its contents instead of reallocating it. + */ + private StringBuffer _line; + + + /** + * Holds the currently accumulating text that follows {@link #_line}. + * When the end of the part is identified by a call to {@link #printSpace} + * or {@link #breakLine}, this part is added to the accumulated line. + */ + private StringBuffer _text; + + + /** + * Counts how many white spaces come between the accumulated line and the + * current accumulated text. Multiple spaces at the end of the a line + * will not be printed. + */ + private int _spaces; + + + /** + * Holds the indentation for the current line that is now accumulating in + * memory and will be sent for printing shortly. + */ + private int _thisIndent; + + + /** + * Holds the indentation for the next line to be printed. After this line is + * printed, {@link #_nextIndent} is assigned to {@link #_thisIndent}. + */ + private int _nextIndent; + + + public IndentPrinter( Writer writer, OutputFormat format) + { + super( writer, format ); + // Initialize everything for a first/second run. + _line = new StringBuffer( 80 ); + _text = new StringBuffer( 20 ); + _spaces = 0; + _thisIndent = _nextIndent = 0; + } + + + /** + * Called by any of the DTD handlers to enter DTD mode. + * Once entered, all output will be accumulated in a string + * that can be printed as part of the document's DTD. + * This method may be called any number of time but will only + * have affect the first time it's called. To exist DTD state + * and get the accumulated DTD, call {@link #leaveDTD}. + */ + public void enterDTD() + { + // Can only enter DTD state once. Once we're out of DTD + // state, can no longer re-enter it. + if ( _dtdWriter == null ) { + _line.append( _text ); + _text = new StringBuffer( 20 ); + flushLine( false ); + _dtdWriter = new StringWriter(); + _docWriter = _writer; + _writer = _dtdWriter; + } + } + + + /** + * Called by the root element to leave DTD mode and if any + * DTD parts were printer, will return a string with their + * textual content. + */ + public String leaveDTD() + { + // Only works if we're going out of DTD mode. + if ( _writer == _dtdWriter ) { + _line.append( _text ); + _text = new StringBuffer( 20 ); + flushLine( false ); + _writer = _docWriter; + return _dtdWriter.toString(); + } + return null; + } + + + /** + * Called to print additional text. Each time this method is called + * it accumulates more text. When a space is printed ({@link + * #printSpace}) all the accumulated text becomes one part and is + * added to the accumulate line. When a line is long enough, it can + * be broken at its text boundary. + * + * @param text The text to print + */ + public void printText( String text ) + { + _text.append( text ); + } + + + public void printText( StringBuffer text ) + { + _text.append( text.toString() ); + } + + + public void printText( char ch ) + { + _text.append( ch ); + } + + + public void printText( char[] chars, int start, int length ) + { + _text.append( chars, start, length ); + } + + + /** + * Called to print a single space between text parts that may be + * broken into separate lines. Must not be called to print a space + * when preserving spaces. The text accumulated so far with {@link + * #printText} will be added to the accumulated line, and a space + * separator will be counted. If the line accumulated so far is + * long enough, it will be printed. + */ + public void printSpace() + { + // The line consists of the text accumulated in _line, + // followed by one or more spaces as counted by _spaces, + // followed by more space accumulated in _text: + // - Text is printed and accumulated into _text. + // - A space is printed, so _text is added to _line and + // a space is counted. + // - More text is printed and accumulated into _text. + // - A space is printed, the previous spaces are added + // to _line, the _text is added to _line, and a new + // space is counted. + + // If text was accumulated with printText(), then the space + // means we have to move that text into the line and + // start accumulating new text with printText(). + if ( _text.length() > 0 ) { + // If the text breaks a line bounary, wrap to the next line. + // The printed line size consists of the indentation we're going + // to use next, the accumulated line so far, some spaces and the + // accumulated text so far. + if ( _format.getLineWidth() > 0 && + _thisIndent + _line.length() + _spaces + _text.length() > _format.getLineWidth() ) { + flushLine( false ); + try { + // Print line and new line, then zero the line contents. + _writer.write( _format.getLineSeparator() ); + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + } + } + + // Add as many spaces as we accumulaed before. + // At the end of this loop, _spaces is zero. + while ( _spaces > 0 ) { + _line.append( ' ' ); + --_spaces; + } + _line.append( _text ); + _text = new StringBuffer( 20 ); + } + // Starting a new word: accumulate the text between the line + // and this new word; not a new word: just add another space. + ++_spaces; + } + + + /** + * Called to print a line consisting of the text accumulated so + * far. This is equivalent to calling {@link #printSpace} but + * forcing the line to print and starting a new line ({@link + * #printSpace} will only start a new line if the current line + * is long enough). + */ + public void breakLine() + { + breakLine( false ); + } + + + public void breakLine( boolean preserveSpace ) + { + // Equivalent to calling printSpace and forcing a flushLine. + if ( _text.length() > 0 ) { + while ( _spaces > 0 ) { + _line.append( ' ' ); + --_spaces; + } + _line.append( _text ); + _text = new StringBuffer( 20 ); + } + flushLine( preserveSpace ); + try { + // Print line and new line, then zero the line contents. + _writer.write( _format.getLineSeparator() ); + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + } + } + + + /** + * Flushes the line accumulated so far to the writer and get ready + * to accumulate the next line. This method is called by {@link + * #printText} and {@link #printSpace} when the accumulated line plus + * accumulated text are two long to fit on a given line. At the end of + * this method _line is empty and _spaces is zero. + */ + public void flushLine( boolean preserveSpace ) + { + int indent; + + if ( _line.length() > 0 ) { + try { + + if ( _format.getIndenting() && ! preserveSpace ) { + // Make sure the indentation does not blow us away. + indent = _thisIndent; + if ( ( 2 * indent ) > _format.getLineWidth() && _format.getLineWidth() > 0 ) + indent = _format.getLineWidth() / 2; + // Print the indentation as spaces and set the current + // indentation to the next expected indentation. + while ( indent > 0 ) { + _writer.write( ' ' ); + --indent; + } + } + _thisIndent = _nextIndent; + + // There is no need to print the spaces at the end of the line, + // they are simply stripped and replaced with a single line + // separator. + _spaces = 0; + _writer.write( _line.toString() ); + + _line = new StringBuffer( 40 ); + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + } + } + } + + + /** + * Flush the output stream. Must be called when done printing + * the document, otherwise some text might be buffered. + */ + public void flush() + { + if ( _line.length() > 0 || _text.length() > 0 ) + breakLine(); + try { + _writer.flush(); + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + } + } + + + /** + * Increment the indentation for the next line. + */ + public void indent() + { + _nextIndent += _format.getIndent(); + } + + + /** + * Decrement the indentation for the next line. + */ + public void unindent() + { + _nextIndent -= _format.getIndent(); + if ( _nextIndent < 0 ) + _nextIndent = 0; + // If there is no current line and we're de-identing then + // this indentation level is actually the next level. + if ( ( _line.length() + _spaces + _text.length() ) == 0 ) + _thisIndent = _nextIndent; + } + + + public int getNextIndent() + { + return _nextIndent; + } + + + public void setNextIndent( int indent ) + { + _nextIndent = indent; + } + + + public void setThisIndent( int indent ) + { + _thisIndent = indent; + } + + +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/LineSeparator.java b/resources/xerces2-j-src/org/apache/xml/serialize/LineSeparator.java new file mode 100644 index 0000000..7b85795 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/LineSeparator.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + + +package org.apache.xml.serialize; + + +/** + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see OutputFormat + */ +public final class LineSeparator +{ + + + /** + * Line separator for Unix systems (\n). + */ + public static final String Unix = "\n"; + + + /** + * Line separator for Windows systems (\r\n). + */ + public static final String Windows = "\r\n"; + + + /** + * Line separator for Macintosh systems (\r). + */ + public static final String Macintosh = "\r"; + + + /** + * Line separator for the Web (\n). + */ + public static final String Web = "\n"; + + +} + + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/Method.java b/resources/xerces2-j-src/org/apache/xml/serialize/Method.java new file mode 100644 index 0000000..87ddf61 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/Method.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + + +package org.apache.xml.serialize; + + +/** + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see OutputFormat + */ +public final class Method +{ + + + /** + * The output method for XML documents. + */ + public static final String XML = "xml"; + + + /** + * The output method for HTML documents. + */ + public static final String HTML = "html"; + + + /** + * The output method for HTML documents as XHTML. + */ + public static final String XHTML = "xhtml"; + + + /** + * The output method for text documents. + */ + public static final String TEXT = "text"; + + + /** + * The output method for FO documents as PDF. + */ + public static final String FOP = "fop"; + + +} + + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/ObjectFactory.java b/resources/xerces2-j-src/org/apache/xml/serialize/ObjectFactory.java new file mode 100644 index 0000000..1373231 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/ObjectFactory.java @@ -0,0 +1,543 @@ +/* + * 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. + */ + +package org.apache.xml.serialize; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; + +/** + * This class is duplicated for each JAXP subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of the JAXP + * API. + *

        + * This code is designed to implement the JAXP 1.1 spec pluggability + * feature and is designed to run on JDK version 1.1 and + * later, and to compile on JDK 1.2 and onward. + * The code also runs both as part of an unbundled jar file and + * when bundled as part of the JDK. + *

        + * + * @version $Id$ + */ +final class ObjectFactory { + + // + // Constants + // + + // name of default properties file to look for in JDK's jre/lib directory + private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties"; + + /** Set to true for debugging */ + private static final boolean DEBUG = isDebugEnabled(); + + /** + * Default columns per line. + */ + private static final int DEFAULT_LINE_LENGTH = 80; + + /** cache the contents of the xerces.properties file. + * Until an attempt has been made to read this file, this will + * be null; if the file does not exist or we encounter some other error + * during the read, this will be empty. + */ + private static Properties fXercesProperties = null; + + /*** + * Cache the time stamp of the xerces.properties file so + * that we know if it's been modified and can invalidate + * the cache when necessary. + */ + private static long fLastModified = -1; + + // + // static methods + // + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *

          + *
        1. query the system property using System.getProperty + *
        2. read META-INF/services/factoryId file + *
        3. use fallback classname + *
        + * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, String fallbackClassName) + throws ConfigurationError { + return createObject(factoryId, null, fallbackClassName); + } // createObject(String,String):Object + + /** + * Finds the implementation Class object in the specified order. The + * specified order is the following: + *
          + *
        1. query the system property using System.getProperty + *
        2. read $java.home/lib/propertiesFilename file + *
        3. read META-INF/services/factoryId file + *
        4. use fallback classname + *
        + * + * @return Class object of factory, never null + * + * @param factoryId Name of the factory to find, same as + * a property name + * @param propertiesFilename The filename in the $java.home/lib directory + * of the properties file. If none specified, + * ${java.home}/lib/xerces.properties will be used. + * @param fallbackClassName Implementation class name, if nothing else + * is found. Use null to mean no fallback. + * + * @exception ObjectFactory.ConfigurationError + */ + static Object createObject(String factoryId, + String propertiesFilename, + String fallbackClassName) + throws ConfigurationError + { + if (DEBUG) debugPrintln("debug is on"); + + ClassLoader cl = findClassLoader(); + + // Use the system property first + try { + String systemProp = SecuritySupport.getSystemProperty(factoryId); + if (systemProp != null && systemProp.length() > 0) { + if (DEBUG) debugPrintln("found system property, value=" + systemProp); + return newInstance(systemProp, cl, true); + } + } catch (SecurityException se) { + // Ignore and continue w/ next location + } + + // Try to read from propertiesFilename, or $java.home/lib/xerces.properties + String factoryClassName = null; + // no properties file name specified; use $JAVA_HOME/lib/xerces.properties: + if (propertiesFilename == null) { + File propertiesFile = null; + boolean propertiesFileExists = false; + try { + String javah = SecuritySupport.getSystemProperty("java.home"); + propertiesFilename = javah + File.separator + + "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME; + propertiesFile = new File(propertiesFilename); + propertiesFileExists = SecuritySupport.getFileExists(propertiesFile); + } catch (SecurityException e) { + // try again... + fLastModified = -1; + fXercesProperties = null; + } + + synchronized (ObjectFactory.class) { + boolean loadProperties = false; + FileInputStream fis = null; + try { + // file existed last time + if(fLastModified >= 0) { + if(propertiesFileExists && + (fLastModified < (fLastModified = SecuritySupport.getLastModified(propertiesFile)))) { + loadProperties = true; + } else { + // file has stopped existing... + if(!propertiesFileExists) { + fLastModified = -1; + fXercesProperties = null; + } // else, file wasn't modified! + } + } else { + // file has started to exist: + if(propertiesFileExists) { + loadProperties = true; + fLastModified = SecuritySupport.getLastModified(propertiesFile); + } // else, nothing's changed + } + if(loadProperties) { + // must never have attempted to read xerces.properties before (or it's outdeated) + fXercesProperties = new Properties(); + fis = SecuritySupport.getFileInputStream(propertiesFile); + fXercesProperties.load(fis); + } + } catch (Exception x) { + fXercesProperties = null; + fLastModified = -1; + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if(fXercesProperties != null) { + factoryClassName = fXercesProperties.getProperty(factoryId); + } + } else { + FileInputStream fis = null; + try { + fis = SecuritySupport.getFileInputStream(new File(propertiesFilename)); + Properties props = new Properties(); + props.load(fis); + factoryClassName = props.getProperty(factoryId); + } catch (Exception x) { + // assert(x instanceof FileNotFoundException + // || x instanceof SecurityException) + // In both cases, ignore and continue w/ next location + } + finally { + // try to close the input stream if one was opened. + if (fis != null) { + try { + fis.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + } + } + if (factoryClassName != null) { + if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName); + return newInstance(factoryClassName, cl, true); + } + + // Try Jar Service Provider Mechanism + Object provider = findJarServiceProvider(factoryId); + if (provider != null) { + return provider; + } + + if (fallbackClassName == null) { + throw new ConfigurationError( + "Provider for " + factoryId + " cannot be found", null); + } + + if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); + return newInstance(fallbackClassName, cl, true); + } // createObject(String,String,String):Object + + // + // Private static methods + // + + /** Returns true if debug has been enabled. */ + private static boolean isDebugEnabled() { + try { + String val = SecuritySupport.getSystemProperty("xerces.debug"); + // Allow simply setting the prop to turn on debug + return (val != null && (!"false".equals(val))); + } + catch (SecurityException se) {} + return false; + } // isDebugEnabled() + + /** Prints a message to standard error if debugging is enabled. */ + private static void debugPrintln(String msg) { + if (DEBUG) { + System.err.println("XERCES: " + msg); + } + } // debugPrintln(String) + + /** + * Figure out which ClassLoader to use. For JDK 1.2 and later use + * the context ClassLoader. + */ + static ClassLoader findClassLoader() + throws ConfigurationError + { + // Figure out which ClassLoader to use for loading the provider + // class. If there is a Context ClassLoader then use it. + ClassLoader context = SecuritySupport.getContextClassLoader(); + ClassLoader system = SecuritySupport.getSystemClassLoader(); + + ClassLoader chain = system; + while (true) { + if (context == chain) { + // Assert: we are on JDK 1.1 or we have no Context ClassLoader + // or any Context ClassLoader in chain of system classloader + // (including extension ClassLoader) so extend to widest + // ClassLoader (always look in system ClassLoader if Xerces + // is in boot/extension/system classpath and in current + // ClassLoader otherwise); normal classloaders delegate + // back to system ClassLoader first so this widening doesn't + // change the fact that context ClassLoader will be consulted + ClassLoader current = ObjectFactory.class.getClassLoader(); + + chain = system; + while (true) { + if (current == chain) { + // Assert: Current ClassLoader in chain of + // boot/extension/system ClassLoaders + return system; + } + if (chain == null) { + break; + } + chain = SecuritySupport.getParentClassLoader(chain); + } + + // Assert: Current ClassLoader not in chain of + // boot/extension/system ClassLoaders + return current; + } + + if (chain == null) { + // boot ClassLoader reached + break; + } + + // Check for any extension ClassLoaders in chain up to + // boot ClassLoader + chain = SecuritySupport.getParentClassLoader(chain); + }; + + // Assert: Context ClassLoader not in chain of + // boot/extension/system ClassLoaders + return context; + } // findClassLoader():ClassLoader + + /** + * Create an instance of a class using the specified ClassLoader + */ + static Object newInstance(String className, ClassLoader cl, + boolean doFallback) + throws ConfigurationError + { + // assert(className != null); + try{ + Class providerClass = findProviderClass(className, cl, doFallback); + Object instance = providerClass.newInstance(); + if (DEBUG) debugPrintln("created new instance of " + providerClass + + " using ClassLoader: " + cl); + return instance; + } catch (ClassNotFoundException x) { + throw new ConfigurationError( + "Provider " + className + " not found", x); + } catch (Exception x) { + throw new ConfigurationError( + "Provider " + className + " could not be instantiated: " + x, + x); + } + } + + /** + * Find a Class using the specified ClassLoader + */ + static Class findProviderClass(String className, ClassLoader cl, + boolean doFallback) + throws ClassNotFoundException, ConfigurationError + { + //throw security exception if the calling thread is not allowed to access the package + //restrict the access to package as specified in java.security policy + SecurityManager security = System.getSecurityManager(); + if (security != null) { + final int lastDot = className.lastIndexOf('.'); + String packageName = className; + if (lastDot != -1) packageName = className.substring(0, lastDot); + security.checkPackageAccess(packageName); + } + Class providerClass; + if (cl == null) { + // XXX Use the bootstrap ClassLoader. There is no way to + // load a class using the bootstrap ClassLoader that works + // in both JDK 1.1 and Java 2. However, this should still + // work b/c the following should be true: + // + // (cl == null) iff current ClassLoader == null + // + // Thus Class.forName(String) will use the current + // ClassLoader which will be the bootstrap ClassLoader. + providerClass = Class.forName(className); + } else { + try { + providerClass = cl.loadClass(className); + } catch (ClassNotFoundException x) { + if (doFallback) { + // Fall back to current classloader + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (current == null) { + providerClass = Class.forName(className); + } else if (cl != current) { + cl = current; + providerClass = cl.loadClass(className); + } else { + throw x; + } + } else { + throw x; + } + } + } + + return providerClass; + } + + /* + * Try to find provider using Jar Service Provider Mechanism + * + * @return instance of provider class if found or null + */ + private static Object findJarServiceProvider(String factoryId) + throws ConfigurationError + { + String serviceId = "META-INF/services/" + factoryId; + InputStream is = null; + + // First try the Context ClassLoader + ClassLoader cl = findClassLoader(); + + is = SecuritySupport.getResourceAsStream(cl, serviceId); + + // If no provider found then try the current ClassLoader + if (is == null) { + ClassLoader current = ObjectFactory.class.getClassLoader(); + if (cl != current) { + cl = current; + is = SecuritySupport.getResourceAsStream(cl, serviceId); + } + } + + if (is == null) { + // No provider found + return null; + } + + if (DEBUG) debugPrintln("found jar resource=" + serviceId + + " using ClassLoader: " + cl); + + // Read the service provider name in UTF-8 as specified in + // the jar spec. Unfortunately this fails in Microsoft + // VJ++, which does not implement the UTF-8 + // encoding. Theoretically, we should simply let it fail in + // that case, since the JVM is obviously broken if it + // doesn't support such a basic standard. But since there + // are still some users attempting to use VJ++ for + // development, we have dropped in a fallback which makes a + // second attempt using the platform's default encoding. In + // VJ++ this is apparently ASCII, which is a subset of + // UTF-8... and since the strings we'll be reading here are + // also primarily limited to the 7-bit ASCII range (at + // least, in English versions), this should work well + // enough to keep us on the air until we're ready to + // officially decommit from VJ++. [Edited comment from + // jkesselm] + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); + } catch (java.io.UnsupportedEncodingException e) { + rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); + } + + String factoryClassName = null; + try { + // XXX Does not handle all possible input as specified by the + // Jar Service Provider specification + factoryClassName = rd.readLine(); + } catch (IOException x) { + // No provider found + return null; + } + finally { + try { + // try to close the reader. + rd.close(); + } + // Ignore the exception. + catch (IOException exc) {} + } + + if (factoryClassName != null && + ! "".equals(factoryClassName)) { + if (DEBUG) debugPrintln("found in resource, value=" + + factoryClassName); + + // Note: here we do not want to fall back to the current + // ClassLoader because we want to avoid the case where the + // resource file was found using one ClassLoader and the + // provider class was instantiated using a different one. + return newInstance(factoryClassName, cl, false); + } + + // No provider found + return null; + } + + // + // Classes + // + + /** + * A configuration error. + */ + static final class ConfigurationError + extends Error { + + /** Serialization version. */ + static final long serialVersionUID = 937647395548533254L; + + // + // Data + // + + /** Exception. */ + private Exception exception; + + // + // Constructors + // + + /** + * Construct a new instance with the specified detail string and + * exception. + */ + ConfigurationError(String msg, Exception x) { + super(msg); + this.exception = x; + } // (String,Exception) + + // + // methods + // + + /** Returns the exception associated to this error. */ + Exception getException() { + return exception; + } // getException():Exception + + } // class ConfigurationError + +} // class ObjectFactory diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/OutputFormat.java b/resources/xerces2-j-src/org/apache/xml/serialize/OutputFormat.java new file mode 100644 index 0000000..6b7892e --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/OutputFormat.java @@ -0,0 +1,967 @@ +/* + * 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. + */ + + +// Aug 21, 2000: +// Added ability to omit DOCTYPE declaration. +// Reported by Lars Martin +// Aug 25, 2000: +// Added ability to omit comments. +// Contributed by Anupam Bagchi + + +package org.apache.xml.serialize; + + +import java.io.UnsupportedEncodingException; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Node; +import org.w3c.dom.html.HTMLDocument; + + +/** + * Specifies an output format to control the serializer. Based on the + * XSLT specification for output format, plus additional parameters. + * Used to select the suitable serializer and determine how the + * document should be formatted on output. + *

        + * The two interesting constructors are: + *

          + *
        • {@link #OutputFormat(String,String,boolean)} creates a format + * for the specified method (XML, HTML, Text, etc), encoding and indentation + *
        • {@link #OutputFormat(Document,String,boolean)} creates a format + * compatible with the document type (XML, HTML, Text, etc), encoding and + * indentation + *
        + * + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML and HTML. See the Xerces documentation for + * more information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * Keith Visco + * @see Serializer + * @see Method + * @see LineSeparator + */ +public class OutputFormat +{ + /** + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML and HTML. See the Xerces documentation for + * more information. + */ + public static class DTD + { + + /** + * Public identifier for HTML 4.01 (Strict) document type. + */ + public static final String HTMLPublicId = "-//W3C//DTD HTML 4.01//EN"; + + /** + * System identifier for HTML 4.01 (Strict) document type. + */ + public static final String HTMLSystemId = + "http://www.w3.org/TR/html4/strict.dtd"; + + /** + * Public identifier for XHTML 1.0 (Strict) document type. + */ + public static final String XHTMLPublicId = + "-//W3C//DTD XHTML 1.0 Strict//EN"; + + /** + * System identifier for XHTML 1.0 (Strict) document type. + */ + public static final String XHTMLSystemId = + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; + + } + + /** + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML and HTML. See the Xerces documentation for + * more information. + */ + public static class Defaults + { + + /** + * If indentation is turned on, the default identation + * level is 4. + * + * @see #setIndenting(boolean) + */ + public static final int Indent = 4; + + /** + * The default encoding for Web documents it UTF-8. + * + * @see #getEncoding() + */ + public static final String Encoding = "UTF-8"; + + /** + * The default line width at which to break long lines + * when identing. This is set to 72. + */ + public static final int LineWidth = 72; + + } + + + /** + * Holds the output method specified for this document, + * or null if no method was specified. + */ + private String _method; + + + /** + * Specifies the version of the output method. + */ + private String _version; + + + /** + * The indentation level, or zero if no indentation + * was requested. + */ + private int _indent = 0; + + + /** + * The encoding to use, if an input stream is used. + * The default is always UTF-8. + */ + private String _encoding = Defaults.Encoding; + + /** + * The EncodingInfo instance for _encoding. + */ + private EncodingInfo _encodingInfo = null; + + // whether java names for encodings are permitted + private boolean _allowJavaNames = false; + + /** + * The specified media type or null. + */ + private String _mediaType; + + + /** + * The specified document type system identifier, or null. + */ + private String _doctypeSystem; + + + /** + * The specified document type public identifier, or null. + */ + private String _doctypePublic; + + + /** + * True if the XML declaration should be ommited; + */ + private boolean _omitXmlDeclaration = false; + + + /** + * True if the DOCTYPE declaration should be ommited; + */ + private boolean _omitDoctype = false; + + + /** + * True if comments should be ommited; + */ + private boolean _omitComments = false; + + + /** + * True if the document type should be marked as standalone. + */ + private boolean _standalone = false; + + + /** + * List of element tag names whose text node children must + * be output as CDATA. + */ + private String[] _cdataElements; + + + /** + * List of element tag names whose text node children must + * be output unescaped. + */ + private String[] _nonEscapingElements; + + + /** + * The selected line separator. + */ + private String _lineSeparator = LineSeparator.Web; + + + /** + * The line width at which to wrap long lines when indenting. + */ + private int _lineWidth = Defaults.LineWidth; + + + /** + * True if spaces should be preserved in elements that do not + * specify otherwise, or specify the default behavior. + */ + private boolean _preserve = false; + /** If true, an empty string valued attribute is output as "". If false and + * and we are using the HTMLSerializer, then only the attribute name is + * serialized. Defaults to false for backwards compatibility. + */ + private boolean _preserveEmptyAttributes = false; + + /** + * Constructs a new output format with the default values. + */ + public OutputFormat() + { + } + + + /** + * Constructs a new output format with the default values for + * the specified method and encoding. If indent + * is true, the document will be pretty printed with the default + * indentation level and default line wrapping. + * + * @param method The specified output method + * @param encoding The specified encoding + * @param indenting True for pretty printing + * @see #setEncoding + * @see #setIndenting + * @see #setMethod + */ + public OutputFormat( String method, String encoding, boolean indenting ) + { + setMethod( method ); + setEncoding( encoding ); + setIndenting( indenting ); + } + + + /** + * Constructs a new output format with the proper method, + * document type identifiers and media type for the specified + * document. + * + * @param doc The document to output + * @see #whichMethod + */ + public OutputFormat( Document doc ) + { + setMethod( whichMethod( doc ) ); + setDoctype( whichDoctypePublic( doc ), whichDoctypeSystem( doc ) ); + setMediaType( whichMediaType( getMethod() ) ); + } + + + /** + * Constructs a new output format with the proper method, + * document type identifiers and media type for the specified + * document, and with the specified encoding. If indent + * is true, the document will be pretty printed with the default + * indentation level and default line wrapping. + * + * @param doc The document to output + * @param encoding The specified encoding + * @param indenting True for pretty printing + * @see #setEncoding + * @see #setIndenting + * @see #whichMethod + */ + public OutputFormat( Document doc, String encoding, boolean indenting ) + { + this( doc ); + setEncoding( encoding ); + setIndenting( indenting ); + } + + + /** + * Returns the method specified for this output format. + * Typically the method will be xml, html + * or text, but it might be other values. + * If no method was specified, null will be returned + * and the most suitable method will be determined for + * the document by calling {@link #whichMethod}. + * + * @return The specified output method, or null + */ + public String getMethod() + { + return _method; + } + + + /** + * Sets the method for this output format. + * + * @see #getMethod + * @param method The output method, or null + */ + public void setMethod( String method ) + { + _method = method; + } + + + /** + * Returns the version for this output method. + * If no version was specified, will return null + * and the default version number will be used. + * If the serializer does not support that particular + * version, it should default to a supported version. + * + * @return The specified method version, or null + */ + public String getVersion() + { + return _version; + } + + + /** + * Sets the version for this output method. + * For XML the value would be "1.0", for HTML + * it would be "4.0". + * + * @see #getVersion + * @param version The output method version, or null + */ + public void setVersion( String version ) + { + _version = version; + } + + + /** + * Returns the indentation specified. If no indentation + * was specified, zero is returned and the document + * should not be indented. + * + * @return The indentation or zero + * @see #setIndenting + */ + public int getIndent() + { + return _indent; + } + + + /** + * Returns true if indentation was specified. + */ + public boolean getIndenting() + { + return ( _indent > 0 ); + } + + + /** + * Sets the indentation. The document will not be + * indented if the indentation is set to zero. + * Calling {@link #setIndenting} will reset this + * value to zero (off) or the default (on). + * + * @param indent The indentation, or zero + */ + public void setIndent( int indent ) + { + if ( indent < 0 ) + _indent = 0; + else + _indent = indent; + } + + + /** + * Sets the indentation on and off. When set on, the default + * indentation level and default line wrapping is used + * (see {@link Defaults#Indent} and {@link Defaults#LineWidth}). + * To specify a different indentation level or line wrapping, + * use {@link #setIndent} and {@link #setLineWidth}. + * + * @param on True if indentation should be on + */ + public void setIndenting( boolean on ) + { + if ( on ) { + _indent = Defaults.Indent; + _lineWidth = Defaults.LineWidth; + } else { + _indent = 0; + _lineWidth = 0; + } + } + + + /** + * Returns the specified encoding. If no encoding was + * specified, the default is always "UTF-8". + * + * @return The encoding + */ + public String getEncoding() + { + return _encoding; + } + + + /** + * Sets the encoding for this output method. If no + * encoding was specified, the default is always "UTF-8". + * Make sure the encoding is compatible with the one + * used by the {@link java.io.Writer}. + * + * @see #getEncoding + * @param encoding The encoding, or null + */ + public void setEncoding( String encoding ) + { + _encoding = encoding; + _encodingInfo = null; + } + + /** + * Sets the encoding for this output method with an EncodingInfo + * instance. + */ + public void setEncoding(EncodingInfo encInfo) { + _encoding = encInfo.getIANAName(); + _encodingInfo = encInfo; + } + + /** + * Returns an EncodingInfo instance for the encoding. + * + * @see #setEncoding + */ + public EncodingInfo getEncodingInfo() throws UnsupportedEncodingException { + if (_encodingInfo == null) + _encodingInfo = Encodings.getEncodingInfo(_encoding, _allowJavaNames); + return _encodingInfo; + } + + /** + * Sets whether java encoding names are permitted + */ + public void setAllowJavaNames (boolean allow) { + _allowJavaNames = allow; + } + + /** + * Returns whether java encoding names are permitted + */ + public boolean setAllowJavaNames () { + return _allowJavaNames; + } + + /** + * Returns the specified media type, or null. + * To determine the media type based on the + * document type, use {@link #whichMediaType}. + * + * @return The specified media type, or null + */ + public String getMediaType() + { + return _mediaType; + } + + + /** + * Sets the media type. + * + * @see #getMediaType + * @param mediaType The specified media type + */ + public void setMediaType( String mediaType ) + { + _mediaType = mediaType; + } + + + /** + * Sets the document type public and system identifiers. + * Required only if the DOM Document or SAX events do not + * specify the document type, and one must be present in + * the serialized document. Any document type specified + * by the DOM Document or SAX events will override these + * values. + * + * @param publicId The public identifier, or null + * @param systemId The system identifier, or null + */ + public void setDoctype( String publicId, String systemId ) + { + _doctypePublic = publicId; + _doctypeSystem = systemId; + } + + + /** + * Returns the specified document type public identifier, + * or null. + */ + public String getDoctypePublic() + { + return _doctypePublic; + } + + + /** + * Returns the specified document type system identifier, + * or null. + */ + public String getDoctypeSystem() + { + return _doctypeSystem; + } + + + /** + * Returns true if comments should be ommited. + * The default is false. + */ + public boolean getOmitComments() + { + return _omitComments; + } + + + /** + * Sets comment omitting on and off. + * + * @param omit True if comments should be ommited + */ + public void setOmitComments( boolean omit ) + { + _omitComments = omit; + } + + + /** + * Returns true if the DOCTYPE declaration should + * be ommited. The default is false. + */ + public boolean getOmitDocumentType() + { + return _omitDoctype; + } + + + /** + * Sets DOCTYPE declaration omitting on and off. + * + * @param omit True if DOCTYPE declaration should be ommited + */ + public void setOmitDocumentType( boolean omit ) + { + _omitDoctype = omit; + } + + + /** + * Returns true if the XML document declaration should + * be ommited. The default is false. + */ + public boolean getOmitXMLDeclaration() + { + return _omitXmlDeclaration; + } + + + /** + * Sets XML declaration omitting on and off. + * + * @param omit True if XML declaration should be ommited + */ + public void setOmitXMLDeclaration( boolean omit ) + { + _omitXmlDeclaration = omit; + } + + + /** + * Returns true if the document type is standalone. + * The default is false. + */ + public boolean getStandalone() + { + return _standalone; + } + + + /** + * Sets document DTD standalone. The public and system + * identifiers must be null for the document to be + * serialized as standalone. + * + * @param standalone True if document DTD is standalone + */ + public void setStandalone( boolean standalone ) + { + _standalone = standalone; + } + + + /** + * Returns a list of all the elements whose text node children + * should be output as CDATA, or null if no such elements were + * specified. + */ + public String[] getCDataElements() + { + return _cdataElements; + } + + + /** + * Returns true if the text node children of the given elements + * should be output as CDATA. + * + * @param tagName The element's tag name + * @return True if should serialize as CDATA + */ + public boolean isCDataElement( String tagName ) + { + int i; + + if ( _cdataElements == null ) + return false; + for ( i = 0 ; i < _cdataElements.length ; ++i ) + if ( _cdataElements[ i ].equals( tagName ) ) + return true; + return false; + } + + + /** + * Sets the list of elements for which text node children + * should be output as CDATA. + * + * @param cdataElements List of CDATA element tag names + */ + public void setCDataElements( String[] cdataElements ) + { + _cdataElements = cdataElements; + } + + + /** + * Returns a list of all the elements whose text node children + * should be output unescaped (no character references), or null + * if no such elements were specified. + */ + public String[] getNonEscapingElements() + { + return _nonEscapingElements; + } + + + /** + * Returns true if the text node children of the given elements + * should be output unescaped. + * + * @param tagName The element's tag name + * @return True if should serialize unescaped + */ + public boolean isNonEscapingElement( String tagName ) + { + int i; + + if ( _nonEscapingElements == null ) { + return false; + } + for ( i = 0 ; i < _nonEscapingElements.length ; ++i ) + if ( _nonEscapingElements[ i ].equals( tagName ) ) + return true; + return false; + } + + + /** + * Sets the list of elements for which text node children + * should be output unescaped (no character references). + * + * @param nonEscapingElements List of unescaped element tag names + */ + public void setNonEscapingElements( String[] nonEscapingElements ) + { + _nonEscapingElements = nonEscapingElements; + } + + + + /** + * Returns a specific line separator to use. The default is the + * Web line separator (\n). A string is returned to + * support double codes (CR + LF). + * + * @return The specified line separator + */ + public String getLineSeparator() + { + return _lineSeparator; + } + + + /** + * Sets the line separator. The default is the Web line separator + * (\n). The machine's line separator can be obtained + * from the system property line.separator, but is only + * useful if the document is edited on machines of the same type. + * For general documents, use the Web line separator. + * + * @param lineSeparator The specified line separator + */ + public void setLineSeparator( String lineSeparator ) + { + if ( lineSeparator == null ) + _lineSeparator = LineSeparator.Web; + else + _lineSeparator = lineSeparator; + } + + + /** + * Returns true if the default behavior for this format is to + * preserve spaces. All elements that do not specify otherwise + * or specify the default behavior will be formatted based on + * this rule. All elements that specify space preserving will + * always preserve space. + */ + public boolean getPreserveSpace() + { + return _preserve; + } + + + /** + * Sets space preserving as the default behavior. The default is + * space stripping and all elements that do not specify otherwise + * or use the default value will not preserve spaces. + * + * @param preserve True if spaces should be preserved + */ + public void setPreserveSpace( boolean preserve ) + { + _preserve = preserve; + } + + + /** + * Return the selected line width for breaking up long lines. + * When indenting, and only when indenting, long lines will be + * broken at space boundaries based on this line width. + * No line wrapping occurs if this value is zero. + */ + public int getLineWidth() + { + return _lineWidth; + } + + + /** + * Sets the line width. If zero then no line wrapping will + * occur. Calling {@link #setIndenting} will reset this + * value to zero (off) or the default (on). + * + * @param lineWidth The line width to use, zero for default + * @see #getLineWidth + * @see #setIndenting + */ + public void setLineWidth( int lineWidth ) + { + if ( lineWidth <= 0 ) + _lineWidth = 0; + else + _lineWidth = lineWidth; + } + /** + * Returns the preserveEmptyAttribute flag. If flag is false, then' + * attributes with empty string values are output as the attribute + * name only (in HTML mode). + * @return preserve the preserve flag + */ public boolean getPreserveEmptyAttributes () { return _preserveEmptyAttributes; } /** + * Sets the preserveEmptyAttribute flag. If flag is false, then' + * attributes with empty string values are output as the attribute + * name only (in HTML mode). + * @param preserve the preserve flag + */ public void setPreserveEmptyAttributes (boolean preserve) { _preserveEmptyAttributes = preserve; } + + /** + * Returns the last printable character based on the selected + * encoding. Control characters and non-printable characters + * are always printed as character references. + */ + public char getLastPrintable() + { + if ( getEncoding() != null && + ( getEncoding().equalsIgnoreCase( "ASCII" ) ) ) { + return 0xFF; + } + return 0xFFFF; + } + + + /** + * Determine the output method for the specified document. + * If the document is an instance of {@link org.w3c.dom.html.HTMLDocument} + * then the method is said to be html. If the root + * element is 'html' and all text nodes preceding the root + * element are all whitespace, then the method is said to be + * html. Otherwise the method is xml. + * + * @param doc The document to check + * @return The suitable method + */ + public static String whichMethod( Document doc ) + { + Node node; + String value; + int i; + + // If document is derived from HTMLDocument then the default + // method is html. + if ( doc instanceof HTMLDocument ) + return Method.HTML; + + // Lookup the root element and the text nodes preceding it. + // If root element is html and all text nodes contain whitespace + // only, the method is html. + + // FIXME (SM) should we care about namespaces here? + + node = doc.getFirstChild(); + while (node != null) { + // If the root element is html, the method is html. + if ( node.getNodeType() == Node.ELEMENT_NODE ) { + if ( node.getNodeName().equalsIgnoreCase( "html" ) ) { + return Method.HTML; + } else if ( node.getNodeName().equalsIgnoreCase( "root" ) ) { + return Method.FOP; + } else { + return Method.XML; + } + } else if ( node.getNodeType() == Node.TEXT_NODE ) { + // If a text node preceding the root element contains + // only whitespace, this might be html, otherwise it's + // definitely xml. + value = node.getNodeValue(); + for ( i = 0 ; i < value.length() ; ++i ) + if ( value.charAt( i ) != 0x20 && value.charAt( i ) != 0x0A && + value.charAt( i ) != 0x09 && value.charAt( i ) != 0x0D ) + return Method.XML; + } + node = node.getNextSibling(); + } + // Anything else, the method is xml. + return Method.XML; + } + + + /** + * Returns the document type public identifier + * specified for this document, or null. + */ + public static String whichDoctypePublic( Document doc ) + { + DocumentType doctype; + + /* DOM Level 2 was introduced into the code base*/ + doctype = doc.getDoctype(); + if ( doctype != null ) { + // Note on catch: DOM Level 1 does not specify this method + // and the code will throw a NoSuchMethodError + try { + return doctype.getPublicId(); + } catch ( Error except ) { } + } + + if ( doc instanceof HTMLDocument ) + return DTD.XHTMLPublicId; + return null; + } + + + /** + * Returns the document type system identifier + * specified for this document, or null. + */ + public static String whichDoctypeSystem( Document doc ) + { + DocumentType doctype; + + /* DOM Level 2 was introduced into the code base*/ + doctype = doc.getDoctype(); + if ( doctype != null ) { + // Note on catch: DOM Level 1 does not specify this method + // and the code will throw a NoSuchMethodError + try { + return doctype.getSystemId(); + } catch ( Error except ) { } + } + + if ( doc instanceof HTMLDocument ) + return DTD.XHTMLSystemId; + return null; + } + + + /** + * Returns the suitable media format for a document + * output with the specified method. + */ + public static String whichMediaType( String method ) + { + if ( method.equalsIgnoreCase( Method.XML ) ) + return "text/xml"; + if ( method.equalsIgnoreCase( Method.HTML ) ) + return "text/html"; + if ( method.equalsIgnoreCase( Method.XHTML ) ) + return "text/html"; + if ( method.equalsIgnoreCase( Method.TEXT ) ) + return "text/plain"; + if ( method.equalsIgnoreCase( Method.FOP ) ) + return "application/pdf"; + return null; + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/Printer.java b/resources/xerces2-j-src/org/apache/xml/serialize/Printer.java new file mode 100644 index 0000000..dff702a --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/Printer.java @@ -0,0 +1,366 @@ +/* + * 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. + */ + + +// Sep 14, 2000: +// Fixed serializer to report IO exception directly, instead at +// the end of document processing. +// Reported by Patrick Higgins + + +package org.apache.xml.serialize; + + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; + + +/** + * The printer is responsible for sending text to the output stream + * or writer. This class performs direct writing for efficiency. + * {@link IndentPrinter} supports indentation and line wrapping by + * extending this class. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + */ +public class Printer +{ + + + /** + * The output format associated with this serializer. This will never + * be a null reference. If no format was passed to the constructor, + * the default one for this document type will be used. The format + * object is never changed by the serializer. + */ + protected final OutputFormat _format; + + + /** + * The writer to which the document is written. + */ + protected Writer _writer; + + + /** + * The DTD writer. When we switch to DTD mode, all output is + * accumulated in this DTD writer. When we switch out of it, + * the output is obtained as a string. Must not be reset to + * null until we're done with the document. + */ + protected StringWriter _dtdWriter; + + + /** + * Holds a reference to the document writer while we are + * in DTD mode. + */ + protected Writer _docWriter; + + + /** + * Holds the exception thrown by the serializer. Exceptions do not cause + * the serializer to quit, but are held and one is thrown at the end. + */ + protected IOException _exception; + + + /** + * The size of the output buffer. + */ + private static final int BufferSize = 4096; + + + /** + * Output buffer. + */ + private final char[] _buffer = new char[ BufferSize ]; + + + /** + * Position within the output buffer. + */ + private int _pos = 0; + + + public Printer( Writer writer, OutputFormat format) + { + _writer = writer; + _format = format; + _exception = null; + _dtdWriter = null; + _docWriter = null; + _pos = 0; + } + + + public IOException getException() + { + return _exception; + } + + + /** + * Called by any of the DTD handlers to enter DTD mode. + * Once entered, all output will be accumulated in a string + * that can be printed as part of the document's DTD. + * This method may be called any number of time but will only + * have affect the first time it's called. To exist DTD state + * and get the accumulated DTD, call {@link #leaveDTD}. + */ + public void enterDTD() + throws IOException + { + // Can only enter DTD state once. Once we're out of DTD + // state, can no longer re-enter it. + if ( _dtdWriter == null ) { + flushLine( false ); + + _dtdWriter = new StringWriter(); + _docWriter = _writer; + _writer = _dtdWriter; + } + } + + + /** + * Called by the root element to leave DTD mode and if any + * DTD parts were printer, will return a string with their + * textual content. + */ + public String leaveDTD() + throws IOException + { + // Only works if we're going out of DTD mode. + if ( _writer == _dtdWriter ) { + flushLine( false ); + + _writer = _docWriter; + return _dtdWriter.toString(); + } + return null; + } + + + public void printText( String text ) + throws IOException + { + try { + int length = text.length(); + for ( int i = 0 ; i < length ; ++i ) { + if ( _pos == BufferSize ) { + _writer.write( _buffer ); + _pos = 0; + } + _buffer[ _pos ] = text.charAt( i ); + ++_pos; + } + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + throw except; + } + } + + + public void printText( StringBuffer text ) + throws IOException + { + try { + int length = text.length(); + for ( int i = 0 ; i < length ; ++i ) { + if ( _pos == BufferSize ) { + _writer.write( _buffer ); + _pos = 0; + } + _buffer[ _pos ] = text.charAt( i ); + ++_pos; + } + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + throw except; + } + } + + + public void printText( char[] chars, int start, int length ) + throws IOException + { + try { + while ( length-- > 0 ) { + if ( _pos == BufferSize ) { + _writer.write( _buffer ); + _pos = 0; + } + _buffer[ _pos ] = chars[ start ]; + ++start; + ++_pos; + } + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + throw except; + } + } + + + public void printText( char ch ) + throws IOException + { + try { + if ( _pos == BufferSize ) { + _writer.write( _buffer ); + _pos = 0; + } + _buffer[ _pos ] = ch; + ++_pos; + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + throw except; + } + } + + + public void printSpace() + throws IOException + { + try { + if ( _pos == BufferSize ) { + _writer.write( _buffer ); + _pos = 0; + } + _buffer[ _pos ] = ' '; + ++_pos; + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + throw except; + } + } + + + public void breakLine() + throws IOException + { + try { + if ( _pos == BufferSize ) { + _writer.write( _buffer ); + _pos = 0; + } + _buffer[ _pos ] = '\n'; + ++_pos; + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + throw except; + } + } + + + public void breakLine( boolean preserveSpace ) + throws IOException + { + breakLine(); + } + + + public void flushLine( boolean preserveSpace ) + throws IOException + { + // Write anything left in the buffer into the writer. + try { + _writer.write( _buffer, 0, _pos ); + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + } + _pos = 0; + } + + + /** + * Flush the output stream. Must be called when done printing + * the document, otherwise some text might be buffered. + */ + public void flush() + throws IOException + { + try { + _writer.write( _buffer, 0, _pos ); + _writer.flush(); + } catch ( IOException except ) { + // We don't throw an exception, but hold it + // until the end of the document. + if ( _exception == null ) + _exception = except; + throw except; + } + _pos = 0; + } + + + public void indent() + { + // NOOP + } + + + public void unindent() + { + // NOOP + } + + + public int getNextIndent() + { + return 0; + } + + + public void setNextIndent( int indent ) + { + } + + + public void setThisIndent( int indent ) + { + } + + +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/SecuritySupport.java b/resources/xerces2-j-src/org/apache/xml/serialize/SecuritySupport.java new file mode 100644 index 0000000..d2e13f7 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/SecuritySupport.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +package org.apache.xml.serialize; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * This class is duplicated for each subpackage so keep it in sync. + * It is package private and therefore is not exposed as part of any API. + * + * @xerces.internal + * + * @version $Id$ + */ +final class SecuritySupport { + + static ClassLoader getContextClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (SecurityException ex) { } + return cl; + } + }); + } + + static ClassLoader getSystemClassLoader() { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (SecurityException ex) {} + return cl; + } + }); + } + + static ClassLoader getParentClassLoader(final ClassLoader cl) { + return (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader parent = null; + try { + parent = cl.getParent(); + } catch (SecurityException ex) {} + + // eliminate loops in case of the boot + // ClassLoader returning itself as a parent + return (parent == cl) ? null : parent; + } + }); + } + + static String getSystemProperty(final String propName) { + return (String) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(propName); + } + }); + } + + static FileInputStream getFileInputStream(final File file) + throws FileNotFoundException + { + try { + return (FileInputStream) + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws FileNotFoundException { + return new FileInputStream(file); + } + }); + } catch (PrivilegedActionException e) { + throw (FileNotFoundException)e.getException(); + } + } + + static InputStream getResourceAsStream(final ClassLoader cl, + final String name) + { + return (InputStream) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + InputStream ris; + if (cl == null) { + ris = ClassLoader.getSystemResourceAsStream(name); + } else { + ris = cl.getResourceAsStream(name); + } + return ris; + } + }); + } + + static boolean getFileExists(final File f) { + return ((Boolean) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return f.exists() ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + } + + static long getLastModified(final File f) { + return ((Long) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return new Long(f.lastModified()); + } + })).longValue(); + } + + private SecuritySupport () {} +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/Serializer.java b/resources/xerces2-j-src/org/apache/xml/serialize/Serializer.java new file mode 100644 index 0000000..b8ceff5 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/Serializer.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + + +package org.apache.xml.serialize; + + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.ContentHandler; +import org.xml.sax.DocumentHandler; + + +/** + * Interface for a DOM serializer implementation, factory for DOM and SAX + * serializers, and static methods for serializing DOM documents. + *

        + * To serialize a document using SAX events, create a compatible serializer + * and pass it around as a {@link + * org.xml.sax.DocumentHandler}. If an I/O error occurs while serializing, it will + * be thrown by {@link DocumentHandler#endDocument}. The SAX serializer + * may also be used as {@link org.xml.sax.DTDHandler}, {@link org.xml.sax.ext.DeclHandler} and + * {@link org.xml.sax.ext.LexicalHandler}. + *

        + * To serialize a DOM document or DOM element, create a compatible + * serializer and call it's {@link + * DOMSerializer#serialize(Document)} or {@link DOMSerializer#serialize(Element)} methods. + * Both methods would produce a full XML document, to serizlie only + * the portion of the document use {@link OutputFormat#setOmitXMLDeclaration} + * and specify no document type. + *

        + * The {@link OutputFormat} dictates what underlying serialized is used + * to serialize the document based on the specified method. If the output + * format or method are missing, the default is an XML serializer with + * UTF-8 encoding and now indentation. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML and HTML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @author Scott Boag + * @see DocumentHandler + * @see ContentHandler + * @see OutputFormat + * @see DOMSerializer + */ +public interface Serializer +{ + + + /** + * Specifies an output stream to which the document should be + * serialized. This method should not be called while the + * serializer is in the process of serializing a document. + */ + public void setOutputByteStream(OutputStream output); + + + /** + * Specifies a writer to which the document should be serialized. + * This method should not be called while the serializer is in + * the process of serializing a document. + */ + public void setOutputCharStream( Writer output ); + + + /** + * Specifies an output format for this serializer. It the + * serializer has already been associated with an output format, + * it will switch to the new format. This method should not be + * called while the serializer is in the process of serializing + * a document. + * + * @param format The output format to use + */ + public void setOutputFormat( OutputFormat format ); + + + /** + * Return a {@link DocumentHandler} interface into this serializer. + * If the serializer does not support the {@link DocumentHandler} + * interface, it should return null. + */ + public DocumentHandler asDocumentHandler() + throws IOException; + + + /** + * Return a {@link ContentHandler} interface into this serializer. + * If the serializer does not support the {@link ContentHandler} + * interface, it should return null. + */ + public ContentHandler asContentHandler() + throws IOException; + + + /** + * Return a {@link DOMSerializer} interface into this serializer. + * If the serializer does not support the {@link DOMSerializer} + * interface, it should return null. + */ + public DOMSerializer asDOMSerializer() + throws IOException; + + +} + + + + + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/SerializerFactory.java b/resources/xerces2-j-src/org/apache/xml/serialize/SerializerFactory.java new file mode 100644 index 0000000..4ccdf2b --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/SerializerFactory.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package org.apache.xml.serialize; + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.util.Hashtable; +import java.util.StringTokenizer; + +/** + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML and HTML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Scott Boag + * @author Assaf Arkin + */ +public abstract class SerializerFactory { + + public static final String FactoriesProperty = "org.apache.xml.serialize.factories"; + + private static Hashtable _factories = new Hashtable(); + + static + { + SerializerFactory factory; + String list; + StringTokenizer token; + String className; + + // The default factories are always registered first, + // any factory specified in the properties file and supporting + // the same method will override the default factory. + factory = new SerializerFactoryImpl( Method.XML ); + registerSerializerFactory( factory ); + factory = new SerializerFactoryImpl( Method.HTML ); + registerSerializerFactory( factory ); + factory = new SerializerFactoryImpl( Method.XHTML ); + registerSerializerFactory( factory ); + factory = new SerializerFactoryImpl( Method.TEXT ); + registerSerializerFactory( factory ); + + list = SecuritySupport.getSystemProperty( FactoriesProperty ); + if ( list != null ) { + token = new StringTokenizer( list, " ;,:" ); + while ( token.hasMoreTokens() ) { + className = token.nextToken(); + try { + factory = (SerializerFactory) ObjectFactory.newInstance( className, + SerializerFactory.class.getClassLoader(), true); + if ( _factories.containsKey( factory.getSupportedMethod() ) ) + _factories.put( factory.getSupportedMethod(), factory ); + } catch ( Exception except ) { } + } + } + } + + + /** + * Register a serializer factory, keyed by the given + * method string. + */ + public static void registerSerializerFactory( SerializerFactory factory ) + { + String method; + + synchronized ( _factories ) { + method = factory.getSupportedMethod(); + _factories.put( method, factory ); + } + } + + + /** + * Register a serializer factory, keyed by the given + * method string. + */ + public static SerializerFactory getSerializerFactory( String method ) + { + return (SerializerFactory) _factories.get( method ); + } + + + /** + * Returns the method supported by this factory and used to register + * the factory. This call is required so factories can be added from + * a properties file by knowing only the class name. This method is + * protected, it is only required by this class but must be implemented + * in derived classes. + */ + protected abstract String getSupportedMethod(); + + + /** + * Create a new serializer based on the {@link OutputFormat}. + * If this method is used to create the serializer, the {@link + * Serializer#setOutputByteStream} or {@link Serializer#setOutputCharStream} + * methods must be called before serializing a document. + */ + public abstract Serializer makeSerializer(OutputFormat format); + + + /** + * Create a new serializer, based on the {@link OutputFormat} and + * using the writer as the output character stream. If this + * method is used, the encoding property will be ignored. + */ + public abstract Serializer makeSerializer( Writer writer, + OutputFormat format ); + + + /** + * Create a new serializer, based on the {@link OutputFormat} and + * using the output byte stream and the encoding specified in the + * output format. + * + * @throws UnsupportedEncodingException The specified encoding is + * not supported + */ + public abstract Serializer makeSerializer( OutputStream output, + OutputFormat format ) + throws UnsupportedEncodingException; + + +} + + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/SerializerFactoryImpl.java b/resources/xerces2-j-src/org/apache/xml/serialize/SerializerFactoryImpl.java new file mode 100644 index 0000000..4f42b52 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/SerializerFactoryImpl.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + + +package org.apache.xml.serialize; + + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import org.apache.xerces.dom.DOMMessageFormatter; + +/** + * Default serializer factory can construct serializers for the three + * markup serializers (XML, HTML, XHTML ). + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML and HTML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Scott Boag + * @author Assaf Arkin + */ +final class SerializerFactoryImpl + extends SerializerFactory +{ + + + private String _method; + + + SerializerFactoryImpl( String method ) + { + _method = method; + if ( ! _method.equals( Method.XML ) && + ! _method.equals( Method.HTML ) && + ! _method.equals( Method.XHTML ) && + ! _method.equals( Method.TEXT ) ) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "MethodNotSupported", new Object[]{method}); + throw new IllegalArgumentException(msg); + } + } + + + public Serializer makeSerializer( OutputFormat format ) + { + Serializer serializer; + + serializer = getSerializer( format ); + serializer.setOutputFormat( format ); + return serializer; + } + + + + public Serializer makeSerializer( Writer writer, + OutputFormat format ) + { + Serializer serializer; + + serializer = getSerializer( format ); + serializer.setOutputCharStream( writer ); + return serializer; + } + + + public Serializer makeSerializer( OutputStream output, + OutputFormat format ) + throws UnsupportedEncodingException + { + Serializer serializer; + + serializer = getSerializer( format ); + serializer.setOutputByteStream( output ); + return serializer; + } + + + private Serializer getSerializer( OutputFormat format ) + { + if ( _method.equals( Method.XML ) ) { + return new XMLSerializer( format ); + } else if ( _method.equals( Method.HTML ) ) { + return new HTMLSerializer( format ); + } else if ( _method.equals( Method.XHTML ) ) { + return new XHTMLSerializer( format ); + } else if ( _method.equals( Method.TEXT ) ) { + return new TextSerializer(); + } else { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "MethodNotSupported", new Object[]{_method}); + throw new IllegalStateException(msg); + } + } + + + protected String getSupportedMethod() + { + return _method; + } + + +} + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/TextSerializer.java b/resources/xerces2-j-src/org/apache/xml/serialize/TextSerializer.java new file mode 100644 index 0000000..696ae60 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/TextSerializer.java @@ -0,0 +1,393 @@ +/* + * 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. + */ + + +// Sep 14, 2000: +// Fixed serializer to report IO exception directly, instead at +// the end of document processing. +// Reported by Patrick Higgins + + +package org.apache.xml.serialize; + + +import java.io.IOException; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.AttributeList; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + + +/** + * Implements a text serializer supporting both DOM and SAX + * serializing. For usage instructions see {@link Serializer}. + *

        + * If an output stream is used, the encoding is taken from the + * output format (defaults to UTF-8). If a writer is + * used, make sure the writer uses the same encoding (if applies) + * as specified in the output format. + *

        + * The serializer supports both DOM and SAX. DOM serializing is done + * by calling {@link #serialize} and SAX serializing is done by firing + * SAX events and using the serializer as a document handler. + *

        + * If an I/O exception occurs while serializing, the serializer + * will not throw an exception directly, but only throw it + * at the end of serializing (either DOM or SAX's {@link + * org.xml.sax.DocumentHandler#endDocument}. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML and HTML. See the Xerces documentation for more + * information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see Serializer + */ +public class TextSerializer + extends BaseMarkupSerializer +{ + + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public TextSerializer() + { + super( new OutputFormat( Method.TEXT, null, false ) ); + } + + + public void setOutputFormat( OutputFormat format ) + { + super.setOutputFormat( format != null ? format : new OutputFormat( Method.TEXT, null, false ) ); + } + + + //-----------------------------------------// + // SAX content handler serializing methods // + //-----------------------------------------// + + + public void startElement( String namespaceURI, String localName, + String rawName, Attributes attrs ) + throws SAXException + { + startElement( rawName == null ? localName : rawName, null ); + } + + + public void endElement( String namespaceURI, String localName, + String rawName ) + throws SAXException + { + endElement( rawName == null ? localName : rawName ); + } + + + //------------------------------------------// + // SAX document handler serializing methods // + //------------------------------000---------// + + + public void startElement( String tagName, AttributeList attrs ) + throws SAXException + { + boolean preserveSpace; + ElementState state; + + try { + state = getElementState(); + if ( isDocumentState() ) { + // If this is the root element handle it differently. + // If the first root element in the document, serialize + // the document's DOCTYPE. Space preserving defaults + // to that of the output format. + if ( ! _started ) + startDocument( tagName ); + } + // For any other element, if first in parent, then + // use the parnet's space preserving. + preserveSpace = state.preserveSpace; + + // Do not change the current element state yet. + // This only happens in endElement(). + + // Ignore all other attributes of the element, only printing + // its contents. + + // Now it's time to enter a new element state + // with the tag name and space preserving. + // We still do not change the curent element state. + state = enterElementState( null, null, tagName, preserveSpace ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void endElement( String tagName ) + throws SAXException + { + try { + endElementIO( tagName ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + public void endElementIO( String tagName ) + throws IOException + { + ElementState state; + + // Works much like content() with additions for closing + // an element. Note the different checks for the closed + // element's state and the parent element's state. + state = getElementState(); + // Leave the element state and update that of the parent + // (if we're not root) to not empty and after element. + state = leaveElementState(); + state.afterElement = true; + state.empty = false; + if ( isDocumentState() ) + _printer.flush(); + } + + + public void processingInstructionIO( String target, String code ) throws IOException + { + } + + + public void comment( String text ) + { + } + + + public void comment( char[] chars, int start, int length ) + { + } + + + public void characters( char[] chars, int start, int length ) + throws SAXException + { + ElementState state; + + try { + state = content(); + state.doCData = state.inCData = false; + printText( chars, start, length, true, true ); + } catch ( IOException except ) { + throw new SAXException( except ); + } + } + + + protected void characters( String text, boolean unescaped ) + throws IOException + { + ElementState state; + + state = content(); + state.doCData = state.inCData = false; + printText( text, true, true ); + } + + + //------------------------------------------// + // Generic node serializing methods methods // + //------------------------------------------// + + + /** + * Called to serialize the document's DOCTYPE by the root element. + *

        + * This method will check if it has not been called before ({@link #_started}), + * will serialize the document type declaration, and will serialize all + * pre-root comments and PIs that were accumulated in the document + * (see {@link #serializePreRoot}). Pre-root will be serialized even if + * this is not the first root element of the document. + */ + protected void startDocument( String rootTagName ) + throws IOException + { + // Required to stop processing the DTD, even though the DTD + // is not printed. + _printer.leaveDTD(); + + _started = true; + // Always serialize these, even if not te first root element. + serializePreRoot(); + } + + + /** + * Called to serialize a DOM element. Equivalent to calling {@link + * #startElement}, {@link #endElement} and serializing everything + * inbetween, but better optimized. + */ + protected void serializeElement( Element elem ) + throws IOException + { + Node child; + ElementState state; + boolean preserveSpace; + String tagName; + + tagName = elem.getTagName(); + state = getElementState(); + if ( isDocumentState() ) { + // If this is the root element handle it differently. + // If the first root element in the document, serialize + // the document's DOCTYPE. Space preserving defaults + // to that of the output format. + if ( ! _started ) + startDocument( tagName ); + } + // For any other element, if first in parent, then + // use the parnet's space preserving. + preserveSpace = state.preserveSpace; + + // Do not change the current element state yet. + // This only happens in endElement(). + + // Ignore all other attributes of the element, only printing + // its contents. + + // If element has children, then serialize them, otherwise + // serialize en empty tag. + if ( elem.hasChildNodes() ) { + // Enter an element state, and serialize the children + // one by one. Finally, end the element. + state = enterElementState( null, null, tagName, preserveSpace ); + child = elem.getFirstChild(); + while ( child != null ) { + serializeNode( child ); + child = child.getNextSibling(); + } + endElementIO( tagName ); + } else { + if ( ! isDocumentState() ) { + // After element but parent element is no longer empty. + state.afterElement = true; + state.empty = false; + } + } + } + + + /** + * Serialize the DOM node. This method is unique to the Text serializer. + * + * @param node The node to serialize + */ + protected void serializeNode( Node node ) + throws IOException + { + // Based on the node type call the suitable SAX handler. + // Only comments entities and documents which are not + // handled by SAX are serialized directly. + switch ( node.getNodeType() ) { + case Node.TEXT_NODE : { + String text; + + text = node.getNodeValue(); + if ( text != null ) + characters( node.getNodeValue(), true ); + break; + } + + case Node.CDATA_SECTION_NODE : { + String text; + + text = node.getNodeValue(); + if ( text != null ) + characters( node.getNodeValue(), true ); + break; + } + + case Node.COMMENT_NODE : + break; + + case Node.ENTITY_REFERENCE_NODE : + // Ignore. + break; + + case Node.PROCESSING_INSTRUCTION_NODE : + break; + + case Node.ELEMENT_NODE : + serializeElement( (Element) node ); + break; + + case Node.DOCUMENT_NODE : + // !!! Fall through + case Node.DOCUMENT_FRAGMENT_NODE : { + Node child; + + // By definition this will happen if the node is a document, + // document fragment, etc. Just serialize its contents. It will + // work well for other nodes that we do not know how to serialize. + child = node.getFirstChild(); + while ( child != null ) { + serializeNode( child ); + child = child.getNextSibling(); + } + break; + } + + default: + break; + } + } + + + protected ElementState content() + { + ElementState state; + + state = getElementState(); + if ( ! isDocumentState() ) { + // If this is the first content in the element, + // change the state to not-empty. + if ( state.empty ) + state.empty = false; + // Except for one content type, all of them + // are not last element. That one content + // type will take care of itself. + state.afterElement = false; + } + return state; + } + + + protected String getEntityRef( int ch ) + { + return null; + } + + +} + + diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/XHTMLSerializer.java b/resources/xerces2-j-src/org/apache/xml/serialize/XHTMLSerializer.java new file mode 100644 index 0000000..9f4cff1 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/XHTMLSerializer.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + + +package org.apache.xml.serialize; + + +import java.io.OutputStream; +import java.io.Writer; + + +/** + * Implements an XHTML serializer supporting both DOM and SAX + * pretty serializing. For usage instructions see either {@link + * Serializer} or {@link BaseMarkupSerializer}. + * + * @deprecated This class was deprecated in Xerces 2.6.2. It is + * recommended that new applications use JAXP's Transformation API + * for XML (TrAX) for serializing XHTML. See the Xerces documentation + * for more information. + * @version $Revision$ $Date$ + * @author Assaf Arkin + * @see Serializer + */ +public class XHTMLSerializer + extends HTMLSerializer +{ + + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public XHTMLSerializer() + { + super( true, new OutputFormat( Method.XHTML, null, false ) ); + } + + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public XHTMLSerializer( OutputFormat format ) + { + super( true, format != null ? format : new OutputFormat( Method.XHTML, null, false ) ); + } + + + /** + * Constructs a new serializer that writes to the specified writer + * using the specified output format. If format is null, + * will use a default output format. + * + * @param writer The writer to use + * @param format The output format to use, null for the default + */ + public XHTMLSerializer( Writer writer, OutputFormat format ) + { + super( true, format != null ? format : new OutputFormat( Method.XHTML, null, false ) ); + setOutputCharStream( writer ); + } + + + /** + * Constructs a new serializer that writes to the specified output + * stream using the specified output format. If format + * is null, will use a default output format. + * + * @param output The output stream to use + * @param format The output format to use, null for the default + */ + public XHTMLSerializer( OutputStream output, OutputFormat format ) + { + super( true, format != null ? format : new OutputFormat( Method.XHTML, null, false ) ); + setOutputByteStream( output ); + } + + + public void setOutputFormat( OutputFormat format ) + { + super.setOutputFormat( format != null ? format : new OutputFormat( Method.XHTML, null, false ) ); + } + + +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/XML11Serializer.java b/resources/xerces2-j-src/org/apache/xml/serialize/XML11Serializer.java new file mode 100644 index 0000000..ee14783 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/XML11Serializer.java @@ -0,0 +1,540 @@ +/* + * 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. + */ + +// Sep 14, 2000: +// Fixed problem with namespace handling. Contributed by +// David Blondeau +// Sep 14, 2000: +// Fixed serializer to report IO exception directly, instead at +// the end of document processing. +// Reported by Patrick Higgins +// Aug 21, 2000: +// Fixed bug in startDocument not calling prepare. +// Reported by Mikael Staldal +// Aug 21, 2000: +// Added ability to omit DOCTYPE declaration. + +package org.apache.xml.serialize; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XML11Char; +import org.apache.xerces.util.XMLChar; +import org.w3c.dom.DOMError; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +/** + * Implements an XML serializer supporting both DOM and SAX pretty + * serializing. For usage instructions see {@link Serializer}. + *

        + * If an output stream is used, the encoding is taken from the + * output format (defaults to UTF-8). If a writer is + * used, make sure the writer uses the same encoding (if applies) + * as specified in the output format. + *

        + * The serializer supports both DOM and SAX. SAX serializing is done by firing + * SAX events and using the serializer as a document handler. DOM serializing is done + * by calling {@link #serialize(Document)} or by using DOM Level 3 + * {@link org.w3c.dom.ls.LSSerializer} and + * serializing with {@link org.w3c.dom.ls.LSSerializer#write}, + * {@link org.w3c.dom.ls.LSSerializer#writeToString}. + *

        + * If an I/O exception occurs while serializing, the serializer + * will not throw an exception directly, but only throw it + * at the end of serializing (either DOM or SAX's {@link + * org.xml.sax.DocumentHandler#endDocument}. + *

        + * For elements that are not specified as whitespace preserving, + * the serializer will potentially break long text lines at space + * boundaries, indent lines, and serialize elements on separate + * lines. Line terminators will be regarded as spaces, and + * spaces at beginning of line will be stripped. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @author Assaf Arkin + * @author Rahul Srivastava + * @author Elena Litani IBM + * @version $Revision$ $Date$ + * @see Serializer + */ +public class XML11Serializer +extends XMLSerializer { + + // + // constants + // + + protected static final boolean DEBUG = false; + + // + // data + // + + // + // DOM Level 3 implementation: variables intialized in DOMSerializerImpl + // + + /** stores namespaces in scope */ + protected NamespaceSupport fNSBinder; + + /** stores all namespace bindings on the current element */ + protected NamespaceSupport fLocalNSBinder; + + /** symbol table for serialization */ + protected SymbolTable fSymbolTable; + + // is node dom level 1 node? + protected boolean fDOML1 = false; + // counter for new prefix names + protected int fNamespaceCounter = 1; + protected final static String PREFIX = "NS"; + + /** + * Controls whether namespace fixup should be performed during + * the serialization. + * NOTE: if this field is set to true the following + * fields need to be initialized: fNSBinder, fLocalNSBinder, fSymbolTable, + * XMLSymbols.EMPTY_STRING, fXmlSymbol, fXmlnsSymbol, fNamespaceCounter. + */ + protected boolean fNamespaces = false; + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public XML11Serializer() { + super( ); + _format.setVersion("1.1"); + } + + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public XML11Serializer( OutputFormat format ) { + super( format ); + _format.setVersion("1.1"); + } + + + /** + * Constructs a new serializer that writes to the specified writer + * using the specified output format. If format is null, + * will use a default output format. + * + * @param writer The writer to use + * @param format The output format to use, null for the default + */ + public XML11Serializer( Writer writer, OutputFormat format ) { + super( writer, format ); + _format.setVersion("1.1"); + } + + + /** + * Constructs a new serializer that writes to the specified output + * stream using the specified output format. If format + * is null, will use a default output format. + * + * @param output The output stream to use + * @param format The output format to use, null for the default + */ + public XML11Serializer( OutputStream output, OutputFormat format ) { + super( output, format != null ? format : new OutputFormat( Method.XML, null, false ) ); + _format.setVersion("1.1"); + } + + //-----------------------------------------// + // SAX content handler serializing methods // + //-----------------------------------------// + + + public void characters( char[] chars, int start, int length ) + throws SAXException + { + ElementState state; + + try { + state = content(); + + // Check if text should be print as CDATA section or unescaped + // based on elements listed in the output format (the element + // state) or whether we are inside a CDATA section or entity. + + if ( state.inCData || state.doCData ) { + int saveIndent; + + // Print a CDATA section. The text is not escaped, but ']]>' + // appearing in the code must be identified and dealt with. + // The contents of a text node is considered space preserving. + if ( ! state.inCData ) { + _printer.printText( "' ) { + _printer.printText("]]]]>"); + index +=2; + continue; + } + if (!XML11Char.isXML11Valid(ch)) { + // check if it is surrogate + if (++index < end) { + surrogates(ch, chars[index], true); + } + else { + fatalError("The character '"+ch+"' is an invalid XML character"); + } + continue; + } + if ( _encodingInfo.isPrintable(ch) && XML11Char.isXML11ValidLiteral(ch)) { + _printer.printText(ch); + } + else { + // The character is not printable -- split CDATA section + _printer.printText("]]>&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";= ' ' && _encodingInfo.isPrintable((char) ch))) { + _printer.printText((char) ch); + } + else { + printHex(ch); + } + } + } + + protected final void printCDATAText(String text) throws IOException { + int length = text.length(); + char ch; + + for (int index = 0; index < length; ++index) { + ch = text.charAt(index); + + if (ch == ']' + && index + 2 < length + && text.charAt(index + 1) == ']' + && text.charAt(index + 2) == '>') { // check for ']]>' + if (fDOMErrorHandler != null){ + // REVISIT: this means that if DOM Error handler is not registered we don't report any + // fatal errors and might serialize not wellformed document + if ((features & DOMSerializerImpl.SPLITCDATA) == 0 + && (features & DOMSerializerImpl.WELLFORMED) == 0) { + // issue fatal error + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "EndingCDATA", + null); + modifyDOMError( + msg, + DOMError.SEVERITY_FATAL_ERROR, + null, fCurrentNode); + boolean continueProcess = + fDOMErrorHandler.handleError(fDOMError); + if (!continueProcess) { + throw new IOException(); + } + } else { + // issue warning + String msg = + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "SplittingCDATA", + null); + modifyDOMError( + msg, + DOMError.SEVERITY_WARNING, + null, fCurrentNode); + fDOMErrorHandler.handleError(fDOMError); + } + } + // split CDATA section + _printer.printText("]]]]>"); + index += 2; + continue; + } + + if (!XML11Char.isXML11Valid(ch)) { + // check if it is surrogate + if (++index < length) { + surrogates(ch, text.charAt(index), true); + } + else { + fatalError("The character '" + ch + "' is an invalid XML character"); + } + continue; + } + if (_encodingInfo.isPrintable(ch) + && XML11Char.isXML11ValidLiteral(ch)) { + _printer.printText(ch); + } + else { + // The character is not printable -- split CDATA section + _printer.printText("]]>&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";'){ + // character sequence "]]>" can't appear in content, therefore + // we should escape '>' + _printer.printText(">"); + } + else if ( _encodingInfo.isPrintable((char)ch) && XML11Char.isXML11ValidLiteral(ch)) { + _printer.printText((char)ch); + } + else { + printHex(ch); + } + } + + protected final void surrogates(int high, int low, boolean inContent) throws IOException{ + if (XMLChar.isHighSurrogate(high)) { + if (!XMLChar.isLowSurrogate(low)) { + //Invalid XML + fatalError("The character '"+(char)low+"' is an invalid XML character"); + } + else { + int supplemental = XMLChar.supplemental((char)high, (char)low); + if (!XML11Char.isXML11Valid(supplemental)) { + //Invalid XML + fatalError("The character '"+(char)supplemental+"' is an invalid XML character"); + } + else { + if (inContent && content().inCData) { + _printer.printText("]]>&#x"); + _printer.printText(Integer.toHexString(supplemental)); + _printer.printText("; 0 ) { + char ch = chars[start++]; + if (!XML11Char.isXML11Valid(ch)) { + // check if it is surrogate + if ( length-- > 0) { + surrogates(ch, chars[start++], true); + } else { + fatalError("The character '"+ch+"' is an invalid XML character"); + } + continue; + } + if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) { + _printer.printText( ch ); + } + else { + printXMLChar( ch ); + } + } + } + else { + // Not preserving spaces: print one part at a time, and + // use spaces between parts to break them into different + // lines. Spaces at beginning of line will be stripped + // by printing mechanism. Line terminator is treated + // no different than other text part. + while ( length-- > 0 ) { + char ch = chars[start++]; + if (!XML11Char.isXML11Valid(ch)) { + // check if it is surrogate + if ( length-- > 0) { + surrogates(ch, chars[start++], true); + } else { + fatalError("The character '"+ch+"' is an invalid XML character"); + } + continue; + } + if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) { + _printer.printText( ch ); + } + else { + printXMLChar( ch ); + } + } + } + } + + public boolean reset() { + super.reset(); + return true; + } + +} diff --git a/resources/xerces2-j-src/org/apache/xml/serialize/XMLSerializer.java b/resources/xerces2-j-src/org/apache/xml/serialize/XMLSerializer.java new file mode 100644 index 0000000..c600c49 --- /dev/null +++ b/resources/xerces2-j-src/org/apache/xml/serialize/XMLSerializer.java @@ -0,0 +1,1474 @@ +/* + * 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. + */ + +// Sep 14, 2000: +// Fixed problem with namespace handling. Contributed by +// David Blondeau +// Sep 14, 2000: +// Fixed serializer to report IO exception directly, instead at +// the end of document processing. +// Reported by Patrick Higgins +// Aug 21, 2000: +// Fixed bug in startDocument not calling prepare. +// Reported by Mikael Staldal +// Aug 21, 2000: +// Added ability to omit DOCTYPE declaration. + +package org.apache.xml.serialize; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.util.Iterator; +import java.util.Map; + +import org.apache.xerces.dom.DOMMessageFormatter; +import org.apache.xerces.util.NamespaceSupport; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLChar; +import org.apache.xerces.util.XMLSymbols; +import org.apache.xerces.xni.NamespaceContext; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMError; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeFilter; +import org.xml.sax.AttributeList; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +/** + * Implements an XML serializer supporting both DOM and SAX pretty + * serializing. For usage instructions see {@link Serializer}. + *

        + * If an output stream is used, the encoding is taken from the + * output format (defaults to UTF-8). If a writer is + * used, make sure the writer uses the same encoding (if applies) + * as specified in the output format. + *

        + * The serializer supports both DOM and SAX. SAX serializing is done by firing + * SAX events and using the serializer as a document handler. DOM serializing is done + * by calling {@link #serialize(Document)} or by using DOM Level 3 + * {@link org.w3c.dom.ls.LSSerializer} and + * serializing with {@link org.w3c.dom.ls.LSSerializer#write}, + * {@link org.w3c.dom.ls.LSSerializer#writeToString}. + *

        + * If an I/O exception occurs while serializing, the serializer + * will not throw an exception directly, but only throw it + * at the end of serializing (either DOM or SAX's {@link + * org.xml.sax.DocumentHandler#endDocument}. + *

        + * For elements that are not specified as whitespace preserving, + * the serializer will potentially break long text lines at space + * boundaries, indent lines, and serialize elements on separate + * lines. Line terminators will be regarded as spaces, and + * spaces at beginning of line will be stripped. + * + * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended + * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation + * API for XML (TrAX) for serializing XML. See the Xerces documentation for more + * information. + * @author Assaf Arkin + * @author Rahul Srivastava + * @author Elena Litani IBM + * @version $Revision$ $Date$ + * @see Serializer + */ +public class XMLSerializer +extends BaseMarkupSerializer { + + // + // constants + // + + protected static final boolean DEBUG = false; + + // + // data + // + + // + // DOM Level 3 implementation: variables intialized in DOMSerializerImpl + // + + /** stores namespaces in scope */ + protected NamespaceSupport fNSBinder; + + /** stores all namespace bindings on the current element */ + protected NamespaceSupport fLocalNSBinder; + + /** symbol table for serialization */ + protected SymbolTable fSymbolTable; + + protected final static String PREFIX = "NS"; + + /** + * Controls whether namespace fixup should be performed during + * the serialization. + * NOTE: if this field is set to true the following + * fields need to be initialized: fNSBinder, fLocalNSBinder, fSymbolTable, + * XMLSymbols.EMPTY_STRING, fXmlSymbol, fXmlnsSymbol + */ + protected boolean fNamespaces = false; + + /** + * Controls whether namespace prefixes will be printed out during serialization + */ + protected boolean fNamespacePrefixes = true; + + + private boolean fPreserveSpace; + + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public XMLSerializer() { + super( new OutputFormat( Method.XML, null, false ) ); + } + + + /** + * Constructs a new serializer. The serializer cannot be used without + * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} + * first. + */ + public XMLSerializer( OutputFormat format ) { + super( format != null ? format : new OutputFormat( Method.XML, null, false ) ); + _format.setMethod( Method.XML ); + } + + + /** + * Constructs a new serializer that writes to the specified writer + * using the specified output format. If format is null, + * will use a default output format. + * + * @param writer The writer to use + * @param format The output format to use, null for the default + */ + public XMLSerializer( Writer writer, OutputFormat format ) { + super( format != null ? format : new OutputFormat( Method.XML, null, false ) ); + _format.setMethod( Method.XML ); + setOutputCharStream( writer ); + } + + + /** + * Constructs a new serializer that writes to the specified output + * stream using the specified output format. If format + * is null, will use a default output format. + * + * @param output The output stream to use + * @param format The output format to use, null for the default + */ + public XMLSerializer( OutputStream output, OutputFormat format ) { + super( format != null ? format : new OutputFormat( Method.XML, null, false ) ); + _format.setMethod( Method.XML ); + setOutputByteStream( output ); + } + + + public void setOutputFormat( OutputFormat format ) { + super.setOutputFormat( format != null ? format : new OutputFormat( Method.XML, null, false ) ); + } + + + /** + * This methods turns on namespace fixup algorithm during + * DOM serialization. + * @see org.w3c.dom.ls.LSSerializer + * + * @param namespaces + */ + public void setNamespaces (boolean namespaces){ + fNamespaces = namespaces; + if (fNSBinder == null) { + fNSBinder = new NamespaceSupport(); + fLocalNSBinder = new NamespaceSupport(); + fSymbolTable = new SymbolTable(); + } + } + + //-----------------------------------------// + // SAX content handler serializing methods // + //-----------------------------------------// + + + public void startElement( String namespaceURI, String localName, + String rawName, Attributes attrs ) + throws SAXException + { + int i; + boolean preserveSpace; + ElementState state; + String name; + String value; + + if (DEBUG) { + System.out.println("==>startElement("+namespaceURI+","+localName+ + ","+rawName+")"); + } + + try { + if (_printer == null) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "NoWriterSupplied", null); + throw new IllegalStateException(msg); + } + + state = getElementState(); + if (isDocumentState()) { + // If this is the root element handle it differently. + // If the first root element in the document, serialize + // the document's DOCTYPE. Space preserving defaults + // to that of the output format. + if (! _started) + startDocument( ( localName == null || localName.length() == 0 ) ? rawName : localName ); + } else { + // For any other element, if first in parent, then + // close parent's opening tag and use the parnet's + // space preserving. + if (state.empty) + _printer.printText( '>' ); + // Must leave CData section first + if (state.inCData) { + _printer.printText( "]]>" ); + state.inCData = false; + } + // Indent this element on a new line if the first + // content of the parent element or immediately + // following an element or a comment + if (_indenting && ! state.preserveSpace && + ( state.empty || state.afterElement || state.afterComment)) + _printer.breakLine(); + } + preserveSpace = state.preserveSpace; + + //We remove the namespaces from the attributes list so that they will + //be in _prefixes + attrs = extractNamespaces(attrs); + + // Do not change the current element state yet. + // This only happens in endElement(). + if (rawName == null || rawName.length() == 0) { + if (localName == null) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "NoName", null); + throw new SAXException(msg); + } + if (namespaceURI != null && ! namespaceURI.equals( "" )) { + String prefix; + prefix = getPrefix( namespaceURI ); + if (prefix != null && prefix.length() > 0) { + rawName = prefix + ":" + localName; + } + else { + rawName = localName; + } + } + else { + rawName = localName; + } + } + + _printer.printText( '<' ); + _printer.printText( rawName ); + _printer.indent(); + + // For each attribute print it's name and value as one part, + // separated with a space so the element can be broken on + // multiple lines. + if (attrs != null) { + for (i = 0 ; i < attrs.getLength() ; ++i) { + _printer.printSpace(); + + name = attrs.getQName( i ); + if (name != null && name.length() == 0) { + String prefix; + String attrURI; + + name = attrs.getLocalName( i ); + attrURI = attrs.getURI( i ); + if (( attrURI != null && attrURI.length() != 0 ) && + ( namespaceURI == null || namespaceURI.length() == 0 || + ! attrURI.equals( namespaceURI ) )) { + prefix = getPrefix( attrURI ); + if (prefix != null && prefix.length() > 0) + name = prefix + ":" + name; + } + } + + value = attrs.getValue( i ); + if (value == null) + value = ""; + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + + // If the attribute xml:space exists, determine whether + // to preserve spaces in this and child nodes based on + // its value. + if (name.equals( "xml:space" )) { + if (value.equals( "preserve" )) + preserveSpace = true; + else + preserveSpace = _format.getPreserveSpace(); + } + } + } + + if (_prefixes != null) { + Iterator entries = _prefixes.entrySet().iterator(); + while (entries.hasNext()) { + _printer.printSpace(); + Map.Entry entry = (Map.Entry) entries.next(); + value = (String) entry.getKey(); + name = (String) entry.getValue(); + if (name.length() == 0) { + _printer.printText( "xmlns=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + else { + _printer.printText( "xmlns:" ); + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + } + } + + // Now it's time to enter a new element state + // with the tag name and space preserving. + // We still do not change the curent element state. + state = enterElementState( namespaceURI, localName, rawName, preserveSpace ); + name = ( localName == null || localName.length() == 0 ) ? rawName : namespaceURI + "^" + localName; + state.doCData = _format.isCDataElement( name ); + state.unescaped = _format.isNonEscapingElement( name ); + } catch (IOException except) { + throw new SAXException( except ); + } + } + + + public void endElement( String namespaceURI, String localName, + String rawName ) + throws SAXException + { + try { + endElementIO( namespaceURI, localName, rawName ); + } catch (IOException except) { + throw new SAXException( except ); + } + } + + + public void endElementIO( String namespaceURI, String localName, + String rawName ) + throws IOException + { + ElementState state; + if (DEBUG) { + System.out.println("==>endElement: " +rawName); + } + // Works much like content() with additions for closing + // an element. Note the different checks for the closed + // element's state and the parent element's state. + _printer.unindent(); + state = getElementState(); + if (state.empty) { + _printer.printText( "/>" ); + } else { + // Must leave CData section first + if (state.inCData) + _printer.printText( "]]>" ); + // This element is not empty and that last content was + // another element, so print a line break before that + // last element and this element's closing tag. + if (_indenting && ! state.preserveSpace && (state.afterElement || state.afterComment)) + _printer.breakLine(); + _printer.printText( "' ); + } + // Leave the element state and update that of the parent + // (if we're not root) to not empty and after element. + state = leaveElementState(); + state.afterElement = true; + state.afterComment = false; + state.empty = false; + if (isDocumentState()) + _printer.flush(); + } + + + //------------------------------------------// + // SAX document handler serializing methods // + //------------------------------------------// + + + public void startElement( String tagName, AttributeList attrs ) + throws SAXException + { + int i; + boolean preserveSpace; + ElementState state; + String name; + String value; + + + if (DEBUG) { + System.out.println("==>startElement("+tagName+")"); + } + + try { + if (_printer == null) { + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "NoWriterSupplied", null); + throw new IllegalStateException(msg); + } + + state = getElementState(); + if (isDocumentState()) { + // If this is the root element handle it differently. + // If the first root element in the document, serialize + // the document's DOCTYPE. Space preserving defaults + // to that of the output format. + if (! _started) + startDocument( tagName ); + } else { + // For any other element, if first in parent, then + // close parent's opening tag and use the parnet's + // space preserving. + if (state.empty) + _printer.printText( '>' ); + // Must leave CData section first + if (state.inCData) { + _printer.printText( "]]>" ); + state.inCData = false; + } + // Indent this element on a new line if the first + // content of the parent element or immediately + // following an element. + if (_indenting && ! state.preserveSpace && + ( state.empty || state.afterElement || state.afterComment)) + _printer.breakLine(); + } + preserveSpace = state.preserveSpace; + + // Do not change the current element state yet. + // This only happens in endElement(). + + _printer.printText( '<' ); + _printer.printText( tagName ); + _printer.indent(); + + // For each attribute print it's name and value as one part, + // separated with a space so the element can be broken on + // multiple lines. + if (attrs != null) { + for (i = 0 ; i < attrs.getLength() ; ++i) { + _printer.printSpace(); + name = attrs.getName( i ); + value = attrs.getValue( i ); + if (value != null) { + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + + // If the attribute xml:space exists, determine whether + // to preserve spaces in this and child nodes based on + // its value. + if (name.equals( "xml:space" )) { + if (value.equals( "preserve" )) + preserveSpace = true; + else + preserveSpace = _format.getPreserveSpace(); + } + } + } + // Now it's time to enter a new element state + // with the tag name and space preserving. + // We still do not change the curent element state. + state = enterElementState( null, null, tagName, preserveSpace ); + state.doCData = _format.isCDataElement( tagName ); + state.unescaped = _format.isNonEscapingElement( tagName ); + } catch (IOException except) { + throw new SAXException( except ); + } + + } + + + public void endElement( String tagName ) + throws SAXException + { + endElement( null, null, tagName ); + } + + + + //------------------------------------------// + // Generic node serializing methods methods // + //------------------------------------------// + + + /** + * Called to serialize the document's DOCTYPE by the root element. + * The document type declaration must name the root element, + * but the root element is only known when that element is serialized, + * and not at the start of the document. + *

        + * This method will check if it has not been called before ({@link #_started}), + * will serialize the document type declaration, and will serialize all + * pre-root comments and PIs that were accumulated in the document + * (see {@link #serializePreRoot}). Pre-root will be serialized even if + * this is not the first root element of the document. + */ + protected void startDocument( String rootTagName ) + throws IOException + { + int i; + String dtd; + + dtd = _printer.leaveDTD(); + if (! _started) { + + if (! _format.getOmitXMLDeclaration()) { + StringBuffer buffer; + + // Serialize the document declaration appreaing at the head + // of very XML document (unless asked not to). + buffer = new StringBuffer( "" ); + _printer.printText( buffer ); + _printer.breakLine(); + } + + if (! _format.getOmitDocumentType()) { + if (_docTypeSystemId != null) { + // System identifier must be specified to print DOCTYPE. + // If public identifier is specified print 'PUBLIC + // ', if not, print 'SYSTEM '. + _printer.printText( " 0) { + _printer.printText( " [" ); + printText( dtd, true, true ); + _printer.printText( ']' ); + } + + _printer.printText( ">" ); + _printer.breakLine(); + } else if (dtd != null && dtd.length() > 0) { + _printer.printText( "" ); + _printer.breakLine(); + } + } + } + _started = true; + // Always serialize these, even if not te first root element. + serializePreRoot(); + } + + + /** + * Called to serialize a DOM element. Equivalent to calling {@link + * #startElement}, {@link #endElement} and serializing everything + * inbetween, but better optimized. + */ + protected void serializeElement( Element elem ) + throws IOException + { + Attr attr; + NamedNodeMap attrMap; + int i; + Node child; + ElementState state; + String name; + String value; + String tagName; + + String prefix, localUri; + String uri; + if (fNamespaces) { + // local binder stores namespace declaration + // that has been printed out during namespace fixup of + // the current element + fLocalNSBinder.reset(); + + // add new namespace context + fNSBinder.pushContext(); + } + + if (DEBUG) { + System.out.println("==>startElement: " +elem.getNodeName() +" ns="+elem.getNamespaceURI()); + } + tagName = elem.getTagName(); + state = getElementState(); + if (isDocumentState()) { + // If this is the root element handle it differently. + // If the first root element in the document, serialize + // the document's DOCTYPE. Space preserving defaults + // to that of the output format. + + if (! _started) { + startDocument( tagName); + } + } else { + // For any other element, if first in parent, then + // close parent's opening tag and use the parent's + // space preserving. + if (state.empty) + _printer.printText( '>' ); + // Must leave CData section first + if (state.inCData) { + _printer.printText( "]]>" ); + state.inCData = false; + } + // Indent this element on a new line if the first + // content of the parent element or immediately + // following an element. + if (_indenting && ! state.preserveSpace && + ( state.empty || state.afterElement || state.afterComment)) + _printer.breakLine(); + } + + // Do not change the current element state yet. + // This only happens in endElement(). + fPreserveSpace = state.preserveSpace; + + + int length = 0; + attrMap = null; + // retrieve attributes + if (elem.hasAttributes()) { + attrMap = elem.getAttributes(); + length = attrMap.getLength(); + } + + if (!fNamespaces) { // no namespace fixup should be performed + + // serialize element name + _printer.printText( '<' ); + _printer.printText( tagName ); + _printer.indent(); + + // For each attribute print it's name and value as one part, + // separated with a space so the element can be broken on + // multiple lines. + for ( i = 0 ; i < length ; ++i ) { + attr = (Attr) attrMap.item( i ); + name = attr.getName(); + value = attr.getValue(); + if ( value == null ) + value = ""; + printAttribute (name, value, attr.getSpecified(), attr); + } + } else { // do namespace fixup + + // REVISIT: some optimization could probably be done to avoid traversing + // attributes twice. + // + + // --------------------------------------- + // record all valid namespace declarations + // before attempting to fix element's namespace + // --------------------------------------- + + for (i = 0;i < length;i++) { + + attr = (Attr) attrMap.item( i ); + uri = attr.getNamespaceURI(); + // check if attribute is a namespace decl + if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) { + + value = attr.getNodeValue(); + if (value == null) { + value=XMLSymbols.EMPTY_STRING; + } + + if (value.equals(NamespaceContext.XMLNS_URI)) { + if (fDOMErrorHandler != null) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.XML_DOMAIN,"CantBindXMLNS",null ); + modifyDOMError(msg, DOMError.SEVERITY_ERROR, null, attr); + boolean continueProcess = fDOMErrorHandler.handleError(fDOMError); + if (!continueProcess) { + // stop the namespace fixup and validation + throw new RuntimeException( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "SerializationStopped", null)); + } + } + } else { + prefix = attr.getPrefix(); + prefix = (prefix == null || + prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix); + String localpart = fSymbolTable.addSymbol( attr.getLocalName()); + if (prefix == XMLSymbols.PREFIX_XMLNS) { //xmlns:prefix + value = fSymbolTable.addSymbol(value); + // record valid decl + if (value.length() != 0) { + fNSBinder.declarePrefix(localpart, value); + } else { + // REVISIT: issue error on invalid declarations + // xmlns:foo = "" + } + continue; + } + // xmlns --- empty prefix is always bound ("" or some string) + value = fSymbolTable.addSymbol(value); + fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value); + continue; + } // end-else: valid declaration + } // end-if: namespace declaration + } // end-for + + //----------------------- + // get element uri/prefix + //----------------------- + uri = elem.getNamespaceURI(); + prefix = elem.getPrefix(); + + //---------------------- + // output element name + //---------------------- + // REVISIT: this could be removed if we always convert empty string to null + // for the namespaces. + if ((uri !=null && prefix !=null ) && uri.length() == 0 && prefix.length()!=0) { + // uri is an empty string and element has some prefix + // the namespace alg later will fix up the namespace attributes + // remove element prefix + prefix = null; + _printer.printText( '<' ); + _printer.printText( elem.getLocalName() ); + _printer.indent(); + } else { + _printer.printText( '<' ); + _printer.printText( tagName ); + _printer.indent(); + } + + + // --------------------------------------------------------- + // Fix up namespaces for element: per DOM L3 + // Need to consider the following cases: + // + // case 1: + // Assume "foo", "ns1" are declared on the parent. We should not miss + // redeclaration for both "ns1" and default namespace. To solve this + // we add a local binder that stores declaration only for current element. + // This way we avoid outputing duplicate declarations for the same element + // as well as we are not omitting redeclarations. + // + // case 2: + // We need to bind default namespace to empty string, to be able to + // omit duplicate declarations for the same element + // + // case 3: + // We create another element body bound to the "http://xsl" namespace + // as well as namespace attribute rebounding xsl to another namespace. + // + // Need to make sure that the new namespace decl value is changed to + // "http://xsl" + // + // --------------------------------------------------------- + // check if prefix/namespace is correct for current element + // --------------------------------------------------------- + + + if (uri != null) { // Element has a namespace + uri = fSymbolTable.addSymbol(uri); + prefix = (prefix == null || + prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix); + if (fNSBinder.getURI(prefix) == uri) { + // The xmlns:prefix=namespace or xmlns="default" was declared at parent. + // The binder always stores mapping of empty prefix to "". + // (NOTE: local binder does not store this kind of binding!) + // Thus the case where element was declared with uri="" (with or without a prefix) + // will be covered here. + + } else { + // the prefix is either undeclared + // or + // conflict: the prefix is bound to another URI + if (fNamespacePrefixes) { + printNamespaceAttr(prefix, uri); + } + fLocalNSBinder.declarePrefix(prefix, uri); + fNSBinder.declarePrefix(prefix, uri); + } + } else { // Element has no namespace + if (elem.getLocalName() == null) { + // DOM Level 1 node! + if (fDOMErrorHandler != null) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, "NullLocalElementName", + new Object[]{elem.getNodeName()}); + modifyDOMError(msg,DOMError.SEVERITY_ERROR, null, elem); + boolean continueProcess = fDOMErrorHandler.handleError(fDOMError); + // REVISIT: should we terminate upon request? + if (!continueProcess) { + throw new RuntimeException( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "SerializationStopped", null)); + } + } + } else { // uri=null and no colon (DOM L2 node) + uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING); + + if (uri !=null && uri.length() > 0) { + // there is a default namespace decl that is bound to + // non-zero length uri, output xmlns="" + if (fNamespacePrefixes) { + printNamespaceAttr(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING); + } + fLocalNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING); + fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING); + } + } + } + + + // ----------------------------------------- + // Fix up namespaces for attributes: per DOM L3 + // check if prefix/namespace is correct the attributes + // ----------------------------------------- + + for (i = 0; i < length; i++) { + + attr = (Attr) attrMap.item( i ); + value = attr.getValue(); + name = attr.getNodeName(); + + uri = attr.getNamespaceURI(); + + // Fix attribute that was declared with a prefix and namespace="" + if (uri !=null && uri.length() == 0) { + uri=null; + // we must remove prefix for this attribute + name=attr.getLocalName(); + } + + if (DEBUG) { + System.out.println("==>process attribute: "+attr.getNodeName()); + } + // make sure that value is never null. + if (value == null) { + value=XMLSymbols.EMPTY_STRING; + } + + if (uri != null) { // attribute has namespace !=null + prefix = attr.getPrefix(); + prefix = prefix == null ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix); + String localpart = fSymbolTable.addSymbol( attr.getLocalName()); + + + + // --------------------------------------------------- + // print namespace declarations namespace declarations + // --------------------------------------------------- + if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) { + // check if we need to output this declaration + prefix = attr.getPrefix(); + prefix = (prefix == null || + prefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(prefix); + localpart = fSymbolTable.addSymbol( attr.getLocalName()); + if (prefix == XMLSymbols.PREFIX_XMLNS) { //xmlns:prefix + localUri = fLocalNSBinder.getURI(localpart); // local prefix mapping + value = fSymbolTable.addSymbol(value); + if (value.length() != 0 ) { + if (localUri == null) { + // declaration was not printed while fixing element namespace binding + + // If the DOM Level 3 namespace-prefixes feature is set to false + // do not print xmlns attributes + if (fNamespacePrefixes) { + printNamespaceAttr(localpart, value); + } + + // case 4: + // where attribute is bound to "bar". + // If the xmlns:xx is output here first, later we should not + // redeclare "xx" prefix. Instead we would pick up different prefix + // for the attribute. + // final: + fLocalNSBinder.declarePrefix(localpart, value); + } + } else { + // REVISIT: issue error on invalid declarations + // xmlns:foo = "" + } + continue; + } + // xmlns --- empty prefix is always bound ("" or some string) + uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING); + localUri= fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING); + value = fSymbolTable.addSymbol(value); + if (localUri == null ) { + // declaration was not printed while fixing element namespace binding + if (fNamespacePrefixes) { + printNamespaceAttr(XMLSymbols.EMPTY_STRING, value); + } + // case 4 does not apply here since attributes can't use + // default namespace + } + continue; + + } + uri = fSymbolTable.addSymbol(uri); + + // find if for this prefix a URI was already declared + String declaredURI = fNSBinder.getURI(prefix); + + if (prefix == XMLSymbols.EMPTY_STRING || declaredURI != uri) { + // attribute has no prefix (default namespace decl does not apply to attributes) + // OR + // attribute prefix is not declared + // OR + // conflict: attr URI does not match the prefix in scope + + name = attr.getNodeName(); + // Find if any prefix for attributes namespace URI is available + // in the scope + String declaredPrefix = fNSBinder.getPrefix(uri); + + if (declaredPrefix !=null && declaredPrefix !=XMLSymbols.EMPTY_STRING) { + // use the prefix that was found + prefix = declaredPrefix; + name=prefix+":"+localpart; + } else { + if (DEBUG) { + System.out.println("==> cound not find prefix for the attribute: " +prefix); + } + + if (prefix != XMLSymbols.EMPTY_STRING && fLocalNSBinder.getURI(prefix) == null) { + // the current prefix is not null and it has no in scope declaration + + // use this prefix + } else { + // find a prefix following the pattern "NS" +index (starting at 1) + // make sure this prefix is not declared in the current scope. + int counter = 1; + prefix = fSymbolTable.addSymbol(PREFIX + counter++); + while (fLocalNSBinder.getURI(prefix)!=null) { + prefix = fSymbolTable.addSymbol(PREFIX +counter++); + } + name=prefix+":"+localpart; + } + // add declaration for the new prefix + if (fNamespacePrefixes) { + printNamespaceAttr(prefix, uri); + } + value = fSymbolTable.addSymbol(value); + fLocalNSBinder.declarePrefix(prefix, value); + fNSBinder.declarePrefix(prefix, uri); + } + + // change prefix for this attribute + } + + printAttribute (name, (value==null)?XMLSymbols.EMPTY_STRING:value, attr.getSpecified(), attr); + } else { // attribute uri == null + if (attr.getLocalName() == null) { + if (fDOMErrorHandler != null) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "NullLocalAttrName", new Object[]{attr.getNodeName()}); + modifyDOMError(msg, DOMError.SEVERITY_ERROR, null, attr); + boolean continueProcess = fDOMErrorHandler.handleError(fDOMError); + if (!continueProcess) { + // stop the namespace fixup and validation + throw new RuntimeException( + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "SerializationStopped", null)); + } + } + printAttribute (name, value, attr.getSpecified(), attr); + } else { // uri=null and no colon + + // no fix up is needed: default namespace decl does not + // apply to attributes + printAttribute (name, value, attr.getSpecified(), attr); + } + } + } // end loop for attributes + + }// end namespace fixup algorithm + + + // If element has children, then serialize them, otherwise + // serialize en empty tag. + if (elem.hasChildNodes()) { + // Enter an element state, and serialize the children + // one by one. Finally, end the element. + state = enterElementState( null, null, tagName, fPreserveSpace ); + state.doCData = _format.isCDataElement( tagName ); + state.unescaped = _format.isNonEscapingElement( tagName ); + child = elem.getFirstChild(); + while (child != null) { + serializeNode( child ); + child = child.getNextSibling(); + } + if (fNamespaces) { + fNSBinder.popContext(); + } + endElementIO( null, null, tagName ); + } else { + if (DEBUG) { + System.out.println("==>endElement: " +elem.getNodeName()); + } + if (fNamespaces) { + fNSBinder.popContext(); + } + _printer.unindent(); + _printer.printText( "/>" ); + // After element but parent element is no longer empty. + state.afterElement = true; + state.afterComment = false; + state.empty = false; + if (isDocumentState()) + _printer.flush(); + } + } + + + + /** + * Serializes a namespace attribute with the given prefix and value for URI. + * In case prefix is empty will serialize default namespace declaration. + * + * @param prefix + * @param uri + * @exception IOException + */ + + private void printNamespaceAttr(String prefix, String uri) throws IOException{ + _printer.printSpace(); + if (prefix == XMLSymbols.EMPTY_STRING) { + if (DEBUG) { + System.out.println("=>add xmlns=\""+uri+"\" declaration"); + } + _printer.printText( XMLSymbols.PREFIX_XMLNS ); + } else { + if (DEBUG) { + System.out.println("=>add xmlns:"+prefix+"=\""+uri+"\" declaration"); + } + _printer.printText( "xmlns:"+prefix ); + } + _printer.printText( "=\"" ); + printEscaped( uri ); + _printer.printText( '"' ); + } + + + + /** + * Prints attribute. + * NOTE: xml:space attribute modifies output format + * + * @param name + * @param value + * @param isSpecified + * @exception IOException + */ + private void printAttribute (String name, String value, boolean isSpecified, Attr attr) throws IOException{ + + if (isSpecified || (features & DOMSerializerImpl.DISCARDDEFAULT) == 0) { + if (fDOMFilter !=null && + (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_ATTRIBUTE)!= 0) { + short code = fDOMFilter.acceptNode(attr); + switch (code) { + case NodeFilter.FILTER_REJECT: + case NodeFilter.FILTER_SKIP: { + return; + } + default: { + // fall through + } + } + } + _printer.printSpace(); + _printer.printText( name ); + _printer.printText( "=\"" ); + printEscaped( value ); + _printer.printText( '"' ); + } + + // If the attribute xml:space exists, determine whether + // to preserve spaces in this and child nodes based on + // its value. + if (name.equals( "xml:space" )) { + if (value.equals( "preserve" )) + fPreserveSpace = true; + else + fPreserveSpace = _format.getPreserveSpace(); + } + } + + protected String getEntityRef( int ch ) { + // Encode special XML characters into the equivalent character references. + // These five are defined by default for all XML documents. + switch (ch) { + case '<': + return "lt"; + case '>': + return "gt"; + case '"': + return "quot"; + case '\'': + return "apos"; + case '&': + return "amp"; + } + return null; + } + + + /** Retrieve and remove the namespaces declarations from the list of attributes. + * + */ + private Attributes extractNamespaces( Attributes attrs ) + throws SAXException + { + AttributesImpl attrsOnly; + String rawName; + int i; + int length; + + if (attrs == null) { + return null; + } + length = attrs.getLength(); + attrsOnly = new AttributesImpl( attrs ); + + for (i = length - 1 ; i >= 0 ; --i) { + rawName = attrsOnly.getQName( i ); + + //We have to exclude the namespaces declarations from the attributes + //Append only when the feature http://xml.org/sax/features/namespace-prefixes" + //is TRUE + if (rawName.startsWith( "xmlns" )) { + if (rawName.length() == 5) { + startPrefixMapping( "", attrs.getValue( i ) ); + attrsOnly.removeAttribute( i ); + } else if (rawName.charAt(5) == ':') { + startPrefixMapping(rawName.substring(6), attrs.getValue(i)); + attrsOnly.removeAttribute( i ); + } + } + } + return attrsOnly; + } + + // + // Printing attribute value + // + protected void printEscaped(String source) throws IOException { + int length = source.length(); + for (int i = 0; i < length; ++i) { + int ch = source.charAt(i); + if (!XMLChar.isValid(ch)) { + if (++i < length) { + surrogates(ch, source.charAt(i), false); + } else { + fatalError("The character '" + (char) ch + "' is an invalid XML character"); + } + continue; + } + // escape NL, CR, TAB + if (ch == '\n' || ch == '\r' || ch == '\t') { + printHex(ch); + } else if (ch == '<') { + _printer.printText("<"); + } else if (ch == '&') { + _printer.printText("&"); + } else if (ch == '"') { + _printer.printText("""); + } else if ((ch >= ' ' && _encodingInfo.isPrintable((char) ch))) { + _printer.printText((char) ch); + } else { + printHex(ch); + } + } + } + + /** print text data */ + protected void printXMLChar( int ch) throws IOException { + if (ch == '\r') { + printHex(ch); + } else if ( ch == '<') { + _printer.printText("<"); + } else if (ch == '&') { + _printer.printText("&"); + } else if (ch == '>'){ + // character sequence "]]>" can't appear in content, therefore + // we should escape '>' + _printer.printText(">"); + } else if ( ch == '\n' || ch == '\t' || + ( ch >= ' ' && _encodingInfo.isPrintable((char)ch))) { + _printer.printText((char)ch); + } else { + printHex(ch); + } + } + + protected void printText( String text, boolean preserveSpace, boolean unescaped ) + throws IOException { + int index; + char ch; + int length = text.length(); + if ( preserveSpace ) { + // Preserving spaces: the text must print exactly as it is, + // without breaking when spaces appear in the text and without + // consolidating spaces. If a line terminator is used, a line + // break will occur. + for ( index = 0 ; index < length ; ++index ) { + ch = text.charAt( index ); + if (!XMLChar.isValid(ch)) { + // check if it is surrogate + if (++index 0 ) { + char ch = chars[start++]; + if (!XMLChar.isValid(ch)) { + // check if it is surrogate + if ( length-- > 0 ) { + surrogates(ch, chars[start++], true); + } + else { + fatalError("The character '"+ch+"' is an invalid XML character"); + } + continue; + } + if ( unescaped ) { + _printer.printText( ch ); + } + else { + printXMLChar( ch ); + } + } + } else { + // Not preserving spaces: print one part at a time, and + // use spaces between parts to break them into different + // lines. Spaces at beginning of line will be stripped + // by printing mechanism. Line terminator is treated + // no different than other text part. + while ( length-- > 0 ) { + char ch = chars[start++]; + if (!XMLChar.isValid(ch)) { + // check if it is surrogate + if ( length-- > 0 ) { + surrogates(ch, chars[start++], true); + } + else { + fatalError("The character '"+ch+"' is an invalid XML character"); + } + continue; + } + if ( unescaped ) { + _printer.printText( ch ); + } + else { + printXMLChar( ch ); + } + } + } + } + + + /** + * DOM Level 3: + * Check a node to determine if it contains unbound namespace prefixes. + * + * @param node The node to check for unbound namespace prefices + */ + protected void checkUnboundNamespacePrefixedNode (Node node) throws IOException{ + + if (fNamespaces) { + + if (DEBUG) { + System.out.println("==>serializeNode("+node.getNodeName()+") [Entity Reference - Namespaces on]"); + System.out.println("==>Declared Prefix Count: " + fNSBinder.getDeclaredPrefixCount()); + System.out.println("==>Node Name: " + node.getNodeName()); + System.out.println("==>First Child Node Name: " + node.getFirstChild().getNodeName()); + System.out.println("==>First Child Node Prefix: " + node.getFirstChild().getPrefix()); + System.out.println("==>First Child Node NamespaceURI: " + node.getFirstChild().getNamespaceURI()); + } + + + Node child, next; + for (child = node.getFirstChild(); child != null; child = next) { + next = child.getNextSibling(); + if (DEBUG) { + System.out.println("==>serializeNode("+child.getNodeName()+") [Child Node]"); + System.out.println("==>serializeNode("+child.getPrefix()+") [Child Node Prefix]"); + } + + //If a NamespaceURI is not declared for the current + //node's prefix, raise a fatal error. + String prefix = child.getPrefix(); + prefix = (prefix == null || + prefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(prefix); + if (fNSBinder.getURI(prefix) == null && prefix != null) { + fatalError("The replacement text of the entity node '" + + node.getNodeName() + + "' contains an element node '" + + child.getNodeName() + + "' with an undeclared prefix '" + + prefix + "'."); + } + + if (child.getNodeType() == Node.ELEMENT_NODE) { + + NamedNodeMap attrs = child.getAttributes(); + + for (int i = 0; i< attrs.getLength(); i++ ) { + + String attrPrefix = attrs.item(i).getPrefix(); + attrPrefix = (attrPrefix == null || + attrPrefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(attrPrefix); + if (fNSBinder.getURI(attrPrefix) == null && attrPrefix != null) { + fatalError("The replacement text of the entity node '" + + node.getNodeName() + + "' contains an element node '" + + child.getNodeName() + + "' with an attribute '" + + attrs.item(i).getNodeName() + + "' an undeclared prefix '" + + attrPrefix + "'."); + } + + } + + } + + if (child.hasChildNodes()) { + checkUnboundNamespacePrefixedNode(child); + } + } + } + } + + public boolean reset() { + super.reset(); + if (fNSBinder != null){ + fNSBinder.reset(); + // during serialization always have a mapping to empty string + // so we assume there is a declaration. + fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING); + } + return true; + } + +} + + + + diff --git a/resources/xerces2-j-src/org/w3c/dom/html/HTMLDOMImplementation.java b/resources/xerces2-j-src/org/w3c/dom/html/HTMLDOMImplementation.java new file mode 100644 index 0000000..c6ed97d --- /dev/null +++ b/resources/xerces2-j-src/org/w3c/dom/html/HTMLDOMImplementation.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2000 World Wide Web Consortium, + * (Massachusetts Institute of Technology, Institut National de + * Recherche en Informatique et en Automatique, Keio University). All + * Rights Reserved. This program is distributed under the W3C's Software + * Intellectual Property License. This program is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See W3C License http://www.w3.org/Consortium/Legal/ for more + * details. + */ + +package org.w3c.dom.html; + +import org.w3c.dom.DOMImplementation; + +/** + * The HTMLDOMImplementation interface extends the + * DOMImplementation interface with a method for creating an + * HTML document instance. + * @since DOM Level 2 + */ +public interface HTMLDOMImplementation extends DOMImplementation { + /** + * Creates an HTMLDocument object with the minimal tree made + * of the following elements: HTML , HEAD , + * TITLE , and BODY . + * @param title The title of the document to be set as the content of the + * TITLE element, through a child Text node. + * @return A new HTMLDocument object. + */ + public HTMLDocument createHTMLDocument(String title); + +} +