前言
调用一些soap协议的项目你或许使用的到,也许我是在造轮子,但是我没在网上找到合适的轮子,就根据现有的项目自己造了一个,废话不说,说思路
使用反射获取对象的属性,根据属性的类型做出相应的处理,如果为基本类型直接使用dom4j创建节点赋值,如果遇到的集合递归处理集合中的对象,并生成相应的节点
自定义了几个注解处理相应的 标签别名、根对象别名、属性为集合类型的别名
先引入依赖
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
项目背景,调用soap协议的项目,但是xml参数有点和想想中的不一样,下面看一下
属性大部分都是下划线命名;
如果你直接创建的java对象也使用这样的命名,然后使用 dom4j的Document也能生成,但是以前学习的时候 命名规范是不是驼峰命名法
代码
自定义注解
package com.zxw.xml.annotation;
import java.lang.annotation.*;
/**
* @author zhangxuewei
* @description 标签内的属性注解
* @date 2023/7/6 17:08
*/
@Target({ElementType.TYPE,ElementType.FIELD})//@Target其中参数类型是ElementType[]数组,其中ElementType是枚举类型
@Retention(RetentionPolicy.RUNTIME)//@Retention 表明该注解的生命周期,其中RetentionPolicy 是枚举类型
@Documented//表明该注解标记的元素可以被Javadoc 或类似的工具文档化
public @interface XmlAttributeName {
String tagName() default "";// 标签名称
}
package com.zxw.xml.annotation;
import java.lang.annotation.*;
/**
* @author zhangxuewei
* @description 标签根对象的 标签别名 注解
* @date 2023/7/6 17:07
*/
@Target({ElementType.TYPE})//@Target其中参数类型是ElementType[]数组,其中ElementType是枚举类型
@Retention(RetentionPolicy.RUNTIME)//@Retention 表明该注解的生命周期,其中RetentionPolicy 是枚举类型
@Documented//表明该注解标记的元素可以被Javadoc 或类似的工具文档化
public @interface XmlRootElementName {
String tagName() default "";// 标签名称
}
package com.zxw.xml.annotation;
import java.lang.annotation.*;
/**
* @author zhangxuewei
* @description 对象属性的标签别名注解
* @date 2023/7/6 17:09
*/
@Target({ElementType.TYPE,ElementType.FIELD})//@Target其中参数类型是ElementType[]数组,其中ElementType是枚举类型
@Retention(RetentionPolicy.RUNTIME)//@Retention 表明该注解的生命周期,其中RetentionPolicy 是枚举类型
@Documented//表明该注解标记的元素可以被Javadoc 或类似的工具文档化
public @interface XmlTagName {
String tagName() default "";// 标签名称
/**
* 如果属性为List,需要在集合对象追加标签名称,使用这个属性
*
* 使用样例
* public class SyncNcRecSettleBIillVO {
* @XmlTagName(tagName = "items", arrayObjTagName = "item")
* private List<RecSettleBIillDetail> items;
* ....
* }
*
* <items>
* <item>
* <billdetail_no></billdetail_no>
* <memo></memo>
* <pk_account></pk_account>
* </item>
* <item>
* <billdetail_no></billdetail_no>
* <memo></memo>
* <pk_account></pk_account>
* </item>
* </items>
* @return
*/
String arrayObjTagName() default "";
}
需要生成xml的java对象
package com.zxw.xml.domain.vo;
import com.zxw.xml.annotation.XmlAttributeName;
import com.zxw.xml.annotation.XmlRootElementName;
import com.zxw.xml.annotation.XmlTagName;
/**
* @projectName: ruoyi
* @package: com.ruoyi.bmp.fi.domain.vo
* @className: SyncNcUfinterface
* @author: zhangxuewei
* @description: TODO
* @date: 2023/7/6 13:57
* @version: 1.0
*/
@XmlRootElementName(tagName = "ufinterface")
public class SyncNcUfinterface {
@XmlAttributeName(tagName = "account")
private String account = "develop";
@XmlAttributeName(tagName = "billtype")
private String billtype;
@XmlAttributeName(tagName = "filename")
private String filename;
@XmlAttributeName(tagName = "groupcode")
private String groupcode;
@XmlAttributeName(tagName = "isexchange")
private String isexchange = "Y";
@XmlAttributeName(tagName = "replace")
private String replace = "Y";
@XmlAttributeName(tagName = "roottag")
private String roottag;
@XmlAttributeName(tagName = "sender")
private String sender;
@XmlTagName(tagName = "bill")
private Bill bill;
public String getAccount() {
return account;
}
public SyncNcUfinterface setAccount(String account) {
this.account = account;
return this;
}
public String getBilltype() {
return billtype;
}
public SyncNcUfinterface setBilltype(String billtype) {
this.billtype = billtype;
return this;
}
public String getFilename() {
return filename;
}
public SyncNcUfinterface setFilename(String filename) {
this.filename = filename;
return this;
}
public String getGroupcode() {
return groupcode;
}
public SyncNcUfinterface setGroupcode(String groupcode) {
this.groupcode = groupcode;
return this;
}
public String getIsexchange() {
return isexchange;
}
public SyncNcUfinterface setIsexchange(String isexchange) {
this.isexchange = isexchange;
return this;
}
public String getReplace() {
return replace;
}
public SyncNcUfinterface setReplace(String replace) {
this.replace = replace;
return this;
}
public String getRoottag() {
return roottag;
}
public SyncNcUfinterface setRoottag(String roottag) {
this.roottag = roottag;
return this;
}
public String getSender() {
return sender;
}
public SyncNcUfinterface setSender(String sender) {
this.sender = sender;
return this;
}
public Bill getBill() {
return bill;
}
public Bill setBill(Object ob) {
this.bill = new Bill();
this.bill.setObject(ob);
return this.bill;
}
class Bill {
@XmlTagName(tagName = "billhead")
private Object object;
@XmlAttributeName(tagName = "id")
private String id;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
}
package com.zxw.xml.domain.vo;
import com.zxw.xml.annotation.XmlAttributeName;
import com.zxw.xml.annotation.XmlRootElementName;
import com.zxw.xml.annotation.XmlTagName;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* @projectName: ruoyi
* @package: com.ruoyi.bmp.fi.domain.vo
* @className: SyncncRecSettleBIillVO
* @author: zhangxuewei
* @description: 同步nc首款结算单VO
* @date: 2023/7/6 10:06
* @version: 1.0
*/
public class SyncNcRecSettleBIillVO {
// 单据日期
@XmlTagName(tagName = "bill_date")
private Date billDate;
// 制单人
private String billmaker;
// 制单日期
@XmlTagName(tagName = "billmaker_date")
private Date billmakerDate;
// 创建人
private String creator;
// 币种
@XmlTagName(tagName = "pk_currtype")
private String pkCurrtype;
// 所属集团
@XmlTagName(tagName = "pk_group")
private String pkGroup;
// 结算财务组织
@XmlTagName(tagName = "pk_org")
private String pkOrg;
@XmlTagName(tagName = "items", arrayObjTagName = "item")
private List<RecSettleBIillDetail> items;
public static class RecSettleBIillDetail {
// 单据分录编号
@XmlTagName(tagName = "billdetail_no")
private String billdetailNo;
// 摘要
private String memo;
// 收款银行账户
@XmlTagName(tagName = "pk_account")
private String pkAccount;
// 所属集团
@XmlTagName(tagName = "pk_group")
private String pkGroup;
// 结算财务组织
@XmlTagName(tagName = "pk_org")
private String pkOrg;
// 收支项目
@XmlTagName(tagName = "pk_recproject")
private String pkRecproject;
// 收款原币金额
@XmlTagName(tagName = "rec_primal")
private BigDecimal recPrimal;
public String getBilldetailNo() {
return billdetailNo;
}
public void setBilldetailNo(String billdetailNo) {
this.billdetailNo = billdetailNo;
}
public String getMemo() {
return memo;
}
public void setMemo(String memo) {
this.memo = memo;
}
public String getPkAccount() {
return pkAccount;
}
public void setPkAccount(String pkAccount) {
this.pkAccount = pkAccount;
}
}
public Date getBillDate() {
return billDate;
}
public void setBillDate(Date billDate) {
this.billDate = billDate;
}
public String getBillmaker() {
return billmaker;
}
public void setBillmaker(String billmaker) {
this.billmaker = billmaker;
}
public Date getBillmakerDate() {
return billmakerDate;
}
public void setBillmakerDate(Date billmakerDate) {
this.billmakerDate = billmakerDate;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getPkCurrtype() {
return pkCurrtype;
}
public void setPkCurrtype(String pkCurrtype) {
this.pkCurrtype = pkCurrtype;
}
public String getPkGroup() {
return pkGroup;
}
public void setPkGroup(String pkGroup) {
this.pkGroup = pkGroup;
}
public String getPkOrg() {
return pkOrg;
}
public void setPkOrg(String pkOrg) {
this.pkOrg = pkOrg;
}
public List<RecSettleBIillDetail> getItems() {
return items;
}
public void setItems(List<RecSettleBIillDetail> items) {
this.items = items;
}
}
工具类
package com.zxw.xml.util;
import cn.hutool.core.date.DateUtil;
import com.zxw.xml.annotation.XmlAttributeName;
import com.zxw.xml.annotation.XmlRootElementName;
import com.zxw.xml.annotation.XmlTagName;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.util.ObjectUtils;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @projectName: ruoyi
* @package: com.ruoyi.common.utils.xml
* @className: ObjectToXmlConverter
* @author: zhangxuewei
* @description: TODO
* @date: 2023/7/6 13:15
* @version: 1.0
*/
public class ObjectToXmlConverter {
public static String convertToXml(Object object) {
Document document = DocumentHelper.createDocument();
XmlRootElementName an = object.getClass().getDeclaredAnnotation(XmlRootElementName.class);
Element rootElement = document.addElement(ObjectUtils.isEmpty(an.tagName()) ? object.getClass().getSimpleName() : an.tagName());
convertObjectToElements(object, rootElement, document);
return document.asXML();
}
private static void convertObjectToElements(Object object, Element parentElement, Document document) {
for (Field field : object.getClass().getDeclaredFields()) {
try {
field.setAccessible(true);
Object value = field.get(object);
// 如果为空,给个空字符串,这样即使 属性为null 也会生成标签
if (value == null) {
value = "";
}
if (!(field.getName().indexOf("this") > -1)) {
if (!ObjectUtils.isEmpty(field.getAnnotation(XmlAttributeName.class))) {
parentElement.addAttribute(ObjectUtils.isEmpty(field.getAnnotation(XmlAttributeName.class)) ? field.getName() : field.getAnnotation(XmlAttributeName.class).tagName(), value.toString());
} else {
Element element = parentElement.addElement(ObjectUtils.isEmpty(field.getAnnotation(XmlTagName.class)) ? field.getName() : field.getAnnotation(XmlTagName.class).tagName());
if (value instanceof String || value instanceof Integer || value instanceof Boolean || value instanceof Long || value instanceof BigDecimal) {
element.setText(String.valueOf(value));
} else if (value instanceof Double || value instanceof Float) {
element.setText(Double.toString(Double.valueOf(value.toString())));
} else if (value instanceof Date) {
element.setText(DateUtil.format((Date) value, "yyyy-MM-dd HH:mm:ss"));
} else if (value instanceof List) {
for (Object listValue : (List) value) {
Element elementL;
if (!ObjectUtils.isEmpty(field.getAnnotation(XmlTagName.class)) && !ObjectUtils.isEmpty(field.getAnnotation(XmlTagName.class).arrayObjTagName()))
elementL = element.addElement(field.getAnnotation(XmlTagName.class).arrayObjTagName());
else
elementL = element.addElement("item");
convertObjectToElements(listValue, elementL, document);
}
} else if (value instanceof Map) {
for (Map.Entry<String, Object> mapEntry : ((Map<String, Object>) value).entrySet()) {
Element mapElement = element.addElement(mapEntry.getKey());
convertObjectToElements(mapEntry.getValue(), mapElement, document);
}
} else {
convertObjectToElements(value, element, document);
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
测试
package com.zxw.xml.test;
import com.zxw.xml.domain.vo.SyncNcRecSettleBIillVO;
import com.zxw.xml.domain.vo.SyncNcUfinterface;
import com.zxw.xml.util.ObjectToXmlConverter;
import org.apache.tools.ant.util.DateUtils;
import java.util.ArrayList;
import java.util.Date;
/**
* @projectName: util-cloud
* @package: com.zxw.xml.test
* @className: Test
* @author: zhangxuewei
* @description: TODO
* @date: 2023/7/6 17:07
* @version: 1.0
*/
public class Test {
public static void main(String[] args) {
SyncNcRecSettleBIillVO s = new SyncNcRecSettleBIillVO();
s.setBillDate(new Date());
s.setPkCurrtype("10001kjhhj1232321");
s.setItems(new ArrayList<SyncNcRecSettleBIillVO.RecSettleBIillDetail>() {{
SyncNcRecSettleBIillVO.RecSettleBIillDetail detail = new SyncNcRecSettleBIillVO.RecSettleBIillDetail();
SyncNcRecSettleBIillVO.RecSettleBIillDetail detail2 = new SyncNcRecSettleBIillVO.RecSettleBIillDetail();
add(detail);
add(detail2);
}});
SyncNcUfinterface syncNcUfinterface = new SyncNcUfinterface();
syncNcUfinterface.setBilltype("RecSettleBillFromBmp").setSender("Bmp").setBill(s);
System.out.println(ObjectToXmlConverter.convertToXml(syncNcUfinterface));
}
}
测试结果
D:\mcdev\jdk8\bin\java.exe -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:53019,suspend=y,server=n -javaagent:C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2020.1\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\mcdev\jdk8\jre\lib\charsets.jar;D:\mcdev\jdk8\jre\lib\deploy.jar;D:\mcdev\jdk8\jre\lib\ext\access-bridge-64.jar;D:\mcdev\jdk8\jre\lib\ext\cldrdata.jar;D:\mcdev\jdk8\jre\lib\ext\dnsns.jar;D:\mcdev\jdk8\jre\lib\ext\jaccess.jar;D:\mcdev\jdk8\jre\lib\ext\jfxrt.jar;D:\mcdev\jdk8\jre\lib\ext\localedata.jar;D:\mcdev\jdk8\jre\lib\ext\nashorn.jar;D:\mcdev\jdk8\jre\lib\ext\sunec.jar;D:\mcdev\jdk8\jre\lib\ext\sunjce_provider.jar;D:\mcdev\jdk8\jre\lib\ext\sunmscapi.jar;D:\mcdev\jdk8\jre\lib\ext\sunpkcs11.jar;D:\mcdev\jdk8\jre\lib\ext\zipfs.jar;D:\mcdev\jdk8\jre\lib\javaws.jar;D:\mcdev\jdk8\jre\lib\jce.jar;D:\mcdev\jdk8\jre\lib\jfr.jar;D:\mcdev\jdk8\jre\lib\jfxswt.jar;D:\mcdev\jdk8\jre\lib\jsse.jar;D:\mcdev\jdk8\jre\lib\management-agent.jar;D:\mcdev\jdk8\jre\lib\plugin.jar;D:\mcdev\jdk8\jre\lib\resources.jar;D:\mcdev\jdk8\jre\lib\rt.jar;C:\workspace\program\util-cloud\target\classes;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter-web\2.7.9\spring-boot-starter-web-2.7.9.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter\2.7.9\spring-boot-starter-2.7.9.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot\2.7.9\spring-boot-2.7.9.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-autoconfigure\2.7.9\spring-boot-autoconfigure-2.7.9.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter-logging\2.7.9\spring-boot-starter-logging-2.7.9.jar;C:\workspace\mavenRepository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;C:\workspace\mavenRepository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;C:\workspace\mavenRepository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;C:\workspace\mavenRepository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;C:\workspace\mavenRepository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;C:\workspace\mavenRepository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\workspace\mavenRepository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter-json\2.7.9\spring-boot-starter-json-2.7.9.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\core\jackson-databind\2.13.5\jackson-databind-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\core\jackson-annotations\2.13.5\jackson-annotations-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\core\jackson-core\2.13.5\jackson-core-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.5\jackson-datatype-jdk8-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.5\jackson-datatype-jsr310-2.13.5.jar;C:\workspace\mavenRepository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.5\jackson-module-parameter-names-2.13.5.jar;C:\workspace\mavenRepository\org\springframework\boot\spring-boot-starter-tomcat\2.7.9\spring-boot-starter-tomcat-2.7.9.jar;C:\workspace\mavenRepository\org\apache\tomcat\embed\tomcat-embed-core\9.0.71\tomcat-embed-core-9.0.71.jar;C:\workspace\mavenRepository\org\apache\tomcat\embed\tomcat-embed-el\9.0.71\tomcat-embed-el-9.0.71.jar;C:\workspace\mavenRepository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.71\tomcat-embed-websocket-9.0.71.jar;C:\workspace\mavenRepository\org\springframework\spring-web\5.3.25\spring-web-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-beans\5.3.25\spring-beans-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-webmvc\5.3.25\spring-webmvc-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-aop\5.3.25\spring-aop-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-context\5.3.25\spring-context-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-expression\5.3.25\spring-expression-5.3.25.jar;C:\workspace\mavenRepository\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar;C:\workspace\mavenRepository\com\google\protobuf\protobuf-java\3.11.4\protobuf-java-3.11.4.jar;C:\workspace\mavenRepository\org\projectlombok\lombok\1.18.26\lombok-1.18.26.jar;C:\workspace\mavenRepository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;C:\workspace\mavenRepository\org\springframework\spring-core\5.3.25\spring-core-5.3.25.jar;C:\workspace\mavenRepository\org\springframework\spring-jcl\5.3.25\spring-jcl-5.3.25.jar;C:\workspace\mavenRepository\org\jsoup\jsoup\1.13.1\jsoup-1.13.1.jar;C:\workspace\mavenRepository\org\apache\poi\poi\3.10-beta2\poi-3.10-beta2.jar;C:\workspace\mavenRepository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;C:\workspace\mavenRepository\org\apache\poi\poi-ooxml\3.10-beta2\poi-ooxml-3.10-beta2.jar;C:\workspace\mavenRepository\dom4j\dom4j\1.6.1\dom4j-1.6.1.jar;C:\workspace\mavenRepository\xml-apis\xml-apis\1.0.b2\xml-apis-1.0.b2.jar;C:\workspace\mavenRepository\org\apache\poi\poi-ooxml-schemas\3.10-beta2\poi-ooxml-schemas-3.10-beta2.jar;C:\workspace\mavenRepository\org\apache\xmlbeans\xmlbeans\2.3.0\xmlbeans-2.3.0.jar;C:\workspace\mavenRepository\stax\stax-api\1.0.1\stax-api-1.0.1.jar;C:\workspace\mavenRepository\org\apache\poi\poi-scratchpad\3.0.2-FINAL\poi-scratchpad-3.0.2-FINAL.jar;C:\workspace\mavenRepository\commons-logging\commons-logging\1.1\commons-logging-1.1.jar;C:\workspace\mavenRepository\log4j\log4j\1.2.13\log4j-1.2.13.jar;C:\workspace\mavenRepository\cn\hutool\hutool-all\5.8.15\hutool-all-5.8.15.jar;C:\workspace\mavenRepository\cglib\cglib\3.2.5\cglib-3.2.5.jar;C:\workspace\mavenRepository\org\ow2\asm\asm\6.0_ALPHA\asm-6.0_ALPHA.jar;C:\workspace\mavenRepository\org\apache\ant\ant\1.9.6\ant-1.9.6.jar;C:\workspace\mavenRepository\org\apache\ant\ant-launcher\1.9.6\ant-launcher-1.9.6.jar;C:\workspace\mavenRepository\commons-io\commons-io\2.6\commons-io-2.6.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar" com.zxw.xml.test.Test
Connected to the target VM, address: '127.0.0.1:53019', transport: 'socket'
<?xml version="1.0" encoding="UTF-8"?>
<ufinterface account="develop" billtype="RecSettleBillFromBmp" filename="" groupcode="" isexchange="Y" replace="Y" roottag="" sender="Bmp"><bill id=""><billhead><bill_date>2023-07-06 17:40:45</bill_date><billmaker></billmaker><billmaker_date></billmaker_date><creator></creator><pk_currtype>10001kjhhj1232321</pk_currtype><pk_group></pk_group><pk_org></pk_org><items><item><billdetail_no></billdetail_no><memo></memo><pk_account></pk_account><pk_group></pk_group><pk_org></pk_org><pk_recproject></pk_recproject><rec_primal></rec_primal></item><item><billdetail_no></billdetail_no><memo></memo><pk_account></pk_account><pk_group></pk_group><pk_org></pk_org><pk_recproject></pk_recproject><rec_primal></rec_primal></item></items></billhead></bill></ufinterface>
Disconnected from the target VM, address: '127.0.0.1:53019', transport: 'socket'
Process finished with exit code 0
格式化后的结果
<?xml version="1.0" encoding="UTF-8"?>
<ufinterface account="develop" billtype="RecSettleBillFromBmp" filename="" groupcode="" isexchange="Y" replace="Y" roottag="" sender="Bmp">
<bill id="">
<billhead>
<bill_date>2023-07-06 17:40:45</bill_date>
<billmaker></billmaker>
<billmaker_date></billmaker_date>
<creator></creator>
<pk_currtype>10001kjhhj1232321</pk_currtype>
<pk_group></pk_group>
<pk_org></pk_org>
<items>
<item>
<billdetail_no></billdetail_no>
<memo></memo>
<pk_account></pk_account>
<pk_group></pk_group>
<pk_org></pk_org>
<pk_recproject></pk_recproject>
<rec_primal></rec_primal>
</item>
<item>
<billdetail_no></billdetail_no>
<memo></memo>
<pk_account></pk_account>
<pk_group></pk_group>
<pk_org></pk_org>
<pk_recproject></pk_recproject>
<rec_primal></rec_primal>
</item>
</items>
</billhead>
</bill>
</ufinterface>