converting XML nodes to JavaBean and storing them in a database

Source: Internet
Author: User
Tags abstract empty implement insert variables table name variable stringbuffer
xml| Data | database | conversion

1. Overview

We will parse the XML file from the external system and deposit it into the database.

But we don't have a DTD or schema, there is only one document in Word format; more to the point, the structure of the XML node tree (the relationship between the XML node and the XML node) and the structure of the business bean tree (that is, the relationship between the business bean and the business bean) are not exactly the same, for example, From a business point of view, a pig has a head, and in XML, but written in the pig--content--pighead three-level relationship, the end of a more than a content node! Without Dtd/schema, the structure is not standard, we can not use the automated Third-party Java Transformation API to parse, but only manually, one by one to parse. But in the process of manual parsing, we still find that there are many things in common in the parsing and warehousing of each node. Or there is a common rule that these things can be drawn out as a quasi frame, and then open the different parts of the node, allowing specific nodes to do the specific implementation, and eventually form a semi-automatic interpretation/ Warehousing Framework.

Why does it say it's semi-automatic? What are its limitations?

Automatic: Do not have to write XML parsing code and inbound code for each node

"Half": you need to write each javabean manually, and manually build a table for each bean

Limit:

A. The types of all business fields can only be set to String/varchar, and the type of the non-business field cannot be string in the bean

The B.bean name must be the same as the table name, or it can be mapped one-to-one

The C.bean member variable name must be the same as the attribute name/element name of the XML node, or it can be mapped one-to-one

These three kinds of restrictions are the premise of using the Java reflection mechanism for automatic operation.

2. Basic Ideas

The so-called XML parsing is to convert the XML node into JavaBean instance, and the attribute value and element value of the XML node are the member variable values of the JavaBean instance; The so-called persistence is to turn the JavaBean instance into a record in the database table, and the member variable value of the JavaBean instance is the value of a field in the record, or another record in another table that references the record.

In XML, in the JavaBean system, the relationship between node and node is tree-shaped in the relational structure of data table. The whole parsing and warehousing is to perform the conversion action when traversing the tree. And we know that the traversal of the tree can be achieved by recursive algorithm, and recursion, needless to say, it is the implementation of the program "Automation" one of the main ways.

The following is a detailed analysis of the "trees":

Suppose there is an aggregation relationship (parent-child relationship) between two business entities A and B. Then the concrete can be divided into three kinds of situations:

A.B is an atomic field (that is, it cannot be divided) and is an attribute of a.

In XML, B is the XML attribute of a or the atomic element of a

In the Bean, B is a member variable, and B is a Java built-in data type

Database, B is a column of table A

B.B is a compound field and is a property of a, and a is a 1:1 relationship

In XML, B is the element of a, and B has its own element or attribute

In the Bean, B is a member variable, and there is a Class B in the program

In the database, the B table is the child table of Table A (that is, the B foreign key references a table)

C.B is a compound field and is a property of a, and a is a n:1 relationship

In XML, B is the element of a, and B has its own element or attribute

In a bean, B makes up a class set (List,set) as a member variable, and there is a Class B in the program

In the database, the B table is the child table of Table A (that is, the B foreign key references a table)

Understanding these three kinds of situation, the next is good to do. Each node that is caught by the program has to do the following recursively: deal with its atomic properties (case a), then deal with its individual sub node (case b), and finally process its Class collection node (case c).

3. The focus of the code implementation

Two key points:

A. How do I get business entities to correspond to one by one in three trees?

B. How to find a tree relationship, such as the attributes of a and what are the child nodes of a?

Question A is very simple, that is, the same business entities in the three trees to take the same name.

A. When parsing xml, the attribute y of node x equals value Z, then the Propertyutils.setproperty (node x, attribute y, value z) is executed. Here x,y,z is a variable, and the program doesn't care what the specific nodes and attributes are. Note that if the attribute Y is an atomic field, you require that the property y must be of type string or the program does not know which type to convert value Z to (note: For Propertyutils, see Apache Commons beanutils)

B. Found X.gety () =z in storage. If the attribute Y is an atomic field, then execute SQL INSERT INTO X (..., y,...) values (..., z,...), where the Y field is required to be a varchar/char type, lest a type conversion error occurs.

About question B

XML tree: JDOM, dom4j, etc. can directly find a parent-child relationship

Bean System:

I. Atomic properties. We limit the types of all business-meaningful atomic fields in a bean to string, and all string types are business fields

Ii. a single child node. We have all the non atomic fields that have business significance implement a common interface businode, so that all Businode members in a bean are the child nodes of this bean

Class Iii. Collection node. We can also qualify all and only class-node nodes to use the list or set type, so that you can filter out all of the class's collection nodes. However, in the JAVA1.4 and previous versions, the program does not know which class (because there is no generic) the filtered cluster node is an instance of the class, and there is no way to instantiate a collection node (see later), so you can only manually register the attribute name and class of the cluster node. JAVA1.5 above version I did not use, I do not know can solve this problem.

