1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xerces.internal.impl.xs.identity;
23
24import com.sun.org.apache.xerces.internal.impl.xpath.XPathException;
25import com.sun.org.apache.xerces.internal.util.SymbolTable;
26import com.sun.org.apache.xerces.internal.util.XMLChar;
27import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
28import com.sun.org.apache.xerces.internal.xni.QName;
29import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
30import com.sun.org.apache.xerces.internal.xs.ShortList;
31import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
32
33/**
34 * Schema identity constraint selector.
35 *
36 * @xerces.internal
37 *
38 * @author Andy Clark, IBM
39 */
40public class Selector {
41
42    //
43    // Data
44    //
45
46    /** XPath. */
47    protected final Selector.XPath fXPath;
48
49    /** Identity constraint. */
50    protected final IdentityConstraint fIdentityConstraint;
51
52    // the Identity constraint we're the matcher for.  Only
53    // used for selectors!
54    protected IdentityConstraint fIDConstraint;
55
56    //
57    // Constructors
58    //
59
60    /** Constructs a selector. */
61    public Selector(Selector.XPath xpath,
62                    IdentityConstraint identityConstraint) {
63        fXPath = xpath;
64        fIdentityConstraint = identityConstraint;
65    } // <init>(Selector.XPath,IdentityConstraint)
66
67    //
68    // Public methods
69    //
70
71    /** Returns the selector XPath. */
72    public com.sun.org.apache.xerces.internal.impl.xpath.XPath getXPath() {
73        return fXPath;
74    } // getXPath():com.sun.org.apache.xerces.internal.v1.schema.identity.XPath
75
76    /** Returns the identity constraint. */
77    public IdentityConstraint getIDConstraint() {
78        return fIdentityConstraint;
79    } // getIDConstraint():IdentityConstraint
80
81    // factory method
82
83    /** Creates a selector matcher.
84     * @param activator     The activator for this selector's fields.
85     * @param initialDepth  The depth in the document at which this matcher began its life;
86     *                          used in correctly handling recursive elements.
87     */
88    public XPathMatcher createMatcher(FieldActivator activator, int initialDepth) {
89        return new Selector.Matcher(fXPath, activator, initialDepth);
90    } // createMatcher(FieldActivator):XPathMatcher
91
92    //
93    // Object methods
94    //
95
96    /** Returns a string representation of this object. */
97    public String toString() {
98        return fXPath.toString();
99    } // toString():String
100
101    //
102    // Classes
103    //
104
105    /**
106     * Schema identity constraint selector XPath expression.
107     *
108     * @author Andy Clark, IBM
109     */
110    public static class XPath
111    extends com.sun.org.apache.xerces.internal.impl.xpath.XPath {
112
113        //
114        // Constructors
115        //
116
117        /** Constructs a selector XPath expression. */
118        public XPath(String xpath, SymbolTable symbolTable,
119                     NamespaceContext context) throws XPathException {
120            super(normalize(xpath), symbolTable, context);
121            // verify that an attribute is not selected
122            for (int i=0;i<fLocationPaths.length;i++) {
123                com.sun.org.apache.xerces.internal.impl.xpath.XPath.Axis axis =
124                fLocationPaths[i].steps[fLocationPaths[i].steps.length-1].axis;
125                if (axis.type == XPath.Axis.ATTRIBUTE) {
126                    throw new XPathException("c-selector-xpath");
127                }
128            }
129
130        } // <init>(String,SymbolTable,NamespacesScope)
131
132        private static String normalize(String xpath) {
133            // NOTE: We have to prefix the selector XPath with "./" in
134            //       order to handle selectors such as "." that select
135            //       the element container because the fields could be
136            //       relative to that element. -Ac
137            //       Unless xpath starts with a descendant node -Achille Fokoue
138            //      ... or a '.' or a '/' - NG
139            //  And we also need to prefix exprs to the right of | with ./ - NG
140            StringBuffer modifiedXPath = new StringBuffer(xpath.length()+5);
141            int unionIndex = -1;
142            do {
143                if(!(XMLChar.trim(xpath).startsWith("/") || XMLChar.trim(xpath).startsWith("."))) {
144                    modifiedXPath.append("./");
145                }
146                unionIndex = xpath.indexOf('|');
147                if(unionIndex == -1) {
148                    modifiedXPath.append(xpath);
149                    break;
150                }
151                modifiedXPath.append(xpath.substring(0,unionIndex+1));
152                xpath = xpath.substring(unionIndex+1, xpath.length());
153            } while(true);
154            return modifiedXPath.toString();
155        }
156
157    } // class Selector.XPath
158
159    /**
160     * Selector matcher.
161     *
162     * @author Andy Clark, IBM
163     */
164    public class Matcher
165    extends XPathMatcher {
166
167        //
168        // Data
169        //
170
171        /** Field activator. */
172        protected final FieldActivator fFieldActivator;
173
174        /** Initial depth in the document at which this matcher was created. */
175        protected final int fInitialDepth;
176
177        /** Element depth. */
178        protected int fElementDepth;
179
180        /** Depth at match. */
181        protected int fMatchedDepth;
182
183        //
184        // Constructors
185        //
186
187        /** Constructs a selector matcher. */
188        public Matcher(Selector.XPath xpath, FieldActivator activator,
189                int initialDepth) {
190            super(xpath);
191            fFieldActivator = activator;
192            fInitialDepth = initialDepth;
193        } // <init>(Selector.XPath,FieldActivator)
194
195        //
196        // XMLDocumentFragmentHandler methods
197        //
198
199        public void startDocumentFragment(){
200            super.startDocumentFragment();
201            fElementDepth = 0;
202            fMatchedDepth = -1;
203        } // startDocumentFragment()
204
205        /**
206         * The start of an element. If the document specifies the start element
207         * by using an empty tag, then the startElement method will immediately
208         * be followed by the endElement method, with no intervening methods.
209         *
210         * @param element    The name of the element.
211         * @param attributes The element attributes.
212         *
213         */
214        public void startElement(QName element, XMLAttributes attributes) {
215            super.startElement(element, attributes);
216            fElementDepth++;
217            // activate the fields, if selector is matched
218            //int matched = isMatched();
219
220            if (isMatched()) {
221/*            (fMatchedDepth == -1 && ((matched & MATCHED) == MATCHED)) ||
222                    ((matched & MATCHED_DESCENDANT) == MATCHED_DESCENDANT)) { */
223                fMatchedDepth = fElementDepth;
224                fFieldActivator.startValueScopeFor(fIdentityConstraint, fInitialDepth);
225                int count = fIdentityConstraint.getFieldCount();
226                for (int i = 0; i < count; i++) {
227                    Field field = fIdentityConstraint.getFieldAt(i);
228                    XPathMatcher matcher = fFieldActivator.activateField(field, fInitialDepth);
229                    matcher.startElement(element, attributes);
230                }
231            }
232
233        } // startElement(QName,XMLAttrList,int)
234
235        public void endElement(QName element, XSTypeDefinition type, boolean nillable, Object actualValue, short valueType, ShortList itemValueType) {
236            super.endElement(element, type, nillable, actualValue, valueType, itemValueType);
237            if (fElementDepth-- == fMatchedDepth) {
238                fMatchedDepth = -1;
239                fFieldActivator.endValueScopeFor(fIdentityConstraint, fInitialDepth);
240            }
241        }
242
243        /** Returns the identity constraint. */
244        public IdentityConstraint getIdentityConstraint() {
245            return fIdentityConstraint;
246        } // getIdentityConstraint():IdentityConstraint
247
248        /** get the initial depth at which this selector matched. */
249        public int getInitialDepth() {
250            return fInitialDepth;
251        } // getInitialDepth():  int
252
253
254    } // class Matcher
255
256} // class Selector
257