diff --git a/.classpath b/.classpath index 37c8adf..931c5c0 100644 --- a/.classpath +++ b/.classpath @@ -10,5 +10,6 @@ + diff --git a/buildjar.xml b/buildjar.xml index da1bef1..dee1465 100644 --- a/buildjar.xml +++ b/buildjar.xml @@ -121,7 +121,7 @@ - + diff --git a/lib/README b/lib/README index f7df234..429f99f 100644 --- a/lib/README +++ b/lib/README @@ -1,4 +1,5 @@ Description of used libraries: +- commons-lang: useful tools (StringUtils...) - hamcrest-core: required by junit - junit: unit tests API - log4j: log API diff --git a/lib/commons-lang3-3.1-sources.jar b/lib/commons-lang3-3.1-sources.jar new file mode 100644 index 0000000..02cd2f2 Binary files /dev/null and b/lib/commons-lang3-3.1-sources.jar differ diff --git a/lib/commons-lang3-3.1.jar b/lib/commons-lang3-3.1.jar new file mode 100644 index 0000000..a85e539 Binary files /dev/null and b/lib/commons-lang3-3.1.jar differ diff --git a/src/fr/devinsy/util/StringList.java b/src/fr/devinsy/util/StringList.java index fb26648..bd9ea6b 100755 --- a/src/fr/devinsy/util/StringList.java +++ b/src/fr/devinsy/util/StringList.java @@ -16,7 +16,7 @@ import java.util.ArrayList; public class StringList extends ArrayList { private static final long serialVersionUID = -1154185934830213732L; - public String LINE_SEPARATOR = "\n"; + public static final String LINE_SEPARATOR = "\n"; /** * @@ -34,6 +34,22 @@ public class StringList extends ArrayList super(size); } + /** + * + */ + public StringList(final String[] source) + { + super(); + + if (source != null) + { + for (String string : source) + { + this.add(string); + } + } + } + /** * */ @@ -49,6 +65,37 @@ public class StringList extends ArrayList return (result); } + /** + * + */ + public StringList append(final double value) + { + StringList result; + + result = this.append(String.valueOf(value)); + + // + return (result); + } + + /** + * + */ + public StringList append(final Double value) + { + StringList result; + + if (value != null) + { + this.append(String.valueOf(value)); + } + + result = this; + + // + return (result); + } + /** * */ @@ -117,15 +164,15 @@ public class StringList extends ArrayList /** * */ - public StringList append(final StringList string) + public StringList append(final StringList strings) { StringList result; - if (string != null) + if (strings != null) { - for (int nString = 0; nString < string.size(); nString++) + for (String string : strings) { - this.add(string.getByIndex(nString)); + this.add(string); } } @@ -163,6 +210,19 @@ public class StringList extends ArrayList return (result); } + /** + * + */ + public StringList appendln(final double value) + { + StringList result; + + result = this.append(value).appendln(); + + // + return (result); + } + /** * */ @@ -248,9 +308,9 @@ public class StringList extends ArrayList { int result = 0; - for (int nString = 0; nString < this.size(); nString++) + for (String string : this) { - result += this.getByIndex(nString).length(); + result += string.length(); } @@ -284,27 +344,64 @@ public class StringList extends ArrayList { String result; - StringBuffer preResult = new StringBuffer(this.lenght()); + StringBuffer buffer = new StringBuffer(this.lenght()); - for (int nString = 0; nString < this.size(); nString++) + for (String string : this) { - preResult.append(this.getByIndex(nString)); + buffer.append(string); } - result = new String(preResult); + result = buffer.toString(); // return (result); } + /** + * + */ + public String toStringSeparatedBy(final String separator) + { + String result; + + // + StringList buffer = new StringList(this.lenght() * 2); + for (String string : this) + { + buffer.append(string); + buffer.append(separator); + } + + if (separator != null) + { + buffer.removeLast(); + } + + result = buffer.toString(); + + // + return (result); + } + + /** + * + */ + public void writeInto(final java.io.PrintWriter out) throws IOException + { + for (String string : this) + { + out.write(string); + } + } + /** * */ public void writeInto(final java.io.Writer out) throws IOException { - for (int nString = 0; nString < this.size(); nString++) + for (String string : this) { - out.write(this.getByIndex(nString)); + out.write(string); } } @@ -315,7 +412,7 @@ public class StringList extends ArrayList { String result; - StringList strings = new StringList(); + StringList strings = new StringList(number); for (int index = 0; index < number; index++) { strings.append(source); @@ -330,29 +427,17 @@ public class StringList extends ArrayList /** * */ - static public String toString(final String[] strings) + static public String toString(final String[] source) { String result; - if (strings == null) + if (source == null) { result = null; } else { - StringConcatenator string = new StringConcatenator(); - - for (int nString = 0; nString < strings.length; nString++) - { - string.append(strings[nString]); - - if (nString < strings.length - 1) - { - string.append(' '); - } - } - - result = string.toString(); + result = new StringList(source).toString(); } // @@ -424,19 +509,19 @@ public class StringList extends ArrayList /** * */ - static public String toStringWithBrackets(final String[] strings) + static public String toStringWithBrackets(final String[] source) { String result; - if (strings == null) + if (source == null) { result = null; } else { - StringConcatenator merge = new StringConcatenator(); + StringList merge = new StringList(); - for (String string : strings) + for (String string : source) { merge.append("[").append(string).append("]"); } @@ -451,29 +536,17 @@ public class StringList extends ArrayList /** * */ - static public String toStringWithCommas(final String[] strings) + static public String toStringWithCommas(final String[] source) { String result; - if (strings == null) + if (source == null) { result = null; } else { - StringConcatenator merge = new StringConcatenator(); - - for (String string : strings) - { - if (merge.size() != 0) - { - merge.append(","); - } - - merge.append(string); - } - - result = merge.toString(); + result = new StringList(source).toStringSeparatedBy(","); } // @@ -483,29 +556,17 @@ public class StringList extends ArrayList /** * */ - static public String toStringWithFrenchCommas(final String[] strings) + static public String toStringWithFrenchCommas(final String[] source) { String result; - if (strings == null) + if (source == null) { result = null; } else { - StringConcatenator merge = new StringConcatenator(); - - for (String string : strings) - { - if (merge.size() != 0) - { - merge.append(", "); - } - - merge.append(string); - } - - result = merge.toString(); + result = new StringList(source).toStringSeparatedBy(", "); } // diff --git a/src/fr/devinsy/util/ToolBox.java b/src/fr/devinsy/util/ToolBox.java new file mode 100644 index 0000000..fd7f6fa --- /dev/null +++ b/src/fr/devinsy/util/ToolBox.java @@ -0,0 +1,404 @@ +package fr.devinsy.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; + +/** + * + @author christian.momon@devinsy.fr, June 2008, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + * + */ +public class ToolBox +{ + + /** + * + * + * @param file + * Source. + * + * @return Extension value or null. + */ + public static File addToName(final File file, final String addition) + { + File result; + + if (file == null) + { + result = null; + } + else if (addition == null) + { + result = file; + } + else + { + // + String sourceFileName = file.getAbsolutePath(); + int separatorIndex = sourceFileName.lastIndexOf('.'); + + // + String targetFileName; + if (separatorIndex > 0) + { + targetFileName = sourceFileName.substring(0, separatorIndex) + addition + sourceFileName.substring(separatorIndex); + } + else + { + targetFileName = sourceFileName + addition; + } + + // + result = new File(targetFileName); + } + + // + return result; + } + + public static String clean(final String source) + { + String result; + + result = source.replaceAll("[^\\w ]", " "); + + // + return result; + } + + /** + * Returns information about the calling class of a calledClass. + * + * @param calledClassName + * the class name which is the subject of the search. + * + * @return information about the calling class. + */ + public static StackTraceElement getCaller(final String calledClassName) + { + StackTraceElement result; + + // + StackTraceElement[] stack = Thread.currentThread().getStackTrace(); + // System.out.println("////////////////////////////"); + // for (int i = 0; (i < stack.length) && (i < 4); i++) { + // System.out.println(i + " " + stack[i].getClassName()); + // } + + // Search for first entry of class called. + boolean ended = false; + Integer indexOfCalled = null; + int depth = 1; + while (!ended) + { + if (depth < stack.length) + { + String currentClassName = stack[depth].getClassName(); + if (currentClassName.equals(calledClassName)) + { + ended = true; + indexOfCalled = Integer.valueOf(depth); + } + else + { + depth += 1; + } + } + else + { + ended = true; + result = null; + } + } + + // Search for caller of class called. + if (indexOfCalled == null) + { + result = null; + } + else + { + result = null; + ended = false; + depth = indexOfCalled; + while (!ended) + { + if (depth < stack.length) + { + String currentClassName = stack[depth].getClassName(); + if (currentClassName.equals(calledClassName)) + { + depth += 1; + } + else + { + ended = true; + result = stack[depth]; + } + } + else + { + ended = true; + result = null; + } + } + } + + // + return result; + } + + /** + * Get the extension of a file. + * + * @param file + * Source. + * + * @return Extension value or null. + */ + public static String getExtension(final File file) + { + String result; + + if (file == null) + { + result = null; + } + else + { + int separatorIndex = file.getName().lastIndexOf('.'); + if (separatorIndex > 0) + { + result = file.getName().substring(separatorIndex + 1).toLowerCase(); + } + else + { + result = null; + } + } + + // + return result; + } + + /** + * + * @param pattern + * @param source + * @return + */ + public static int indexOf(final String pattern, final List source) + { + int result; + + if (source == null) + { + result = -1; + } + else + { + boolean ended = false; + result = -1; + int currentIndex = 0; + while (!ended) + { + if (currentIndex < source.size()) + { + String sourceString = source.get(currentIndex); + if (StringUtils.equals(sourceString, pattern)) + { + ended = true; + result = currentIndex; + } + else + { + currentIndex += 1; + } + } + else + { + ended = true; + currentIndex = -1; + } + } + } + + // + return result; + } + + /** + * + * @param file + * @throws FileNotFoundException + * @throws UnsupportedEncodingException + */ + public static void save(final File file, final String string) throws UnsupportedEncodingException, FileNotFoundException + { + PrintWriter out = null; + try + { + out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); + + out.println(string); + } + finally + { + if (out != null) + { + out.close(); + } + } + } + + /** + * + * @param source + * @param extension + * @return + */ + public static File setExtension(final File source, final String extension) + { + File result; + + if ((source == null) || (extension == null)) + { + result = source; + } + else + { + String sourceFileName = source.getAbsolutePath(); + int separatorIndex = sourceFileName.lastIndexOf('.'); + + // + String targetFileName; + if (separatorIndex > 0) + { + targetFileName = sourceFileName.substring(0, separatorIndex) + extension; + } + else + { + targetFileName = sourceFileName + extension; + } + + // + result = new File(targetFileName); + } + + // + return result; + } + + /** + * + * @return + */ + public static Double[] sort(final Set source) + { + Double[] result; + + if (source == null) + { + result = null; + } + else + { + result = new Double[source.size()]; + + source.toArray(result); + Arrays.sort(result); + } + + // + return result; + } + + /** + * Concatenates int values from an array, adding decoration strings. + * + * @param values + * Source of int values. + * @param prefix + * Decoration to put on start. + * @param separator + * Decoration to put between values. + * @param postfix + * Decoration to put on end. + * + * @return A decorated string representing the int values. + */ + public static String toString(final int[] values, final String prefix, final String separator, final String postfix) + { + String result; + + StringList buffer = new StringList(); + + // + if (prefix != null) + { + buffer.append(prefix); + } + + // + boolean firstPassed = false; + for (int value : values) + { + if (firstPassed) + { + buffer.append(separator); + } + else + { + firstPassed = true; + } + buffer.append(value); + } + + // + if (postfix != null) + { + buffer.append(postfix); + } + + // + result = buffer.toString(); + + // + return result; + } + + /** + * + * @param source + * @return + */ + public static String toString(final String source) + { + String result; + + if (source == null) + { + result = ""; + } + else + { + result = source; + } + + // + return result; + } +} diff --git a/src/fr/devinsy/util/xml/XMLAttributes.java b/src/fr/devinsy/util/xml/XMLAttributes.java new file mode 100644 index 0000000..9b982fa --- /dev/null +++ b/src/fr/devinsy/util/xml/XMLAttributes.java @@ -0,0 +1,131 @@ +package fr.devinsy.util.xml; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.events.Attribute; + +/** + * + * @author christian.momon@devinsy.fr, 2013, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + */ +public class XMLAttributes extends HashMap implements Iterable { + + private static final long serialVersionUID = 8456469741805779474L; + + /** + * + */ + public XMLAttributes() { + super(); + } + + /** + * + */ + public XMLAttributes(final int capacity) { + super(capacity); + } + + /** + * + */ + public XMLAttributes(final Iterator source) { + super(); + if (source != null) { + while (source.hasNext()) { + Attribute attribute = source.next(); + + add(attribute); + } + } + } + + /** + * + */ + public XMLAttributes(final XMLAttributes source) { + super(); + addAll(source); + } + + /** + * + * @param attribute + */ + public void add(final Attribute attribute) { + if (attribute != null) { + put(attribute.getName().getLocalPart(), attribute); + } + } + + /** + * + * @param source + */ + public void addAll(final XMLAttributes source) { + for (Attribute attribute : source) { + this.add(attribute); + } + } + + /** + * + * @param label + * @return + */ + public Attribute getByLabel(final String label) { + Attribute result; + + result = get(label); + + // + return result; + } + + /** + * + */ + @Override + public Iterator iterator() { + Iterator result; + + result = this.values().iterator(); + + // + return result; + } + + /** + * + * @return + */ + public Set labels() { + Set result; + + result = this.keySet(); + + // + return result; + } + + /** + * + * @return + */ + public List toList() { + List result; + + result = new ArrayList(values()); + + // + return result; + } +} diff --git a/src/fr/devinsy/util/xml/XMLBadFormatException.java b/src/fr/devinsy/util/xml/XMLBadFormatException.java new file mode 100644 index 0000000..e360fbc --- /dev/null +++ b/src/fr/devinsy/util/xml/XMLBadFormatException.java @@ -0,0 +1,32 @@ +package fr.devinsy.util.xml; + +/** + * @author christian.momon@devinsy.fr, 2013, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + */ +public class XMLBadFormatException extends Exception { + + private static final long serialVersionUID = 768256303984176512L; + + /** + * + * @param code + * @param message + */ + public XMLBadFormatException(final String message) { + super(message); + } + + /** + * + * @param code + * @param message + * @param exception + */ + public XMLBadFormatException(final String message, final Exception exception) { + super(message, exception); + } +} diff --git a/src/fr/devinsy/util/xml/XMLReader.java b/src/fr/devinsy/util/xml/XMLReader.java new file mode 100644 index 0000000..aee7919 --- /dev/null +++ b/src/fr/devinsy/util/xml/XMLReader.java @@ -0,0 +1,497 @@ +package fr.devinsy.util.xml; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fr.devinsy.util.xml.XMLTag.TagType; + +/** + * + @author christian.momon@devinsy.fr, 2013, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + */ +public class XMLReader { + + static private final Logger logger = LoggerFactory.getLogger(XMLReader.class); + + protected XMLEventReader in; + private XMLEvent nextEvent; + + /** + * + */ + protected XMLReader() { + this.in = null; + this.nextEvent = null; + } + + /** + * + * @param file + * @throws XMLStreamException + * @throws FileNotFoundException + * @throws UnsupportedEncodingException + */ + public XMLReader(final File file) throws FileNotFoundException, XMLStreamException { + + this.nextEvent = null; + XMLInputFactory factory = XMLInputFactory.newInstance(); + this.in = factory.createXMLEventReader(new FileInputStream(file), "UTF-8"); + } + + /** + * + * @param target + * @throws XMLStreamException + * @throws UnsupportedEncodingException + */ + public XMLReader(final InputStream source) throws XMLStreamException { + + this.nextEvent = null; + XMLInputFactory factory = XMLInputFactory.newInstance(); + this.in = factory.createXMLEventReader(source); + } + + /** + * @throws XMLStreamException + * + */ + public void close() { + if (this.in != null) { + try { + this.in.close(); + } catch (XMLStreamException exception) { + exception.printStackTrace(); + } + } + } + + /** + * This methods does a premonition act. Useful to detect end of a list. + * + * @param label + * @return + * @throws XMLStreamException + */ + public boolean hasNextStartTag(final String label) throws XMLStreamException { + boolean result; + + // Load next event. + if (this.nextEvent == null) { + if (in.hasNext()) { + this.nextEvent = in.nextEvent(); + } + } + + // Analyze next event. + if (this.nextEvent == null) { + result = false; + } else if ((this.nextEvent.isStartElement()) && (StringUtils.equals(this.nextEvent.asStartElement().getName().getLocalPart(), label))) { + result = true; + } else { + result = false; + } + + // + return result; + } + + /** + * + * @param label + * @return + * @throws XMLBadFormatException + * @throws XMLStreamException + */ + public XMLTag readContentTag(final String label) throws XMLBadFormatException, XMLStreamException { + XMLTag result; + + // + result = readTag(); + + // + if (result == null) { + throw new XMLBadFormatException("XML file ends prematurely, content tag [" + label + "] is expected."); + } else if (result.getType() != TagType.CONTENT) { + throw new XMLBadFormatException("Content tag [" + label + "] is missing."); + } else if (!StringUtils.equals(label, result.getLabel())) { + throw new XMLBadFormatException("Tag with label [" + label + "] is missing."); + } + + // + return result; + } + + /** + * + * @param label + * @return + * @throws XMLStreamException + * @throws XMLBadFormatException + */ + public XMLTag readEndTag(final String label) throws XMLStreamException, XMLBadFormatException { + XMLTag result; + + // + result = readTag(); + + // + if (result == null) { + throw new XMLBadFormatException("XML file ends prematurely, end tag [" + label + "] is expected."); + } else if (result.getType() != TagType.END) { + throw new XMLBadFormatException("End tag [" + label + "] is missing."); + } else if (!StringUtils.equals(result.getLabel(), label)) { + throw new XMLBadFormatException("Tag with label [" + label + "] is missing."); + } + + // + return result; + } + + /** + * + * @param label + * @return + * @throws XMLStreamException + * @throws XMLBadFormatException + * @throws Exception + */ + public XMLTag readListTag(final String label) throws XMLStreamException, XMLBadFormatException { + XMLTag result; + + // + result = readTag(); + + // + if (result == null) { + throw new XMLBadFormatException("XML file ends prematurely, tag [" + label + "] is expected."); + } else if ((result.getType() != TagType.START) && (result.getType() != TagType.EMPTY)) { + throw new XMLBadFormatException("List tag [" + label + "] is missing."); + } else if (!StringUtils.equals(label, result.getLabel())) { + throw new XMLBadFormatException("Tag with label [" + label + "] is missing."); + } + + // + return result; + } + + /** + * + * @param label + * @return + * @throws XMLStreamException + * @throws XMLBadFormatException + * @throws Exception + */ + public XMLTag readNullableContentTag(final String label) throws XMLStreamException, XMLBadFormatException { + XMLTag result; + + // + result = readTag(); + + // + if (result == null) { + throw new XMLBadFormatException("XML file ends prematurely, tag [" + label + "] is expected."); + } else if (!StringUtils.equals(label, result.getLabel())) { + throw new XMLBadFormatException("Nullable content tag [" + label + "] is missing."); + } else if ((result.getType() != TagType.EMPTY) && (result.getType() != TagType.CONTENT)) { + throw new XMLBadFormatException("Nullable content tag [" + label + "] is missing."); + } + + // + return result; + } + + /** + * + * @param label + * @return + * @throws XMLStreamException + * @throws XMLBadFormatException + * @throws Exception + */ + public XMLTag readStartTag(final String label) throws XMLStreamException, XMLBadFormatException { + XMLTag result; + + // + result = readTag(); + + // + if (result == null) { + throw new XMLBadFormatException("XML file ends prematurely, start tag [" + label + "] is expected."); + } else if (result.getType() != TagType.START) { + throw new XMLBadFormatException("Start tag [" + label + "] is missing."); + } else if (!StringUtils.equals(result.getLabel(), label)) { + throw new XMLBadFormatException("Tag with label [" + label + "] is missing."); + } + + // + return result; + } + + /** + * Transducer graph : + *
    + *
  • START_DOCUMENT => HEADER TAG + *
  • START_ELEMENT(X) + START_ELEMENT(Y) => => START TAG + *
  • START_ELEMENT(X) + CHARACTERS(C) + START_ELEMENT(Y) => SPACES=> + * START TAG + *
  • START_ELEMENT(X) + CHARACTERS(C) + END_ELEMENT(X) => C => + * CONTENT TAG + *
  • START_ELEMENT(X) + END_ELEMENT(X) => => => EMPTY + *
  • END_ELEMENT(X) => => END TAG + *
  • END_DOCUMENT => FOOTER TAG + *
+ * + * @throws XMLStreamException + * @throws XMLBadFormatException + * + */ + public XMLTag readTag() throws XMLStreamException, XMLBadFormatException { + XMLTag result; + + int level = 1; + boolean ended = false; + result = null; + XMLAttributes attributesBuffer = null; + QName nameBuffer = null; + String contentBuffer = null; + while (!ended) { + // + XMLEvent event; + if (this.nextEvent != null) { + event = this.nextEvent; + this.nextEvent = null; + } else if (in.hasNext()) { + event = in.nextEvent(); + } else { + event = null; + } + + if (event == null) { + result = null; + } else { + logger.debug("eventType=" + XMLTools.toString(event)); + switch (level) { + case 1: + switch (event.getEventType()) { + case XMLEvent.START_DOCUMENT: + // START_DOCUMENT => START DOCUMENT TAG + ended = true; + result = new XMLTag(null, TagType.HEADER, null); + break; + case XMLEvent.START_ELEMENT: + // START_ELEMENT(X) => ... + nameBuffer = event.asStartElement().getName(); + attributesBuffer = new XMLAttributes(event.asStartElement().getAttributes()); + level += 1; + break; + case XMLEvent.END_ELEMENT: + // END_ELEMENT(X) => => END TAG + ended = true; + result = new XMLTag(event.asEndElement().getName(), TagType.END, null); + break; + case XMLEvent.END_DOCUMENT: + // END_DOCUMENT => END DOCUMENT TAG + ended = true; + result = new XMLTag(null, TagType.FOOTER, null); + break; + } + break; + case 2: + switch (event.getEventType()) { + case XMLEvent.START_ELEMENT: + // START_ELEMENT(X) + START_ELEMENT(Y) => + // => START TAG + ended = true; + result = new XMLTag(nameBuffer, TagType.START, attributesBuffer); + this.nextEvent = event; + break; + case XMLEvent.CHARACTERS: + // START_ELEMENT(X) + CHARACTERS(C) => ... + contentBuffer = event.asCharacters().getData(); + level += 1; + break; + case XMLEvent.END_ELEMENT: + // START_ELEMENT(X) + END_ELEMENT(X) => + // => => EMPTY + ended = true; + result = new XMLTag(nameBuffer, TagType.EMPTY, attributesBuffer); + break; + default: + throw new XMLBadFormatException("Unexpected XMLEvent [" + event.getEventType() + "]."); + } + break; + case 3: + switch (event.getEventType()) { + case XMLEvent.START_ELEMENT: + // START_ELEMENT(X) + CHARACTERS(C) + + // START_ELEMENT(Y) => + // SPACES => START TAG + ended = true; + result = new XMLTag(nameBuffer, TagType.START, attributesBuffer); + this.nextEvent = event; + break; + case XMLEvent.CHARACTERS: + // START_ELEMENT(X) + CHARACTERS(C1) + + // CHARACTERS(C2)=> ... + contentBuffer += event.asCharacters().getData(); + break; + case XMLEvent.END_ELEMENT: + // START_ELEMENT(X) + CHARACTERS(C) + + // END_ELEMENT(X) => C + // => CONTENT TAG + ended = true; + result = new XMLTag(nameBuffer, TagType.CONTENT, attributesBuffer); + result.setContent(contentBuffer); + break; + default: + throw new XMLBadFormatException("Unexpected XMLEvent [" + event.getEventType() + "]."); + } + break; + default: + throw new XMLBadFormatException("Unexpected level [" + level + "]."); + } + } + } + + logger.debug("=> " + XMLTools.toString(result)); + + // + return result; + } + + /** + * + * @param label + * @return + * @throws XMLStreamException + * @throws XMLBadFormatException + */ + public XMLTag readXMLFooter() throws XMLStreamException, XMLBadFormatException { + XMLTag result; + + // + result = readTag(); + + // + if (result == null) { + throw new XMLBadFormatException("XML file ends prematurely, end document event is expected."); + } else if (result.getType() != TagType.FOOTER) { + throw new XMLBadFormatException("End document tag is missing."); + } + + // + return result; + } + + /** + * + * @return + * @throws XMLException + * @throws XMLStreamException + * @throws XMLBadFormatException + */ + public XMLTag readXMLHeader() throws XMLStreamException, XMLBadFormatException { + XMLTag result; + + // + result = readTag(); + + // + // + if (result == null) { + throw new XMLBadFormatException("XML file ends prematurely, start document event is expected."); + } else if (result.getType() != TagType.HEADER) { + throw new XMLBadFormatException("XML header is missing."); + } + + // + return result; + } + + /** + * + * @param args + * @throws Exception + */ + public static void main(final String args[]) throws Exception { + + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLEventReader in = factory.createXMLEventReader(new FileReader("/home/cpm/C/Puck/Dev/Puck/test/TT/t3.puc")); + + XMLEvent event; + while (in.hasNext()) { + event = in.nextEvent(); + + switch (event.getEventType()) { + case XMLEvent.ATTRIBUTE: + System.out.println("ATTRIBUTE "); + break; + case XMLEvent.CDATA: + System.out.println("CDATA"); + break; + case XMLEvent.CHARACTERS: + System.out.println("CHARACTERS [" + event.asCharacters().getData() + "]"); + break; + case XMLEvent.COMMENT: + System.out.println("COMMENT"); + break; + case XMLEvent.DTD: + System.out.println("DTD"); + break; + case XMLEvent.END_DOCUMENT: + System.out.println("END_DOCUMENT"); + break; + case XMLEvent.END_ELEMENT: + System.out.println("END_ELEMENT " + event.asEndElement().getName()); + break; + case XMLEvent.ENTITY_DECLARATION: + System.out.println("ENTITY_DECLARATION"); + break; + case XMLEvent.ENTITY_REFERENCE: + System.out.println("ENTITY_REFERENCE"); + break; + case XMLEvent.NAMESPACE: + System.out.println("NAMESPACE"); + break; + case XMLEvent.NOTATION_DECLARATION: + System.out.println("NOTATION_DECLARATION"); + break; + case XMLEvent.PROCESSING_INSTRUCTION: + System.out.println("PROCESSING_INSTRUCTION"); + break; + case XMLEvent.SPACE: + System.out.println("SPACE"); + break; + case XMLEvent.START_DOCUMENT: + System.out.println("START_DOCUMENT"); + break; + case XMLEvent.START_ELEMENT: + System.out.println("START_ELEMENT [name=" + event.asStartElement().getName() + "][namespaceURI=" + + event.asStartElement().getName().getNamespaceURI() + "][prefix=" + event.asStartElement().getName().getPrefix() + "][localPart=" + + event.asStartElement().getName().getLocalPart() + "]"); + break; + default: + System.out.println("DEFAULT"); + } + } + } +} diff --git a/src/fr/devinsy/util/xml/XMLTag.java b/src/fr/devinsy/util/xml/XMLTag.java new file mode 100644 index 0000000..b92f1b6 --- /dev/null +++ b/src/fr/devinsy/util/xml/XMLTag.java @@ -0,0 +1,117 @@ +package fr.devinsy.util.xml; + +import javax.xml.namespace.QName; + +/** + * + @author christian.momon@devinsy.fr, 2013, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + */ +public class XMLTag { + + public enum TagType { + HEADER, + START, + END, + EMPTY, + CONTENT, + FOOTER + } + + private QName name; + private TagType type; + private XMLAttributes attributes; + private String content; + + /** + * + */ + public XMLTag(final QName name, final TagType type, final XMLAttributes attributes) { + this.name = name; + this.type = type; + this.attributes = attributes; + this.content = null; + } + + public XMLAttributes attributes() { + return this.attributes; + } + + public String getContent() { + return content; + } + + /** + * + * @return + */ + public String getLabel() { + String result; + + if (this.name == null) { + result = ""; + } else { + result = this.name.getLocalPart(); + } + + // + return result; + } + + public QName getName() { + return name; + } + + /** + * + * @return + */ + public String getNamespaceURI() { + String result; + + if (this.name == null) { + result = ""; + } else { + result = this.name.getNamespaceURI(); + } + + // + return result; + } + + /** + * + * @return + */ + public String getPrefix() { + String result; + + if (this.name == null) { + result = ""; + } else { + result = this.name.getPrefix(); + } + + // + return result; + } + + public TagType getType() { + return type; + } + + public void setContent(final String content) { + this.content = content; + } + + public void setName(final QName name) { + this.name = name; + } + + public void setType(final TagType type) { + this.type = type; + } +} diff --git a/src/fr/devinsy/util/xml/XMLTools.java b/src/fr/devinsy/util/xml/XMLTools.java new file mode 100644 index 0000000..fffe435 --- /dev/null +++ b/src/fr/devinsy/util/xml/XMLTools.java @@ -0,0 +1,303 @@ +package fr.devinsy.util.xml; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.ZipInputStream; + +import javax.xml.stream.events.XMLEvent; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * @author christian.momon@devinsy.fr, 2013, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + */ +public class XMLTools +{ + /** + * + * + * @param source + * @throws SAXException + * @throws IOException + * @throws PuckException + */ + static public boolean isValid(final File xmlFile, final File xsdFile) throws SAXException, IOException + { + boolean result; + + // + InputStream xmlSource; + if (isZipFile(xmlFile)) + { + ZipInputStream zin = new ZipInputStream(new FileInputStream(xmlFile)); + zin.getNextEntry(); + xmlSource = zin; + } + else + { + xmlSource = new FileInputStream(xmlFile); + } + + // + result = isValid(xmlSource, new FileInputStream(xsdFile)); + + // + return result; + } + + /** + * + * + * @param source + * @throws SAXException + * @throws IOException + * @throws PuckException + */ + static public boolean isValid(final File xmlFile, final InputStream xsdSource) throws SAXException, IOException + { + boolean result; + + // + InputStream xmlSource; + if (isZipFile(xmlFile)) + { + ZipInputStream zin = new ZipInputStream(new FileInputStream(xmlFile)); + zin.getNextEntry(); + xmlSource = zin; + } + else + { + xmlSource = new FileInputStream(xmlFile); + } + + // + result = isValid(xmlSource, xsdSource); + + // + return result; + } + + /** + * + * + * @param source + * @throws SAXException + * @throws IOException + * @throws PuckException + */ + static public boolean isValid(final InputStream xmlSource, final InputStream xsdSource) throws SAXException, IOException + { + boolean result; + + if (xmlSource == null) + { + result = false; + } + else + { + try + { + // + SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); + InputSource sourceentree = new InputSource(xsdSource); + SAXSource sourceXSD = new SAXSource(sourceentree); + Schema schema = factory.newSchema(sourceXSD); + Validator validator = schema.newValidator(); + + // + validator.validate(new StreamSource(xmlSource)); + result = true; + + } + catch (final IllegalArgumentException exception) + { + exception.printStackTrace(); + result = false; + } + } + + // + return result; + } + + /** + * + * @param file + * @return + * @throws IOException + */ + public static boolean isZipFile(final File file) throws IOException + { + boolean result; + + // + byte[] buffer = new byte[4]; + FileInputStream is = null; + try + { + is = new FileInputStream(file); + is.read(buffer); + } + finally + { + if (is != null) + { + is.close(); + } + } + + // 50 4B 3 4 + if ((buffer[0] == 0x50) && (buffer[1] == 0x4B) && (buffer[2] == 0x03) && (buffer[3] == 0x04)) + { + result = true; + } + else + { + result = false; + } + + // + return result; + } + + /** + * + */ + static public String readTag(final BufferedReader in) throws Exception + { + String result; + + Pattern TAG_PATTERN = Pattern.compile("^<([\\w-_\\.]+)>.*$"); + Pattern SHORT_TAG_PATTERN = Pattern.compile("^<.+/>$"); + + result = in.readLine(); + boolean ended = false; + while (!ended) + { + /* + * DEBUG Matcher tagMatcher2 = TAG_PATTERN.matcher(result); if + * (tagMatcher2.find()) { logger.info("group count,0,1,2 = [" + + * tagMatcher2.groupCount() + "][" + tagMatcher2.group(0) + "][" + + * tagMatcher2.group(1) + "][" + tagMatcher2.group(2) + "]"); } + */ + + Matcher tagMatcher = TAG_PATTERN.matcher(result); + Matcher shortTagMatcher = SHORT_TAG_PATTERN.matcher(result); + + if ((tagMatcher.find()) && (tagMatcher.groupCount() == 2) && (tagMatcher.group(1).equals(tagMatcher.group(2)))) + { + ended = true; + } + else if (shortTagMatcher.matches()) + { + ended = true; + } + else + { + result += in.readLine(); + } + } + + // + return (result); + } + + /** + * + * @param value + * @return + */ + public static String toString(final XMLEvent source) + { + String result; + + switch (source.getEventType()) + { + case XMLEvent.ATTRIBUTE: + result = "ATTRIBUTE "; + break; + case XMLEvent.CDATA: + result = "CDATA"; + break; + case XMLEvent.CHARACTERS: + result = "CHARACTERS [" + source.asCharacters().getData() + "]"; + break; + case XMLEvent.COMMENT: + result = "COMMENT"; + break; + case XMLEvent.DTD: + result = "DTD"; + break; + case XMLEvent.END_DOCUMENT: + result = "END_DOCUMENT"; + break; + case XMLEvent.END_ELEMENT: + result = "END_ELEMENT " + source.asEndElement().getName(); + break; + case XMLEvent.ENTITY_DECLARATION: + result = "ENTITY_DECLARATION"; + break; + case XMLEvent.ENTITY_REFERENCE: + result = "ENTITY_REFERENCE"; + break; + case XMLEvent.NAMESPACE: + result = "NAMESPACE"; + break; + case XMLEvent.NOTATION_DECLARATION: + result = "NOTATION_DECLARATION"; + break; + case XMLEvent.PROCESSING_INSTRUCTION: + result = "PROCESSING_INSTRUCTION"; + break; + case XMLEvent.SPACE: + result = "SPACE"; + break; + case XMLEvent.START_DOCUMENT: + result = "START_DOCUMENT"; + break; + case XMLEvent.START_ELEMENT: + result = "START_ELEMENT [name=" + source.asStartElement().getName() + "][namespaceURI=" + source.asStartElement().getName().getNamespaceURI() + "][prefix=" + + source.asStartElement().getName().getPrefix() + "][localPart=" + source.asStartElement().getName().getLocalPart() + "]"; + break; + default: + result = null; + } + + // + return result; + } + + /** + * + * @param event + * @return + */ + public static String toString(final XMLTag source) + { + String result; + + if (source == null) + { + result = "null"; + } + result = "[label=" + source.getLabel() + "][type=" + source.getType().toString() + "][content=" + source.getContent() + "]"; + + // + return result; + } +} diff --git a/src/fr/devinsy/util/xml/XMLWriter.java b/src/fr/devinsy/util/xml/XMLWriter.java new file mode 100644 index 0000000..2b4396a --- /dev/null +++ b/src/fr/devinsy/util/xml/XMLWriter.java @@ -0,0 +1,209 @@ +package fr.devinsy.util.xml; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * @author christian.momon@devinsy.fr, 2013, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + */ +public class XMLWriter { + + protected PrintWriter out; + + /** + * + */ + protected XMLWriter() { + this.out = null; + } + + /** + * + * @param file + * @throws FileNotFoundException + * @throws UnsupportedEncodingException + */ + public XMLWriter(final File file) throws UnsupportedEncodingException, FileNotFoundException { + this.out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); + } + + /** + * + * @param target + * @throws UnsupportedEncodingException + */ + public XMLWriter(final OutputStream target) throws UnsupportedEncodingException { + this.out = new PrintWriter(new OutputStreamWriter(target, "UTF-8")); + } + + /** + * + */ + public void close() { + if (this.out != null) { + this.out.flush(); + this.out.close(); + } + } + + /** + * + */ + public void flush() { + if (this.out != null) { + this.out.flush(); + } + } + + /** + * + * @param comment + */ + public void writeComment(final String comment) { + out.print(""); + } + + /** + * + */ + public void writeEmptyTag(final String label, final String... attributes) { + out.print("<"); + out.print(label); + writeTagAttributes(attributes); + out.print("/>"); + } + + /** + * + */ + public void writeEndTag(final String label) { + out.print(""); + } + + /** + * + */ + public void writeStartTag(final String label, final String... attributes) { + out.print("<"); + out.print(label); + writeTagAttributes(attributes); + out.print(">"); + } + + /** + * + */ + public void writeTag(final String label, final String content, final String... attributes) { + + if (content == null) { + writeEmptyTag(label, attributes); + } else { + writeStartTag(label, attributes); + writeTagContent(content); + writeEndTag(label); + } + } + + /** + * + */ + public void writeTagAttributes(final String... attributes) { + // + if ((attributes != null) && (attributes.length > 0)) { + for (int count = 0; count < attributes.length; count += 2) { + out.print(" "); + out.print(attributes[count]); + out.print("=\""); + out.print(attributes[count + 1]); + out.print("\""); + } + } + } + + /** + * + */ + public void writeTagContent(final String content) { + // + for (int count = 0; count < content.length(); count++) { + // + char car = content.charAt(count); + + switch (car) { + case '<': + out.print("<"); + break; + case '>': + out.print(">"); + break; + case '&': + out.print("&"); + break; + case '"': + out.print("""); + break; + case '\'': + out.print("'"); + break; + default: + out.print(car); + } + } + } + + /** + * + */ + public void writeXMLHeader(final String... attributes) { + + // + out.print(""); + } +} diff --git a/src/fr/devinsy/util/xml/XMLZipReader.java b/src/fr/devinsy/util/xml/XMLZipReader.java new file mode 100644 index 0000000..b5f10aa --- /dev/null +++ b/src/fr/devinsy/util/xml/XMLZipReader.java @@ -0,0 +1,51 @@ +package fr.devinsy.util.xml; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipInputStream; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; + +/** + * + @author christian.momon@devinsy.fr, 2013, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + */ +public class XMLZipReader extends XMLReader { + + /** + * + * @param file + * @throws IOException + * @throws XMLStreamException + */ + public XMLZipReader(final File file) throws IOException, XMLStreamException { + super(); + + XMLInputFactory factory = XMLInputFactory.newInstance(); + ZipInputStream zis = new ZipInputStream(new FileInputStream(file)); + zis.getNextEntry(); + this.in = factory.createXMLEventReader(zis, "UTF-8"); + } + + /** + * + * @param target + * @throws IOException + * @throws XMLStreamException + */ + public XMLZipReader(final InputStream source) throws IOException, XMLStreamException { + super(); + + XMLInputFactory factory = XMLInputFactory.newInstance(); + ZipInputStream zis = new ZipInputStream(source); + zis.getNextEntry(); + this.in = factory.createXMLEventReader(zis, "UTF-8"); + } +} diff --git a/src/fr/devinsy/util/xml/XMLZipWriter.java b/src/fr/devinsy/util/xml/XMLZipWriter.java new file mode 100644 index 0000000..b6e1ebb --- /dev/null +++ b/src/fr/devinsy/util/xml/XMLZipWriter.java @@ -0,0 +1,52 @@ +package fr.devinsy.util.xml; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.util.zip.Deflater; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * + @author christian.momon@devinsy.fr, 2013, copyright. + * + * This file is free software under the terms of the GNU Library General + * Public License as published by the Free Software Foundation version 3 + * or any later version. + */ +public class XMLZipWriter extends XMLWriter { + + /** + * + * @param file + * @throws IOException + */ + public XMLZipWriter(final File file) throws IOException { + super(); + + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(file)); + zos.setLevel(Deflater.BEST_COMPRESSION); + zos.setMethod(ZipOutputStream.DEFLATED); + zos.setComment("Generated by PUCK"); + zos.putNextEntry(new ZipEntry(file.getName() + ".xml")); + this.out = new PrintWriter(new OutputStreamWriter(zos, "UTF-8")); + } + + /** + * + * @param target + * @throws IOException + */ + public XMLZipWriter(final OutputStream target) throws IOException { + super(); + ZipOutputStream zos = new ZipOutputStream(target); + zos.setLevel(Deflater.BEST_COMPRESSION); + zos.setMethod(ZipOutputStream.DEFLATED); + zos.putNextEntry(new ZipEntry("noname")); + this.out = new PrintWriter(new OutputStreamWriter(zos, "UTF-8")); + } +}