UF3: Persistència en BD natives XML

Resultats d'aprenentatge:

  1. Desenvolupa aplicacions que gestionen la informació emmagatzemada en bases de dades natives XML avaluant i utilitzant classes específiques.

Adquisició de dades

Formats habituals en què ens podem trobar les dades:

  • CSV
  • JSON
  • XML

Tots aquests formats són de tipus text. Una forma adient d'obrir i tornar a escriure les dades en aquests formats és mitjançant l'ús de BufferedReader i BufferedWriter. Com que són classes que implementen AutoCloseable, podem utilitzar el try-with-resources.

BufferedReader

try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
    String line;
    while ((line = br.readLine()) != null) {
        // ...
    }
}

A Java, podem resoldre la conversió de dades utilitzant diferents eines.

Conversió numèrica, booleana i de dates

La conversió més habitual és la de cadenes (String) en nombres.

El mètodes més habituals són:

  • Per a les subclasses de Number (Integer, Long, Float, Double), tenim el mètode estàtic parseXXXX() que converteix des de String. Per exemple, Integer.parseInt().
  • BigDecimal té un constructor amb String que també fa la conversió.
  • Boolean.valueOf(string) permet convertir un String a boolean.
  • Les dates es poden convertir mitjançant la classe SimpleDateFormat. Aquesta classe admet un constructor que inclou les parts de la data a convertir.

La conversió numèrica pot generar una excepció NumberFormatException (comprovar-ho a la documentació). Com que es tracta d'una excepció "unchecked", el compilador no ens obliga a fer catch. Si volem tractar el problema de conversió, haurem de fer-lo.

CSV

Els arxius CSV consten, habitualment, d'una capçalera amb els noms dels camps i seguidament una línia per cada registre. El separador pot variar, tot i que habitualment es tracta d'una coma, un punt i coma o un tabulador.

El processament es pot realitzar utilitzant el mètode de la class String anomenat split:

  • String[] split(String regexp)

Aquest mètode separa la cadena mitjançant el separador que es passa com a paràmetre. Compte, perquè el paràmetre és una expressió regular. Si volem utilitzar algun metacaràcter (<([{\^-=$!|]})?*+.>) l'haurem de escapar amb la doble barra inversa o bé utilitzant Pattern.quote(str).

De vegades els camps poden contenir el caràcter separador. Per exemple, la coma. Llavors hem de distingir si es troben a dins d'unes cometes, i podem utilitzar una expressió regular per evitar tallar al mig del camp:

  • line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");

Per treure les cometes a un camp, podem fer:

  • camp.replaceAll("^\"|\"$", "");

L'array resultant es podrà processar per fer les conversions tal i com hem explicat.

JSON

Els arxius amb contingut JSON solen tenir una línia de text per cada objecte JSON, i per tant es poden tractar individualment. El tractament es pot fer amb alguna de les múltiples llibreries JSON lliures que existeixen.

Per exemple, utilitzant la llibreria json-simple:

JSONParser parser = new JSONParser();
JSONObject object = (JSONObject) parser.parse(line);

L'objecte JSONObject implementa Map, i per tant és fàcil de tractar.

XML

El tractament d'arxius XML es pot fer mitjançant el Java SAX Parser que ja hem tractat en aquests apunts.

Escriptura de dades

Podem escriure les dades utilitzant el BufferedWriter. Aquesta seria la forma d'escriure un String per línies:

try (BufferedWriter bw = new BufferedWriter(new FileWriter(filename))) {
    while (weHaveDataToWrite) {
        bw.write(someString);
        bw.newLine();
    }
}

CSV

L'escriptura d'un arxiu CSV es pot fer directament amb una sentència:

bw.write(camp1 + "," + camp2 + "," + camp3);
bw.newLine();

O bé amb un bucle, fent un truc per escriure les comes només al mig dels camps amb un booleà:

boolean primer = true;
for (String camp: camps) {
    if (primer) primer = false;
    else bw.write(",");
    bw.write(camp);
}
bw.newLine();

JSON

Per escriure un JSON en una línia utilitzant la llibreria json-simple cal primer tenir un objecte JSONObject.

El podem crear fàcilment amb els mètodes de Map, ja que JSONObject implementa Map:

  • jsonObject.put(key, value)

Si tenim els valors en un Map, podem copiar-los al JSONObject, o bé pasar el Map com a paràmetre al constructor:

  • jsonObject.putAll(map);
  • new JSONObject(map);

Finalment, per escriure el JSONObject només cal utilitzar el mètode toString(), que genera automàticament el JSON:

bw.write(jsonObject.toString());
bw.newLine();

XML

La forma més senzilla d'escriure un XML és utilitzant directament la sintaxi XML a les sentències d'escriptura. Per exemple:

bw.write("<registre>");
bw.write("<camp1>" + valor1 + "</camp1>");
bw.write("<camp2>" + valor2 + "</camp2>");
bw.write("</registre>");
bw.newLine();