Skip to content
Advertisement

How to pars inner XML Tags with SAX

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);
    }
}
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement