Springboot自定义xml文件解析

Springboot自定义xml文件解析,第1张

有时候,要通过自定义XML配置文件来实现一些特定的功能。这里通过例子来说明。

首先,看部分spring加载bean文件的源码:

spring-beans-506RELEASEjar!/org/springframework/beans/factory/xml/PluggableSchemaResolverclass :

spring-beans-506RELEASEjar!/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolverclass :

可以看出,spring在加载xml文件的时候,会默认读取配置文件 META-INF/springschemas 和 META-INF/springhandlers 。这样,我们就可以在这两个文件添加我们自定义的xml文件格式和xml文件解析处理器。

新建一个Springboot工程,pom如下。

SelfDefineXmlTrial/pomxml :

然后,新建一个用于测试controller。

comlfqyspringbootselfdefxmlcontrollerSelfDefXmlController :

最后,创建一个Springboot的启动类。

comlfqyspringbootselfdefxmlSelfDefXmlApplication :

运行启动之后,浏览器访问 http://localhost:8080/selfdefxml/hello 效果如下:

修改前面提到的配置文件 META-INF/springschemas 、 META-INF/springhandlers ,添加xml格式说明。

META-INF/springschemas :

META-INF/springhandlers :

添加xml格式说明配置文件。

META-INF/selfdefxsd :

添加自定义xml格式处理器类。

comlfqyspringbootselfdefxmlselxmlparseUserNamespaceHandler :

新增xml格式解析类。

comlfqyspringbootselfdefxmlselxmlparseUserBeanDefinitionParser :

新增自定义xml对应的bean类。

comlfqyspringbootselfdefxmlbeansUser :

添加自定义xml配置文件读取的相关逻辑。

comlfqyspringbootselfdefxmlSelfDefXmlApplication :

到这里,编码就完成了,工程的目录结构如下。

运行之后,控制台输出如下:

这里,通过实现一个启动时自动初始化的一个servlet来实现。

comlfqyspringbootselfdefxmlservletStartupServlet :

在启动时加载servlet,为了方便区分,这里新写一个启动类。

comlfqyspringbootselfdefxmlSelfDefXmlLoadOnStartupApplication

到这里,编码已经完成,工程的目录结构如下:

运行之后,控制台输出如下:

/ 前段时间恰好做过类似的东西,代码可以给你参考下。

   Xml配置见最后

 /

typedef struct SrcFileFmt

{

    int   ColID;

    char  ColCode[64];      / 字段英文名称 /

    char  ColName[128];     / 字段中文名称/

    char  ColType[20];      / 字段类型(包含长度) /

    char  ColComment[128];  / 字段描述 /

}SrcFileFmt;

int main(int argc, char argv)

{

    SrcFileFmt SrcFileFmt[128];

    int iNum = -1;

    if ( 2 > argc )

    {

        printf("Usage: %s SrcXmlFile\n", argv[0]);

        return -1;

    }

    iNum = parseSourceCfg(SrcCfgFile, SrcFileFmt);

    if (iNum == -1)

    {

        return -1;

    }

    return 0;

}

/ 调用此函数后,xml文件的内容会被存储到结构体数组SrcFileFmt srcfilefmt[]中

  此函数依赖于libxml2-292tarxz

 /

int parseSourceCfg(char FileName, SrcFileFmt srcfilefmt[])

{ / 解析源文件xml,FileName 为源xml文件名 /

    xmlDocPtr doc;

    xmlNodePtr cur, root;

    char sFileName[64] = {'\0'};

    int cnt = 0;

    if (FileName == NULL)

    {

        return -1;

    }

    sprintf(sFileName, "%sxml", FileName);

    doc = xmlParseFile(sFileName);

    if (doc == NULL)

    {

        return -1;

    }

    root = xmlDocGetRootElement(doc);

    if (root == NULL) {

        xmlFreeDoc(doc);

        return(-1);

    }

    if (xmlStrcmp(root->name, (const xmlChar ) "SrcRoot"))

    {

        xmlFreeDoc(doc);

        return -1;

    }

    

    cur = root->xmlChildrenNode;

    while (cur != NULL) 

    {

        if ((!xmlStrcmp(cur->name, (const xmlChar )"Column")))

        {

            xmlChar key;

            xmlNodePtr cur_sub = cur;

            cur_sub = cur_sub->xmlChildrenNode;

            while (cur_sub != NULL) 

            {

                if ((!xmlStrcmp(cur_sub->name, (const xmlChar )"ColID"))) {

                    key = xmlNodeListGetString(doc, cur_sub->xmlChildrenNode, 1);

                    killblank((char)key);

                    srcfilefmt[cnt]ColID = atoi((char)key);

                    xmlFree(key);

                }

                if ((!xmlStrcmp(cur_sub->name, (const xmlChar )"ColCode"))) {

                    key = xmlNodeListGetString(doc, cur_sub->xmlChildrenNode, 1);

                    killblank((char)key);

                    strcpy(srcfilefmt[cnt]ColCode, (char)key);

                    xmlFree(key);

                }

                else if ((!xmlStrcmp(cur_sub->name, (const xmlChar )"ColName"))) {

                    key = xmlNodeListGetString(doc, cur_sub->xmlChildrenNode, 1);

                    killblank((char)key);

                    strcpy(srcfilefmt[cnt]ColName, (char)key);

                    xmlFree(key);

                }

                else if ((!xmlStrcmp(cur_sub->name, (const xmlChar )"ColType"))) {

                    key = xmlNodeListGetString(doc, cur_sub->xmlChildrenNode, 1);

                     killblank((char)key);

                    strcpy(srcfilefmt[cnt]ColType, (char)key);

                    xmlFree(key);

                }

                else if ((!xmlStrcmp(cur_sub->name, (const xmlChar )"ColComment"))) {

                    key = xmlNodeListGetString(doc, cur_sub->xmlChildrenNode, 1);

                    killblank((char)key);

                    strcpy(srcfilefmt[cnt]ColComment, (char)key);

                    xmlFree(key);

                }

                cur_sub = cur_sub->next;

            }

            cnt++;

        }

        cur = cur->next;

    }

    xmlFreeDoc(doc); 

    return cnt;

}

