KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > dom > EntityReferenceImpl


1 /*
2  * Copyright 1999-2002,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.dom;
18
19 import org.apache.xerces.util.URI;
20 import org.w3c.dom.DocumentType JavaDoc;
21 import org.w3c.dom.EntityReference JavaDoc;
22 import org.w3c.dom.NamedNodeMap JavaDoc;
23 import org.w3c.dom.Node JavaDoc;
24
25 /**
26  * EntityReference models the XML &entityname; syntax, when used for
27  * entities defined by the DOM. Entities hardcoded into XML, such as
28  * character entities, should instead have been translated into text
29  * by the code which generated the DOM tree.
30  * <P>
31  * An XML processor has the alternative of fully expanding Entities
32  * into the normal document tree. If it does so, no EntityReference nodes
33  * will appear.
34  * <P>
35  * Similarly, non-validating XML processors are not required to read
36  * or process entity declarations made in the external subset or
37  * declared in external parameter entities. Hence, some applications
38  * may not make the replacement value available for Parsed Entities
39  * of these types.
40  * <P>
41  * EntityReference behaves as a read-only node, and the children of
42  * the EntityReference (which reflect those of the Entity, and should
43  * also be read-only) give its replacement value, if any. They are
44  * supposed to automagically stay in synch if the DocumentType is
45  * updated with new values for the Entity.
46  * <P>
47  * The defined behavior makes efficient storage difficult for the DOM
48  * implementor. We can't just look aside to the Entity's definition
49  * in the DocumentType since those nodes have the wrong parent (unless
50  * we can come up with a clever "imaginary parent" mechanism). We
51  * must at least appear to clone those children... which raises the
52  * issue of keeping the reference synchronized with its parent.
53  * This leads me back to the "cached image of centrally defined data"
54  * solution, much as I dislike it.
55  * <P>
56  * For now I have decided, since REC-DOM-Level-1-19980818 doesn't
57  * cover this in much detail, that synchronization doesn't have to be
58  * considered while the user is deep in the tree. That is, if you're
59  * looking within one of the EntityReferennce's children and the Entity
60  * changes, you won't be informed; instead, you will continue to access
61  * the same object -- which may or may not still be part of the tree.
62  * This is the same behavior that obtains elsewhere in the DOM if the
63  * subtree you're looking at is deleted from its parent, so it's
64  * acceptable here. (If it really bothers folks, we could set things
65  * up so deleted subtrees are walked and marked invalid, but that's
66  * not part of the DOM's defined behavior.)
67  * <P>
68  * As a result, only the EntityReference itself has to be aware of
69  * changes in the Entity. And it can take advantage of the same
70  * structure-change-monitoring code I implemented to support
71  * DeepNodeList.
72  *
73  * @xerces.internal
74  *
75  * @author Arnaud Le Hors, IBM
76  * @author Joe Kesselman, IBM
77  * @author Andy Clark, IBM
78  * @author Ralf Pfeiffer, IBM
79  * @version $Id: EntityReferenceImpl.java,v 1.27 2004/10/05 17:12:51 mrglavas Exp $
80  * @since PR-DOM-Level-1-19980818.
81  */

82 public class EntityReferenceImpl
83 extends ParentNode
84 implements EntityReference JavaDoc {
85
86     //
87
// Constants
88
//
89

90     /** Serialization version. */
91     static final long serialVersionUID = -7381452955687102062L;
92
93     //
94
// Data
95
//
96

97     /** Name of Entity referenced */
98     protected String JavaDoc name;
99     /** Base URI*/
100     protected String JavaDoc baseURI;
101     
102
103     /** Entity changes. */
104     //protected int entityChanges = -1;
105

106     /** Enable synchronize. */
107     //protected boolean fEnableSynchronize = false;
108

109     //
110
// Constructors
111
//
112

113     /** Factory constructor. */
114     public EntityReferenceImpl(CoreDocumentImpl ownerDoc, String JavaDoc name) {
115         super(ownerDoc);
116         this.name = name;
117         isReadOnly(true);
118         needsSyncChildren(true);
119     }
120
121     //
122
// Node methods
123
//
124

125     /**
126      * A short integer indicating what type of node this is. The named
127      * constants for this value are defined in the org.w3c.dom.Node interface.
128      */

129     public short getNodeType() {
130         return Node.ENTITY_REFERENCE_NODE;
131     }
132
133     /**
134      * Returns the name of the entity referenced
135      */

136     public String JavaDoc getNodeName() {
137         if (needsSyncData()) {
138             synchronizeData();
139         }
140         return name;
141     }
142
143     /** Clone node. */
144     public Node JavaDoc cloneNode(boolean deep) {
145         EntityReferenceImpl er = (EntityReferenceImpl)super.cloneNode(deep);
146         er.setReadOnly(true, deep);
147         return er;
148     }
149
150     /**
151      * Returns the absolute base URI of this node or null if the implementation
152      * wasn't able to obtain an absolute URI. Note: If the URI is malformed, a
153      * null is returned.
154      *
155      * @return The absolute base URI of this node or null.
156      * @since DOM Level 3
157      */

158     public String JavaDoc getBaseURI() {
159         if (needsSyncData()) {
160             synchronizeData();
161         }
162         if (baseURI == null) {
163             DocumentType JavaDoc doctype;
164             NamedNodeMap JavaDoc entities;
165             EntityImpl entDef;
166             if (null != (doctype = getOwnerDocument().getDoctype()) &&
167                 null != (entities = doctype.getEntities())) {
168
169                 entDef = (EntityImpl)entities.getNamedItem(getNodeName());
170                 if (entDef !=null) {
171                     return entDef.getBaseURI();
172                 }
173             }
174         } else if (baseURI != null && baseURI.length() != 0 ) {// attribute value is always empty string
175
try {
176                 return new URI(baseURI).toString();
177             }
178             catch (org.apache.xerces.util.URI.MalformedURIException e){
179                 // REVISIT: what should happen in this case?
180
return null;
181             }
182         }
183         return baseURI;
184     }
185
186
187     /** NON-DOM: set base uri*/
188     public void setBaseURI(String JavaDoc uri){
189         if (needsSyncData()) {
190             synchronizeData();
191         }
192         baseURI = uri;
193     }
194     
195     /**
196      * NON-DOM: compute string representation of the entity reference.
197      * This method is used to retrieve a string value for an attribute node that has child nodes.
198      * @return String representing a value of this entity ref. or
199      * null if any node other than EntityReference, Text is encountered
200      * during computation
201      */

202     protected String JavaDoc getEntityRefValue (){
203         if (needsSyncChildren()){
204             synchronizeChildren();
205         }
206        
207         String JavaDoc value = "";
208         if (firstChild != null){
209           if (firstChild.getNodeType() == Node.ENTITY_REFERENCE_NODE){
210               value = ((EntityReferenceImpl)firstChild).getEntityRefValue();
211           }
212           else if (firstChild.getNodeType() == Node.TEXT_NODE){
213             value = firstChild.getNodeValue();
214           }
215           else {
216              // invalid to have other types of nodes in attr value
217
return null;
218           }
219           
220           if (firstChild.nextSibling == null){
221             return value;
222           }
223           else {
224             StringBuffer JavaDoc buff = new StringBuffer JavaDoc(value);
225             ChildNode next = firstChild.nextSibling;
226             while (next != null){
227             
228                 if (next.getNodeType() == Node.ENTITY_REFERENCE_NODE){
229                    value = ((EntityReferenceImpl)next).getEntityRefValue();
230                 }
231                 else if (next.getNodeType() == Node.TEXT_NODE){
232                   value = next.getNodeValue();
233                 }
234                 else {
235                     // invalid to have other types of nodes in attr value
236
return null;
237                 }
238                 buff.append(value);
239                 next = next.nextSibling;
240
241             }
242             return buff.toString();
243           }
244         }
245         return "";
246     }
247
248     /**
249      * EntityReference's children are a reflection of those defined in the
250      * named Entity. This method creates them if they haven't been created yet.
251      * This doesn't support editing the Entity though, since this only called
252      * once for all.
253      */

254     protected void synchronizeChildren() {
255         // no need to synchronize again
256
needsSyncChildren(false);
257
258         DocumentType JavaDoc doctype;
259         NamedNodeMap JavaDoc entities;
260         EntityImpl entDef;
261         if (null != (doctype = getOwnerDocument().getDoctype()) &&
262             null != (entities = doctype.getEntities())) {
263
264             entDef = (EntityImpl)entities.getNamedItem(getNodeName());
265
266             // No Entity by this name, stop here.
267
if (entDef == null)
268                 return;
269
270             // If entity's definition exists, clone its kids
271
isReadOnly(false);
272             for (Node JavaDoc defkid = entDef.getFirstChild();
273                 defkid != null;
274                 defkid = defkid.getNextSibling()) {
275                 Node JavaDoc newkid = defkid.cloneNode(true);
276                 insertBefore(newkid, null);
277             }
278             setReadOnly(true, true);
279         }
280     }
281
282
283     /**
284      * NON-DOM: sets the node and its children value.
285      * <P>
286      * Note: make sure that entity reference and its kids could be set readonly.
287      */

288     public void setReadOnly(boolean readOnly, boolean deep) {
289
290         if (needsSyncData()) {
291             synchronizeData();
292         }
293         if (deep) {
294
295             if (needsSyncChildren()) {
296                 synchronizeChildren();
297             }
298             // Recursively set kids
299
for (ChildNode mykid = firstChild;
300                  mykid != null;
301                  mykid = mykid.nextSibling) {
302                      
303                 mykid.setReadOnly(readOnly,true);
304                 
305             }
306         }
307         isReadOnly(readOnly);
308     } // setReadOnly(boolean,boolean)
309

310
311     /**
312      * Enable the synchronize method which may do cloning. This method is enabled
313      * when the parser is done with an EntityReference.
314     /***
315     // revisit: enable editing of Entity
316     public void enableSynchronize(boolean enableSynchronize) {
317         fEnableSynchronize= enableSynchronize;
318     }
319     /***/

320
321     /**
322      * EntityReference's children are a reflection of those defined in the
323      * named Entity. This method updates them if the Entity is changed.
324      * <P>
325      * It is unclear what the least-cost resynch mechanism is.
326      * If we expect the kids to be shallow, and/or expect changes
327      * to the Entity contents to be rare, wiping them all out
328      * and recloning is simplest.
329      * <P>
330      * If we expect them to be deep,
331      * it might be better to first decide which kids (if any)
332      * persist, and keep the ones (if any) that are unchanged
333      * rather than doing all the work of cloning them again.
334      * But that latter gets into having to convolve the two child lists,
335      * insert new information in the right order (and possibly reorder
336      * the existing kids), and a few other complexities that I really
337      * don't want to deal with in this implementation.
338      * <P>
339      * Note that if we decide that we need to update the EntityReference's
340      * contents, we have to turn off the readOnly flag temporarily to do so.
341      * When we get around to adding multitasking support, this whole method
342      * should probably be an atomic operation.
343      *
344      * @see DocumentTypeImpl
345      * @see EntityImpl
346      */

347     // The Xerces parser invokes callbacks for startEnityReference
348
// the parsed value of the entity EACH TIME, so it is actually
349
// easier to create the nodes through the callbacks rather than
350
// clone the Entity.
351
/***
352     // revisit: enable editing of Entity
353     private void synchronize() {
354         if (!fEnableSynchronize) {
355             return;
356         }
357         DocumentType doctype;
358         NamedNodeMap entities;
359         EntityImpl entDef;
360         if (null != (doctype = getOwnerDocument().getDoctype()) &&
361             null != (entities = doctype.getEntities())) {
362             
363             entDef = (EntityImpl)entities.getNamedItem(getNodeName());
364
365             // No Entity by this name. If we had a change count, reset it.
366             if(null==entDef)
367                 entityChanges=-1;
368
369             // If no kids availalble, wipe any pre-existing children.
370             // (See discussion above.)
371             // Note that we have to use the superclass to avoid recursion
372             // through Synchronize.
373             readOnly=false;
374             if(null==entDef || !entDef.hasChildNodes())
375                 for(Node kid=super.getFirstChild();
376                     kid!=null;
377                     kid=super.getFirstChild())
378                     removeChild(kid);
379
380             // If entity's definition changed, clone its kids
381             // (See discussion above.)
382             if(null!=entDef && entDef.changes!=entityChanges) {
383                 for(Node defkid=entDef.getFirstChild();
384                     defkid!=null;
385                     defkid=defkid.getNextSibling()) {
386                     
387                     NodeImpl newkid=(NodeImpl) defkid.cloneNode(true);
388                     newkid.setReadOnly(true,true);
389                     insertBefore(newkid,null);
390                 }
391                 entityChanges=entDef.changes;
392             }
393             readOnly=true;
394         }
395     }
396      /***/

397
398
399 } // class EntityReferenceImpl
400
Popular Tags