2011-08-25 95 views
8

我有一个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> 

回答

5

UPDATE

你可以得到这个通过引入一个中间层typexsi: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域对象自己继承的指标。我们目前没有为数据类型属性提供这种类型的定制:

+0

感谢您的答复,布莱斯。拥有命名空间我很好。但是,在XML中是否有可能没有命名空间(因为它将面向开发用户),但是将这些信息与Java类注释保持一致,以便当jaxb解析XML时,它看到“type”并知道“aha,它是根据Java类声明命名空间'xsi'“。与“xs:boolean”相同。你看到我在说什么吗?或者它仍然不可能?我需要这个,因为我们的开发人员将创建这样的XML声明,我们需要将它们解组到Java。 – Andrey

+0

@Andrey - 你可以做这个工作,下面是一个你可以做的解组方法。 –

+0

嗨,Blaise。删除“type”属性的命名空间效果很好,感谢!!! !!!但我仍然可以如何删除“type”属性值 - “xs:boolean”的“xs”命名空间声明。我玩重写了一些StreamReaderDelegate方法,但没有成功。 – Andrey

2

基于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); 
    } 
} 
} 
7

更简单的方法可能是使用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