Reputation: 29806
I want to use XML file as database. Where I want to store an ID and its correspondingly a String path. Like:
<item>
<Id>id</Id>
<Path>path</Path>
</item>
or like that. Now in runtime a Name-Value Collection will load this data stored in XML document and check the Id against some data and will be processed accordingly and also update (that is change path of same Id)and delete(removal of an existing item) of items is needed in that XML file. Hope I make you able to understand my idea! I have no code to show as this is in conceptual level. What I need is that how can I achieve this, is there any tutorial I can read or API available which is able to do this? Thank you. I am in JAVA.
Upvotes: 4
Views: 22159
Reputation: 551
I prefer using Joox, a fluent api to manage dom in jquery like style. It has not dependencies, you can install with maven.
Just because java performance, It's better to use attributes than elements* (experience from coleages).
So I suggest you use your model in this way:
<items>
<item id="1" path="path"/>
...
</items>
I created this class using Joox for you:
package test;
import static org.joox.JOOX.$;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.commons.io.FileUtils;
import org.joox.JOOX;
import org.joox.Match;
import org.xml.sax.SAXException;
public class XmlDBTable{
private Match dbMatch;
private String xmlBeforeCommit;
private boolean building;
private String root;
private String item;
private String itemXpathTemplate;
private File file;
public void setRoot(String root){
this.root=root;
}
public void setItemTemplate(String item){
this.item=item;
}
public void setItemXpathTemplate(String itemXpath){
this.itemXpathTemplate=itemXpath;
}
public void setFile(String path){
file=new File(path);
if(file.exists())
try {
dbMatch=$(file);
} catch (SAXException | IOException e) {
e.printStackTrace();
}
}
public Match xml() {
Match dbMatch= dbMatch();
building=true;
return dbMatch;
}
public void insertOrUpdate(String keyEqualsValueList){
Match dbMatch= dbMatch();
String newItem=item;
if(keyEqualsValueList.contains(",")) {
String[] keyValues=keyEqualsValueList.split(",");
for(String keyValue:keyValues) {
String key=keyValue.split("=")[0].toUpperCase();
String value=keyValue.split("=")[1];
newItem=newItem.replace(key,value);
}
}else {
String key=keyEqualsValueList.split("=")[0].toUpperCase();
String value=keyEqualsValueList.split("=")[1];
newItem=newItem.replace(key,value);
}
String id=itemId(newItem);
String itemXpath=itemXpath(id);
Match item=$(dbMatch).xpath(itemXpath);
if ($(item).isEmpty()){
$(dbMatch).append(newItem);
}else{
if(keyEqualsValueList.contains(",")) {
String[] keyValues=keyEqualsValueList.split(",");
for(String keyValue:keyValues) {
String key=keyValue.split("=")[0];
String value=keyValue.split("=")[1];
$(dbMatch).xpath(itemXpath).attr(key,value);
}
}else {
String key=keyEqualsValueList.split("=")[0].toUpperCase();
String value=keyEqualsValueList.split("=")[1];
$(dbMatch).xpath(itemXpath).attr(key,value);
}
}
building=true;
System.out.println("Item id "+id+" added ok");
}
public void delete(String id){
Match dbMatch= dbMatch();
String itemXpath=itemXpath(id);
Match item=$(dbMatch).xpath(itemXpath);
if (!$(item).isEmpty()){
$(dbMatch).xpath(itemXpath).remove();
System.out.println("Item id "+id+" deleted ok");
}else{
System.out.println("The item didn't exist");
}
building=true;
}
private String itemId(String item) {
String id=xmlStrToMatch(item, "UTF-8").attr("id");
return id;
}
private String itemXpath(String id) {
String itemXpath=itemXpathTemplate.replace("ID", id);
return itemXpath;
}
public synchronized boolean commit(){
try {
FileUtils.writeStringToFile(file,dbMatch().toString(),"UTF-8");
building=false;
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
public boolean rollBack(){
dbMatch();
dbMatch=xmlStrToMatch(xmlBeforeCommit, "UTF-8");
System.out.println("Removed all changes after last commit");
building=false;
return true;
}
private Match dbMatch(){
if(dbMatch==null){
dbMatch=xmlStrToMatch(root,"UTF-8");
}
if(!building){
if(xmlBeforeCommit!=null){
xmlBeforeCommit=dbMatch.toString();
}else {
xmlBeforeCommit=root;
}
}
return dbMatch;
}
private static Match xmlStrToMatch(String xmlString, String encoding){
Match match = null;
try {
match = $(JOOX.builder().parse(new ByteArrayInputStream(xmlString.getBytes(encoding))));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return match;
}
}
To use it, you can use:
package test;
public class ItemsTable{
public static void main(String... args){
XmlDBTable itemsTable= new XmlDBTable();
itemsTable.setRoot("<items></items>");
itemsTable.setItemTemplate("<item id=\"ID\" path=\"PATH\"/>");
itemsTable.setItemXpathTemplate("/items/item[@id='ID']");
itemsTable.setFile("C:\\users\\jesus\\Downloads\\temp\\itemsTable.xml");
itemsTable.insertOrUpdate("id=1,path=myPath");
itemsTable.insertOrUpdate("id=2,path=myPath2");
itemsTable.delete("2");
itemsTable.insertOrUpdate("id=3,path=myPath3");
//save changes
itemsTable.commit();
//you can use all power of Joox Methods too to do the same or more
//Select path from item with id=1
String path1=itemsTable.xml().xpath("//item[@id='1']").attr("path");
//print it
System.out.println(path1);
//Add subItem id=0 to item with id=1
itemsTable.xml().xpath("//item[@id='1']").append("<subitem id=\"0\" color=\"black\">Super Subitem</subitem>");
//print the text of subitem recently added
String subitem1=itemsTable.xml().xpath("//subitem[@id='0']").text();
System.out.println(subitem1);
//save changes
itemsTable.commit();
//Add subItem id=1 to item with id=1
itemsTable.xml().xpath("//item[@id='1']").append("<subitem id=\"1\" color=\"blue\">Super Subitem</subitem>");
//rollback changes after last commit (subitem id=1 in item id=1 deleted)
itemsTable.rollBack();
itemsTable.insertOrUpdate("id=4,path=myPath4");
//save changes
itemsTable.commit();
}
}
*Please note that string templates use caps as default value,e.g. id="ID" *Another thing methods insertOrUpdate, and delete only works with attributes as columns. *You can use Joox methods to insert new lines, as shown.
This is the file produced:
<items>
<item id="1" path="myPath">
<subitem color="black" id="0">Super Subitem</subitem>
</item>
<item id="3" path="myPath3"/>
<item id="4" path="myPath4"/>
</items>
This is the output in console:
Item id 2 added ok
Item id 2 deleted ok
Item id 3 added ok
myPath
Super Subitem
Removed all changes after last commit
Item id 4 added ok
My maven dependencies:
<dependency>
<groupId>org.jooq</groupId>
<artifactId>joox</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
Upvotes: 0
Reputation: 13728
On the other hand you are closer to XML if you use XML-Database Systems, which offer XML database APIs. Like Exist or Apache Xindice.
Upvotes: 6
Reputation: 1500504
I'll assume this is actually a good idea for your application - that's a whole different discussion.
I would treat this as three separate problems:
Map<String, String>
)Most of your code should probably be unaware that your collection will be stored in XML.
There are various XML APIs available for Java - the built-in ones tend to be quite a pain to use. I don't know what the latest and greatest ones are, but historically JDOM has proved fairly simple.
Note that your choice of in-memory collection will depend on your requirements - is the ordering important, for example?
Upvotes: 4
Reputation: 75376
This will scale badly as you have to rewrite the whole XML file whenever you change the data. Just imagine you have 100000 entries and consider how much work you will have to do when using this database.
As a serialized form of an in-memory hashmap it is a different matter, though, as HashMap lookups are very fast. However, the easiest and fastest way to serialize a hashmap is to use the built-in XMLSerializer in the standard libraries.
Upvotes: 3