database table Relationship: This is needless to say, is through the foreign key reference. Therefore, each type of node corresponding to the table, must have a foreign key to refer to its parent node, and must have a primary key for its child node reference. The foreign key names of each table must be the same and a constant, otherwise the program generates insert SQL to ignore the specific foreign key name of the specific table.

When the program is parsing, it traverses the bean tree; The Bean tree represents the true business structure compared to the XML tree, and the bean tree can be traversed by the parent to the first sequence, compared to the database table relational tree

4. Other issues

A. To let the program know which of the atomic attributes is the attribute of the XML node and which are the atomic element of the XML node. This is the two abstract method in the code that must be implemented by the specific node class

B. Recalling the "Pig--content--pighead three-level relationship, which is the end of a single content node" in the overview section of this article, we have to let the program know that the child nodes of Pighead,pigfoot and other nodes are pig, or the content under the pig. Pay attention to this problem when dealing with nonstandard XML. This is also an abstract method that must allow specific node classes to implement

C. Similar to the previous one, but more perverted, is the problem of irregular class aggregation points. Suppose that a pig has more than one pighead, the structure may be pig--pighead,pighead,..., or it may be pig--pigheads--content,content .... You must let the program know which pattern is used for a particular node.

5. Code

The core: Polymorphic + recursive

A. Interface Businode

 
       
         import Java.util.*;import org.do M4j.  element;/** * interface to be implemented for each node * It provides a number of methods to facilitate recursive XML parsing and persistence * */public interface Businode {/** * All types of attributes of an irreducible type *        A collection of @return attribute names */public List getatomicpropnames (); /** * Some member variables.        These member variables are the attributes of the XML node * @return/Public List getxmlattributes (); /** * Some member variables.            These member variables are child elements of the XML node, and the type is an getxmlatomicelements * @return/public List ();     /** * All types are properties of the class set, and the type of each element in the class set is Businode * @return Key = property name, value = Class object of the attribute class.        * If NULL is not returned, it is empty map */public map getcollectionpropsmap ();            /** * All attributes of type Businode * @return The set of attribute names/public List getbusinodepropnames ();     The/** * is parsed from the XML.        * @param element * @return/public void Parsefromxml (element element); }
     
       

B. Default implementation

       
        
Import Java.lang.reflect.field;import Java.util.*;import Org.apache.commons.beanutils.propertyutils;import Org.dom4j.attribute;import org.dom4j.element;/** * Default Busi NODE.    Busi NODE that inherits this class needs to satisfy all attributes set =string type of attribute sets * Myutils class code is not available * */public abstract class Defaultbusinode implements Businode {    Public List Getatomicpropnames () {return Myutils.getfieldnamesofclass (This.getclass (), string.class);    Public List Getbusinodepropnames () {return Myutils.getfieldnamesofclass (This.getclass (), businode.class); } * * The parent element of all child elements. Sometimes this node, sometimes the element under the node.    Pervert */Public abstract element Getxmlelementparent (element rootelement); * * The iterator of the root element of the collection node. Suppose a pig has multiple pighead, * that structure may be pig--pighead,pighead,..., * may also be pig--pigheads--content,content ... * must let the program know a specific knot            What kind of pattern is it? * * If NULL returns an empty class set of iterator, do not return null/public abstract iterator Getcollectionelementiterator (    Element xmlelementparent, String attname); /** * Parsing XML attribute * * @param rootelement * * protected void Parseattributesfromxml (Element rootelement) {List xml        Attributes = This.getxmlattributes ();            for (int i = 0; i < this.getxmlattributes (). Size (); i++) {String AttName = (String) xmlattributes.get (i);            Attribute att = rootelement.attribute (attname);                if (att!= null) {try {Propertyutils.setproperty (this, AttName, Att.getvalue ());                catch (Exception e) {throw new RuntimeException (e); }}}/** * resolves an irreducible element * * @param rootelement/protected void Parseatom        Icelementfromxml (element rootelement) {element xmlelementparent = getxmlelementparent (rootelement);        if (xmlelementparent = = null) {return;        List xmlelements = this.getxmlatomicelements (); for (int i = 0; i < xmlelements.size (); i++) {STring AttName = (String) xmlelements.get (i);            Element ELMT = xmlelementparent.element (AttName);                if (ELMT!= null) {try {Propertyutils.setproperty (this, AttName, Elmt.gettext ());                catch (Exception e) {throw new RuntimeException (e); /** * resolves businode properties * * @param rootelement/protected void Parsebusin        Odeelementfromxml (element rootelement) {element xmlelementparent = getxmlelementparent (rootelement);        if (xmlelementparent = = null) {return;        }//again resolves the businode attribute List businodepropnames = This.getbusinodepropnames (); for (int i = 0; i < businodepropnames.size (); i++) {try {String AttName = (string) businode                Propnames.get (i);                Element ELMT = xmlelementparent.element (AttName); if (ELMT!= null) {Field field= This.getclass (). Getdeclaredfield (AttName);                    Businode att = (businode) field.gettype (). newinstance ();                    Att.parsefromxml (ELMT);                Propertyutils.setproperty (this, AttName, ATT);            The catch (Exception e) {throw new RuntimeException (e); /** * Resolves class set properties * * @param rootelement/protected void Parsecollectionpropsfromxml (E        Lement rootelement) {//Parse XML attribute Element xmlelementparent = getxmlelementparent (rootelement) first;        if (xmlelementparent = = null) {return;        }//finally resolves the class set attribute Map Collectionpropsmap = This.getcollectionpropsmap (); for (Iterator it = Collectionpropsmap.keyset (). iterator (); It.hasnext ();)                {try {string attname = (string) it.next ();                Collection coll = (Collection) propertyutils.getproperty (this, attname); Class atttype = (Class) collectionpropsmap.get (AttName);                Iterator collelementsit = This.getcollectionelementiterator (xmlelementparent, AttName);                Xmlelementparent.elementiterator (AttName);                    while (Collelementsit.hasnext ()) {element collelmt = (Element) Collelementsit.next ();                    Businode Sinlgeatt = (businode) atttype.newinstance ();                    Sinlgeatt.parsefromxml (COLLELMT);                Coll.add (Sinlgeatt);            The catch (Exception e) {throw new RuntimeException (e); {}}}/** * resolves the node from XML. This method may throw rumtimeexception */public void Parsefromxml (Element rootelement) {THIS.PARSEATTRIBUTESFROMX        ML (rootelement);        This.parseatomicelementfromxml (rootelement);        This.parsebusinodeelementfromxml (rootelement);    This.parsecollectionpropsfromxml (rootelement); }}/** * Warehousing * JdbcutiL,myutils Code owed * */public class Businodedao {private long Savebusinode (Businode node, Long Parentnodeid) {        First store atomic attribute Long id = savebarebusinode (node, parentnodeid);        Re-store class set properties Map Collectionpropsmap = Node.getcollectionpropsmap (); for (Iterator it = Collectionpropsmap.keyset (). iterator (); It.hasnext ();)            {String attname = (string) it.next ();            Collection coll = null;            try {coll = (Collection) propertyutils.getproperty (node, attname);            catch (Exception e) {throw new RuntimeException ("Encoding Error"); for (Iterator Iitt = Coll.iterator (); Iitt.hasnext ();)                {Businode subnode = (businode) iitt.next ();            Savebusinode (subnode, id);        }//finally store all Businode properties Iterator Iitt = Node.getbusinodepropnames (). iterator ();        while (Iitt.hasnext ()) {Businode subnode = null;    try {subnode = (businode) propertyutils.getproperty (node, (String) Iitt.next ())            ;            catch (Exception e) {throw new RuntimeException ("Encoding Error");            } if (subnode!= null) {Savebusinode (subnode, id);    } return ID; /** * Inserts a businode root node, this method may throw runtimeexception * * @param node * @return/Private Long Save        Barebusinode (Businode node, Long parentnodeid) {StringBuffer sbforsql = new StringBuffer ();        List paramvalues = new ArrayList ();        Geninsertsqlandparam (node, Parentnodeid, Node.getatomicpropnames (), Sbforsql, paramvalues);    return new Long (Jdbcutil.queryforlong (sbforsql.tostring (), Paramvalues.toarray ())); /** * Generates INSERT statements and paramvalues arrays for a node that may throw runtimeexception * * @param node * @param columnnames * @ Param Sbforsql * @param paramvalues * * private void Geninsertsqlandparam (Businode node, Long Parentnodeid, List columnnames, String        Buffer Sbforsql, List paramvalues) {sbforsql.append ("insert into");        Sbforsql.append (Myutils.getclassbarename (Node.getclass ()));        List CNS = new ArrayList ();        Cns.addall (ColumnNames);        Cns.add ("Parentnodeid");        Sbforsql.append (Myutils.enclosewithcurve (myutils. joincollectionstrings (CNS, ","));        Sbforsql.append ("values"); List QMS = new ArrayList (); Question mark for (Iterator it = Columnnames.iterator (); It.hasnext ();)            {Qms.add ("?");            String cn = (String) it.next ();            try {paramvalues.add (Propertyutils.getproperty (node, CN));            catch (Exception e) {throw new RuntimeException (e); } qms.add ("?");        Parentnodeid Paramvalues.add (Parentnodeid); Sbforsql.append (Myutils.enclosewithcurve (myUtil. Joincollectionstrings (QMS, ","));    Sbforsql.append ("; select @ @identity"); }}
       


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.