KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > pde > internal > ui > editor > contentassist > XMLElementProposalComputer


1 /*******************************************************************************
2  * Copyright (c) 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.pde.internal.ui.editor.contentassist;
13
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16
17 import org.eclipse.pde.internal.core.ischema.ISchemaComplexType;
18 import org.eclipse.pde.internal.core.ischema.ISchemaCompositor;
19 import org.eclipse.pde.internal.core.ischema.ISchemaElement;
20 import org.eclipse.pde.internal.core.ischema.ISchemaObject;
21 import org.eclipse.pde.internal.core.text.IDocumentNode;
22
23 /**
24  * XMLElementProposalComputer
25  *
26  */

27 public class XMLElementProposalComputer {
28
29     /**
30      * @param sElement
31      * @param node
32      * @return A set of elements that can be added as children to element,
33      * <code>node</code>, as described by schema element, <code>sElement</code>,
34      * given multiplicity constraints and existing children found under
35      * <code>node</code>.
36      */

37     public static HashSet JavaDoc computeElementProposal(ISchemaElement sElement,
38             IDocumentNode node) {
39         // Calculate the number of occurrences of each XML tag name
40
// in the node's direct children
41
HashMap JavaDoc tagNameMap = countXMLChildrenByTagName(node);
42         return computeElementProposal(sElement, tagNameMap);
43     }
44     
45     /**
46      * @param sElement
47      * @param tagNameMap
48      * @return
49      */

50     private static HashSet JavaDoc computeElementProposal(ISchemaElement sElement,
51             HashMap JavaDoc tagNameMap) {
52         
53         HashSet JavaDoc elementSet = new HashSet JavaDoc();
54         // Get this element's compositor
55
ISchemaCompositor compositor =
56             ((ISchemaComplexType)sElement.getType()).getCompositor();
57         // Track multiplicity
58
int multiplicityTracker = 1;
59         // Process the compositor
60
computeCompositorChildProposal(compositor,
61                 elementSet, tagNameMap, multiplicityTracker);
62         return elementSet;
63     }
64     
65     /**
66      * @param node
67      * @return A hash containing singleton entries of node's children mapped
68      * against the number of occurrences found
69      * Key is children's XML tag name
70      * Value is number of occurrences found amongst siblings
71      */

72     private static HashMap JavaDoc countXMLChildrenByTagName(IDocumentNode node) {
73         IDocumentNode[] children = node.getChildNodes();
74         HashMap JavaDoc tagNameMap = new HashMap JavaDoc();
75         for (int i = 0; i < children.length; i++) {
76             String JavaDoc key = children[i].getXMLTagName();
77             if (tagNameMap.containsKey(key)) {
78                 int value = ((Integer JavaDoc)tagNameMap.get(key)).intValue();
79                 value++;
80                 tagNameMap.put(key, new Integer JavaDoc(value));
81             } else {
82                 tagNameMap.put(key, new Integer JavaDoc(1));
83             }
84         }
85         return tagNameMap;
86     }
87     
88     /**
89      * @param compositor
90      * @param proposalList
91      * @param siblings
92      * @param multiplicityTracker
93      */

94     private static void computeCompositorChildProposal(
95             ISchemaCompositor compositor, HashSet JavaDoc elementSet,
96             HashMap JavaDoc siblings, int multiplicityTracker) {
97         // Compositor can be null only in cases where we had a schema complex
98
// type but that complex type was complex because it had attributes
99
// rather than element children
100
// All we care about is choices and sequences (Alls and groups not
101
// supported)
102
if (compositor == null) {
103             return;
104         } else if (compositor.getKind() == ISchemaCompositor.CHOICE) {
105             computeCompositorChoiceProposal(compositor, elementSet, siblings,
106                     multiplicityTracker);
107         } else if (compositor.getKind() == ISchemaCompositor.SEQUENCE) {
108             computeCompositorSequenceProposal(compositor, elementSet, siblings,
109                     multiplicityTracker);
110         }
111     }
112
113     /**
114      * @param compositor
115      * @param elementSet
116      * @param siblings
117      * @param multiplicityTracker
118      */

119     private static void computeCompositorSequenceProposal(
120             ISchemaCompositor compositor, HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
121             int multiplicityTracker) {
122
123         ISchemaObject[] schemaObject = compositor.getChildren();
124         // Unbounded max occurs are represented by the maximum integer value
125
if (multiplicityTracker < Integer.MAX_VALUE) {
126             // Multiply the max occurs amount to the overall multiplicity
127
multiplicityTracker = compositor.getMaxOccurs() * multiplicityTracker;
128         }
129         // Process the compositors children
130
for (int i = 0; i < compositor.getChildCount(); i++) {
131             computeObjectChildProposal(schemaObject[i], elementSet,
132                     siblings, multiplicityTracker);
133         }
134     }
135     
136     /**
137      * @param compositor
138      * @param elementSet
139      * @param siblings
140      * @param multiplicityTracker
141      */

142     private static void computeCompositorChoiceProposal(
143             ISchemaCompositor compositor, HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
144             int multiplicityTracker) {
145
146         // Unbounded max occurs are represented by the maximum integer value
147
if (multiplicityTracker < Integer.MAX_VALUE) {
148             // Multiply the max occurs amount to the overall multiplicity
149
multiplicityTracker = compositor.getMaxOccurs() * multiplicityTracker;
150         }
151         adjustChoiceSiblings(compositor, siblings);
152         
153         ISchemaObject[] schemaObject = compositor.getChildren();
154         // Process the compositors children
155
for (int i = 0; i < compositor.getChildCount(); i++) {
156             computeObjectChildProposal(schemaObject[i], elementSet,
157                     siblings, multiplicityTracker);
158         }
159     }
160     
161     /**
162      * @param compositor
163      * @param siblings
164      */

165     private static void adjustChoiceSiblings(ISchemaCompositor compositor,
166             HashMap JavaDoc siblings) {
167
168         ISchemaObject[] schemaObject = compositor.getChildren();
169         // Count the number of child element occurrences of the choice
170
// Compositor
171
int childElementCount = 0;
172         for (int i = 0; i < compositor.getChildCount(); i++) {
173             if (schemaObject[i] instanceof ISchemaElement) {
174                 String JavaDoc name = schemaObject[i].getName();
175                 if (siblings.containsKey(name)) {
176                     int occurences = ((Integer JavaDoc)siblings.get(name)).intValue();
177                     childElementCount = childElementCount + occurences;
178                 }
179             }
180         }
181         // Update all child element occurrences of the choice compositor
182
// to the number of occurences found
183
// Each choice occurence counts as one occurence for all child elements
184
// of that choice
185
// IMPORTANT: Any child of choice that is not an element (e.g.
186
// sequence, choice) is not supported, in future could recursively
187
// caculate, but time vs benefit is not worth it
188
for (int i = 0; i < compositor.getChildCount(); i++) {
189             if (schemaObject[i] instanceof ISchemaElement) {
190                 String JavaDoc name = schemaObject[i].getName();
191                 siblings.put(name, new Integer JavaDoc(childElementCount));
192             }
193         }
194     }
195     
196     /**
197      * @param schemaObject
198      * @param proposalList
199      * @param siblings
200      * @param multiplicityTracker
201      */

202     private static void computeObjectChildProposal(ISchemaObject schemaObject,
203             HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
204             int multiplicityTracker) {
205         if (schemaObject instanceof ISchemaElement) {
206             ISchemaElement schemaElement = (ISchemaElement)schemaObject;
207             computeElementChildProposal(schemaElement, elementSet,
208                     siblings, multiplicityTracker);
209         } else if (schemaObject instanceof ISchemaCompositor) {
210             ISchemaCompositor sCompositor = (ISchemaCompositor)schemaObject;
211             computeCompositorChildProposal(sCompositor, elementSet,
212                     siblings, multiplicityTracker);
213         }
214     }
215     
216     /**
217      * @param schemaElement
218      * @param proposalList
219      * @param siblings
220      * @param multiplicityTracker
221      */

222     private static void computeElementChildProposal(ISchemaElement schemaElement,
223             HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
224             int multiplicityTracker) {
225
226         int occurrences = 0;
227         // Determine the number of occurrences found of this element
228
if (siblings.containsKey(schemaElement.getName())) {
229             occurrences = ((Integer JavaDoc) siblings.get(schemaElement.getName()))
230                     .intValue();
231         }
232         // Determine if the elements max occurrences is respected
233
if (multiplicityTracker < Integer.MAX_VALUE) {
234             multiplicityTracker = schemaElement.getMaxOccurs() * multiplicityTracker;
235         }
236         // Only add a new proposal for a given element if it has not exceeded
237
// the multiplicity
238
// Note: This is a simple calculation that does not address all complex
239
// XML Schema multiplity rules. For instance, multiple layers of
240
// choices and sequences compositors coupled with varying siblings
241
// elements require a regex processor
242
// For the PDE space this is not required as extension point schemas
243
// are always very simple
244
if (occurrences < multiplicityTracker) {
245             elementSet.add(schemaElement);
246         }
247     }
248 }
249
Popular Tags