File: SOAPElementImpl.java

package info (click to toggle)
libjboss-web-services-java 0.0%2Bsvn5660%2Bdak2-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 7,276 kB
  • sloc: java: 79,207; xml: 29; makefile: 19; sh: 16
file content (859 lines) | stat: -rw-r--r-- 30,845 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.ws.core.soap;

// $Id: SOAPElementImpl.java 3959 2007-07-20 14:44:19Z heiko.braun@jboss.com $

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.soap.Name;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.Text;

import org.jboss.logging.Logger;
import org.jboss.util.NotImplementedException;
import org.jboss.ws.Constants;
import org.jboss.ws.WSException;
import org.jboss.wsf.common.DOMUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.w3c.dom.TypeInfo;

/**
 * An object representing an element of a SOAP message that is allowed but not specifically prescribed by a
 * SOAP specification. This interface serves as the base interface for those objects that are specifically
 * prescribed by a SOAP specification.
 *
 * Methods in this interface that are required to return SAAJ specific objects may "silently" replace nodes
 * in the tree as required to successfully return objects of the correct type.
 *
 * @author Thomas.Diesler@jboss.org
 */
public class SOAPElementImpl extends NodeImpl implements SOAPElement, SAAJVisitable
{
   // provide logging
   private static Logger log = Logger.getLogger(SOAPElementImpl.class);

   // The org.w3c.dom.Element
   private Element element;
   // The element name
   private Name elementName;

   /** Called by SOAPFactory */
   public SOAPElementImpl(String localPart)
   {
      super(DOMUtils.createElement(localPart, null, null));
      this.element = (Element)domNode;
      log.trace("new SOAPElementImpl: " + getElementName());
   }

   /** Called by SOAPFactory */
   public SOAPElementImpl(String localPart, String prefix, String nsURI)
   {
      super(DOMUtils.createElement(localPart, prefix, nsURI));
      this.element = (Element)domNode;
      log.trace("new SOAPElementImpl: " + getElementName());
   }

   /** Called by SOAPFactory */
   public SOAPElementImpl(Name name)
   {
      this(name.getLocalName(), name.getPrefix(), name.getURI());
   }

   /** Called by SOAPFactory */
   public SOAPElementImpl(QName qname)
   {
      this(qname.getLocalPart(), qname.getPrefix(), qname.getNamespaceURI());
   }

   /** Copy constructor for converting SOAPElement types
    */
   protected SOAPElementImpl(SOAPElementImpl element)
   {
      super(element);
      this.element = (Element)domNode;
      log.trace("new SOAPElementImpl: " + getElementName());
   }

   /** Get the SOAPEnvelope for this SOAPElement */
   public SOAPEnvelope getSOAPEnvelope()
   {
      SOAPElement soapElement = this;
      while (soapElement != null && (soapElement instanceof SOAPEnvelope) == false)
         soapElement = soapElement.getParentElement();

      return (SOAPEnvelope)soapElement;
   }

   //  javax.xml.soap.SOAPElement *************************************************************************************

   public QName getElementQName()
   {
      return ((NameImpl)getElementName()).toQName();
   }

   /**
    * Changes the name of this Element to newName if possible. SOAP Defined elements such as SOAPEnvelope, SOAPHeader, SOAPBody etc. cannot 
    * have their names changed using this method. Any attempt to do so will result in a SOAPException being thrown.
    * 
    * Callers should not rely on the element instance being renamed as is. 
    * Implementations could end up copying the content of the SOAPElement to a renamed instance. 
    * @param qname the new name for the Element.
    * @return The renamed Node
    * @throws SOAPException if changing the name of this Element is not allowed.
    */
   public SOAPElement setElementQName(QName qname) throws SOAPException
   {
      if (Constants.NS_SOAP11_ENV.equals(getNamespaceURI()) || Constants.NS_SOAP12_ENV.equals(getNamespaceURI()))
         throw new SOAPException("Changing the name of this SOAP Element is not allowed: " + getLocalName());

      return setElementQNameInternal(qname);
   }

