JAXB:我如何才能解组XML没有命名空间
问题描述:
我有一个XML文件:JAXB:我如何才能解组XML没有命名空间
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<object>
<str>the type</str>
<bool type="boolean">true</bool>
</object>
而且我想它解组的类的对象下面
@XmlRootElement(name="object")
public class Spec {
public String str;
public Object bool;
}
我该怎么做?除非我指定名称空间(参见下文),否则它不起作用。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<object>
<str>the type</str>
<bool xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xsi:type="xs:boolean">true</bool>
</object>
答
UPDATE
你可以得到这个通过引入一个中间层type
和xsi:type
之间的转换工作。下面是例如使用的StAX StreamReaderDelegate
为JAXB解组操作做到这一点的:
package forum7184526;
import java.io.FileInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
import org.eclipse.persistence.oxm.XMLConstants;
public class Demo {
public static void main(String[] args) throws Exception {
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("input.xml"));
xsr = new XsiTypeReader(xsr);
JAXBContext jc = JAXBContext.newInstance(Spec.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Spec spec = (Spec) unmarshaller.unmarshal(xsr);
}
private static class XsiTypeReader extends StreamReaderDelegate {
public XsiTypeReader(XMLStreamReader reader) {
super(reader);
}
@Override
public String getAttributeNamespace(int arg0) {
if("type".equals(getAttributeLocalName(arg0))) {
return XMLConstants.SCHEMA_INSTANCE_URL;
}
return super.getAttributeNamespace(arg0);
}
}
}
xsi:type
是用于指定实际类型的元件(类似于Java铸造)的模式的机制。如果删除名称空间,则会更改文档的语义。
在EclipseLink JAXB (MOXy)我们允许你指定使用@XmlDescriminatorNode
和@XmlDescrimatorValue
域对象自己继承的指标。我们目前没有为数据类型属性提供这种类型的定制:
答
基于Blaise的评论(感谢布莱斯!)和我的研究。 这是我的问题的解决方案。你赞同那个Blaise,还是你有更好的办法?
package forum7184526;
import java.io.FileInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
import org.eclipse.persistence.oxm.XMLConstants;
public class Demo {
public static void main(String[] args) throws Exception {
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("input.xml"));
xsr = new XsiTypeReader(xsr);
JAXBContext jc = JAXBContext.newInstance(Spec.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Spec spec = (Spec) unmarshaller.unmarshal(xsr);
}
private static class XsiTypeReader extends StreamReaderDelegate {
public XsiTypeReader(XMLStreamReader reader) {
super(reader);
}
@Override
public String getAttributeNamespace(int arg0) {
if("type".equals(getAttributeLocalName(arg0))) {
return "http://www.w3.org/2001/XMLSchema-instance";
}
return super.getAttributeNamespace(arg0);
}
@Override
public String getAttributeValue(int arg0) {
String n = getAttributeLocalName(arg0);
if("type".equals(n)) {
String v = super.getAttributeValue(arg0);
return "xs:"+ v;
}
return super.getAttributeValue(arg0);
}
@Override
public NamespaceContext getNamespaceContext() {
return new MyNamespaceContext(super.getNamespaceContext());
}
}
private static class MyNamespaceContext implements NamespaceContext {
public NamespaceContext _context;
public MyNamespaceContext(NamespaceContext c){
_context = c;
}
@Override
public Iterator<?> getPrefixes(String namespaceURI) {
return _context.getPrefixes(namespaceURI);
}
@Override
public String getPrefix(String namespaceURI) {
return _context.getPrefix(namespaceURI);
}
@Override
public String getNamespaceURI(String prefix) {
if("xs".equals(prefix)) {
return "http://www.w3.org/2001/XMLSchema";
}
return _context.getNamespaceURI(prefix);
}
}
}
答
更简单的方法可能是使用unmarshalByDeclaredType,因为你已经知道你要解组的类型。
通过使用
Unmarshaller.unmarshal(rootNode, MyType.class);
你不需要有在XML命名空间声明,因为你在一个已经设定的命名空间的JAXBElement通过。
这也是完全合法的,因为您不需要在XML实例中引用命名空间,请参阅http://www.w3.org/TR/xmlschema-0/#PO-许多客户端都以这种方式生成XML。
终于搞定了。请注意,您必须删除模式中的任何自定义名称空间;这里的工作示例代码:
的模式:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="customer">
<xsd:complexType>
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1" />
<xsd:element name="phone" type="xsd:string" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
XML:
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<name>Jane Doe</name>
<phone>08154712</phone>
</customer>
JAXB代码:
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Unmarshaller u = jc.createUnmarshaller();
u.setSchema(schemaInputStream); // load your schema from File or any streamsource
Customer = u.unmarshal(new StreamSource(inputStream), clazz); // pass in your XML as inputStream
感谢您的答复,布莱斯。拥有命名空间我很好。但是,在XML中是否有可能没有命名空间(因为它将面向开发用户),但是将这些信息与Java类注释保持一致,以便当jaxb解析XML时,它看到“type”并知道“aha,它是根据Java类声明命名空间'xsi'“。与“xs:boolean”相同。你看到我在说什么吗?或者它仍然不可能?我需要这个,因为我们的开发人员将创建这样的XML声明,我们需要将它们解组到Java。 – Andrey
@Andrey - 你可以做这个工作,下面是一个你可以做的解组方法。 –
嗨,Blaise。删除“type”属性的命名空间效果很好,感谢!!! !!!但我仍然可以如何删除“type”属性值 - “xs:boolean”的“xs”命名空间声明。我玩重写了一些StreamReaderDelegate方法,但没有成功。 – Andrey