我想使用Java的org.w3c.dom
来访问DOM元素的xsi:type
(不是jaxb或guava或apache.commons等)。
我有一个XML,其中一个元素有几种可能的类型,基类型是抽象的 - 像这样:
<xsd:complexType name="AbstractBaseType" abstract="true"/>
<xsd:element name="Derived" type="message:DerivedType1"/>
<xsd:complexType name="DerivedType1">
<xsd:complexContent>
<xsd:extension base="message:AbstractBaseType">
...
在具体的XML中,这看起来像这样:
<ns4:root xmlns:ns="..." ...>
<element xsi:type="ns3:DerivedType1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
现在,<element>
可以是从AbstractBaseType
派生的任何类型,在这种情况下,它是DerivedType1
类型中注明的类型xsi:type
。我假设XML或XSD标准定义了它的工作原理。
我已成功导航<root>
到<element>
,如下所示:
Document doc = parseToDocument("<ns4:root...");
Element documentElement = doc.getDocumentElement()
Element child = (Element)findChild(documentElement, "element", true, 5);
// now 'child' is the '<element>'-node
// - but how do I get 'DerivedType1'?
Attr type = child.getAttributeNodeNS("http://www.w3.org/2001/XMLSchema-instance", "type");
String typeName = type.getValue();
现在typeName
包含"ns3:DerivedType1"
。
有没有办法在没有"DerivedType1"
(和类似)的情况下前往typename.split(":")
?
private Document parseToDocument(String data) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true); // important!
DocumentBuilder builder = domFactory.newDocumentBuilder();
ByteArrayInputStream bis = new ByteArrayInputStream(data.getBytes("UTF8"));
return builder.parse(bis);
}
/** breadth first */
private Node findChild(Node node, final String localName, boolean checkNode, final int limitDepth) {
if(node==null) return null;
if(limitDepth < 0) return null;
if(checkNode && StringUtils.equals(node.getLocalName(), localName)) return node;
final NodeList childNodes = node.getChildNodes();
if(childNodes == null) return null;
for(int i=0; i < childNodes.getLength(); ++i) {
final Node child = childNodes.item(i);
if(StringUtils.equals(child.getLocalName(), localName)) return child;
}
final int limitDepthNew = limitDepth - 1;
for(int i=0; i < childNodes.getLength(); ++i) {
final Node result = findChild(childNodes.item(i), localName, false, limitDepthNew);
if(result != null) return result;
}
return null;
}