/*********************************************************************** This file is part of KEEL-software, the Data Mining tool for regression, classification, clustering, pattern mining and so on. Copyright (C) 2004-2010 F. Herrera (herrera@decsai.ugr.es) L. S�nchez (luciano@uniovi.es) J. Alcal�-Fdez (jalcala@decsai.ugr.es) S. Garc�a (sglopez@ujaen.es) A. Fern�ndez (alberto.fernandez@ujaen.es) J. Luengo (julianlm@decsai.ugr.es) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ **********************************************************************/ /* * XmlToKeel.java */ package keel.Algorithms.Preprocess.Converter; import java.io.*; import org.jdom.*; import org.jdom.input.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * <p> * <b> XmlToKeel </b> * </p> * * Clase extendida de la clase Importer. Esta clase permite convertir * los datos almacenados en un fichero con formato xml a un fichero con * formato de datos Keel. * * @author Teresa Prieto López (UCO) * @version 1.0 */ public class XmlToKeel extends Importer { //Variable que almacena el nombre de la etiqueta o nodo padre //que contiene cada una de las instancias de datos. private String nameChildrenMain = new String();//Variable auxiliar para almacenar el texto de todos los descendientes de un nodo. private String lineAux = new String();//Variable almacena el elemento o etiqueta principal que forma el documento xml. private Element root; /* * Constructor de la Clase XmlToKeel. Inicializa los valores de las variables miembro * nullValue (valor nulo para el texto de una etiqueta xml) con el valor del parámetro * nullValueUser, y la variable nameChildrenMain con el valor del parámetro nameLabelUser. * * @param nullValueUser. Variable de tipo String con el valor nulo para el texto de * una etiqueta xml. * * @param nameLabelUser. Variable de tipo String con el nombre de la etiqueta o nodo * padre que contiene cada una de las instancias de datos. * */ public XmlToKeel(String nullValueUser, String nameLabelUser) { nullValue = nullValueUser; nameChildrenMain = nameLabelUser; } /* * Metodo utilizado para convertir los datos almacenados dentro del fichero * con formato xml indicado mediante la variable pathnameInput a * formato keel en el fichero indicado por la ruta pathnameOutput * * @param pathnameInput ruta del fichero con formato xml * @param pathnameOutput ruta con los datos en formato keel * * @throws Exception */ public void Start(String pathnameInput, String pathnameOutput) throws Exception { Pattern p; Matcher m; int numElements = 0; int j = 0; int i = 0; int k = 0; int type; int cont = 0; int actualValueInt; int labelMain = 0; double min; double max; double actualValue; String nameAttribute = new String(); String nameAttributeInitial = new String(); String valueAttribute = new String(); String value = new String(); String nameChildren = new String(); Vector nameLabelAll = new Vector(); Vector nameLabel = new Vector(); List<Element> firstInstance; String vowel[] = {"a", "e", "i", "o", "u", "A", "E", "I", "O", "U"}; String vowel_accent[] = {"�", "�", "�", "�", "�", "�", "�", "�", "�", "�"}; List elements; try { SAXBuilder builder = new SAXBuilder(false); //construyo el arbol en memoria desde el fichero // que se lo pasaré por parametro. Document doc = builder.build(new File(pathnameInput)); //Si el usuario no introduce ningun nombre de la etiqueta principal if (nameChildrenMain.equals("")) { //cojo el elemento raiz root = doc.getRootElement(); //todos los hijos que tengan elements = root.getChildren(); numElements = elements.size(); // Comprobamos si todos los hijos tienen el mismo nombre for (i = 0; i < numElements; i++) { String text = ((Element) elements.get(i)).getName(); nameLabelAll.add(text); if (!nameLabel.contains(text)) { nameLabel.add(text); } } cont = 0; i = nameLabel.size(); int[] contNameLabel = new int[i]; i = 0; if (nameLabel.size() > 1) { for (i = 0; i < nameLabel.size(); i++) { cont = 0; value = (String) nameLabel.get(i); for (j = 0; j < nameLabelAll.size(); j++) { if (value.equals((String) nameLabelAll.get(j))) { cont++; } } contNameLabel[i] = cont; } } j = 0; if (contNameLabel.length > 1) { labelMain = contNameLabel[0]; for (i = 1; i < contNameLabel.length; i++) { actualValueInt = contNameLabel[i]; if (actualValueInt > labelMain) { labelMain = actualValueInt; j = i; } } } nameChildrenMain = (String) nameLabel.get(j); } else { root = doc.getRootElement(); FindParent(root, nameChildrenMain); //todos los hijos que tengan elements = root.getChildren(); numElements = elements.size(); } //Calculamos el número de hijos que tiene cada elemento if (numElements > 0) { i = 0; Element children = (Element) elements.get(i); nameChildren = children.getName(); while (!nameChildren.equals(nameChildrenMain)) { i++; children = (Element) elements.get(i); nameChildren = children.getName(); } firstInstance = ((Element) elements.get(i)).getChildren(); System.out.println("El fichero tiene " + firstInstance.size() + " atributos"); } else { System.out.println("No hay elementos"); return; } //Reservamos memoria para almacenar la definición de los atributos y de los datos numAttributes = firstInstance.size(); attribute = new keel.Dataset.Attribute[numAttributes]; data = new Vector[numAttributes]; types = new Vector[numAttributes]; for (i = 0; i < numAttributes; i++) { attribute[i] = new keel.Dataset.Attribute(); data[i] = new Vector(); types[i] = new Vector(); } Iterator it = elements.iterator(); cont = 0; while (it.hasNext()) { Element children = (Element) it.next(); nameChildren = (String) children.getName(); if (nameChildren.equals(nameChildrenMain)) { List instances = children.getChildren(); numAttributes = instances.size(); for (j = 0; j < numAttributes; j++) { List attributes = ((Element) instances.get(j)).getAttributes(); nameAttribute = ""; nameAttributeInitial = ""; valueAttribute = ""; if (attributes.size() > 0) { for (k = 0; k < attributes.size(); k++) { nameAttribute = nameAttribute.concat(((org.jdom.Attribute) attributes.get(k)).getValue() + ""); } } if (attributes.size() == 0) { nameAttribute = ((Element) instances.get(j)).getName(); nameAttribute = nameAttribute.replace("'", ""); nameAttribute = nameAttribute.replace("\r", " "); nameAttribute = nameAttribute.replace("\n", " "); p = Pattern.compile("\\s+"); m = p.matcher(nameAttribute); nameAttribute = m.replaceAll(" "); if (nameAttribute.contains(" ")) { StringTokenizer token = new StringTokenizer(nameAttribute, " "); String lineAux = ""; if (token.hasMoreTokens()) { lineAux = token.nextToken(); } while (token.hasMoreTokens()) { lineAux = lineAux.concat(UcFirst(token.nextToken())); } nameAttribute = lineAux; } } if ((((Element) instances.get(j)).getChildren()).size() == 0) { valueAttribute = ((Element) instances.get(j)).getText(); } else { valueAttribute = ListChildrenText((Element) instances.get(j), 0); } p = Pattern.compile("^\\s+"); m = p.matcher(valueAttribute); valueAttribute = m.replaceAll(""); p = Pattern.compile("\\s+$"); m = p.matcher(valueAttribute); valueAttribute = m.replaceAll(""); valueAttribute = valueAttribute.replace("\r", " "); valueAttribute = valueAttribute.replace("\n", " "); valueAttribute = valueAttribute.replace(" ", ""); valueAttribute = valueAttribute.replace("<", "<"); valueAttribute = valueAttribute.replace(">", ">"); valueAttribute = valueAttribute.replace(""", "\""); valueAttribute = valueAttribute.replace("­", "-"); valueAttribute = valueAttribute.replace("&", "&"); valueAttribute = valueAttribute.replace("<", "<"); valueAttribute = valueAttribute.replace(">", ">"); for (k = 0; k < vowel.length; k++) { valueAttribute = valueAttribute.replace("&" + vowel[k] + "acute;", vowel_accent[k]); } if (valueAttribute.equals("") || valueAttribute.equals("<null>") || valueAttribute.equals(nullValue)) { valueAttribute = "?"; } data[j].addElement(valueAttribute); if (cont > 0) { nameAttributeInitial = attribute[j].getName(); if (!nameAttributeInitial.equals(nameAttribute)) { System.out.println(" Los atributos no tienen el mismo nombre en todas las instancias"); System.out.println(" Hay al menos uno diferente, el atributo " + nameAttributeInitial + " de " + nameAttribute); return; } } nameAttribute = nameAttribute.replace(" ", ""); nameAttribute = nameAttribute.replace("<", "<"); nameAttribute = nameAttribute.replace(">", ">"); nameAttribute = nameAttribute.replace(""", "\""); nameAttribute = nameAttribute.replace("­", "-"); nameAttribute = nameAttribute.replace("&", "&"); nameAttribute = nameAttribute.replace("<", "<"); nameAttribute = nameAttribute.replace(">", ">"); for (k = 0; k < vowel.length; k++) { nameAttribute = nameAttribute.replace("&" + vowel[k] + "acute;", vowel_accent[k]); } if (nameAttribute.equals("") || nameAttribute.equals("?") || nameAttribute.equals("<null>") || nameAttribute.equals(nullValue)) { nameAttribute = "ATTRIBUTE_" + (j + 1) + ""; } attribute[j].setName(nameAttribute); }//end for cont++; }//end if(children.getName().equals(nameChildrenMain)) } for (i = 0; i < data[0].size(); i++) { for (j = 0; j < numAttributes; j++) { value = (String) data[j].elementAt(i); types[j].addElement(DataType(value)); } } for (i = 0; i < numAttributes; i++) { if (types[i].contains(NOMINAL)) { attribute[i].setType(NOMINAL); } else { if (types[i].contains(REAL)) { attribute[i].setType(REAL); } else { if (types[i].contains(INTEGER)) { attribute[i].setType(INTEGER); } else { attribute[i].setType(-1); } } } } for (i = 0; i < data[0].size(); i++) { for (j = 0; j < numAttributes; j++) { value = (String) data[j].elementAt(i); type = attribute[j].getType(); if (type == NOMINAL) { p = Pattern.compile("[^A-ZÑa-zñ0-9_-]+"); m = p.matcher(value); /** * Cambio hecho para que los nominales con espacios en blanco se dejen * con subrayado bajo "_" y sin comillas simples. Se añade la siguiente linea */ value = value.replace(" ", "_"); if (m.find() && !value.startsWith("'") && !value.endsWith("'") && !value.equals("?")) { /** * Cambio hecho para que los nominales con espacios en blanco se dejen * con subrayado bajo "_" y sin comillas simples. Se comenta la siguiente linea */ /* //value="'"+value+"'"; */ data[j].set(i, value); } if (!(attribute[j].isNominalValue(value)) && !value.equals("?")) { attribute[j].addNominalValue(value); } } if (type == INTEGER) { if (!value.equals("?")) { actualValueInt = Integer.valueOf(value); data[j].set(i, actualValueInt); if ((attribute[j].getFixedBounds()) == false) { attribute[j].setBounds(actualValueInt, actualValueInt); } else { min = attribute[j].getMinAttribute(); max = attribute[j].getMaxAttribute(); if (actualValueInt < min) { attribute[j].setBounds(actualValueInt, max); } if (actualValueInt > max) { attribute[j].setBounds(min, actualValueInt); } } } } if (type == REAL) { if (!value.equals("?")) { actualValue = Double.valueOf(value); data[j].set(i, actualValue); if ((attribute[j].getFixedBounds()) == false) { attribute[j].setBounds(actualValue, actualValue); } else { min = attribute[j].getMinAttribute(); max = attribute[j].getMaxAttribute(); if (actualValue < min) { attribute[j].setBounds(actualValue, max); } if (actualValue > max) { attribute[j].setBounds(min, actualValue); } } } } }//end while }//end while File fileInput = new File(pathnameInput); nameRelation = fileInput.getName(); p = Pattern.compile("\\.[A-Za-z]+"); m = p.matcher(nameRelation); nameRelation = m.replaceAll(""); p = Pattern.compile("\\s+"); m = p.matcher(nameRelation); nameRelation = m.replaceAll(""); } catch (Exception e) { // e.printStackTrace(); System.err.println(e); System.exit(1); } super.Save(pathnameOutput); }//end start /* * Método recursivo que devuelve el texto que contiene todos los descendientes * de un nodo o etiqueta de un elemento xml. * * @param Element current que indica que nodo o etiqueta xml actual. * @param int cont Variable que se utiliza como contador de descendientes. * * @return String . Devuelve el valor de la variable auxiliar lineAux * que almacena el texto de todos los descendientes de un nodo separado * cada uno por un espacio en blanco. * * @throws Exception */ public String ListChildrenText(Element current, int cont) { if (cont == 0) { lineAux = ""; } if ((current.getChildren()).size() == 0) { lineAux = lineAux.concat(current.getText() + " "); } List children = current.getChildren(); Iterator iterator = children.iterator(); while (iterator.hasNext()) { Element child = (Element) iterator.next(); ListChildrenText(child, cont++); } return lineAux; } //end listChildrenText() /* * Método encargado de recorrer todo el árbol xml para encontrar * el nodo padre del nodo o etiqueta cuyo nombre coincida con el valor del parámetro childrenName. * El nodo padre de dicha etiqueta será asignado a la variable miembro * root. * * @param Element current. Elemento o nodo xml actual. * @param String childrenName. Variable String que indica el * nombre de la etiqueta a buscar. * */ public void FindParent(Element current, String childrenName) { if (current.getName().equalsIgnoreCase(childrenName)) { this.root = current.getParentElement(); return; } else { List children = current.getChildren(); Iterator iterator = children.iterator(); while (iterator.hasNext()) { Element child = (Element) iterator.next(); FindParent(child, childrenName); } } } }//end XmlToKeel