依据xsd定义的xml格式封装数据并生成xml文件

依据xsd定义的xml格式封装数据并生成xml文件

根据xsd定义的xml格式封装数据并生成xml文件
   在项目组最近一次的版本开发中,有个需求是将我们项目数据库中的基础数据生成到xml文件中,并通知第三方获取这个xml文件。刚开始是想将数据按照xml的格式拼接成字符串,并逐行的写到文件中,但是总觉得这样做和java的面向对象格格不入。于是baidu了一下,果然有比拼接字符串更好的办法,具体实现如下:
1、将要生成的xml文件的格式编写到xsd文件中,如我们项目中用到的Channel.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wmh="http://www.wmhelp.com/2003/eGenerator" elementFormDefault="qualified">
  <xs:element name="ADI">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="CategoryList"/>
        <xs:element ref="ChannelList"/>
        <xs:element ref="Mappings"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="CategoryList">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="Objects" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Objects">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="Object" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Object">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="Property" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attribute name="ElementType" type="xs:string" use="required"/>
      <xs:attribute name="ObjectID" type="xs:string" use="required"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="Property">
    <xs:complexType>
      <xs:simpleContent>
        <xs:extension base="xs:string">
          <xs:attribute name="Name" type="xs:string" use="required"/>
        </xs:extension>
      </xs:simpleContent>
    </xs:complexType>
  </xs:element>
  <xs:element name="ChannelList">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="Channel" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Channel">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="Objects"/>
        <xs:element ref="Mappings"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Mappings">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="Mapping" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Mapping">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="Property"/>
      </xs:sequence>
      <xs:attribute name="ParentType" type="xs:string" use="required"/>
      <xs:attribute name="ParentID" type="xs:string" use="required"/>
      <xs:attribute name="ParentCode" type="xs:string" use="required"/>
      <xs:attribute name="ElementType" type="xs:string" use="required"/>
      <xs:attribute name="ElementID" type="xs:string" use="required"/>
      <xs:attribute name="ElementCode" type="xs:string" use="required"/>
    </xs:complexType>
  </xs:element>
</xs:schema>
2、借助于jdk的xjc命令,将xml中的节点转换成java对象类以供数据封装,具体实现是编写一个bat文件,直接执行bat文件即可,bat文件中的命令如下:
xjc -d "D:\Lcug30Code\1.7.08_EPG\src" -p "com.xxx.xxx.epg.xml.bean.channel" "D:\Lcug30Code\aa\Channel.xsd",
这样就会在com.xxx.xxx.epg.xml.bean.channel包下生成节点对象类ADI.java、CategoryList.java等和ObjectFactory(创建对象的工厂类)
3、准备数据封装,将从数据库中查询出来的数据按照xml格式从底层节点开始,逐层向上封装,如封装CategoryList节点:
/**
     * 将频道栏目信息封装成CategoryList节点
     *
     * @return CategoryList
     * @see [类、类#方法、类#成员]
     */
private CategoryList createCategoryList()
    {
        Map<String, TypeInfoRecord> map = getNDSIPTVSubjectData();
       
        CategoryList category = factory.createCategoryList();
        List<Objects> list = category.getObjects();
       
        Objects objects = null;
        ObjectNode object = null;
        TypeInfoRecord[] typeInfos = map.values()
                .toArray(new TypeInfoRecord[map.size()]);
        List<ObjectNode> objectList = null;
        List<Property> propertyList = null;
        Map<String, String> typeDomain = null;
        for (int i = 0; i < typeInfos.length; i++)
        {
            objects = factory.createObjects();
            objectList = objects.getObject();
           
            object = factory.createObject();
            propertyList = object.getProperty();
            object.setElementType("Category");
            object.setObjectID("Category@" + typeInfos[i].getTypeId());
            propertyList.add(getProperty("ContentID", typeInfos[i].getTypeId()));
            propertyList.add(getProperty("Name", typeInfos[i].getTypeNamelang1()));
            propertyList.add(getProperty("Name_fg", typeInfos[i].getTypeNamelang2()));
            propertyList.add(getProperty("ParentID", typeInfos[i].getParentTypeId()));
            propertyList.add(getProperty("Sequence", String.valueOf(typeInfos[i].getDisplayIndex())));
            propertyList.add(getProperty("Description", typeInfos[i].getTypeIntrolang1()));
            propertyList.add(getProperty("Description_fg", typeInfos[i].getTypeIntrolang2()));
            propertyList.add(getProperty("Display_index", String.valueOf(typeInfos[i].getOrderType())));
            propertyList.add(getProperty("Service_type", String.valueOf(typeInfos[i].getServiceConstraint())));
            typeDomain = typeInfos[i].getTypeDomains();
            String[] typeDomains = typeDomain.keySet()
                    .toArray(new String[typeDomain.size()]);
            propertyList.add(getProperty("Domain", getTypeDomainStr(typeDomains)));
           
            objectList.add(object);
            list.add(objects);
        }
       
        return category;
    }

/**
     * 根据Name和Value生成Property节点
     *
     * @param name
     * @param value
     * @return Property
     * @see [类、类#方法、类#成员]
     */
    private Property getProperty(String name, String value)
    {
        Property property = factory.createProperty();
        property.setName(name);
        property.setValue(value);
       
        return property;
    }

/**
     * 生成ADI对象
     * @return ADI XML文件的根节点
     */
    public ADI getAdiInfo()
    {
        createXMLRunnable = true;
       
        // 获取XML文件的根对象
        ADI adi = factory.createADI();
       
        // 分别设置节点
        adi.setCategoryList(createCategoryList());
        adi.setChannelList(createChannelList());
        adi.setMappings(createMappings());
       
        // 如果标识位为false,那么就返回NULL
        if (!createXMLRunnable)
        {
            return null;
        }
       
        return adi;
    }
4、使用jdk的JAXBContext将封装好的数据输出到xml文件:
public static void buildXml(java.lang.Object adi, String filePath,
            String packageName)
    {
        FileOutputStream fileOutputStream = null;
       
        File file;
       
        try
        {
            file = new File(filePath);
           
            fileOutputStream = new FileOutputStream(file);
            jaxbContext = JAXBContext.newInstance(packageName);
            marshaller = jaxbContext.createMarshaller();
           
            // 设置XML文件的编码格式
            marshaller.setProperty("jaxb.encoding", EPGConfig.getInstance()
                    .getXmlEncode());
           
            // 将XML文件格式化输出
            marshaller.setProperty("jaxb.formatted.output", true);
            marshaller.marshal(adi, fileOutputStream);
        }
        catch (JAXBException e)
        {
            EPGSysLogger.error(EPGConstants.ALL_AREA,
                    "Exception in buildXml , the Exception is " + e.toString());
           
            createXMLRunnable = false;
        }
        catch (FileNotFoundException e)
        {
            EPGSysLogger.error(EPGConstants.ALL_AREA,
                    "Exception in buildXml , the Exception is " + e.toString());
           
            createXMLRunnable = false;
        }
        finally
        {
            // 关流
            if (null != fileOutputStream)
            {
                try
                {
                    fileOutputStream.close();
                }
                catch (IOException e)
                {
                    EPGSysLogger.error(EPGConstants.ALL_AREA,
                            "Exception in buildXml , the Exception is "
                                    + e.toString());
                   
                    createXMLRunnable = false;
                }
            }
        }
    }
其中参数adi就是第3步的getAdiInfo封装的ADI对象,filePath是文件名(包含完整的绝对路径),packageName就是xml节点对应的java对象所在的包名(见步骤2),
这样一个完整的满足换行和缩进的xml文件就生成了。