   public SOAPElement setElementQNameInternal(QName qname) throws SOAPException
   {
      elementName = new NameImpl(qname);

      Document owner = domNode.getOwnerDocument();
      domNode = owner.renameNode(domNode, elementName.getURI(), elementName.getQualifiedName());
      element = (Element)domNode;

      return this.completeNamespaceDeclaration();
   }

   /**
    * Adds an attribute with the specified name and value to this SOAPElement object.
    *
    * @param name  a Name object with the name of the attribute
    * @param value a String giving the value of the attribute
    * @return the SOAPElement object into which the attribute was inserted
    * @throws javax.xml.soap.SOAPException if there is an error in creating the Attribute
    */
   public SOAPElement addAttribute(Name name, String value) throws SOAPException
   {
      // xml:lang='en'
      if ("xml".equals(name.getPrefix()))
      {
         setAttribute(name.getQualifiedName(), value);
      }
      else
      {
         setAttributeNS(name.getURI(), name.getQualifiedName(), value);
      }
      return this;
   }

   public SOAPElement addAttribute(QName qname, String value) throws SOAPException
   {
      return addAttribute(new NameImpl(qname), value);
   }

   /**
    * Creates a new SOAPElement object initialized with the specified local name and adds the new element to this SOAPElement object.
    *
    * @param name a String giving the local name for the element
    * @return the new SOAPElement object that was created
    * @throws javax.xml.soap.SOAPException if there is an error in creating the SOAPElement object
    */
   public SOAPElement addChildElement(String name) throws SOAPException
   {
      SOAPElement soapElement = new SOAPElementImpl(name);
      soapElement = addChildElement(soapElement);
      return soapElement;
   }

   /**
    * Creates a new SOAPElement object initialized with the specified local name and prefix and adds the new element to this SOAPElement object.
    *
    * @param localName a String giving the local name for the new element
    * @param prefix    a String giving the namespace prefix for the new element
    * @return the new SOAPElement object that was created
    * @throws javax.xml.soap.SOAPException if there is an error in creating the SOAPElement object
    */
   public SOAPElement addChildElement(String localName, String prefix) throws SOAPException
   {
      String nsURI = getNamespaceURI(prefix);
      if (nsURI == null)
         throw new IllegalArgumentException("Cannot obtain namespace URI for prefix: " + prefix);

      SOAPElement soapElement = new SOAPElementImpl(localName, prefix, nsURI);
      soapElement = addChildElement(soapElement);
      return soapElement;
   }

   /**
    * Creates a new SOAPElement object initialized with the specified local name, prefix, and URI and adds the new element to this SOAPElement object.
    *
    * @param localName a String giving the local name for the new element
    * @param prefix    a String giving the namespace prefix for the new element
    * @param uri       a String giving the URI of the namespace to which the new element belongs
    * @return the new SOAPElement object that was created
    * @throws javax.xml.soap.SOAPException if there is an error in creating the SOAPElement object
    */
   public SOAPElement addChildElement(String localName, String prefix, String uri) throws SOAPException
   {
      SOAPElement soapElement = new SOAPElementImpl(localName, prefix, uri);
      soapElement = addChildElement(soapElement);
      return soapElement;
   }

   /**
    * Creates a new SOAPElement object initialized with the given Name object and adds the new element to this SOAPElement object.
    *
    * @param name a Name object with the XML name for the new element
    * @return the new SOAPElement object that was created
    * @throws javax.xml.soap.SOAPException if there is an error in creating the SOAPElement object
    */
   public SOAPElement addChildElement(Name name) throws SOAPException
   {
      SOAPElement soapElement = new SOAPElementImpl(name);
      soapElement = addChildElement(soapElement);
      return soapElement;
   }

   public SOAPElement addChildElement(QName qname) throws SOAPException
   {
      return addChildElement(new NameImpl(qname));
   }

   /**
    * Add a SOAPElement as a child of this SOAPElement instance. The SOAPElement is expected to be created by a
    * SOAPElementFactory.
    * <p/>
    * Callers should not rely on the element instance being added as is into the XML tree.
    * Implementations could end up copying the content of the SOAPElement passed into an instance of a different SOAPElement
    * implementation. For instance if addChildElement() is called on a SOAPHeader, element will be copied into an instance
    * of a SOAPHeaderElement.
    * <p/>
    * The fragment rooted in element is either added as a whole or not at all, if there was an error.
    * <p/>
    * The fragment rooted in element cannot contain elements named "Envelope", "Header" or "Body" and in the SOAP namespace.
    * Any namespace prefixes present in the fragment should be fully resolved using appropriate namespace declarations
    * within the fragment itself.
    *
    * @param child the SOAPElement to be added as a new child
    * @return an instance representing the new SOAP element that was actually added to the tree.
    * @throws javax.xml.soap.SOAPException if there was an error in adding this element as a child
    */
   public SOAPElement addChildElement(SOAPElement child) throws SOAPException
   {
      log.trace("addChildElement: " + getElementName() + " -> " + child.getElementName());
      SOAPElementImpl soapElement = (SOAPElementImpl)child;
      soapElement = (SOAPElementImpl)appendChild(soapElement);
      return soapElement.completeNamespaceDeclaration();
   }

   /**
    * Adds a namespace declaration with the specified prefix and URI to this SOAPElement object.
    *
    * @param prefix a String giving the prefix of the namespace
    * @param nsURI    a String giving the uri of the namespace
    * @return the SOAPElement object into which this namespace declaration was inserted.
    * @throws javax.xml.soap.SOAPException if there is an error in creating the namespace
    */
   public SOAPElement addNamespaceDeclaration(String prefix, String nsURI)
   {
      if (nsURI == null)
         throw new IllegalArgumentException("Invalid 'null' namespace URI");
      if (nsURI.length() == 0)
         throw new IllegalArgumentException("Invalid empty namespace URI");

      String qualifiedName = "xmlns";
      if (prefix != null && prefix.length() > 0)
         qualifiedName += ":" + prefix;

      log.trace("addNamespaceDeclaration: " + qualifiedName + "='" + nsURI + "'");
      element.setAttributeNS("http://www.w3.org/2000/xmlns/", qualifiedName, nsURI);
      return this;
   }

   // Add the namespace declaration if it is not visible yet
   private SOAPElement completeNamespaceDeclaration()
   {
      String prefix = getPrefix();
      String nsURI = getNamespaceURI();
      if (prefix != null && nsURI != null)
      {
         String prevNS = getNamespaceURI(prefix);
         if (nsURI.equals(prevNS) == false)
            addNamespaceDeclaration(prefix, nsURI);
      }
      return this;
   }

   /**
    * Creates a new Text object initialized with the given String and adds it to this SOAPElement object.
    *
    * @param value a String object with the textual content to be added
    * @return the SOAPElement object into which the new Text object was inserted
    * @throws javax.xml.soap.SOAPException if there is an error in creating the new Text object
    *  or if it is not legal to attach it as a child to this SOAPElement
    */
   public SOAPElement addTextNode(String value) throws SOAPException
   {
      log.trace("addTextNode: " + value);
      org.w3c.dom.Node domNode;
      if (value.startsWith("<!--") && value.endsWith("-->"))
      {
         value = value.substring(4, value.length() - 3);
         domNode = element.getOwnerDocument().createComment(value);
      }
      else
      {
         domNode = element.getOwnerDocument().createTextNode(value);
      }
      javax.xml.soap.Text soapText = new TextImpl(domNode);
      appendChild(soapText);
      return this;
   }

   /**
    * Returns an Iterator over all of the attribute Name objects in this SOAPElement object.
    * <p/>
    * The iterator can be used to get the attribute names, which can then be passed to the method getAttributeValue to
    * retrieve the value of each attribute.
    *
    * @return an iterator over the names of the attributes
    */
   public Iterator getAllAttributes()
   {
      ArrayList list = new ArrayList();
      NamedNodeMap nnm = getAttributes();
      for (int i = 0; i < nnm.getLength(); i++)
      {
         org.w3c.dom.Node node = (org.w3c.dom.Node)nnm.item(i);
         String local = node.getLocalName();
         String prefix = node.getPrefix();
         String uri = node.getNamespaceURI();
         if ("xmlns".equals(prefix) == false)
         {
            Name name;
            if (uri != null && uri.length() > 0)
            {
               name = new NameImpl(local, prefix, uri);
            }
            else
            {
               name = new NameImpl(local);
            }
            list.add(name);
         }
      }
      return list.iterator();
   }

   public Iterator getAllAttributesAsQNames()
   {
      ArrayList list = new ArrayList();
      NamedNodeMap nnm = getAttributes();
      for (int i = 0; i < nnm.getLength(); i++)
      {
         org.w3c.dom.Node node = (org.w3c.dom.Node)nnm.item(i);
         String local = node.getLocalName();
         String prefix = node.getPrefix();
         String uri = node.getNamespaceURI();
         if ("xmlns".equals(prefix) == false)
         {
            QName qname;
            if (uri != null && uri.length() > 0)
            {
               qname = new QName(uri, local, prefix);
            }
            else
            {
               qname = new QName(local);
            }
            list.add(qname);
         }
      }
      return list.iterator();
   }

   /**
    * Returns the value of the attribute with the specified name.
    *
    * @param name a Name object with the name of the attribute
    * @return a String giving the value of the specified attribute
    */
   public String getAttributeValue(Name name)
   {
      Attr attr = getAttributeNode(name);
      return (attr != null ? attr.getValue() : null);
   }

   public String getAttributeValue(QName qname)
   {
      return getAttributeValue(new NameImpl(qname));
   }

   private Attr getAttributeNode(Name name)
   {
      Attr attr = null;
      String nsURI = name.getURI();
      if (nsURI.length() > 0)
         attr = element.getAttributeNodeNS(nsURI, name.getLocalName());
      else attr = element.getAttributeNode(name.getLocalName());

      return attr;
   }

   /**
    * Creates a QName whose namespace URI is the one associated with the parameter, prefix, in the context of this SOAPElement. 
    * The remaining elements of the new QName are taken directly from the parameters, localName and prefix.
    * @param localName a String containing the local part of the name.
    * @param prefix a String containing the prefix for the name.
    * @return a QName with the specified localName  and prefix, and with a namespace that is associated with the prefix in the context of this SOAPElement. 
    *    This namespace will be the same as the one that would be returned by getNamespaceURI(String) if it were given prefix as it's parameter.
    * @throws SOAPException if the QName cannot be created.
    * @since SAAJ 1.3
    */
   public QName createQName(String localName, String prefix) throws SOAPException
   {
      String nsURI = getNamespaceURI(prefix);
      if (nsURI == null)
         throw new SOAPException("CAnnot obtain namespace URI for prefix: " + prefix);

      return new QName(nsURI, localName, prefix);
   }

   /**
    * Returns an Iterator over all the immediate child Nodes of this element.
    * <p/>
    * This includes javax.xml.soap.Text objects as well as SOAPElement objects.
    * Calling this method may cause child Element, SOAPElement and org.w3c.dom.Text nodes to be replaced by SOAPElement,
    * SOAPHeaderElement, SOAPBodyElement or javax.xml.soap.Text nodes as appropriate for the type of this parent node.
    * As a result the calling application must treat any existing references to these child nodes that have been obtained
    * through DOM APIs as invalid and either discard them or refresh them with the values returned by this Iterator.
    * This behavior can be avoided by calling the equivalent DOM APIs. See javax.xml.soap for more details.
    *
    * @return an iterator with the content of this SOAPElement object
    */
   public Iterator getChildElements()
   {
      List list = new ArrayList();
      NodeList nodeList = getChildNodes();
      for (int i = 0; i < nodeList.getLength(); i++)
      {
         org.w3c.dom.Node node = nodeList.item(i);
         if (node instanceof SOAPElement)
         {
            list.add(node);
         }
         else if (node instanceof Text)
         {
            list.add(node);
         }
      }
      return list.iterator();
   }

   /**
    * Returns an Iterator over all the immediate child Nodes of this element with the specified name.
    * <p/>
    * All of these children will be SOAPElement nodes.
    * Calling this method may cause child Element, SOAPElement and org.w3c.dom.Text nodes to be replaced by SOAPElement,
    * SOAPHeaderElement, SOAPBodyElement or javax.xml.soap.Text nodes as appropriate for the type of this parent node.
    * As a result the calling application must treat any existing references to these child nodes that have been obtained
    * through DOM APIs as invalid and either discard them or refresh them with the values returned by this Iterator.
    * This behavior can be avoided by calling the equivalent DOM APIs. See javax.xml.soap for more details.
    *
    * @param name a Name object with the name of the child elements to be returned
    * @return an Iterator object over all the elements in this SOAPElement object with the specified name
    */
   public Iterator getChildElements(Name name)
   {
      return getChildElements(((NameImpl)name).toQName());
   }

   public Iterator getChildElements(QName qname)
   {
      List<SOAPElement> list = new ArrayList<SOAPElement>();
      Iterator it = getChildElements();
      while (it.hasNext())
      {
         Object elementOrTextNode = it.next();
         if (elementOrTextNode instanceof SOAPElement)
         {
            SOAPElement el = (SOAPElement)elementOrTextNode;
            if (el.getElementQName().equals(qname))
               list.add(el);
         }
      }
      return list.iterator();
   }

   /**
    * Returns the name of this SOAPElement object.
    *
    * @return a Name object with the name of this SOAPElement object
    */
   public Name getElementName()
   {
      if (elementName == null)
      {
         String nsURI = element.getNamespaceURI();
         if (nsURI != null && nsURI.length() > 0)
         {
            String prefix = element.getPrefix();
            String localName = element.getLocalName();
            elementName = new NameImpl(localName, prefix, nsURI);
         }
         else
         {
            String nodeName = element.getNodeName();
            elementName = new NameImpl(nodeName);
         }
      }
      return elementName;
   }

   /**
    * Returns an Iterator over the namespace prefix Strings declared by this element.
    * <p/>
    * The prefixes returned by this iterator can be passed to the method getNamespaceURI to retrieve the URI of each namespace.
    *
    * @return an iterator over the namespace prefixes in this SOAPElement object
    */
   public Iterator getNamespacePrefixes()
   {
      ArrayList list = getNamespacePrefixList();
      return list.iterator();
   }

   private ArrayList getNamespacePrefixList()
   {
      ArrayList list = new ArrayList();
      NamedNodeMap attrMap = element.getAttributes();
      for (int i = 0; i < attrMap.getLength(); i++)
      {
         Attr attr = (Attr)attrMap.item(i);
         String attrName = attr.getNodeName();
         if (attrName.startsWith("xmlns:"))
            list.add(attrName.substring(6));
      }
      return list;
   }

   /**
    * Returns the URI of the namespace that has the given prefix.
    *
    * @param prefix a String giving the prefix of the namespace for which to search
    * @return a String with the uri of the namespace that has the given prefix
    */
   public String getNamespaceURI(String prefix)
   {
      String nsURI = element.getAttribute("xmlns:" + prefix);
      if (nsURI.length() == 0 && getParentElement() != null)
         return getParentElement().getNamespaceURI(prefix);

      return (nsURI.length() > 0 ? nsURI : null);
   }

   /**
    * Returns an Iterator over the namespace prefix Strings visible to this element.
    * <p/>
    * The prefixes returned by this iterator can be passed to the method getNamespaceURI to retrieve the URI of each namespace.
    *
    * @return an iterator over the namespace prefixes are within scope of this SOAPElement object
    */
   public Iterator getVisibleNamespacePrefixes()
   {
      ArrayList list = getNamespacePrefixList();
      SOAPElementImpl parent = (SOAPElementImpl)getParentElement();
      while (parent != null)
      {
         list.addAll(parent.getNamespacePrefixList());
         parent = (SOAPElementImpl)parent.getParentElement();
      }
      return list.iterator();
   }

   /**
    * Removes the attribute with the specified name.
    *
    * @param name the Name object with the name of the attribute to be removed
    * @return true if the attribute was removed successfully; false if it was not
    */
   public boolean removeAttribute(Name name)
   {
      Attr attr = getAttributeNode(name);
      if (attr != null)
      {
         element.removeAttributeNode(attr);
         return true;
      }
      return false;
   }

   public boolean removeAttribute(QName qname)
   {
      return removeAttribute(new NameImpl(qname));
   }

   /**
    * Detaches all children of this SOAPElement.
    * <p/>
    * This method is useful for rolling back the construction of partially completed SOAPHeaders and SOAPBodys in
    * preparation for sending a fault when an error condition is detected.
    * It is also useful for recycling portions of a document within a SOAP message.
    */
   public void removeContents()
   {
      log.trace("removeContents");
      Iterator it = getChildElements();
      while (it.hasNext())
      {
         Node el = (Node)it.next();
         el.detachNode();
      }
   }

   /**
    * Removes the namespace declaration corresponding to the given prefix.
    *
    * @param prefix a String giving the prefix for which to search
    * @return true if the namespace declaration was removed successfully; false if it was not
    */
   public boolean removeNamespaceDeclaration(String prefix)
   {
      boolean ret = getAttributeNode("xmlns:" + prefix) != null;
      removeAttribute("xmlns:" + prefix);
      return ret;
   }

   /**
    * Returns the encoding style for this SOAPElement object.
    * @return a String giving the encoding style
    */
   public String getEncodingStyle()
   {
      // JBCTS-440 #getEncodingStyleTest1 expects the initial value of the encodingStyle property to be null
      String encodingStyle = getAttribute(Constants.PREFIX_ENV + ":encodingStyle");
      return (encodingStyle.length() > 0 ? encodingStyle : null);
   }

   /**
    * Sets the encoding style for this SOAPElement object to one specified.
    * 
    * @see http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383495
    * @see http://www.w3.org/TR/soap12-part1/#soapencattr
    *
    * @param encodingStyle a String giving the encoding style
    * @throws IllegalArgumentException if there was a problem in the encoding style being set.
    * @throws javax.xml.soap.SOAPException if setting the encodingStyle is invalid for this SOAPElement.
    */
   public void setEncodingStyle(String encodingStyle) throws SOAPException
   {
      String namespaceURI = getNamespaceURI(Constants.PREFIX_ENV);
      NameImpl name = new NameImpl("encodingStyle", Constants.PREFIX_ENV, namespaceURI);
      addAttribute(name, encodingStyle);
   }

   public String getTagName()
   {
      return element.getTagName();
   }

   public void removeAttribute(String name) throws DOMException
   {
      element.removeAttribute(name);
   }

   public boolean hasAttribute(String name)
   {
      return element.hasAttribute(name);
   }

   public String getAttribute(String name)
   {
      return element.getAttribute(name);
   }

   public void removeAttributeNS(String namespaceURI, String localName) throws DOMException
   {
      element.removeAttributeNS(namespaceURI, localName);
   }

   public void setAttribute(String name, String value) throws DOMException
   {
      element.setAttribute(name, value);
   }

   public boolean hasAttributeNS(String namespaceURI, String localName)
   {
      return element.hasAttributeNS(namespaceURI, localName);
   }

   public Attr getAttributeNode(String name)
   {
      Attr attr = element.getAttributeNode(name);

      return (attr == null) ? null : new AttrImpl(this, attr);
   }

   public Attr removeAttributeNode(Attr oldAttr) throws DOMException
   {
      return element.removeAttributeNode(oldAttr);
   }

   public Attr setAttributeNode(Attr newAttr) throws DOMException
   {
      return element.setAttributeNode(newAttr);
   }

   public Attr setAttributeNodeNS(Attr newAttr) throws DOMException
   {
      return element.setAttributeNodeNS(newAttr);
   }

   public NodeList getElementsByTagName(String name)
   {
      return new NodeListImpl(DOMUtils.getChildElements(this, name));
   }

   public String getAttributeNS(String namespaceURI, String localName)
   {
      return element.getAttributeNS(namespaceURI, localName);
   }

   public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException
   {
      element.setAttributeNS(namespaceURI, qualifiedName, value);
   }

   public Attr getAttributeNodeNS(String namespaceURI, String localName)
   {
      /* FIXME We really need to do more than just return an object wrapper.
       * All Attrs should be stored as nodes on our local tree, so that
       * they are discovered during node traversal calls.
       */
      Attr attr = element.getAttributeNodeNS(namespaceURI, localName);

      return (attr == null) ? null : new AttrImpl(this, attr);
   }

   public NodeList getElementsByTagNameNS(String namespaceURI, String localName)
   {
      return new NodeListImpl(DOMUtils.getChildElements(this, new QName(namespaceURI, localName)));
   }

   public TypeInfo getSchemaTypeInfo()
   {
      throw new NotImplementedException("getSchemaTypeInfo");
   }

   public void setIdAttribute(String name, boolean isId) throws DOMException
   {
      throw new NotImplementedException("setIdAttribute");
   }

   public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException
   {
      throw new NotImplementedException("setIdAttributeNode");
   }

   public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException
   {
      throw new NotImplementedException("setIdAttributeNS");
   }

   public void accept(SAAJVisitor visitor)
   {
      visitor.visitSOAPElement(this);
   }

   /**
    * The default implementation uses a DOMWriter.
    * SOAPContentElements overwrite this to optimize DOM callbacks.
    */
   public void writeElement(Writer writer) throws IOException
   {
      String qualName = getElementName().getQualifiedName();
      writer.write("<" + qualName);

      // namespaces
      Iterator nsPrefixes = getNamespacePrefixes();
      while (nsPrefixes.hasNext())
      {
         String prefix = (String)nsPrefixes.next();
         writer.write(" xmlns:" + prefix + "='" + getNamespaceURI(prefix) + "'");
      }

      // attributes
      Iterator attNames = getAllAttributes();
      while (attNames.hasNext())
      {
         NameImpl name = (NameImpl)attNames.next();
         String attPrefix = name.getPrefix() != null ? name.getPrefix() : "";
         String attFqn = attPrefix.length() > 0 ? attPrefix + ":" + name.getLocalName() : name.getLocalName();
         writer.write(" " + attFqn + "='" + getAttributeValue(name) + "'");
      }
      writer.write(">");

      writeElementContent(writer);

      writer.write("</" + qualName + ">");
   }

   protected void writeElementContent(Writer out) throws IOException
   {
      Iterator it = getChildElements();
      if (it.hasNext())
      {
         while (it.hasNext())
         {
            Node node = (Node)it.next();
            if (node instanceof SOAPElementImpl)
            {
               ((SOAPElementImpl)node).writeElement(out);
            }
            else if (node instanceof TextImpl)
            {
               ((TextImpl)node).writeNode(out);
            }
            else
            {
               throw new WSException("Unhandled soap node: " + node.getClass().getName());
            }
         }
      }
      else
      {
         String value = getValue();
         if (value != null)
            out.write(value);
      }
   }
}