📜 ⬆️ ⬇️

Simple class for working with XML

Foreword


Once upon a time, I ran into a problem called the “Document Object Model”. With all the simplicity and intuitive clarity of XML itself, most of the parser APIs offered are something cumbersome and hard to understand for a person who has just begun to delve into the specifics of working with XML. Yes, I do not argue, all these are complex solutions covering all possible aspects, but this is not easier.

For me, it still remains a mystery why no one (or almost none) of the parser developers provides any easy solutions for “everyday use”, so to speak. Even if it borders on profanation, but the essence does not change - by delving into the problem and the whole ideology, we acquire the ability to use a large and powerful tool, while sacrificing more time. Perhaps, for someone, the presence of a simplified version of this tool would allow one to get to the core much faster.
')
However, so far I have to reinvent the wheel for myself.


Today I want to roll out my “bicycle” to you - a small class for working with XML for Android. I am sure that for many it will be useful at least as an orientation course.

I will say straight away that I will not explain in detail why and how I did this or that - the source code of the class is extremely simple, its two largest functions occupy hardly 40 lines each, and the total number of lines is less than 250 lines. You can copy it at the end of this text.

Description


As I said, this class is designed to work with data in XML format. If you say more detailed, it allows you to parse and form XML as a string or stream, provides access to the content and attributes of nodes, but does not work with namespaces. Perhaps the latter is a disadvantage, but I did not meet the need to work with namespaces for myself, attributes and content of nodes are enough for me.

Consider an example:

SimpleXML xml = new SimpleXML ( "Home" ) ;

SimpleXML child = xml. createChild ( "Child" ) ;
child. setAttr ( "name" , "Vasya" ) ;
child. setAttr ( "sex" , "male" ) ;
child. setAttr ( "age" , "5" ) ;

SimpleXML dog = xml. getNodeByPath ( "Pets \\ Dog" , true ) ;
dog. setAttr ( "name" , "Druzshok" ) ;
dog. setAttr ( "age" , "3" ) ;

String xmlOut = SimpleXML. saveXml ( xml ) ;


Using this example, we formed a line with the following contents:

<? xml version = '1.0' encoding = 'Utf-8' standalone = 'yes' ?>
<Home >
<Child sex = "male" age = "5" name = "Vasya" > </ Child >
<pets >
<Dog age = "3" name = "Druzshok" > </ Dog >
</ pets >
</ Home >


Now load the resulting content into the object:

SimpleXML xml2 = SimpleXML. loadXml ( xmlOut ) ;
if ( xml2 ! = null ) {
// Find out how many nodes we have
int nodeCount = xml2. getChildCount ( ) ;

Vector < SimpleXML > children = xml2. getChildren ( "Child" ) ;
if ( children ! = null && children. size ( ) > 0 ) {
for ( SimpleXML child : children ) {
// Perform actions on the Child node set
}
}

SimpleXML dog = xml2. getNodeByPath ( "Pets \\ Dog" , false ) ;
if ( dog ! = null ) {
// Dog found. We learn how to call her.
String dogName = dog. getAttr ( "name" ) ;
if ( ! dogName. equals ( "" ) ) {
// Found out that the dog is called dogName
}

// See how many attributes a dog has
int dogAttrCount = dog. getAttrCount ( ) ;

// Give the dog to the grandmother
SimpleXML xmlGrandma = new SimpleXML ( "Grandma" ) ;

// Even if granny didn’t have animals, she will now know that they are
SimpleXML xmlGrandmaPets = xmlGrandma. getNodeByPath ( "Pets" , true ) ;
dog. setParent ( xmlGrandmaPets ) ;

// And take away the cat's grandmother, if there is one
SimpleXML cat = xmlGrandma. getNodeByPath ( "Pets \\ Cat" , false ) ;
if ( cat ! = null ) {
cat. setParent ( xml2 ) ;
}
}


We were able to get a list of children, find a dog, as well as recognize its name, and give this dog to the grandmother in exchange for a cat, the presence of which, however, is doubtful. And that's great!

And now the class itself:

import java.io.ByteArrayInputStream ;
import java.io.ByteArrayOutputStream ;
import java.io.InputStream ;
import java.util.HashMap ;
import java.util.Iterator ;
import java.util.Vector ;
import java.util.Map.Entry ;
import javax.xml.parsers.DocumentBuilder ;
import javax.xml.parsers.DocumentBuilderFactory ;
import org.w3c.dom.Document ;
import org.w3c.dom.NamedNodeMap ;
import org.w3c.dom.Node ;
import org.w3c.dom.NodeList ;
import org.xmlpull.v1.XmlSerializer ;
import android.util.Log ;
import android.util.Xml ;

public class SimpleXML {

private SimpleXML fparent ;
private String ftext ;
private String fname ;
private Vector < SimpleXML > fchild ;
private HashMap < String, String > fattrs ;

public String getText ( ) {
return ftext ;
}

public void setText ( String newText ) {
ftext = newText ;
}

public String getAttr ( String attrName ) {
if ( fattrs. containsKey ( attrName ) ) return fattrs. get ( attrName ) ;
return "" ;
}

public void setAttr ( String attrName, String attrValue ) {
fattrs. put ( attrName, attrValue ) ;
}

public int getAttrCount ( ) {
return fattrs. size ( ) ;
}

public int getChildCount ( ) {
return fchild. size ( ) ;
}

public Vector < SimpleXML > getChildren ( ) {
return fchild ;
}

public SimpleXML getParent ( ) {
return fparent ;
}

public void setParent ( SimpleXML newParent ) {
if ( fparent ! = null ) {
try {
fparent. fchild . remove ( this ) ;
} catch ( Exception e ) { }
}
if ( newParent instanceof SimpleXML ) {
fparent = newParent ;
try {
fparent. fchild . add ( this ) ;
} catch ( Exception e ) { }
} else {
fparent = null ;
}
}

public SimpleXML ( String nodeName ) {
fname = nodeName ;
ftext = "" ;
fattrs = new HashMap < String, String > ( ) ;
fchild = new Vector < SimpleXML > ( ) ;
fparent = null ;
}

public static SimpleXML fromNode ( Node node ) {
SimpleXML ret = null ;
if ( node ! = null ) {
try {
ret = new SimpleXML ( node. getNodeName ( ) ) ;

if ( node. hasAttributes ( ) ) {
NamedNodeMap nattr = node. getAttributes ( ) ;
for ( int f = 0 ; f < nattr. getLength ( ) ; ++ f ) {
ret. setAttr ( nattr. item ( f ) . getNodeName ( ) , nattr. item ( f ) . getNodeValue ( ) ) ;
}
}

if ( node. hasChildNodes ( ) ) {
NodeList nlc = node. getChildNodes ( ) ;

for ( int f = 0 ; f < nlc. getLength ( ) ; ++ f ) {
if ( nlc. item ( f ) . getNodeType ( ) == Node. TEXT_NODE ) {
ret. ftext + = nlc. item ( f ) . getNodeValue ( ) ;
} else if ( nlc. item ( f ) . getNodeType ( ) == Node. ENTITY_REFERENCE_NODE ) {
String nv = nlc. item ( f ) . getNodeName ( ) ;
if ( nv ! = null && nv. length ( ) > 1 && nv. startsWith ( "#" ) ) {
nv = nv. substring ( 1 ) ;
try {
int [ ] z = { Integer . parseInt ( nv ) } ;
String s = new String ( z, 0 , z. Length ) ;
ret. ftext + = s ;
} catch ( Exception e ) { }
}
} else {
SimpleXML rchild = SimpleXML. fromNode ( nlc. item ( f ) ) ;
if ( rchild ! = null ) ret. getChildren ( ) . add ( rchild ) ;
}
}
}

} catch ( Exception e ) { }
}
return ret ;
}

public SimpleXML createChild ( String nodeName ) {
SimpleXML child = new SimpleXML ( nodeName ) ;
child. setParent ( this ) ;
return child ;
}

public Vector < SimpleXML > getChildren ( String nodeName ) {
Vector < SimpleXML > ret = new Vector < SimpleXML > ( ) ;
try {
Iterator < SimpleXML > i = fchild. iterator ( ) ;
while ( i. hasNext ( ) ) {
SimpleXML xml = i. next ( ) ;
if ( xml. fname . equalsIgnoreCase ( nodeName ) ) {
ret. add ( xml ) ;
}
}
} catch ( Exception e ) { }

return ret ;
}

public SimpleXML getNodeByPath ( String nodePath, boolean createIfNotExists ) {

if ( nodePath == null || nodePath. trim ( ) . equalsIgnoreCase ( "" ) ) return null ;

SimpleXML ret = null ;

try {
String [ ] bpath = nodePath. split ( " \\ \\ " ) ;
if ( bpath ! = null && bpath. length > 0 ) {
int scnt = 0 ;
for ( int f = 0 ; f < bpath. length ; ++ f ) {
String c = bpath [ f ] . trim ( ) ;
if ( c ! = null && c. length ( ) > 0 ) scnt ++;
}

if ( scnt > 0 ) {
ret = this ;
for ( int f = 0 ; f < bpath. length ; ++ f ) {
String c = bpath [ f ] . trim ( ) ;
if ( c ! = null && c. length ( ) > 0 ) {
Vector < SimpleXML > curnodes = ret. getChildren ( c ) ;
if ( curnodes ! = null && curnodes. size ( ) > 0 ) {
ret = curnodes. firstElement ( ) ;
} else {
if ( createIfNotExists ) {
ret = ret. createChild ( c ) ;
} else {
ret = null ;
break ;
}
}
}
}
}
}
} catch ( Exception e ) {
}

return ret ;
}

public static SimpleXML loadXml ( String txxml ) {
SimpleXML ret = null ;
try {
ret = SimpleXML. loadXml ( new ByteArrayInputStream ( txxml. getBytes ( ) ) ) ;
} catch ( Exception e ) { }

return ret ;
}

public static SimpleXML loadXml ( InputStream isxml ) {
SimpleXML ret = null ;
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory. newInstance ( ) ;
DocumentBuilder dbBuilder = dbFactory. newDocumentBuilder ( ) ;

Document doc = dbBuilder. parse ( isxml ) ;
ret = SimpleXML. fromNode ( doc. getDocumentElement ( ) ) ;
} catch ( Exception e ) { }

return ret ;
}

void serializeNode ( XmlSerializer ser ) {
try {
ser. startTag ( "" , fname ) ;
for ( Entry < String, String > ee : fattrs. entrySet ( ) ) {
ser. attribute ( "" , ee. getKey ( ) , ee. getValue ( ) ) ;
}

if ( fchild. size ( ) > 0 ) {
for ( SimpleXML c : fchild ) {
c. serializeNode ( ser ) ;
}
} else {
ser. text ( ftext ) ;
}
ser. endTag ( "" , fname ) ;
} catch ( Exception e ) {
Log d ( "app" , "e:" + e. toString ( ) ) ;
}
}

public static String saveXml ( SimpleXML document ) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream ( ) ;
XmlSerializer xs = Xml. newSerializer ( ) ;
xs. setOutput ( baos, "Utf-8" ) ;
xs. startDocument ( "Utf-8" , true ) ;
document. serializeNode ( xs ) ;
xs. endDocument ( ) ;
return new String ( baos. toByteArray ( ) ) ;
} catch ( Exception e ) { }

return "" ;
}
}

Source: https://habr.com/ru/post/91845/


All Articles