<SrcRoot>

    <Column>

        <ColID>1</ColID>

        <ColCode>kmh</ColCode>

        <ColName>字段1</ColName>

        <ColType>VARCHAR(11)</ColType>

    </Column>

    <Column>

        <ColID>2</ColID>

        <ColCode>dfkmh</ColCode>

        <ColName>字段2</ColName>

        <ColType>VARCHAR(11)</ColType>

    </Column>

    <Column>

        <ColID>3</ColID>

        <ColCode>hbh</ColCode>

        <ColName>字段3</ColName>

        <ColType>INTEGER(10)</ColType>

    </Column>

</SrcRoot>

Python的标准库中,提供了6种可以用于处理XML的包。

(1)xmldom

xmldom实现的是W3C制定的DOM API。如果你习惯于使用DOM API或者有人要求这这样做,可以使用这个包。不过要注意,在这个包中,还提供了几个不同的模块,各自的性能有所区别。

DOM解析器在任何处理开始之前,必须把基于XML文件生成的树状数据放在内存,所以DOM解析器的内存使用量完全根据输入资料的大小。

(2)xmldomminidom

xmldomminidom是DOM API的极简化实现,比完整版的DOM要简单的多,而且这个包也小的多。那些不熟悉DOM的朋友,应该考虑使用xmletreeElementTree模块。据lxml的作者评价,这个模块使用起来并不方便,效率也不高,而且还容易出现问题。

:《Python教程》

(3)xmldompulldom

与其他模块不同,xmldompulldom模块提供的是一个“pull解析器”,其背后的基本概念指的是从XML流中pull事件,然后进行处理。虽然与SAX一样采用事件驱动模型(event-driven processing model),但是不同的是,使用pull解析器时,使用者需要明确地从XML流中pull事件,并对这些事件遍历处理,直到处理完成或者出现错误。

pull解析(pull parsing)是近来兴起的一种XML处理趋势。此前诸如SAX和DOM这些流行的XML解析框架,都是push-based,也就是说对解析工作的控制权,掌握在解析器的手中。

(4)xmlsax

xmlsax模块实现的是SAX API,这个模块牺牲了便捷性来换取速度和内存占用。SAX是Simple API for XML的缩写,它并不是由W3C官方所提出的标准。它是事件驱动的,并不需要一次性读入整个文档,而文档的读入过程也就是SAX的解析过程。所谓事件驱动,是指一种基于回调(callback)机制的程序运行方法。

(5)xmlparserexpat

xmlparserexpat提供了对C语言编写的expat解析器的一个直接的、底层API接口。expat接口与SAX类似,也是基于事件回调机制,但是这个接口并不是标准化的,只适用于expat库。

expat是一个面向流的解析器。您注册的解析器回调(或handler)功能,然后开始搜索它的文档。当解析器识别该文件的指定的位置,它会调用该部分相应的处理程序(如果您已经注册的一个)。该文件被输送到解析器,会被分割成多个片断,并分段装到内存中。因此expat可以解析那些巨大的文件。

(6)xmletreeElementTree(以下简称ET)

xmletreeElementTree模块提供了一个轻量级、Pythonic的API,同时还有一个高效的C语言实现,即xmletreecElementTree。与DOM相比,ET的速度更快,API使用更直接、方便。与SAX相比,ETiterparse函数同样提供了按需解析的功能,不会一次性在内存中读入整个文档。ET的性能与SAX模块大致相仿,但是它的API更加高层次,用户使用起来更加便捷。

建议:在使用Python进行XML解析时,首选使用ET模块,除非你有其他特别的需求,可能需要另外的模块来满足。

在java环境下读取xml文件的方法主要有4种:DOM、SAX、JDOM、JAXB

1 DOM(Document Object Model)

