MeBigFatGuy
MeBigFatGuy

Reputation: 28568

XML: Finding namespace uri from xsi:type attribute in SAX content handler

I have an xml document as

<fr:frame xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:fr="http://mebigfatguy.com/ds/frame" 
      xmlns:comp="http://mebigfatguy.com/ds/component"
      xmlns:cont="http://mebigfatguy.com/ds/container"
      xmlns:b="http://mebigfatguy.com/ds/button">
    <comp:preferredSize>500,300</comp:preferredSize>
    <cont:childComponent>
        <cont:name>CENTER</cont:name>
        <cont:component xsi:type="b:Button">
            <comp:name>Click Me</comp:name>
        </cont:component>
    </cont:childComponent>
    <fr:title>Example</fr:title>
</fr:frame>

where b:Button is an xml extension type of cont:component

In my startElement call, i receive a uri of http://mebigfatguy.com/ds/container and qname of cont:component as expected. The xsi:type="b:Button" is found in the attributes, also as expected.

The question I have is how does one lookup the namespace uri of b:Button as retrieved from the xsi:type attribute. Do i have to manage the xmlns attributes manually myself? or is there a built in way to resolve what the uri is?

Upvotes: 1

Views: 770

Answers (2)

Santhosh Kumar Tekuri
Santhosh Kumar Tekuri

Reputation: 3020

Yes. you have to do lookup namespace uri for b:Button and you have to manage xmlns attributes using org.xml.sax.helpers.NamespaceSupport. It is little tricky to populate NamespaceSupport properly.

Below is the sample code which prints xsi:type value with uri and localname:

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.NamespaceSupport;

import javax.xml.XMLConstants;
import javax.xml.parsers.SAXParserFactory;

/**
 * @author Santhosh Kumar Tekuri
 */
public class XSIHandler extends DefaultHandler{
    private boolean needNewContext;
    private NamespaceSupport nsSupport;

    @Override
    public void startDocument() throws SAXException{
        nsSupport = new NamespaceSupport();
        needNewContext = true;
        super.startDocument();
    }

    @Override
    public void startPrefixMapping(String prefix, String uri) throws SAXException{
        if(needNewContext){
            nsSupport.pushContext();
            needNewContext = false;
        }
        nsSupport.declarePrefix(prefix, uri);
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException{
        if(needNewContext)
            nsSupport.pushContext();
        needNewContext = true;
        String xsiType = atts.getValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type");
        if(xsiType!=null){
            String prefix, suffix;
            int colon = xsiType.indexOf(':');
            if(colon==-1){
                prefix = "";
                suffix = xsiType;
            }else{
                prefix = xsiType.substring(0, colon);
                suffix = xsiType.substring(colon+1);
            }
            System.out.println("xsi:type for " + qName + " is uri: " + nsSupport.getURI(prefix) + " localName: " + suffix);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException{
        nsSupport.popContext();
    }
}

here is the driver function:

public static void main(String[] args) throws Exception{
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setNamespaceAware(true);
    factory.newSAXParser().parse("test.xml", new XSIHandler());
}

the output is:

xsi:type for cont:component is uri: http://mebigfatguy.com/ds/button localName: Button

Upvotes: 0

wero
wero

Reputation: 32980

SAX reports the namespace URI of elements and attributes in ContentHandler.startElement but does not provide a general method to translate a prefix into a namespace URI during parsing.

For that you have to implement startPrefixMappingand endPrefixMapping in your ContentHandlerand keep track of the active bindings. (If done right this must also cover namespace undeclarations).

Upvotes: 2

Related Questions