XML:从 SAX 内容处理程序中的 xsi:type 属性查找名称空间 uri

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

我有一个 xml 文档作为

<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>

其中 b:Button 是 cont:component

的 xml 扩展类型

在我的 startElement 调用中,我按预期收到 http://mebigfatguy.com/ds/container 的 uri 和 cont:component 的 qname。在属性中找到 xsi:type="b:Button",也符合预期。

我的问题是如何查找从 xsi:type 属性检索到的 b:Button 的命名空间 uri。我必须自己手动管理 xmlns 属性吗?还是有内置的方法来解析 uri 是什么?

SAX 报告 ContentHandler.startElement 中元素和属性的名称空间 URI,但不提供在解析期间将前缀转换为名称空间 URI 的通用方法。

为此,您必须在 ContentHandler 中实施 startPrefixMappingendPrefixMapping 并跟踪活动绑定。 (如果做得好,这还必须涵盖名称空间未声明)。

是的。您必须为 b:Button 查找名称空间 uri,并且必须使用 org.xml.sax.helpers.NamespaceSupport 管理 xmlns 属性。正确填充 NamespaceSupport 有点棘手。

下面是使用 urilocalname 打印 xsi:type 值的示例代码:

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();
    }
}

这里是驱动函数:

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

输出是:

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