Write XML as the advanced operation library of the configuration file

Source: Internet
Author: User
ArticleDirectory
    • Overview
    • System Variables
    • Command
    • Conclusion


Write XML as the advanced operation library of the configuration file
Yipsilon original (Participation score: 293, expert score: 180) published: Update: Version: 1.0 read:4059Times

Are you still using XML as a configuration file for simple read/write? In fact, XML has better and more practical operations...

Overview

It is extremely simple to use XML in Java. The advent of JDOM brings Java closer to XML. However, JDOM provides simple static XML operations. If you use XML as a dynamic configuration file or module installation configuration file (at least in the system I developed), the method of using JDOM alone seems a little powerless, we need to make full use of the advantages of JDOM to develop an advanced operating library for XML files.

What kind of operation library should we develop? First, check the following XML Information:

<? XML version = "1.0" encoding = "UTF-8"?>
<Config>
<Dirs>
<Home>/home/myuser </Home>
<TMP>/home/myuser/tmp </tmp>
<Var>/home/myuser/var </var>
</Dirs>
</Config>

This is a simple configuration file, where the main directory path is used repeatedly. Is it very troublesome? However, a good solution here is to use XML internal entities, as shown below:

<? XML version = "1.0" encoding = "UTF-8"?>
<! Doctype config [
<! Entity home "/home/myuser">
]>
<Config>
<Dirs>
<Home> & Home; </Home>
<TMP> & Home;/tmp </tmp>
<Var> & Home;/var </var>
</Dirs>
</Config>

This is a good method. By defining an object, you can replace the reused information. However, I still need to implement my own methods. As for their differences, I will explain them below.
Variable
Because I amProgramClerk, first think of the word "variable" when you see such a problem. Why not use a special element as the definition of a variable? OK. Let's get started. See the following example:

<? XML version = "1.0" encoding = "UTF-8"?>
<Config>
<Property name = "home" value = "/home/myuser"/>
<Dirs>
<! -This section can be omitted'
<Home >$ {home} </Home>
<Property name = "home" value = "$ {home}/tmp"/>
<TMP Path = "$ {dirs. Home}">
<Tmp1 >$ {dirs. Home}/tmp1 </tmp1>
</Tmp>
<Var >$ {home}/var </var>
</Dirs>
</Config>

Here I use the property element as the definition element of the variable. Why? Have you understood it? There are two home variables. How can we solve the conflict? As shown above, what if the element name + "." + variable name is used as the definition of the variable to resolve the conflict? So do it.

OK. The write interpreter is designed for configuring variable rules.

Because an extra interpreter may be added later, we first define an interpreter interface documentparser:

ImportOrg. JDOM. Document;
Public InterfaceDocumentparser {
Public VoidParse (document DOC );
}

Since the interface has been defined, it is time to write the variable interpreter.

/**
* Property element interpreter.
*/
Public ClassDocumentpropertyparserImplementsDocumentparser {
PrivateProperties variables;

PublicDocumentpropertyparser (){
Variables =NewProperties ();
}

Public void parse (document DOC) {
element = Doc. getrootelement ();
string Path = element. getname ();
// parse the variable and add it to the variables property object
parsevariables (path, element );
// analyze the element attributes and values and replace the parsed variables.
parsecontent (element);
}

/**
* Variable Parsing Method
*/
Private VoidParsevariables (string path, element ){
List sublist = element. getchildren ();
Iterator elementi = sublist. iterator ();
While(Elementi. hasnext ()){
Element elements = (element) elementi. Next ();
String name = elements. getname ();

// Processing variable. The case sensitivity of the property element name is ignored here.
// Otherwise, recursively process the elements in it.
If("Property". inclusignorecase (name )){

// Obtain the variable name.
String propname = elements. getattributevalue ("name ");

// If the variable name is not empty, obtain the attribute named value first.
If(Propname! = NULL ){
String propvalue = elements. getattributevalue ("value ");

// If the attribute named value does not exist, the value of this element is obtained.
If(Propvalue = NULL) propvalue = elements. gettext ();

// If the value does not exist, the value of this variable is null.
If(Propvalue = NULL) propvalue = "";

// Add the variable information to the variable list.
Variables. setproperty (path + "." + propname, propvalue );
}
// Delete attribute fields to avoid conflicts.
Elementi. Remove ();
}Else{
Parsevariables (path + "." + name, elements );
}
}
}

/**
* Process the variables in the element.
*/
Private VoidParsecontent (element ){
// First, check whether the element property value has a variable.
List attributes = element. getattributes ();
Iterator attributei = attributes. iterator ();
While(Attributei. hasnext ()){
Attribute attribute = (attribute) attributei. Next ();
String attributevalue = attribute. getvalue ();

// Replace the variable with the string replacement method.
Enumeration propnames = variables. propertynames ();
While (Propnames. hasmoreelements ()){
String propname = (string) propnames. nextelement ();
String propvalue = variables. getproperty (propname );
Attributevalue = strutil. Replace ("$ {" + propname + "}",
Propvalue,
Attributevalue );
}

// Reset the replaced variable value.
Attribute. setvalue (attributevalue );
}
// If there is subinformation, recursively retrieve the subinformation; otherwise, retrieve its value.
List subelements = element. getchildren ();
If (Subelements. Size ()! = 0 ){
// Recursively retrieve element.
Iterator subelementi = subelements. iterator ();
While (Subelementi. hasnext ()){
Element subelement = (element) subelementi. Next ();
Parsecontent (subelement );
}
} Else {
String value = element. gettext ();
If (Value! = NULL ){
// Overwrite the variable.
Enumeration propnames = variables. propertynames ();
While (Propnames. hasmoreelements ()){
String propname = (string) propnames. nextelement ();
String propvalue = variables. getproperty (propname );
Value = strutil. Replace ("$ {" + propname + "}", propvalue, value );
}
Element. settext (value );
}
}
}
}

Note: The strutil. Replace method is a string replacement method.

OK. The simple variable interpreter is complete.

Think about what else we need...
System Variables

Sometimes, the configuration file requires some system information as a reference (I call it a system variable), and the system information is available at runtime, however, we can predefine some variable names so that they can be used in the configuration file in advance and dynamically assign values to this element by interpreting system variables. For example, the configuration file:

<? XML version = "1.0" encoding = "UTF-8"?>
<Config>
<Property name = "version" value = "1705"/>
<Module version = "% {system. Version}. $ {version}" home = "% {system. Home}/helloword">
... ...
</Module>
</Config>

After resolution, it becomes:

<? XML version = "1.0" encoding = "UTF-8"?>
<Config>
<Module version = "1.0.1705" home = "/home/myuser/helloworld">
... ...
</Module>
</Config>

The predefined system variables "system. Version" and "system. Home" are used to represent the system version and the main directory of the system. This allows the configuration file to obtain dynamic system information. Below we use Java to implement the system variable interpreter documentconstantparser:

Public Final ClassDocumentconstantparserImplementsDocumentparser {
PrivateProperties constants;

PublicDocumentconstantparser (){
Constants =NewProperties ();
}

PublicDocumentconstantparser (properties original ){
Constants =NewProperties (original );
}

// Set predefined variables during the runtime so that the configuration file can dynamically read the information.
Public VoidAddconstant (string name, string value ){
Constants. setproperty (name, value );
}

Public VoidRemoveconstant (string name ){
Constants. Remove (name );
}

Public VoidParse (document DOC ){
Parsecontent (Doc. getrootelement ());
}
...
}

Because the parsecontent method is almost the same as the variable interpreter, it will not be written if it saves some space. The system can use the addconstant and removeconstant methods to operate predefined variables in the XML document, which makes the xml configuration more powerful.

Compared with the aforementioned entities, this method is easy to interact with the system and easy to understand.
Command

I have studied ant, And the <javac> and other elements are very attractive to me. Can I add another element with command interpretation capabilities? The answer is yes.

I define the command element in the XML document as the entry element of the command. Execute this command by executing specific commands. First, because there may be many commands, we define a command interface documentcommand:

Public InterfaceDocumentcommand {

// Check whether commands with the specified name are accepted.
Public BooleanAccept (string name );

// Processing Command
Public VoidInvoke (document DOC, element current, documentcommandparser parser)
ThrowsJdomexception;
}

After defining the command interpretation interface, you can design the interpreter. JavaCodeAs follows:

Public Final ClassDocumentcommandparserImplementsDocumentparser {
PrivateHashset commands;
Private BooleanParsing;
PublicDocumentcommandparser (){
Commands =NewHashset (10 );
Parsing =False;
}

// Add command Interpretation Unit
Public Synchronized VoidAddcommand (documentcommand DC ){
If(Parsing)
Try{
Wait ();
}Catch(Interruptedexception IE ){}

If(Commands. Contains (DC ))
Commands. Remove (DC );
Commands. Add (DC );
}

// Delete the command Interpretation Unit
Public Synchronized VoidRemovecommand (documentcommand DC ){
If(Parsing)
Try{
Wait ();
}Catch(Interruptedexception IE ){}
Commands. Remove (DC );
}

Public Synchronized VoidParse (document DOC)ThrowsJdomexception {
Parsing =True;
Parsecommand (Doc, doc. getrootelement ());
Parsing =False;
Policyall ();
}

Private VoidParsecommand (document DOC, element)ThrowsJdomexception {
List sub = element. getchildren ();
For(IntI = 0; I <sub. Size (); I ++ ){
Element subelement = (element) sub. Get (I );

// Check whether the element is a command element. If it is not a recursive interpretation of the sub-element of the element.
If(! "Command". inclusignorecase (subelement. getname ())){
Parsecommand (Doc, subelement );
}Else{

// DELETE command elements to avoid conflicts.
Sub. Remove (I --);

// Obtain the command name. If it is null, continue.
String commandname = subelement. getattributevalue ("name ");
If(Commandname! = NULL ){

// Start to search for the appropriate command processor.
Iterator cmdi = commands. iterator ();
Processing:
While(Cmdi. hasnext ()){
Documentcommand Dc = (documentcommand) cmdi. Next ();

// Find the corresponding command processor and explain the command.
If(Dc. Accept (commandname )){

// Call the command processing method. If the execution is successful, delete the variable.
DC. Invoke (Doc, subelement,This);

// Interrupt command retrieval process.
BreakProcessing;
}
}
}
}
}
}
}

Finally, the command interpretation function is implemented. The following describes its usage.
For example, the file copy command filecopy has two attributes: source is the source file path and target is the copy Destination path. This command can be used to implement multiple functions, for example, when a component is installed, it copies data from other spaces to its home directory. The Code is as follows:

... ...
<Command name = "filecopy" Source = "$ {home}/lib" target = "% {system}/lib/module"/>
... ...

In this way, the library file used by the component is copied to the system library. The code for filecopy is as follows:

Public class filecopycommand implements COM. yipsilon. util. JDOM. documentcommand {
Public Boolean Accept (string S) {
// only the filecopy command is acceptable.
return "filecopy ". equals (s);
}

Public VoidInvoke (document, element, documentcommandparser parser ){
String name = element. getattributevalue ("name ");// The value is filecopy.
String source = element. getattributevalue ("Source ");// The value is the original path.
String target = element. getattributevalue ("target ");// The value is the destination path.
Fileutil. Copy (source, target );
// Due to limited content, no additional error check is added here.
}
}

Note: fileutil. copy is a simple object COPY method. You can implement it on your own.
Conclusion

Using variables, system variables, and commands in the XML document greatly enhances the XML function as a set of configuration information. By implementing different interpreters and command units, you can increase the number of functions to achieve some previously unfeasible goals, such as environment detection and I/O operations as installation files, this improves development speed and content management.

Java and XML are inherent, and many simplified development products such as ant can be developed on them. Sometimes you only need to use your brains to make development easier.

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.