121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson/*
221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * Copyright (C) 2010 The Android Open Source Project
321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson *
421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * you may not use this file except in compliance with the License.
621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * You may obtain a copy of the License at
721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson *
821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson *
1021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * Unless required by applicable law or agreed to in writing, software
1121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
1221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * See the License for the specific language governing permissions and
1421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * limitations under the License.
1521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson */
1621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
1721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilsonpackage org.apache.harmony.xml.dom;
1821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
19e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilsonimport org.apache.xml.serializer.dom3.DOMErrorImpl;
2021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilsonimport org.w3c.dom.DOMConfiguration;
21e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilsonimport org.w3c.dom.DOMError;
2221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilsonimport org.w3c.dom.DOMErrorHandler;
2321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilsonimport org.w3c.dom.DOMException;
2421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilsonimport org.w3c.dom.DOMStringList;
25e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilsonimport org.w3c.dom.NamedNodeMap;
26e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilsonimport org.w3c.dom.Node;
2721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
2821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilsonimport java.util.Map;
2921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilsonimport java.util.TreeMap;
3021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
3121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson/**
3221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * A minimal implementation of DOMConfiguration. This implementation uses inner
3321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson * parameter instances to centralize each parameter's behaviour.
3421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson */
3521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilsonpublic final class DOMConfigurationImpl implements DOMConfiguration {
3621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
3721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private static final Map<String, Parameter> PARAMETERS
3821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            = new TreeMap<String, Parameter>(String.CASE_INSENSITIVE_ORDER);
3921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
4021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    static {
4121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
4221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to canonicalize the document (unsupported). This includes
4321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * removing DocumentType nodes from the tree and removing unused
4421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * namespace declarations. Setting this to true also sets these
4521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * parameters:
4621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   entities = false
4721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   normalize-characters = false
4821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   cdata-sections = false
4921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   namespaces = true
5021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   namespace-declarations = true
5121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   well-formed = true
5221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   element-content-whitespace = true
5321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * Setting these parameters to another value shall revert the canonical
5421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * form to false.
5521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
5621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("canonical-form", new FixedParameter(false));
5721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
5821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
5921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to keep existing CDATA nodes; false to replace them/merge them
6021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * into adjacent text nodes.
6121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
6221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("cdata-sections", new BooleanParameter() {
6321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
6421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.cdataSections;
6521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
6621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
6721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.cdataSections = (Boolean) value;
6821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
6921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
7021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
7121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
7221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to check character normalization (unsupported).
7321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
7421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("check-character-normalization", new FixedParameter(false));
7521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
7621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
7721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to keep comments in the document; false to discard them.
7821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
7921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("comments", new BooleanParameter() {
8021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
8121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.comments;
8221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
8321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
8421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.comments = (Boolean) value;
8521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
8621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
8721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
8821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
8921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to expose schema normalized values. Setting this to true sets
9021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * the validate parameter to true. Has no effect when validate is false.
9121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
9221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("datatype-normalization", new BooleanParameter() {
9321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
9421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.datatypeNormalization;
9521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
9621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
9721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                if ((Boolean) value) {
9821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.datatypeNormalization = true;
9921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.validate = true;
10021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                } else {
10121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.datatypeNormalization = false;
10221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                }
10321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
10421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
10521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
10621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
10721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to keep whitespace elements in the document; false to discard
10821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * them (unsupported).
10921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
11021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("element-content-whitespace", new FixedParameter(true));
11121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
11221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
11321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to keep entity references in the document; false to expand them.
11421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
11521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("entities", new BooleanParameter() {
11621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
11721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.entities;
11821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
11921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
12021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.entities = (Boolean) value;
12121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
12221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
12321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
12421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
12521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * Handler to be invoked when errors are encountered.
12621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
12721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("error-handler", new Parameter() {
12821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
12921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.errorHandler;
13021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
13121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
13221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.errorHandler = (DOMErrorHandler) value;
13321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
13421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public boolean canSet(DOMConfigurationImpl config, Object value) {
13521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return value == null || value instanceof DOMErrorHandler;
13621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
13721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
13821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
13921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
14021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * Bulk alias to set the following parameter values:
14121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   validate-if-schema = false
14221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   entities = false
14321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   datatype-normalization = false
14421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   cdata-sections = false
14521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   namespace-declarations = true
14621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   well-formed = true
14721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   element-content-whitespace = true
14821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   comments = true
14921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *   namespaces = true.
15021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * Querying this returns true if all of the above parameters have the
15121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * listed values; false otherwise.
15221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
15321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("infoset", new BooleanParameter() {
15421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
15521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                // validate-if-schema is always false
15621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                // element-content-whitespace is always true
15721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                // namespace-declarations is always true
15821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return !config.entities
15921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                        && !config.datatypeNormalization
16021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                        && !config.cdataSections
16121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                        && config.wellFormed
16221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                        && config.comments
16321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                        && config.namespaces;
16421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
16521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
16621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                if ((Boolean) value) {
16721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    // validate-if-schema is always false
16821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    // element-content-whitespace is always true
16921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    // namespace-declarations is always true
17021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.entities = false;
17121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.datatypeNormalization = false;
17221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.cdataSections = false;
17321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.wellFormed = true;
17421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.comments = true;
17521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    config.namespaces = true;
17621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                }
17721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
17821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
17921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
18021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
18121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to perform namespace processing; false for none.
18221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
18321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("namespaces", new BooleanParameter() {
18421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
18521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.namespaces;
18621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
18721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
18821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.namespaces = (Boolean) value;
18921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
19021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
19121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
19221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /**
19321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to include namespace declarations; false to discard them
19421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * (unsupported). Even when namespace declarations are discarded,
19521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * prefixes are retained.
19621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *
19721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * Has no effect if namespaces is false.
19821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
19921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("namespace-declarations", new FixedParameter(true));
20021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
20121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
20221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to fully normalize characters (unsupported).
20321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
20421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("normalize-characters", new FixedParameter(false));
20521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
20621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
20721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * A list of whitespace-separated URIs representing the schemas to validate
20821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * against. Has no effect if schema-type is null.
20921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
21021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("schema-location", new Parameter() {
21121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
21221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.schemaLocation;
21321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
21421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
21521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.schemaLocation = (String) value;
21621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
21721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public boolean canSet(DOMConfigurationImpl config, Object value) {
21821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return value == null || value instanceof String;
21921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
22021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
22121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
22221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
22321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * URI representing the type of schema language, such as
22421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * "http://www.w3.org/2001/XMLSchema" or "http://www.w3.org/TR/REC-xml".
22521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
22621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("schema-type", new Parameter() {
22721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
22821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.schemaType;
22921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
23021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
23121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.schemaType = (String) value;
23221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
23321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public boolean canSet(DOMConfigurationImpl config, Object value) {
23421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return value == null || value instanceof String;
23521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
23621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
23721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
23821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
23921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to split CDATA sections containing "]]>"; false to signal an
24021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * error instead.
24121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
24221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("split-cdata-sections", new BooleanParameter() {
24321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
24421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.splitCdataSections;
24521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
24621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
24721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.splitCdataSections = (Boolean) value;
24821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
24921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
25021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
25121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
25221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to require validation against a schema or DTD. Validation will
25321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * recompute element content whitespace, ID and schema type data.
25421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         *
25521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * Setting this unsets validate-if-schema.
25621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
25721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("validate", new BooleanParameter() {
25821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
25921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.validate;
26021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
26121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
26221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                // validate-if-schema is always false
26321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.validate = (Boolean) value;
26421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
26521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
26621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
26721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
26821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to validate if a schema was declared (unsupported). Setting this
26921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * unsets validate.
27021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
27121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("validate-if-schema", new FixedParameter(false));
27221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
27321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        /*
27421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * True to report invalid characters in node names, attributes, elements,
27521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         * comments, text, CDATA sections and processing instructions.
27621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson         */
27721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        PARAMETERS.put("well-formed", new BooleanParameter() {
27821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public Object get(DOMConfigurationImpl config) {
27921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return config.wellFormed;
28021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
28121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
28221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                config.wellFormed = (Boolean) value;
28321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
28421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        });
28521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
28621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        // TODO add "resource-resolver" property for use with LS feature...
28721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    }
28821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
28921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private boolean cdataSections = true;
29021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private boolean comments = true;
29121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private boolean datatypeNormalization = false;
29221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private boolean entities = true;
29321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private DOMErrorHandler errorHandler;
29421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private boolean namespaces = true;
29521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private String schemaLocation;
29621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private String schemaType;
29721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private boolean splitCdataSections = true;
29821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private boolean validate = false;
29921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    private boolean wellFormed = true;
30021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
30121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    interface Parameter {
30221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        Object get(DOMConfigurationImpl config);
30321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        void set(DOMConfigurationImpl config, Object value);
30421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        boolean canSet(DOMConfigurationImpl config, Object value);
30521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    }
30621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
30721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    static class FixedParameter implements Parameter {
30821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        final Object onlyValue;
30921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        FixedParameter(Object onlyValue) {
31021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            this.onlyValue = onlyValue;
31121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        }
31221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        public Object get(DOMConfigurationImpl config) {
31321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            return onlyValue;
31421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        }
31521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        public void set(DOMConfigurationImpl config, Object value) {
31621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            if (!onlyValue.equals(value)) {
31721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
31821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                        "Unsupported value: " + value);
31921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
32021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        }
32121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        public boolean canSet(DOMConfigurationImpl config, Object value) {
32221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            return onlyValue.equals(value);
32321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        }
32421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    }
32521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
32621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    static abstract class BooleanParameter implements Parameter {
32721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        public boolean canSet(DOMConfigurationImpl config, Object value) {
32821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            return value instanceof Boolean;
32921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        }
33021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    }
33121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
33221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    public boolean canSetParameter(String name, Object value) {
33321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        Parameter parameter = PARAMETERS.get(name);
33421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        return parameter != null && parameter.canSet(this, value);
33521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    }
33621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
33721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    public void setParameter(String name, Object value) throws DOMException {
33821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        Parameter parameter = PARAMETERS.get(name);
33921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        if (parameter == null) {
34021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            throw new DOMException(DOMException.NOT_FOUND_ERR, "No such parameter: " + name);
34121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        }
34221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        try {
34321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            parameter.set(this, value);
34421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        } catch (NullPointerException e) {
34521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            throw new DOMException(DOMException.TYPE_MISMATCH_ERR,
34621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    "Null not allowed for " + name);
34721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        } catch (ClassCastException e) {
34821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            throw new DOMException(DOMException.TYPE_MISMATCH_ERR,
34921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                    "Invalid type for " + name + ": " + value.getClass());
35021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        }
35121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    }
35221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
35321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    public Object getParameter(String name) throws DOMException {
35421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        Parameter parameter = PARAMETERS.get(name);
35521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        if (parameter == null) {
35621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            throw new DOMException(DOMException.NOT_FOUND_ERR, "No such parameter: " + name);
35721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        }
35821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        return parameter.get(this);
35921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    }
36021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson
36121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    public DOMStringList getParameterNames() {
36221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        final String[] result = PARAMETERS.keySet().toArray(new String[PARAMETERS.size()]);
36321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        return new DOMStringList() {
36421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public String item(int index) {
36521d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return index < result.length ? result[index] : null;
36621d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
36721d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public int getLength() {
36821d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return result.length;
36921d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
37021d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            public boolean contains(String str) {
37121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson                return PARAMETERS.containsKey(str); // case-insensitive.
37221d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson            }
37321d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson        };
37421d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson    }
375e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
376e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    public void normalize(Node node) {
377e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        /*
378e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson         * Since we don't validate, this code doesn't take into account the
379e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson         * following "supported" parameters: datatype-normalization, entities,
380e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson         * schema-location, schema-type, or validate.
381e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson         *
382e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson         * TODO: normalize namespaces
383e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson         */
384e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
385e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        switch (node.getNodeType()) {
386e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.CDATA_SECTION_NODE:
387e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                CDATASectionImpl cdata = (CDATASectionImpl) node;
388e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                if (cdataSections) {
389e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    if (cdata.needsSplitting()) {
390e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                        if (splitCdataSections) {
391e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                            cdata.split();
392e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                            report(DOMError.SEVERITY_WARNING, "cdata-sections-splitted");
393e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                        } else {
394e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                            report(DOMError.SEVERITY_ERROR, "wf-invalid-character");
395e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                        }
396e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    }
397e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    checkTextValidity(cdata.buffer);
398e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    break;
399e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                }
400e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                node = cdata.replaceWithText();
401e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                // fall through
402e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
403e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.TEXT_NODE:
404e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                TextImpl text = (TextImpl) node;
405e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                text = text.minimize();
406e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                if (text != null) {
407e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    checkTextValidity(text.buffer);
408e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                }
409e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                break;
410e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
411e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.COMMENT_NODE:
412e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                CommentImpl comment = (CommentImpl) node;
413e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                if (!comments) {
414e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    comment.getParentNode().removeChild(comment);
415e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    break;
416e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                }
417e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                if (comment.containsDashDash()) {
418e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    report(DOMError.SEVERITY_ERROR, "wf-invalid-character");
419e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                }
420e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                checkTextValidity(comment.buffer);
421e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                break;
422e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
423e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.PROCESSING_INSTRUCTION_NODE:
424e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                checkTextValidity(((ProcessingInstructionImpl) node).getData());
425e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                break;
426e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
427e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.ATTRIBUTE_NODE:
428e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                checkTextValidity(((AttrImpl) node).getValue());
429e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                break;
430e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
431e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.ELEMENT_NODE:
432e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                ElementImpl element = (ElementImpl) node;
433e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                NamedNodeMap attributes = element.getAttributes();
434e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                for (int i = 0; i < attributes.getLength(); i++) {
435e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    normalize(attributes.item(i));
436e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                }
437e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                // fall through
438e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
439e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.DOCUMENT_NODE:
440e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.DOCUMENT_FRAGMENT_NODE:
441e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                Node next;
442e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                for (Node child = node.getFirstChild(); child != null; child = next) {
443e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    // lookup next eagerly because normalize() may remove its subject
444e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    next = child.getNextSibling();
445e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    normalize(child);
446e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                }
447e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                break;
448e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
449e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.NOTATION_NODE:
450e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.DOCUMENT_TYPE_NODE:
451e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.ENTITY_NODE:
452e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            case Node.ENTITY_REFERENCE_NODE:
453e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                break;
454e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
455e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            default:
456e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
457e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                        "Unsupported node type " + node.getNodeType());
458e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        }
459e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    }
460e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
461e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    private void checkTextValidity(CharSequence s) {
462e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        if (wellFormed && !isValid(s)) {
463e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            report(DOMError.SEVERITY_ERROR, "wf-invalid-character");
464e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        }
465e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    }
466e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
467e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    /**
468e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson     * Returns true if all of the characters in the text are permitted for use
469e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson     * in XML documents.
470e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson     */
471e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    private boolean isValid(CharSequence text) {
472e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        for (int i = 0; i < text.length(); i++) {
473e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            char c = text.charAt(i);
474e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            // as defined by http://www.w3.org/TR/REC-xml/#charsets.
475e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            boolean valid = c == 0x9 || c == 0xA || c == 0xD
476e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    || (c >= 0x20 && c <= 0xd7ff)
477e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                    || (c >= 0xe000 && c <= 0xfffd);
478e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            if (!valid) {
479e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson                return false;
480e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            }
481e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        }
482e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        return true;
483e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    }
484e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson
485e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    private void report(short severity, String type) {
486e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        if (errorHandler != null) {
487e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            // TODO: abort if handleError returns false
488e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson            errorHandler.handleError(new DOMErrorImpl(severity, type, type));
489e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson        }
490e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson    }
49121d27c095fee51fd6eac6a68d50b79df4dc97d85Jesse Wilson}
492