JAXB:如何在没有名称空间的情况下解组 XML
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7184526/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JAXB: How can I unmarshal XML without namespaces
提问by Andrey
I have an XML file:
我有一个 XML 文件:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<object>
<str>the type</str>
<bool type="boolean">true</bool>
</object>
And I want to unmarshal it to an object of the class below
我想将它解组到下面的类的对象
@XmlRootElement(name="object")
public class Spec {
public String str;
public Object bool;
}
How can I do this? Unless I specify namespaces (see below), it doesn't work.
我怎样才能做到这一点?除非我指定命名空间(见下文),否则它不起作用。
<?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>
回答by Gregor
An easier way might be to use unmarshalByDeclaredType, since you already know the type you want to unmarshal.
更简单的方法可能是使用unmarshalByDeclaredType,因为您已经知道要解组的类型。
By using
通过使用
Unmarshaller.unmarshal(rootNode, MyType.class);
you don't need to have a namespace declaration in the XML, since you pass in the JAXBElement that has the namespace already set.
您不需要在 XML 中有名称空间声明,因为您传入了已设置名称空间的 JAXBElement。
This also perfectly legal, since you are not required to reference a namespace in an XML instance, see http://www.w3.org/TR/xmlschema-0/#PO- and many clients produce XML in that fashion.
这也是完全合法的,因为您不需要在 XML 实例中引用名称空间,请参阅http://www.w3.org/TR/xmlschema-0/#PO- 许多客户端以这种方式生成 XML。
Finally got it to work. Note that you have to remove any custom namespace in the schema; here's working sample code:
终于让它工作了。请注意,您必须删除架构中的任何自定义命名空间;这是工作示例代码:
The schema:
架构:
<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:
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<name>Jane Doe</name>
<phone>08154712</phone>
</customer>
JAXB code:
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
回答by bdoughan
UPDATE
更新
You can get this to work by introducing an intermediate layer to translate between typeand xsi:type. Below is example of using the StAX StreamReaderDelegateto do this for the JAXB unmarshal operation:
您可以通过引入一个中间层在type和之间进行转换来实现这一点xsi:type。下面是使用 StAXStreamReaderDelegate为 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:typeis a schema mechanism for specifying the real type of an element (similar to a cast in Java). If you remove the namespace, you are changing the semantics of the document.
xsi:type是一种模式机制,用于指定元素的真实类型(类似于 Java 中的强制转换)。如果删除命名空间,您将更改文档的语义。
In EclipseLink JAXB (MOXy)we allow you to specify your own inheritance indicator for domain objects using @XmlDescriminatorNodeand @XmlDescrimatorValue. We currently do not offer this type of customization for data type properties:
在EclipseLink JAXB (MOXy) 中,我们允许您使用@XmlDescriminatorNode和为域对象指定自己的继承指示符@XmlDescrimatorValue。我们目前不为数据类型属性提供这种类型的自定义:
回答by Andrey
Based on Blaise's comments (thanks Blaise!) and my research. Here is the solution to my problem. Do you agree with that Blaise, or you have a better way?
基于 Blaise 的评论(感谢 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);
}
}
}
回答by Binal Parekh
Thank you all, here shared my solution which works for my code
谢谢大家,这里分享了我的解决方案,适用于我的代码
i try to make it generic every namespace contain ": " i write code if any tag have ":" it will remove from xml.
我尝试使每个命名空间都包含“:”通用,如果任何标签具有“:”,我会编写代码,它将从 xml 中删除。
This is used to skip namespace during unmarshalling using jaxb.
这用于在使用 jaxb 解组期间跳过命名空间。
public class NamespaceFilter {
private NamespaceFilter() {
}
private static final String COLON = ":";
public static XMLReader nameSpaceFilter() throws SAXException {
XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) {
private boolean skipNamespace;
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (qName.indexOf(COLON) > -1) {
skipNamespace = true;
} else {
skipNamespace = false;
super.startElement("", localName, qName, atts);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.indexOf(COLON) > -1) {
skipNamespace = true;
} else {
skipNamespace = false;
super.endElement("", localName, qName);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (!skipNamespace) {
super.characters(ch, start, length);
}
}
};
return xr;
}
}
for unmarshalling ,
用于解组,
XMLReader xr = NamespaceFilter.nameSpaceFilter();
Source src = new SAXSource(xr, new InputSource("filePath"));
StringWriter sw = new StringWriter();
Result res = new StreamResult(sw);
TransformerFactory.newInstance().newTransformer().transform(src, res);
JAXBContext jc = JAXBContext.newInstance(Tab.class);
Unmarshaller u = jc.createUnmarshaller();
String done = sw.getBuffer().toString();
StringReader reader = new StringReader(done);
Tab tab = (Tab) u.unmarshal(reader);
System.out.println(tab);

