我有一个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>
答案 0 :(得分:8)
更简单的方法可能是使用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
答案 1 :(得分:6)
<强>更新强>
您可以通过引入中间层在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
为域对象指定自己的继承指标。我们目前不提供此类数据类型属性的自定义:
答案 2 :(得分:3)
基于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);
}
}
}
答案 3 :(得分:1)
谢谢大家,在这里分享了适用于我的代码的我的解决方案
我尝试使其通用,每个命名空间都包含“:”,如果有任何标记具有“:”,我将编写代码,它将从xml中删除。
这用于在使用jaxb进行编组时跳过命名空间。
import numpy as npy
import pandas as pdas
from matplotlib import pyplot as pt
import matplotlib
from sklearn.linear_model import LinearRegression
import re
from pandasql import sqldf
dataFrame=pdas.read_excel('Project_Airplane_Crashes_and_Fatalities_Since1908.xlsx', sheet="Sheet")
matplotlib.rcParams['figure.figsize'] = (12.0, 8.0)
dataFrame['Year'] = dataFrame['Date'].apply(lambda x: int(str(x)[-4:]))
perYear = dataFrame[['Year','Fatalities']].groupby('Year').agg(['sum','count'])
perYearFig,(xaxis,yaxis)=pt.subplots(2,1,figsize=(15,10))
perYear['Fatalities','sum'].plot(kind='bar',title='Fatalities by Year',grid=True,ax=xaxis,rot=90)
perYear['Fatalities','count'].plot(kind='bar',title='Accidents by Year',grid=True,ax=yaxis,rot=90)
pt.tight_layout()
pt.show()
用于解组,
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;
}
}