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"); }}
|