001package com.hfg.xml;
002
003import org.w3c.dom.*;
004
005import com.hfg.util.StringUtil;
006
007//------------------------------------------------------------------------------
008/**
009  
010  @author J. Alex Taylor, hairyfatguy.com
011 */
012//------------------------------------------------------------------------------
013
014
015public class XMLAttribute implements Node, Cloneable, Comparable<XMLAttribute>
016{
017
018   //###########################################################################
019   // PRIVATE FIELDS
020   //###########################################################################
021
022   private String       mLocalName;
023   private String       mValue;
024   private XMLNamespace mNamespace;
025   private XMLTag       mElement;   // Reference to the element to which this attribute belongs.
026
027   //###########################################################################
028   // CONSTRUCTORS
029   //###########################################################################
030
031   //---------------------------------------------------------------------------
032   public XMLAttribute(String inName, Object inValue)
033   {
034      setName(inName);
035      setValue(inValue);
036   }
037
038   //---------------------------------------------------------------------------
039   public XMLAttribute(String inName, Object inValue, XMLNamespace inNamespace)
040   {
041      this(inName, inValue);
042      mNamespace = inNamespace;
043   }
044
045   //---------------------------------------------------------------------------
046   public XMLAttribute(XMLName inName, Object inValue)
047   {
048      setName(inName.getLocalName());
049      mNamespace = inName.getNamespace();
050      setValue(inValue);
051   }
052
053
054
055   //###########################################################################
056   // PUBLIC METHODS
057   //###########################################################################
058
059
060   //---------------------------------------------------------------------------
061   @Override
062   public XMLAttribute clone()
063   {
064      XMLAttribute obj = null;
065      try 
066      {
067         obj = (XMLAttribute) super.clone(); 
068      }
069      catch (CloneNotSupportedException e)
070      {
071         throw new RuntimeException(e.toString());
072      }
073      
074      return obj;
075   }
076   
077   //---------------------------------------------------------------------------
078   /**
079    XMLAttribute equality and comparison is based on the name.
080    */
081   public int compareTo(XMLAttribute inAttr2)
082   {
083      if (null == inAttr2)
084      {
085         return 1;
086      }
087       
088      return getName().compareTo(inAttr2.getName());
089   }
090
091
092   //---------------------------------------------------------------------------
093   public String getName()
094   {
095      return mLocalName;
096   }
097        
098   //--------------------------------------------------------------------------
099   /**
100     Sets the attribute's local name
101    */
102   public void setName(String inName)
103   {
104      if (null == inName)
105      {
106         throw new InvalidXMLNameException("XML attribute names cannot be set to null!");
107      }
108
109      // Is there a namespace prefix on the name?
110      int index = inName.indexOf(":");
111      if (index > 0)
112      {
113         setNamespace(XMLNamespace.getNamespace(inName.substring(0, index), null));
114         inName = inName.substring(index + 1);
115      }
116
117      // Check the name for XML validity.
118      XMLUtil.checkXMLNameValidity(inName);
119        
120      mLocalName = inName;
121   }
122
123
124   //---------------------------------------------------------------------------
125   public String getQualifiedName()
126   {
127      return (mNamespace != null && StringUtil.isSet(mNamespace.getPrefix()) ? mNamespace.getPrefix() + ":" : "") + mLocalName;
128   }
129
130   //---------------------------------------------------------------------------
131   public String getValue()
132   {
133      return mValue;
134   }
135
136   //---------------------------------------------------------------------------
137   public void setValue(Object inValue)
138   {
139      mValue = null;
140      if (inValue != null)
141      {
142         mValue = inValue.toString();
143      }
144   }
145
146   //---------------------------------------------------------------------------
147   public String getUnscapedValue()
148   {
149      return XMLUtil.unescapeAttributeValue(mValue);
150   }
151
152   //---------------------------------------------------------------------------
153   public String getEscapedValue()
154   {
155      return XMLUtil.escapeAttributeValue(mValue);
156   }
157
158   //---------------------------------------------------------------------------
159   public XMLNamespace getNamespace()
160   {
161      // Dynamically look up the chain for the first namespace instance. XXXXXXXXXXXXX
162      return mNamespace;
163   }
164
165   //---------------------------------------------------------------------------
166   public void setNamespace(XMLNamespace inNamespace)
167   {
168      // Dynamically look up the chain for the first namespace instance. XXXXXXXXXXXXX
169      mNamespace = inNamespace;
170   }
171
172   // Methods for the Node interface.
173
174   //---------------------------------------------------------------------------
175   /**
176    Returns the attribute name.
177    */
178   public String getNodeName()
179   {
180      return mLocalName;
181   }
182
183   //---------------------------------------------------------------------------
184   public String getNodeValue() throws DOMException
185   {
186      return getValue();
187   }
188
189   //---------------------------------------------------------------------------
190   public void setNodeValue(String inValue) throws DOMException
191   {
192      setValue(inValue);
193   }
194
195   //---------------------------------------------------------------------------
196   public short getNodeType()
197   {
198      return Node.ATTRIBUTE_NODE;
199   }
200
201   //---------------------------------------------------------------------------
202   public Node getParentNode()
203   {
204      return null;
205   }
206
207   //---------------------------------------------------------------------------
208   public NodeList getChildNodes()
209   {
210      return null;  //TODO
211   }
212
213   //---------------------------------------------------------------------------
214   public Node getFirstChild()
215   {
216      return null;
217   }
218
219   //---------------------------------------------------------------------------
220   public Node getLastChild()
221   {
222      return null;
223   }
224
225   //---------------------------------------------------------------------------
226   public Node getPreviousSibling()
227   {
228      return null;  //TODO
229   }
230
231   //---------------------------------------------------------------------------
232   public Node getNextSibling()
233   {
234      return null;  //TODO
235   }
236
237   //---------------------------------------------------------------------------
238   public NamedNodeMap getAttributes()
239   {
240      return null;
241   }
242
243   //---------------------------------------------------------------------------
244   public Document getOwnerDocument()
245   {
246      return null;  //TODO
247   }
248
249   //---------------------------------------------------------------------------
250   public Node insertBefore(Node node, Node node1) throws DOMException
251   {
252      throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
253                             "insertBefore() cannot be used on an attribute node!");
254   }
255
256   //---------------------------------------------------------------------------
257   public Node replaceChild(Node node, Node node1) throws DOMException
258   {
259      throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
260                             "replaceChild() cannot be used on an attribute node!");
261   }
262
263   //---------------------------------------------------------------------------
264   public Node removeChild(Node node) throws DOMException
265   {
266      throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
267                             "removeChild() cannot be used on an attribute node!");
268   }
269
270   //---------------------------------------------------------------------------
271   public Node appendChild(Node node) throws DOMException
272   {
273      throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
274                             "appendChild() cannot be used on an attribute node!");
275   }
276
277   //---------------------------------------------------------------------------
278   public boolean hasChildNodes()
279   {
280      return false;
281   }
282
283   //---------------------------------------------------------------------------
284   public Node cloneNode(boolean b)
285   {
286      return clone();
287   }
288
289   //---------------------------------------------------------------------------
290   public void normalize()
291   {
292
293   }
294
295   //---------------------------------------------------------------------------
296   public boolean isSupported(String inFeature, String inVersion)
297   {
298      return false;
299   }
300
301   //---------------------------------------------------------------------------
302   /**
303     Convenience method to get the namespace URI
304    */
305   public String getNamespaceURI()
306   {
307       String uri = null;
308
309       XMLNamespace namespace = getNamespace();
310       if (namespace != null)
311       {
312          uri = namespace.getURI();
313       }
314
315       return uri;
316   }
317
318   //---------------------------------------------------------------------------
319   /**
320    The namespace prefix of this attribute, or null if it is unspecified.
321    */
322   public String getPrefix()
323   {
324       String prefix = null;
325
326       XMLNamespace namespace = getNamespace();
327       if (namespace != null)
328       {
329          prefix = namespace.getPrefix();
330       }
331
332       return prefix;
333   }
334
335   //---------------------------------------------------------------------------
336   /**
337    The namespace prefix of this attribute, or null if it is unspecified.
338    */
339   public void setPrefix(String inValue) throws DOMException
340   {
341      XMLNamespace namespace = (inValue != null ? XMLNamespace.getNamespaceViaPrefix(inValue) : null);
342      setNamespace(namespace);
343   }
344
345   //---------------------------------------------------------------------------
346   /**
347    Returns the local part of the qualified name of this node.
348    */
349   public String getLocalName()
350   {
351      return mLocalName;
352   }
353
354   //---------------------------------------------------------------------------
355   public boolean hasAttributes()
356   {
357      return false;
358   }
359
360   //---------------------------------------------------------------------------
361   public String getBaseURI()
362   {
363      return null;  // TODO
364   }
365
366   //---------------------------------------------------------------------------
367   public short compareDocumentPosition(Node node) throws DOMException
368   {
369      return 0; // TODO
370   }
371
372   //---------------------------------------------------------------------------
373   public String getTextContent() throws DOMException
374   {
375      return null;
376   }
377
378   //---------------------------------------------------------------------------
379   public void setTextContent(String string) throws DOMException
380   {
381
382   }
383
384   //---------------------------------------------------------------------------
385   public boolean isSameNode(Node node)
386   {
387      return false;
388   }
389
390   //---------------------------------------------------------------------------
391   public String lookupPrefix(String string)
392   {
393      return null;
394   }
395
396   //---------------------------------------------------------------------------
397   public boolean isDefaultNamespace(String string)
398   {
399      return false;
400   }
401
402   //---------------------------------------------------------------------------
403   /**
404    Look up the namespace URI associated to the given prefix, starting from this node.
405    */
406   public String lookupNamespaceURI(String inPrefix)
407   {
408      return null;
409   }
410
411   //---------------------------------------------------------------------------
412   public boolean isEqualNode(Node node)
413   {
414      return false;
415   }
416
417   //---------------------------------------------------------------------------
418   public Object getFeature(String string, String string1)
419   {
420      return null;
421   }
422
423   //---------------------------------------------------------------------------
424   public Object setUserData(String string, Object object, UserDataHandler userDataHandler)
425   {
426      return null;
427   }
428
429   //---------------------------------------------------------------------------
430   public Object getUserData(String string)
431   {
432      return null;
433   }
434
435   //###########################################################################
436   // PROTECTED METHODS
437   //###########################################################################
438
439   //---------------------------------------------------------------------------
440   protected void setElement(XMLTag inOwner)
441   {
442      mElement = inOwner;
443   }
444
445   //---------------------------------------------------------------------------
446   protected XMLTag getElement()
447   {
448      return mElement;
449   }
450
451}