181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson/*
281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * Copyright (C) 2010 The Android Open Source Project
381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson *
481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * you may not use this file except in compliance with the License.
681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * You may obtain a copy of the License at
781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson *
881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson *
1081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * Unless required by applicable law or agreed to in writing, software
1181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
1281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * See the License for the specific language governing permissions and
1481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * limitations under the License.
1581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson */
1681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
1781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilsonpackage org.apache.harmony.xml.dom;
1881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
197365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.util.Map;
207365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.util.TreeMap;
2181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilsonimport org.w3c.dom.DOMConfiguration;
228092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilsonimport org.w3c.dom.DOMError;
2381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilsonimport org.w3c.dom.DOMErrorHandler;
2481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilsonimport org.w3c.dom.DOMException;
2581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilsonimport org.w3c.dom.DOMStringList;
268092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilsonimport org.w3c.dom.NamedNodeMap;
278092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilsonimport org.w3c.dom.Node;
2881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
2981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson/**
3081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson * A minimal implementation of DOMConfiguration. This implementation uses inner
315501a3d4b3d7657c183ed5446fe67fa011fbf70bElliott Hughes * parameter instances to centralize each parameter's behavior.
3281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson */
3381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilsonpublic final class DOMConfigurationImpl implements DOMConfiguration {
3481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
3581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private static final Map<String, Parameter> PARAMETERS
3681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            = new TreeMap<String, Parameter>(String.CASE_INSENSITIVE_ORDER);
3781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
3881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    static {
3981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
4081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to canonicalize the document (unsupported). This includes
4181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * removing DocumentType nodes from the tree and removing unused
4281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * namespace declarations. Setting this to true also sets these
4381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * parameters:
4481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   entities = false
4581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   normalize-characters = false
4681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   cdata-sections = false
4781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   namespaces = true
4881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   namespace-declarations = true
4981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   well-formed = true
5081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   element-content-whitespace = true
5181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * Setting these parameters to another value shall revert the canonical
5281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * form to false.
5381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
5481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("canonical-form", new FixedParameter(false));
5581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
5681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
5781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to keep existing CDATA nodes; false to replace them/merge them
5881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * into adjacent text nodes.
5981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
6081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("cdata-sections", new BooleanParameter() {
6181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
6281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.cdataSections;
6381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
6481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
6581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.cdataSections = (Boolean) value;
6681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
6781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
6881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
6981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
7081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to check character normalization (unsupported).
7181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
7281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("check-character-normalization", new FixedParameter(false));
7381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
7481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
7581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to keep comments in the document; false to discard them.
7681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
7781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("comments", new BooleanParameter() {
7881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
7981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.comments;
8081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
8181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
8281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.comments = (Boolean) value;
8381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
8481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
8581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
8681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
8781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to expose schema normalized values. Setting this to true sets
8881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * the validate parameter to true. Has no effect when validate is false.
8981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
9081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("datatype-normalization", new BooleanParameter() {
9181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
9281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.datatypeNormalization;
9381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
9481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
9581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                if ((Boolean) value) {
9681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.datatypeNormalization = true;
9781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.validate = true;
9881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                } else {
9981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.datatypeNormalization = false;
10081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                }
10181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
10281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
10381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
10481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
10581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to keep whitespace elements in the document; false to discard
10681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * them (unsupported).
10781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
10881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("element-content-whitespace", new FixedParameter(true));
10981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
11081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
11181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to keep entity references in the document; false to expand them.
11281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
11381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("entities", new BooleanParameter() {
11481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
11581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.entities;
11681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
11781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
11881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.entities = (Boolean) value;
11981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
12081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
12181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
12281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
12381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * Handler to be invoked when errors are encountered.
12481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
12581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("error-handler", new Parameter() {
12681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
12781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.errorHandler;
12881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
12981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
13081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.errorHandler = (DOMErrorHandler) value;
13181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
13281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public boolean canSet(DOMConfigurationImpl config, Object value) {
13381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return value == null || value instanceof DOMErrorHandler;
13481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
13581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
13681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
13781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
13881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * Bulk alias to set the following parameter values:
13981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   validate-if-schema = false
14081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   entities = false
14181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   datatype-normalization = false
14281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   cdata-sections = false
14381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   namespace-declarations = true
14481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   well-formed = true
14581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   element-content-whitespace = true
14681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   comments = true
14781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *   namespaces = true.
14881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * Querying this returns true if all of the above parameters have the
14981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * listed values; false otherwise.
15081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
15181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("infoset", new BooleanParameter() {
15281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
15381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                // validate-if-schema is always false
15481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                // element-content-whitespace is always true
15581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                // namespace-declarations is always true
15681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return !config.entities
15781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                        && !config.datatypeNormalization
15881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                        && !config.cdataSections
15981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                        && config.wellFormed
16081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                        && config.comments
16181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                        && config.namespaces;
16281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
16381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
16481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                if ((Boolean) value) {
16581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    // validate-if-schema is always false
16681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    // element-content-whitespace is always true
16781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    // namespace-declarations is always true
16881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.entities = false;
16981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.datatypeNormalization = false;
17081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.cdataSections = false;
17181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.wellFormed = true;
17281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.comments = true;
17381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    config.namespaces = true;
17481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                }
17581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
17681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
17781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
17881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
17981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to perform namespace processing; false for none.
18081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
18181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("namespaces", new BooleanParameter() {
18281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
18381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.namespaces;
18481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
18581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
18681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.namespaces = (Boolean) value;
18781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
18881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
18981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
19081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /**
19181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to include namespace declarations; false to discard them
19281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * (unsupported). Even when namespace declarations are discarded,
19381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * prefixes are retained.
19481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *
19581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * Has no effect if namespaces is false.
19681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
19781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("namespace-declarations", new FixedParameter(true));
19881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
19981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
20081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to fully normalize characters (unsupported).
20181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
20281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("normalize-characters", new FixedParameter(false));
20381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
20481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
20581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * A list of whitespace-separated URIs representing the schemas to validate
20681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * against. Has no effect if schema-type is null.
20781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
20881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("schema-location", new Parameter() {
20981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
21081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.schemaLocation;
21181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
21281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
21381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.schemaLocation = (String) value;
21481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
21581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public boolean canSet(DOMConfigurationImpl config, Object value) {
21681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return value == null || value instanceof String;
21781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
21881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
21981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
22081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
22181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * URI representing the type of schema language, such as
22281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * "http://www.w3.org/2001/XMLSchema" or "http://www.w3.org/TR/REC-xml".
22381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
22481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("schema-type", new Parameter() {
22581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
22681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.schemaType;
22781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
22881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
22981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.schemaType = (String) value;
23081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
23181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public boolean canSet(DOMConfigurationImpl config, Object value) {
23281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return value == null || value instanceof String;
23381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
23481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
23581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
23681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
23781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to split CDATA sections containing "]]>"; false to signal an
23881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * error instead.
23981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
24081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("split-cdata-sections", new BooleanParameter() {
24181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
24281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.splitCdataSections;
24381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
24481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
24581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.splitCdataSections = (Boolean) value;
24681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
24781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
24881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
24981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
25081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to require validation against a schema or DTD. Validation will
25181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * recompute element content whitespace, ID and schema type data.
25281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         *
25381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * Setting this unsets validate-if-schema.
25481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
25581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("validate", new BooleanParameter() {
25681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
25781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.validate;
25881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
25981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
26081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                // validate-if-schema is always false
26181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.validate = (Boolean) value;
26281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
26381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
26481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
26581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
26681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to validate if a schema was declared (unsupported). Setting this
26781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * unsets validate.
26881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
26981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("validate-if-schema", new FixedParameter(false));
27081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
27181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        /*
27281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * True to report invalid characters in node names, attributes, elements,
27381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         * comments, text, CDATA sections and processing instructions.
27481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson         */
27581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        PARAMETERS.put("well-formed", new BooleanParameter() {
27681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public Object get(DOMConfigurationImpl config) {
27781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return config.wellFormed;
27881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
27981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public void set(DOMConfigurationImpl config, Object value) {
28081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                config.wellFormed = (Boolean) value;
28181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
28281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        });
28381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
28481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        // TODO add "resource-resolver" property for use with LS feature...
28581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    }
28681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
28781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private boolean cdataSections = true;
28881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private boolean comments = true;
28981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private boolean datatypeNormalization = false;
29081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private boolean entities = true;
29181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private DOMErrorHandler errorHandler;
29281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private boolean namespaces = true;
29381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private String schemaLocation;
29481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private String schemaType;
29581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private boolean splitCdataSections = true;
29681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private boolean validate = false;
29781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    private boolean wellFormed = true;
29881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
29981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    interface Parameter {
30081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        Object get(DOMConfigurationImpl config);
30181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        void set(DOMConfigurationImpl config, Object value);
30281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        boolean canSet(DOMConfigurationImpl config, Object value);
30381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    }
30481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
30581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    static class FixedParameter implements Parameter {
30681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        final Object onlyValue;
30781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        FixedParameter(Object onlyValue) {
30881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            this.onlyValue = onlyValue;
30981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        }
31081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        public Object get(DOMConfigurationImpl config) {
31181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            return onlyValue;
31281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        }
31381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        public void set(DOMConfigurationImpl config, Object value) {
31481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            if (!onlyValue.equals(value)) {
31581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
31681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                        "Unsupported value: " + value);
31781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
31881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        }
31981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        public boolean canSet(DOMConfigurationImpl config, Object value) {
32081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            return onlyValue.equals(value);
32181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        }
32281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    }
32381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
32481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    static abstract class BooleanParameter implements Parameter {
32581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        public boolean canSet(DOMConfigurationImpl config, Object value) {
32681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            return value instanceof Boolean;
32781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        }
32881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    }
32981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
33081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    public boolean canSetParameter(String name, Object value) {
33181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        Parameter parameter = PARAMETERS.get(name);
33281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        return parameter != null && parameter.canSet(this, value);
33381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    }
33481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
33581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    public void setParameter(String name, Object value) throws DOMException {
33681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        Parameter parameter = PARAMETERS.get(name);
33781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        if (parameter == null) {
33881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            throw new DOMException(DOMException.NOT_FOUND_ERR, "No such parameter: " + name);
33981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        }
34081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        try {
34181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            parameter.set(this, value);
34281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        } catch (NullPointerException e) {
34381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            throw new DOMException(DOMException.TYPE_MISMATCH_ERR,
34481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    "Null not allowed for " + name);
34581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        } catch (ClassCastException e) {
34681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            throw new DOMException(DOMException.TYPE_MISMATCH_ERR,
34781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                    "Invalid type for " + name + ": " + value.getClass());
34881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        }
34981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    }
35081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
35181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    public Object getParameter(String name) throws DOMException {
35281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        Parameter parameter = PARAMETERS.get(name);
35381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        if (parameter == null) {
35481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            throw new DOMException(DOMException.NOT_FOUND_ERR, "No such parameter: " + name);
35581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        }
35681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        return parameter.get(this);
35781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    }
35881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
35981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    public DOMStringList getParameterNames() {
36081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        final String[] result = PARAMETERS.keySet().toArray(new String[PARAMETERS.size()]);
36181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        return new DOMStringList() {
36281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public String item(int index) {
36381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return index < result.length ? result[index] : null;
36481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
36581ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public int getLength() {
36681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return result.length;
36781ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
36881ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            public boolean contains(String str) {
36981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson                return PARAMETERS.containsKey(str); // case-insensitive.
37081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            }
37181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson        };
37281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    }
3738092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
3748092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    public void normalize(Node node) {
3758092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        /*
3768092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson         * Since we don't validate, this code doesn't take into account the
3778092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson         * following "supported" parameters: datatype-normalization, entities,
3788092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson         * schema-location, schema-type, or validate.
3798092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson         *
3808092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson         * TODO: normalize namespaces
3818092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson         */
3828092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
3838092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        switch (node.getNodeType()) {
3848092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.CDATA_SECTION_NODE:
3858092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                CDATASectionImpl cdata = (CDATASectionImpl) node;
3868092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                if (cdataSections) {
3878092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    if (cdata.needsSplitting()) {
3888092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                        if (splitCdataSections) {
3898092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                            cdata.split();
3908092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                            report(DOMError.SEVERITY_WARNING, "cdata-sections-splitted");
3918092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                        } else {
3928092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                            report(DOMError.SEVERITY_ERROR, "wf-invalid-character");
3938092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                        }
3948092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    }
3958092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    checkTextValidity(cdata.buffer);
3968092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    break;
3978092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                }
3988092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                node = cdata.replaceWithText();
3998092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                // fall through
4008092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4018092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.TEXT_NODE:
4028092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                TextImpl text = (TextImpl) node;
4038092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                text = text.minimize();
4048092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                if (text != null) {
4058092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    checkTextValidity(text.buffer);
4068092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                }
4078092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                break;
4088092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4098092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.COMMENT_NODE:
4108092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                CommentImpl comment = (CommentImpl) node;
4118092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                if (!comments) {
4128092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    comment.getParentNode().removeChild(comment);
4138092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    break;
4148092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                }
4158092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                if (comment.containsDashDash()) {
4168092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    report(DOMError.SEVERITY_ERROR, "wf-invalid-character");
4178092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                }
4188092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                checkTextValidity(comment.buffer);
4198092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                break;
4208092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4218092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.PROCESSING_INSTRUCTION_NODE:
4228092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                checkTextValidity(((ProcessingInstructionImpl) node).getData());
4238092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                break;
4248092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4258092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.ATTRIBUTE_NODE:
4268092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                checkTextValidity(((AttrImpl) node).getValue());
4278092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                break;
4288092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4298092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.ELEMENT_NODE:
4308092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                ElementImpl element = (ElementImpl) node;
4318092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                NamedNodeMap attributes = element.getAttributes();
4328092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                for (int i = 0; i < attributes.getLength(); i++) {
4338092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    normalize(attributes.item(i));
4348092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                }
4358092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                // fall through
4368092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4378092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.DOCUMENT_NODE:
4388092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.DOCUMENT_FRAGMENT_NODE:
4398092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                Node next;
4408092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                for (Node child = node.getFirstChild(); child != null; child = next) {
4418092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    // lookup next eagerly because normalize() may remove its subject
4428092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    next = child.getNextSibling();
4438092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    normalize(child);
4448092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                }
4458092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                break;
4468092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4478092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.NOTATION_NODE:
4488092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.DOCUMENT_TYPE_NODE:
4498092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.ENTITY_NODE:
4508092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            case Node.ENTITY_REFERENCE_NODE:
4518092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                break;
4528092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4538092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            default:
4548092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
4558092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                        "Unsupported node type " + node.getNodeType());
4568092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        }
4578092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    }
4588092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4598092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    private void checkTextValidity(CharSequence s) {
4608092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        if (wellFormed && !isValid(s)) {
4618092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            report(DOMError.SEVERITY_ERROR, "wf-invalid-character");
4628092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        }
4638092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    }
4648092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4658092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    /**
4668092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * Returns true if all of the characters in the text are permitted for use
4678092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * in XML documents.
4688092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     */
4698092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    private boolean isValid(CharSequence text) {
4708092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        for (int i = 0; i < text.length(); i++) {
4718092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            char c = text.charAt(i);
4728092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            // as defined by http://www.w3.org/TR/REC-xml/#charsets.
4738092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            boolean valid = c == 0x9 || c == 0xA || c == 0xD
4748092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    || (c >= 0x20 && c <= 0xd7ff)
4758092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                    || (c >= 0xe000 && c <= 0xfffd);
4768092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            if (!valid) {
4778092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                return false;
4788092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            }
4798092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        }
4808092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        return true;
4818092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    }
4828092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
4838092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    private void report(short severity, String type) {
4848092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        if (errorHandler != null) {
4858092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            // TODO: abort if handleError returns false
486f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson            errorHandler.handleError(new DOMErrorImpl(severity, type));
4878092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        }
4888092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    }
48981ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson}
490