Castor-xml映射出现节点重复问题解决

最近在使用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);
 

你可能感兴趣的:(cast)