Search code examples
javaxmlstaxxmlstreamreader

How to read namespace as it is in a xml using XMLStreamReader?


I have an xml file from which i read using an XMLStreamReader object. So i'll keep it simple :

Let's take this xml example :

<mySample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attribute1="value1"/>

So what i need is to get the value (as a String) "xmlns:xsi" and get the value (as a String also) "http://www.w3.org/2001/XMLSchema-instance"

I did try to have a test like this :

if (reader.getEventType() != XMLStreamConstants.NAMESPACE){
       attributeName = reader.getAttributeLocalName(i);
       attributeValue = reader.getAttributeValue(i);
}
else{
       attributeName = reader.getNamespacePrefix(i) + reader.getNamespaceURI(i);
       attributeValue = reader.getAttributeValue(i);
}

But it did not work.

Obviously i missed something being a newbie to this API, so any help would be very welcome.


Solution

  • The JSR-173 specification (Stax API for Java) states the following regarding the NAMESPACE event :

    Namespace
    Namespace declarations can also exist outside of a StartElement and may be reported as a standalone information item. In general Namespaces are reported as part of a StartElement event. When namespaces are the result of an XQuery or XPath expression they may be reported as standalone events.

    So if you are looking at namespace events, you should most probably be checking StartElement events, and inspect them. Once again, from the spec :

    Namespaces can be accessed using the following methods:

    int getNamespaceCount();
    String getNamespacePrefix(int index);
    String getNamespaceURI(int index);

    Only the namespaces declared on the current StartElement are available. The list does not contain previously declared namespaces and does not remove redeclared namespaces.

    At any point during the parsing, you can get the current complete namespace context :

    The namespace context of the current state is available by calling XMLStreamReader.getNamespaceContext() or StartElement.getNamespaceContext(). These methods return an instance of the javax.xml.namespace.NamespaceContext interface.

    That's theory : most namespace declarations come from START_ELEMENT, some may come independently.

    In practice, I have never came accross a NAMESPACE event reported by the API when reading from a file. It's almost always reported as part of a START_ELEMENT (and repeated in the corresponding END_ELEMENT), so you must check START_ELEMENT if you are interested in namespace declaration. For example, starting with your document :

    String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><mySample xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" attribute1=\"value1\"/>";
    XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(new StringReader(xml));
    while (reader.hasNext()) {
      int event = reader.next();
      if (XMLStreamConstants.START_ELEMENT == event) {
        if (reader.getNamespaceCount() > 0) {
          // This happens
          System.out.println("ELEMENT START: " + reader.getLocalName() + " , namespace count is: " + reader.getNamespaceCount());
          for (int nsIndex = 0; nsIndex < reader.getNamespaceCount(); nsIndex++) {
            String nsPrefix = reader.getNamespacePrefix(nsIndex);
            String nsId = reader.getNamespaceURI(nsIndex);
            System.out.println("\tNamepsace prefix: " + nsPrefix + " associated with URI " + nsId);
          }
        }
      } else if(XMLStreamConstants.NAMESPACE == event) {
        // This almost never happens
        System.out.println("NAMESPACE EVENT");
      }
    }
    

    Will produce :

    ELEMENT START: mySample , namespace count is: 1

    Namepsace prefix: xsi associated with URI http://www.w3.org/2001/XMLSchema-instance

    Bottom line : you should check for NAMESPACE and START_ELEMENT events, even if most of times, you will only have START_ELEMENT reporting namespace declartions, it is not one or the other, it's both.