Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-4637

XmlSlurper Unable to Access Attributes with Same Name but in Different Namespaces

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 1.7.5
    • 2.0.6, 2.1.0-beta-1
    • XML Processing
    • None
    • JDK 6
    • Patch

    Description

      When using XMLSlurper to parse XML in which there is an element with two attributes having the same name but belonging to different namespaces, one of the attribute values will be unaccessible.
      This is due to XMLSlurper using the local attribute name as a key to a map in which data about the attributes are inserted and thus a key-collision will occur.
      Adding the following method to the groovy.util.XmlSlurperTest in the Groovy source-code will expose the problem:

          void testSameNameAttributes() {
              def theInputData = """
              <RootElement xmlns="http://www.ivan.com/ns1" xmlns:two="http://www.ivan.com/ns2">
                  <ChildElement ItemId="FirstItemId" two:ItemId="SecondItemId">Child element data</ChildElement>
              </RootElement>"""
              def theXml = new MyXmlSlurper().parseText(theInputData).declareNamespace(one:"http://www.ivan.com/ns1", two: "http://www.ivan.com/ns2")
              
              assert theXml.ChildElement.@'ItemId' == "FirstItemId"
              assert theXml.ChildElement.@'two:ItemId' == "SecondItemId"
          }
      

      The following patches will make the above test pass, but I am not entirely sure it is the best solution:
      Patching the XmlSlurper.startElement method:

      public void startElement(final String namespaceURI, final String localName,
              final String qName, final Attributes atts) throws SAXException
          {
              addCdata();
      
              final Map attributes = new HashMap();
              final Map attributeNamespaces = new HashMap();
      
              for (int i = atts.getLength() - 1; i != -1; i--)
              {
                  if (atts.getURI(i).length() == 0)
                  {
                      attributes.put(atts.getQName(i), atts.getValue(i));
                  } else
                  {
                      // PATCHED START - Use fully qualified attribute names instead of just local attribute names
                      attributes.put(atts.getQName(i), atts.getValue(i));
                      attributeNamespaces.put(atts.getQName(i), atts.getURI(i));
                      // PATCH END
      
                  }
      
              }
      
              final Node newElement;
              ...
      

      Patching groovy.util.slurpersupport.Attributes, method iterator() to use namespace-qualified attribute names when looking up attribute value. This is the patch I am unsure whether it is the best solution.

          public Iterator iterator() {
              return new NodeIterator(nodeIterator()) {
                  protected Object getNextNode(final Iterator iter) {
                      while (iter.hasNext()) {
                          final Object next = iter.next();
                          if (next instanceof Attribute) {
                              return next;
                          } else {
                              // PATCH START - Added namespace prefix when looking up attribute.
                              String attributeKey = "";
                              if (Attributes.this.namespacePrefix != null &&
                                  !"*".equals(Attributes.this.namespacePrefix) &&
                                  Attributes.this.namespacePrefix.length() > 0) {
                                  attributeKey = Attributes.this.namespacePrefix + ":";
                              }
                              attributeKey += Attributes.this.attributeName;
                              final String value = (String) ((Node) next).attributes().get(attributeKey);
                              // PATCH END
                              if (value != null) {
                                  return new Attribute(Attributes.this.attributeName,
                                          value,
                                          new NodeChild((Node) next, Attributes.this.parent.parent, "", Attributes.this.namespaceTagHints),
                                          "",
                                          Attributes.this.namespaceTagHints);
                              }
                          }
                      }
                      return null;
                  }
              };
          }
      

      Attachments

        Activity

          People

            paulk Paul King
            krizsan Ivan Krizsan
            Votes:
            3 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: