美文网首页
使用 castor 解析XML

使用 castor 解析XML

作者: 得鹿梦为鱼 | 来源:发表于2019-01-13 22:31 被阅读0次

引包

 <dependency>
            <groupId>org.codehaus.castor</groupId>
            <artifactId>com.springsource.org.exolab.castor.xml</artifactId>
            <version>1.2.0</version>
  </dependency>

目标 XML文件

target.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin name="测试Castor解析" version="1.1">
    <extension element-class="demo.zh.castor.dto.Extension" id="extension">

        <operation name="java对象1">
            <desc>java对象1的描述</desc>
            <index>1</index>
        </operation>

        <operation name="java对象2">
            <desc>java对象2的描述</desc>
            <index>10</index>
        </operation>

    </extension>
</plugin>

配置Mapping需要的配置信息

config.xml
config.xml 的作用是:Mapping对象根据config.xml里的映射关系,将target.xml里解析出来的数据,通过反射注入对我们所需的对象。
案列所示,有三个层级关系,分别使用对象Plugin、Extension、Operation来表示

<?xml version="1.0" encoding="UTF-8"?>
<mapping>
    <description> the Config of the Castor Mapping </description>

    <class name="demo.zh.castor.dto.Plugin" identity="id">
        <map-to xml="plugin"/>
        <field name="id">
            <bind-xml name="id" node="attribute"/>
        </field>
        <field name="name">
            <bind-xml name="name" node="attribute"/>
        </field>
        <field name="version">
            <bind-xml name="version" node="attribute"/>
        </field>
        <field name="extensions"
               type="demo.zh.castor.dto.Extension"
               collection="collection">
            <bind-xml name="extension"/>
        </field>
    </class>

    <class name="demo.zh.castor.dto.Extension"
           identity="id" auto-complete="true">
        <map-to xml="extension"/>
        <field name="id">
            <bind-xml name="id" node="attribute"/>
        </field>
        <field name="className">
            <bind-xml name="element-class" node="attribute"/>
        </field>
        <field name="operationGroup"
               type="demo.zh.castor.dto.Operation"
               collection="collection">
            <bind-xml auto-naming="deriveByClass"/>
        </field>
    </class>

    <class name="demo.zh.castor.dto.Operation" identity="name"
           auto-complete="true">
        <map-to xml="operation"/>
        <field name="name">
            <bind-xml name="name" node="attribute"/>
        </field>
        <field name="desc">
            <bind-xml name="desc" node="element"/>
        </field>
        <field name="index" type="integer">
            <bind-xml name="index" node="element"/>
        </field>
    </class>

</mapping>

所需对象

Plugin

@Getter
@Setter
public class Plugin implements Serializable {

    private Long id;

    private String name;

    private String version;

    private ArrayList<Extension> extensions;

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Plugin{");
        sb.append("name='").append(name).append('\'');
        sb.append(", version='").append(version).append('\'');
        sb.append(", extensions=").append(extensions);
        sb.append('}');
        return sb.toString();
    }
}

Extension

@Getter
@Setter
public class Extension {

    private String id;

    private String className;

    private ArrayList<Operation> operationGroup;

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Extension{");
        sb.append("id='").append(id).append('\'');
        sb.append(", className='").append(className).append('\'');
        sb.append(", operationGroup=").append(operationGroup);
        sb.append('}');
        return sb.toString();
    }
}

Operation

@Getter
@Setter
public class Operation implements Serializable {

    private String name;

    private String desc;

    private Integer index;

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Operation{");
        sb.append("name='").append(name).append('\'');
        sb.append(", desc='").append(desc).append('\'');
        sb.append(", index=").append(index);
        sb.append('}');
        return sb.toString();
    }
}

XMLHelper

解析xml的方法定义在这里


@Slf4j
@Component
public class XMLHelper {

    /**
     * 加载Mapping的配置信息
     *
     * @param mappingPath mapping 文件的地址
     * @return Mapping
     */
    private Mapping loadMapping(String mappingPath) throws CustomException {
        Mapping result;

        if (StringUtil.isEmpty(mappingPath)) {
            throw new CustomException("mappingPath is Empty...");
        }
        result = new Mapping();
        String absolutePath = FileUtil.getFileAbsolutePath(mappingPath, "Mapping配置文件");
        try {
            result.loadMapping(absolutePath);
        } catch (IOException e) {
            log.error("文件不存在");
        } catch (MappingException e) {
            log.error("加载Mapping所需配置信息失败,(可能原因:xml文件中的配置项与java类不合)原因:" + e.getMessage(), e);
            throw new CustomException("加载Mapping所需配置信息失败");
        }

        return result;
    }

    /**
     * 解析xml文件
     *
     * @param xmlPath           xml文件在工程里的相对路径
     * @param mappingConfigPath 解析xml文件,储存Mapping对象需要的配置信息的辛苦xml文件的相对练路径
     * @return Plugin对象
     * @throws CustomException 系统自定义异常
     */
    public Plugin parse(String xmlPath, String mappingConfigPath) throws CustomException {
        if (StringUtil.isEmpty(xmlPath) || StringUtil.isEmpty(mappingConfigPath)) {
            log.error(String.format("解析XML文件时,发现文件地址为空。" +
                    "xmlPath = [%s] , mappingConfigPath = [%s]", xmlPath, mappingConfigPath));
            throw new CustomException("文件地址为空");
        }

        Mapping mapping = this.loadMapping(mappingConfigPath);
        String xmlAbsolutePath = FileUtil.getFileAbsolutePath(xmlPath, "被解析的XML文件");

        String encoding = getDeclaredFileEncoding(xmlAbsolutePath);

        Unmarshaller unmarshaller = new Unmarshaller();
        try {
            unmarshaller.setMapping(mapping);
            return parseByUnmarshaller(unmarshaller, xmlAbsolutePath, encoding);
        } catch (Exception e) {
            log.error("使用Unmarshaller解析XML失败,原因:" + e.getMessage(), e);
            // 解决xml汉字乱码引起的xml解析失败的问题,用UTF-8重新解析一次
            return parseByUnmarshaller(unmarshaller, xmlAbsolutePath, CharSetEnum.UTF8.value);
        }

    }

    private Plugin parseByUnmarshaller(Unmarshaller unmarshaller, String xmlAbsolutePath, String encoding) throws CustomException {
        Plugin result;

        File target = new File(xmlAbsolutePath);

        try (InputStream input = new FileInputStream(target);
             Reader reader = new InputStreamReader(input, encoding)) {

            result = (Plugin) unmarshaller.unmarshal(reader);
        } catch (Exception e) {
            log.error(String.format("解析xml[%s]失败,原因:%s", xmlAbsolutePath, e.getMessage()), e);
            throw new CustomException("解析xml失败");
        }

        return result;
    }

    /**
     * 获取xml文件的编码
     *
     * @param filePath 文件地址
     * @return charSet eg:UTF-8
     */
    private String getDeclaredFileEncoding(String filePath) {
        String encoding = CharSetEnum.GBK.value;

        if (!filePath.endsWith(".xml")) {
            return encoding;
        }

        try (FileReader fileReader = new FileReader(filePath);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {
            String line = bufferedReader.readLine();

            // 简单判断,<?xml version="1.0" encoding="UTF-8" ?> 必须写在首行,且不换行
            if (line.startsWith("<?xml") && line.endsWith("?>") && line.toUpperCase().contains(CharSetEnum.UTF8.value)) {
                encoding = CharSetEnum.UTF8.value;
            }

        } catch (IOException e) {
            log.error("获取文件编码失败,原因:" + e.getMessage(), e);
        }
        return encoding;
    }
}

调用XMLHelper的parse方法

@Slf4j
public class LoadXML {

    public static void main(String[] args) throws CustomException {
        XMLHelper xmlHelper = new XMLHelper();

        String xmlPath = "castor/xml/target.xml";
        String mappingConfigPath = "castor/mapping/config.xml";

        Plugin result = xmlHelper.parse(xmlPath, mappingConfigPath);
        log.info(result.toString());
    }
}

输出结果

...LoadXML - Plugin{name='测试Castor解析', version='1.1', extensions=[Extension{id='extension', className='demo.zh.castor.dto.Extension', operationGroup=[Operation{name='java对象1', desc='java对象1的描述', index=1}, Operation{name='java对象2', desc='java对象2的描述', index=10}]}]}

相关文章

  • 使用 castor 解析XML

    引包 目标 XML文件 target.xml 配置Mapping需要的配置信息 config.xmlconfig....

  • Android15-XML和JSON解析

    1. XML解析的两种方式 服务器返回的XML数据如下 1.1使用Pull方式解析XML数据 使用Pull解析,首...

  • 安卓基础篇之SAX解析XML文件

    SAX解析XML文件 基本使用方法 详细源码解析 SAXParserImpl对象的初始化 在使用SAX解析XML文...

  • python(解析和构建xml文档)

    xml解析 xml文档 code 构建xml文档 简单使用 code

  • 使用java解析xml

    本文使用javax.xml.parsers包下的DocumentBuilderFactory构建解析工具解析xml...

  • SAX和DOM解析XML

    PULL方式 除了可以使用SAX和DOM解析XML文件,也可以使用Android内置的Pull解析器解析XML文件...

  • XML 解析

    XML三种解析方式: 下面简单说明下三种解析方式的使用 XML文件 新建xml文件food.xml 三种解析方式 ...

  • Python解析XML脚本

    解析方法有两种: 推荐2 1.使用xml.dom.minidom解析 2.使用xml.etree.ElementT...

  • Mybatis源码浅析

    Mybatis xml解析流程 Xml解析的常见方式:DOM SAX Xpath ,Mybatis使用的时Xpat...

  • Spring源码学习(未完待续)

    IOC 一. 注册 bean 过程(xml 解析) 使用 BeanDefinitionReader 读取xml配置...

网友评论

      本文标题:使用 castor 解析XML

      本文链接:https://www.haomeiwen.com/subject/lefhdqtx.html