此方法主要由W3C提供,它将xml文件全部读入内存中,然后将各个元素组成一棵数据树,以便快速的访问各个节点 。 因此非常消耗系统性能 ,对比较大的文档不适宜采用DOM方法来解析。 DOM API 直接沿袭了 XML 规范。每个结点都可以扩展的基于 Node 的接口,就多态性的观点来讲,它是优秀的,但是在 Java 语言中的应用不方便,并且可读性不强。

实例:

import javaxxmlparsers;

//XML解析器接口

import orgw3cdom;

//XML的DOM实现

import orgapachecrimsontreeXmlDocument;

//写XML文件要用到

DocumentBuilderFactory factory = DocumentBuilderFactorynewInstance();

//允许名字空间

factorysetNamespaceAware(true);

//允许验证

factorysetValidating(true);

//获得DocumentBuilder的一个实例

try {

DocumentBuilder builder = factorynewDocumentBuilder();

} catch (ParserConfigurationException pce) {

Systemerrprintln(pce);

// 出异常时输出异常信息,然后退出,下同

Systemexit(1);

}

//解析文档,并获得一个Document实例。

try {

Document doc = builderparse(fileURI);

} catch (DOMException dom) {

Systemerrprintln(domgetMessage());

Systemexit(1);

} catch (IOException ioe) {

Systemerrprintln(ioe);

Systemexit(1);

}

//获得根节点StuInfo

Element elmtStuInfo = docgetDocumentElement();

//得到所有student节点

NodeList nlStudent = elmtStuInfogetElementsByTagNameNS(

strNamespace, "student");

for (……){

//当前student节点元素

Element elmtStudent = (Element)nlStudentitem(i);

NodeList nlCurrent = elmtStudentgetElementsByTagNameNS(

strNamespace, "name");

}

[转]

dom和SAX使两种主流的选择,还有JDOM,DOM4J做的不错。

DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。

例: import javaio;import javautil;import orgw3cdom;import javaxxmlparsers;

public class MyXMLReader{

public static void main(String arge[]){

long lasting =SystemcurrentTimeMillis();

try{

File f=new File("data_10kxml");

DocumentBuilderFactory factory=DocumentBuilderFactorynewInstance();

DocumentBuilder builder=factorynewDocumentBuilder();

Document doc = builderparse(f);

NodeList nl = docgetElementsByTagName("VALUE");

for (int i=0;i<nlgetLength();i++){

Systemoutprint("车牌号码:" + docgetElementsByTagName("NO")item(i)getFirstChild()getNodeValue());

Systemoutprintln("车主地址:" + docgetElementsByTagName("ADDR")item(i)getFirstChild()getNodeValue());

}

}catch(Exception e){

eprintStackTrace();

}

SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。

例: import orgxmlsax;import orgxmlsaxhelpers;import javaxxmlparsers;

public class MyXMLReader extends DefaultHandler {

javautilStack tags = new javautilStack();

public MyXMLReader() {

super();}

public static void main(String args[]) {

long lasting = SystemcurrentTimeMillis();

try {

SAXParserFactory sf = SAXParserFactorynewInstance();

SAXParser sp = sfnewSAXParser();

MyXMLReader reader = new MyXMLReader();

spparse(new InputSource("data_10kxml"), reader);

} catch (Exception e) {

eprintStackTrace();

}

Systemoutprintln("运行时间:" + (SystemcurrentTimeMillis() - lasting) + "毫秒");}

public void characters(char ch[], int start, int length) throws SAXException {

String tag = (String) tagspeek();

if (tagequals("NO")) {

Systemoutprint("车牌号码:" + new String(ch, start, length));}if (tagequals("ADDR")) {

Systemoutprintln("地址:" + new String(ch, start, length));}}

public void startElement(String uri,String localName,String qName,Attributes attrs) {

tagspush(qName);}}

注意:当xml数据的形式作为传递时,要获取一条条的纪录是比较适宜于采用dom,虽然它对系统(内存,性能等)有较高的要求,但是一般的服务器都可满足上G的xml文档的处理。

当需要对xml的某些内容或某些节点的特定访问时,或需要一及时地事件相应时,可以用sax来处理。它是基于时间处理机制的,在编程时,通过重载一些事件方法,来获得对xml文档的处理。

有关xml的编码,InputStreamReader和xmlReader的关系:

通常的DOM和SAX对于用ascii编码的文档,通过用InputStreamReader读入xml文档,后变成了unicode码,然后不能用

XMlREader来处理,出现错误的原因是:遇到无效的unicode的字符。(当你用systemoutprintln()输出是没有任何问题,因为它能自动转成本地机的编码)。

解决的方法:

BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(f),"ISO8859-1"));

这样就可以限定它的编码,这样就没有问题。

String 的长度问题:String 类型安标准来说没有长度限制,但是一般jdk中String的最大长度是4G。

String与BufferedString关系:在不涉及到字符串有效的大量处理,通常使用String BufferedString在处理字符串的大量处理上有优势

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/11666507.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-17
下一篇 2023-05-17

发表评论

登录后才能评论

评论列表(0条)

保存