最近在使用Castor-xml生成XML時發現生成的格式不符合要求。
如要求生成以下格式的XML
<Signature> <SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod> <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod> <Reference URI=""> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod> <DigestValue>222</DigestValue> </Reference> </SignedInfo> <SignatureValue>123</SignatureValue> <KeyInfo> <KeyName>1234</KeyName> </KeyInfo> </Signature>
一開始覺得定義一個類及映射一下就可以的,但生成的XML會出現節點順序錯亂及重複節點的問題(對於含有屬性的子節點)
先看錯誤的方法:
類定義:
public class H2010BhlBean implements Serializable
{
private static final long serialVersionUID = 1L;
protected String canonicalizationMethodAlgorithm;
protected String signatureMethodAlgorithm;
protected String uri;
protected String digestMethodAlgorithm;
protected String digestValue;
protected String signatureValue;
protected String keyName;
//以下還有get及set方法,略
}
映射文件定義:
<?xml version="1.0" encoding="UTF-8"?> <mapping> <description>收發貨申報報文</description> <class name="com.eclink.ytcis.bhlbill.vo.BhlBillMap"> <map-to xml="Signature"/> <field name="canonicalizationMethodAlgorithm"> <bind-xml name="Algorithm" node="attribute" location="SignedInfo/CanonicalizationMethod"/> </field> <field name="signatureMethodAlgorithm"> <bind-xml name="Algorithm" node="attribute" location="SignedInfo/SignatureMethod"/> </field> <field name="uri"> <bind-xml name="URI" node="attribute" location="SignedInfo/Reference"/> </field> <field name="digestMethodAlgorithm"> <bind-xml name="Algorithm" node="attribute" location="SignedInfo/Reference/DigestMethod"/> </field> <field name="digestValue"> <bind-xml name="DigestValue" node="element" location="SignedInfo/Reference"/> </field> <field name="signatureValue"> <bind-xml name="SignatureValue" node="element"/> </field> <field name="keyName"> <bind-xml name="KeyName" node="element" location="KeyInfo"/> </field> </mapping>
生成後的結果是這樣:
<?xml version="1.0" encoding="GBK"?> <Signature> <SignedInfo> <Reference URI=""> <DigestValue></DigestValue> </Reference> </SignedInfo> <SignatureValue></SignatureValue> <KeyInfo> <KeyName></KeyName> </KeyInfo> <SignedInfo> <CanonicalizationMethod Algorithm=""/> </SignedInfo> <SignedInfo> <SignatureMethod Algorithm=""/> </SignedInfo> <SignedInfo> <Reference> <DigestMethod Algorithm=""/> </Reference> </SignedInfo> </Signature>
上面的結果顯然不符合要求的。
查了相關castor的資料,基本也沒說到這一塊。。於是對XML進行分析,出現問題是因爲多層節點及節點下面有屬性值的設置,按Castor的映射原理,試着把所有葉子節點的父節點定義成單獨的類,並進行映射,問題得以解決。
正確如下:
<?xml version="1.0" encoding="UTF-8"?> <mapping> <description>收發貨申報報文</description> <class name="com.eclink.ytcis.bhlbill.vo.BhlBillMap"> <map-to xml="Signature"/> <field name="canonicalizationMethodBean" type="com.eclink.ytcis.bhl.bean.CanonicalizationMethodBean"> <bind-xml name="CanonicalizationMethod" location="SignedInfo"/> </field> <field name="signatureMethodBean" type="com.eclink.ytcis.bhl.bean.SignatureMethodBean"> <bind-xml name="SignatureMethod" location="SignedInfo"/> </field> <field name="referenceBean" type="com.eclink.ytcis.bhl.bean.ReferenceBean"> <bind-xml name="Reference" location="SignedInfo"/> </field> <field name="signatureValue"> <bind-xml name="SignatureValue" node="element"/> </field> <field name="keyName"> <bind-xml name="KeyName" node="element" location="KeyInfo"/> </field> <include href="mapping/h2010BhlSignedInfo.xml"/> </mapping>
引用的h2010BhlSignedInfo.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <mapping> <description>H2010報文頭Head info mapping</description> <class name="com.eclink.ytcis.bhl.bean.CanonicalizationMethodBean"> <field name="canonicalizationMethodAlgorithm"> <bind-xml name="Algorithm" node="attribute"/> </field> <field name="canonicalizationMethod"> <bind-xml name="" node="text"/> </field> </class> <class name="com.eclink.ytcis.bhl.bean.SignatureMethodBean"> <field name="signatureMethodAlgorithm"> <bind-xml name="Algorithm" node="attribute"/> </field> <field name="signatureMethod"> <bind-xml name="" node="text" /> </field> </class> <class name="com.eclink.ytcis.bhl.bean.ReferenceBean"> <field name="uri"> <bind-xml name="URI" node="attribute" /> </field> <field name="digestMethod"> <bind-xml name="" node="text" location="DigestMethod"/> </field> <field name="digestMethodAlgorithm"> <bind-xml name="Algorithm" node="attribute" location="DigestMethod"/> </field> <field name="digestValue"> <bind-xml name="DigestValue" node="element" /> </field> </class> </mapping>
實體對象
public class H2010BhlBean implements Serializable
{
private static final long serialVersionUID = 1L;
protected CanonicalizationMethodBean canonicalizationMethodBean;
protected SignatureMethodBean signatureMethodBean;
protected ReferenceBean referenceBean;
protected String signatureValue;
protected String keyName;
//get set方法略
}
其它關聯的類
public class CanonicalizationMethodBean implements Serializable {
private static final long serialVersionUID = 1L;
private String canonicalizationMethodAlgorithm;
private String canonicalizationMethod;
/**
* @return the canonicalizationMethodAlgorithm
*/
public String getCanonicalizationMethodAlgorithm() {
return canonicalizationMethodAlgorithm;
}
/**
* @param canonicalizationMethodAlgorithm the canonicalizationMethodAlgorithm to set
*/
public void setCanonicalizationMethodAlgorithm(
String canonicalizationMethodAlgorithm) {
this.canonicalizationMethodAlgorithm = canonicalizationMethodAlgorithm;
}
/**
* @return the canonicalizationMethod
*/
public String getCanonicalizationMethod() {
return canonicalizationMethod;
}
/**
* @param canonicalizationMethod the canonicalizationMethod to set
*/
public void setCanonicalizationMethod(String canonicalizationMethod) {
this.canonicalizationMethod = canonicalizationMethod;
}
}
public class SignatureMethodBean implements Serializable {
private static final long serialVersionUID = 1L;
private String signatureMethodAlgorithm;
private String signatureMethod;
/**
* @return the signatureMethodAlgorithm
*/
public String getSignatureMethodAlgorithm() {
return signatureMethodAlgorithm;
}
/**
* @param signatureMethodAlgorithm the signatureMethodAlgorithm to set
*/
public void setSignatureMethodAlgorithm(String signatureMethodAlgorithm) {
this.signatureMethodAlgorithm = signatureMethodAlgorithm;
}
/**
* @return the signatureMethod
*/
public String getSignatureMethod() {
return signatureMethod;
}
/**
* @param signatureMethod the signatureMethod to set
*/
public void setSignatureMethod(String signatureMethod) {
this.signatureMethod = signatureMethod;
}
}
public class ReferenceBean implements Serializable {
private static final long serialVersionUID = 1L;
private String uri;
private String digestMethodAlgorithm;
private String digestMethod;
private String digestValue;
/**
* @return the uri
*/
public String getUri() {
return uri;
}
/**
* @param uri the uri to set
*/
public void setUri(String uri) {
this.uri = uri;
}
/**
* @return the digestMethodAlgorithm
*/
public String getDigestMethodAlgorithm() {
return digestMethodAlgorithm;
}
/**
* @param digestMethodAlgorithm the digestMethodAlgorithm to set
*/
public void setDigestMethodAlgorithm(String digestMethodAlgorithm) {
this.digestMethodAlgorithm = digestMethodAlgorithm;
}
/**
* @return the digestMethod
*/
public String getDigestMethod() {
return digestMethod;
}
/**
* @param digestMethod the digestMethod to set
*/
public void setDigestMethod(String digestMethod) {
this.digestMethod = digestMethod;
}
/**
* @return the digestValue
*/
public String getDigestValue() {
return digestValue;
}
/**
* @param digestValue the digestValue to set
*/
public void setDigestValue(String digestValue) {
this.digestValue = digestValue;
}
}
映射後生成的結果:
<?xml version="1.0" encoding="GBK"?> <Signature> <SignedInfo> <CanonicalizationMethod> <CanonicalizationMethod Algorithm=""/> </CanonicalizationMethod> <SignatureMethod> <SignatureMethod Algorithm=""/> </SignatureMethod> <Reference> <Reference URI=""> <DigestMethod Algorithm=""/> <DigestValue></DigestValue> </Reference> </Reference> </SignedInfo> <SignatureValue></SignatureValue> <KeyInfo> <KeyName></KeyName> </KeyInfo> </Signature>
公共處理類:
package com.eclink.util;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.Unmarshaller;
import org.xml.sax.InputSource;
import sun.net.www.content.text.plain;
import com.eclink.spring.ServiceFactory;
import com.eclink.ytcis.workShop.vo.PactList;
public class MarshallerUtil {
/**
*
* @param cls
* @param objectXml
* @return
* @throws Exception
*/
public static Object unmarshaller(@SuppressWarnings("rawtypes") Class cls, String objectXml)
throws Exception {
File f = new File(objectXml);
return unmarshallerNew(cls, f, false);
}
/**
*
* @param cls
* @param objectXml
* @return
* @throws Exception
* @author XuChang
*/
@SuppressWarnings("rawtypes")
public static Object unmarshaller(Class cls, File objectXml)
throws Exception {
return unmarshallerNew(cls, objectXml, false);
}
@SuppressWarnings("rawtypes")
public static Object unmarshaller(Class cls, File objectXml,
boolean namespace) throws Exception {
Unmarshaller unmarshaller = ServiceFactory.getUnmarshaller();
unmarshaller.setClass(cls);
if (namespace == true) {
unmarshaller.setProperty("org.exolab.castor.parser.namespaces",
"true");
}
EncodingDetect detector = new EncodingDetect();
int codingValue = detector.detectEncoding(objectXml);
String encoding = detector.getEncoding(codingValue);
if ("OTHER".equals(encoding)) {
encoding = Constants.XML_ENCODING;
}
Reader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(objectXml), encoding));
Object obj = (Object) unmarshaller.unmarshal(reader);
reader.close();
return obj;
}
@SuppressWarnings("rawtypes")
public static Object unmarshallerNew(Class cls, File objectXml,
boolean namespace) throws Exception {
Unmarshaller unmarshaller = ServiceFactory.getUnmarshaller();
unmarshaller.setClass(cls);
if (namespace == true) {
unmarshaller.setProperty("org.exolab.castor.parser.namespaces",
"true");
}
FileInputStream is = new FileInputStream(objectXml);
byte[] b = new byte[(int) objectXml.length()];
is.read(b);
is.close();
byte[] b2 = null;
boolean isRepeat = false;
if (b[0] == -17 && b[1] == -69 && b[2] == -65) {
b2 = new byte[b.length - 3];
for (int i = 0, len = b2.length; i < len; i++) {
b2[i] = b[i + 3];
}
isRepeat = true;
} else {
b2 = b;
}
String content = new String(b2);
int encodingIndex = content.indexOf("encoding=\"");
String encoding = "UTF-8";
if (encodingIndex > 0) {
int encodingEndIndex = content.indexOf("\"", encodingIndex + 10);
encoding = content.substring(encodingIndex + 10, encodingEndIndex);
}
content = new String(b2, encoding);
// 有命名空間,刪除命名空間
if (content.indexOf("<ExchangeTableEntity>") < 0) {
content = content.replaceAll("<ExchangeTableEntity.*?>",
"<ExchangeTableEntity>");
isRepeat = true;
}
if (isRepeat) {
FileOutputStream fo = new FileOutputStream(objectXml);
fo.write(content.getBytes(encoding));
fo.close();
}
Reader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(objectXml), encoding));
Object obj = (Object) unmarshaller.unmarshal(reader);
reader.close();
return obj;
}
@SuppressWarnings("rawtypes")
public static Object unmarshallerString(Class cls, String objectXml)
throws Exception {
Unmarshaller unmarshaller = ServiceFactory.getUnmarshaller();
unmarshaller.setClass(cls);
int index = objectXml.indexOf("<CONTAINER_ID>");
if (!objectXml.substring(index + 14, index + 15).equals("<")) {
objectXml = objectXml.replaceAll("<CONTAINER_ID>",
"<CONTAINER_ID><ID>");
objectXml = objectXml.replaceAll("</CONTAINER_ID>",
"</ID></CONTAINER_ID>");
}
Object obj = (Object) unmarshaller.unmarshal(new InputSource(
new StringReader(objectXml)));
return obj;
}
@SuppressWarnings("rawtypes")
public static Object unmarshaller(Class cls, byte[] b, boolean namespace)
throws Exception {
Unmarshaller unmarshaller = ServiceFactory.getUnmarshaller();
unmarshaller.setClass(cls);
if (namespace == true) {
unmarshaller.setProperty("org.exolab.castor.parser.namespaces",
"true");
}
String encoding = Constants.XML_ENCODING;
Reader reader = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream(b), encoding));
Object obj = (Object) unmarshaller.unmarshal(reader);
reader.close();
return obj;
}
/**
*
* @param cls
* @param objectXml
* @param mappingXml
* @return
* @throws Exception
*/
public static Object unmarshaller(String objectXml, String mappingXml)
throws Exception {
Unmarshaller unmarshaller = ServiceFactory.getUnmarshaller();
Mapping mapping = new Mapping();
mapping.loadMapping(mappingXml);
EncodingDetect detector = new EncodingDetect();
int codingValue = detector.detectEncoding(new File(objectXml));
String encoding = detector.getEncoding(codingValue);
if ("OTHER".equals(encoding)) {
encoding = Constants.XML_ENCODING;
}
Reader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(objectXml), encoding));
unmarshaller.setMapping(mapping);
Object obj = (Object) unmarshaller.unmarshal(reader);
reader.close();
return obj;
}
public static void marshaller(Object marobject, String filename)
throws Exception {
File f = new File(filename);
marshaller(marobject, f);
}
public static void marshaller(Object marobject, File filename)
throws Exception {
marshaller(marobject, filename, true);
}
public static void marshaller(Object marobject, File filename,
boolean nameSpace) throws Exception {
Marshaller marshaller = (Marshaller) ServiceFactory.getMarshaller();
Writer out = new PrintWriter(filename, Constants.XML_ENCODING);
marshaller.setWriter(out);
marshaller.setProperty("org.exolab.castor.indent", "true");
marshaller.setEncoding(Constants.XML_ENCODING);
if (nameSpace == true) {
marshaller.setProperty("org.exolab.castor.parser.namespaces",
"true");
marshaller.setNamespaceMapping("xsi", Constants.XML_NAMESPACE_XSI);
marshaller.setNamespaceMapping("xsd", Constants.XML_NAMESPACE_XSD);
}
marshaller.marshal(marobject);
out.flush();
out.close();
}
public static String marshallerString(Object marobject, boolean nameSpace)
throws Exception {
Marshaller marshaller = null;
StringWriter sw = null;
try {
marshaller = (Marshaller) ServiceFactory.getMarshaller();
sw = new StringWriter();
marshaller.setWriter(sw);
marshaller.setProperty("org.exolab.castor.indent", "true");
marshaller.setEncoding(Constants.XML_ENCODING);
if (nameSpace == true) {
marshaller.setProperty("org.exolab.castor.parser.namespaces",
"true");
marshaller.setNamespaceMapping("xsi",
Constants.XML_NAMESPACE_XSI);
}
marshaller.marshal(marobject);
} catch (Exception e) {
throw e;
} finally {
sw.flush();
sw.close();
}
return sw.getBuffer().toString();
}
/**
* 生成xml回執文件
* @Title: writeXML
* @param @param filePath 生成文件的路徑,
* @param @param fileName 生成文件的名稱,
* @param @param MappingPath maping文件的路徑
* @param @param entryapplyBack 需要生成的實體類
* @return void
* @throws
*/
public static void writeExportXML(String filePath,String fileName,String MappingPath,Object object)throws Exception{
StringWriter writer=null;
PrintStream pw=null;
try{
File dir=new File(filePath);
if(dir.exists()==false){
dir.mkdirs();
}
String file=filePath+File.separator+fileName;
Mapping map = new Mapping();
map.loadMapping(MappingPath);
writer= new StringWriter();
Marshaller marshaller = new Marshaller(writer);
marshaller.setProperty("org.exolab.castor.indent", "true");
marshaller.setEncoding(Constants.XML_ENCODING);
marshaller.setMapping(map);
marshaller.marshal(object);
writer.close();
pw=new PrintStream(new FileOutputStream(file),true,Constants.XML_ENCODING);
pw.print(writer.toString());
} catch (IOException e) {
e.printStackTrace();
throw new Exception("在生成xml回執文件的時候,打開文件流失敗:"+e.getMessage());
} catch(Exception ex){
ex.printStackTrace();
throw new Exception("生成xml回執文件解析失敗:"+ex.getMessage());
}finally{
if(writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
throw new Exception("在生成xml回執文件的時候,關閉文件流失敗:"+e.getMessage());
}
}
if(pw!=null){
pw.flush();
pw.close();
}
}
}
/**
* @Title: writeXML
* @Description: xml格式返回的字符串
* @param @param MappingPath maping文件的路徑
* @param @param entryapplyBack 需要生成的實體類
* @return String xml格式返回的字符串
* @throws
*/
public static String writeXMLtoString(String MappingPath,Object object)throws Exception{
StringWriter writer=null;
try{
Mapping map = new Mapping();
map.loadMapping(MappingPath);
writer= new StringWriter();
Marshaller marshaller = new Marshaller(writer);
marshaller.setProperty("org.exolab.castor.indent", "true");
marshaller.setEncoding(Constants.XML_ENCODING);
marshaller.setMapping(map);
marshaller.marshal(object);
writer.close();
return writer.toString();
} catch (IOException e) {
e.printStackTrace();
throw new Exception("在生成xml回執文件的時候,打開文件流失敗:"+e.getMessage());
} catch(Exception ex){
ex.printStackTrace();
throw new Exception("生成xml回執文件解析失敗:"+ex.getMessage());
}finally{
if(writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
throw new Exception("在生成xml回執文件的時候,關閉文件流失敗:"+e.getMessage());
}
}
}
}
public static void writeExportXMLByString(String filePath,String fileName,String xmlContent) throws Exception{
StringWriter writer=null;
PrintStream pw=null;
try{
File dir=new File(filePath);
if(dir.exists()==false){
dir.mkdirs();
}
String file=filePath+File.separator+fileName;
pw=new PrintStream(new FileOutputStream(file),true,Constants.XML_ENCODING);
pw.print(xmlContent);
} catch (IOException e) {
e.printStackTrace();
throw new Exception("在生成xml回執文件的時候,打開文件流失敗:"+e.getMessage());
} catch(Exception ex){
ex.printStackTrace();
throw new Exception("生成xml回執文件解析失敗:"+ex.getMessage());
}finally{
if(writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
throw new Exception("在生成xml回執文件的時候,關閉文件流失敗:"+e.getMessage());
}
}
if(pw!=null){
pw.flush();
pw.close();
}
}
}
}
MarshallerUtil.writeXMLtoString(
"mapping/bhl_bill.xml", bhlBillMap)
解編,從XML生成對象:BhlBillRetMap bhlBillRetMap = null;
bhlBillRetMap = (BhlBillRetMap)MarshallerUtil.unmarshaller(BhlBillRetMap.class, file);