I am trying to read data from an XML file by using SAX. But i cant figure out how to handle the inner <Path>
Tag...
How to do pars the inner path element?
This is my XML file.
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<files>
<backup isActive="true">
<Path>way/to/backup</Path>
</backup>
<config>
<Path>way/to/config</Path>
</config>
<data>
<Path>way/to/data</Path>
</data>
</files>
</settings>
Here the neccessary java code snippets.
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("backup")) {
Boolean isActive = Boolean.valueOf(attributes.getValue("isActive"));
System.out.println("isActive : " + isActive);
Settings.Backup.setEnabled(isActive);
hasBackup = true;
} else if (qName.equalsIgnoreCase("config")) {
hasConfig= true;
} else if (qName.equalsIgnoreCase("data")) {
hasData = true;
}
}
@Override
public void characters(char ch[], int start, int length) throws SAXException {
if (hasBackup) {
System.out.println("Backup: "
+ new String(ch, start, length));
hasBackup = false;
} else if (hasConfig) {
System.out.println("Config: " + new String(ch, start, length));
hasConfig = false;
} else if (hasData) {
System.out.println("Data: " + new String(ch, start, length));
hasData = false;
}
}
I dont feel like adding the following code is the right approach at all ...
else if (qName.equalsIgnoreCase("path")) {
System.out.println("path");
...
}
I think i have to trigger new qName somehow ... but i dont know how. Than i would just check for backup and than inside the backup i would than run an
if (qName.equalsIgnoreCase("backup")) {
Boolean isActive = Boolean.valueOf(attributes.getValue("isActive"));
System.out.println("isActive : " + isActive);
Settings.Backup.setEnabled(isActive);
hasBackup = true;
trigger next qName?
if(qname.equalsIgnorCase("path") {
Settings.Backup.setPath(path)
}
}
Also i am asking myself if i should allready handle Attributes inside the startElement or at the characters method.
On style:
Arrays
char ch[] = C/C++ compatible style
char[] ch = brackets with rest of type, Java
Variable and method names are camel case with a starting small letter.
Indentation: 4 spaces
Probably a measure to have less nested blocks.
Primitive types boolean, int, double better than Object wrappers Boolean, Integer, Double.
Some issues: `characters can be called more than once, deliver just a partial text piece. The parsing with startElement events are tiresome
Now to collect characters:
private String path = null;
@Override
public void characters(char[] chs, int start, int length) throws SAXException {
if (path != null) {
path += new String(chs, start, length));
System.out.printf("Path characters from %d, length %d: %s%n", start, length path);
}
}
You'll need endElement too:
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("Start of " + qName);
if (qName.equalsIgnoreCase("path")) {
path = "";
} else if (qName.equalsIgnoreCase("backup")) {
boolean isActive = Boolean.valueOf(attributes.getValue("isActive"));
System.out.println("isActive : " + isActive);
settings.backup.setEnabled(isActive);
hasBackup = true;
hasConfig= false;
hasData = false;
} else if (qName.equalsIgnoreCase("config")) {
hasBackup = false;
hasConfig= true;
hasData = false;
} else if (qName.equalsIgnoreCase("data")) {
hasBackup = false;
hasConfig= false;
hasData = true;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("End of " + qName);
switch (qName) {
case "backup": -> {
System.out.println("backup:" + path);
path = null;
}
case "config": -> {
System.out.println("config:" + path);
path = null;
}
case "data": -> {
System.out.println("data:" + path);
path = null;
}
case "path": -> System.out.println("Path results in: " + path);
}
}