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.
Advertisement
Answer
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); } }