[DEV] start dev of a new parsing model to support sax and big file in stream

This commit is contained in:
Edouard DUPIN 2021-02-25 01:42:08 +01:00
parent e906b9a089
commit d16f4c95e3
30 changed files with 1546 additions and 1414 deletions

View File

@ -1,179 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.Tools;
/**
* Single attribute element
*/
public class Attribute {
protected FilePos pos; //!< position in the read file (null if the file is not parsed);
protected String value; //!< value of the node (for element this is the name, for text it is the inside text ...);
protected String name; //!< Name of the attribute
public Attribute() {
this.pos = null;
this.value = "";
this.name = "";
}
public Attribute(final Attribute _obj) {
this.pos = null;
this.value = _obj.value;
this.name = _obj.name;
}
public Attribute(final String _name) {
this.name = _name;
this.value = "";
}
/**
* Constructor
* @param[in] _name Name of the attribute.
* @param[in] _value Value of the attribute.
*/
public Attribute(final String _name, final String _value) {
this.name = _name;
this.value = _value;
}
public void clear() {
this.value = "";
}
@Override
public Attribute clone() {
return new Attribute(this);
}
/**
* get the current name of the Attribute
* @return String of the attribute
*/
public String getName() {
return this.name;
};
/**
* get the current element Value.
* @return the reference of the string value.
*/
public String getValue() {
return this.value;
};
protected boolean iGenerate(final StringBuilder _data, final int _indent) {
_data.append(" ");
_data.append(this.name);
_data.append("=\"");
_data.append(this.value);
_data.append("\"");
return true;
};
protected boolean iParse(final String _data, final PositionParsing _pos, final boolean _caseSensitive, final FilePos _filePos, final Document _doc) {
Log.verbose("start parse : 'attribute'");
this.pos = _filePos.clone();
// search end of the comment :
int lastElementName = _pos.value;
for (int iii = _pos.value; iii < _data.length(); iii++) {
_filePos.check(_data.charAt(iii));
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (Tools.checkAvaillable(_data.charAt(iii), false) == true) {
lastElementName = iii;
} else {
break;
}
}
this.name = _data.substring(_pos.value, lastElementName + 1);
if (_caseSensitive == true) {
this.name = this.name.toLowerCase();
}
// count white space :
final FilePos tmpPos = new FilePos();
int white = Tools.countWhiteChar(_data, lastElementName + 1, tmpPos);
_filePos.add(tmpPos);
if (lastElementName + white + 1 >= _data.length()) {
_doc.createError(_data, lastElementName + white + 1, _filePos, " parse an xml end with an attribute parsing...");
return false;
}
if (_data.charAt(lastElementName + white + 1) != '=') {
_doc.createError(_data, lastElementName + white + 1, _filePos, " error attribute parsing == > missing '=' ...");
return false;
}
white += Tools.countWhiteChar(_data, lastElementName + white + 2, tmpPos);
_filePos.add(tmpPos);
if (lastElementName + white + 2 >= _data.length()) {
_doc.createError(_data, lastElementName + white + 2, _filePos, " parse an xml end with an attribute parsing...");
return false;
}
boolean simpleQuoteCase = false;
if (_data.charAt(lastElementName + white + 2) == '\'') { // '
simpleQuoteCase = true;
}
if (_data.charAt(lastElementName + white + 2) != '"' && _data.charAt(lastElementName + white + 2) != '\'') { // '
// parse with no element " == > direct value separate with space ...
_filePos.increment();
int lastAttributePos = lastElementName + white + 2;
for (int iii = lastElementName + white + 2; iii < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
_doc.createError(_data, iii, _filePos, "unexpected '\\n' in an attribute parsing");
return false;
}
if (_data.charAt(iii) != ' ' && _data.charAt(iii) != '/' && _data.charAt(iii) != '?' && _data.charAt(iii) != '>') {
lastAttributePos = iii + 1;
} else {
break;
}
}
this.value = _data.substring(lastElementName + white + 2, lastAttributePos);
//EXML_PARSE_ATTRIBUTE(pos << " attribute : " << name << "=\"" << value << "\"");
_pos.value = lastAttributePos - 1;
return true;
}
int lastAttributePos = lastElementName + white + 3;
for (int iii = lastElementName + white + 3; iii < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
_filePos.check(_data.charAt(iii));
if ((_data.charAt(iii) != '"' && simpleQuoteCase == false) || (_data.charAt(iii) != '\'' && simpleQuoteCase == true)) { // '
lastAttributePos = iii + 1;
} else {
break;
}
}
this.value = _data.substring(lastElementName + white + 3, lastAttributePos);
//EXML_PARSE_ATTRIBUTE(pos << " attribute : " << name << "=\"" << value << "\"");
_pos.value = lastAttributePos;
return true;
}
/**
* set the name of the attribute
* @param[in] _name New name of the attribute
*/
public void setName(final String _name) {
this.name = _name;
}
/**
* set the value of the node.
* @param[in] _value New value of the node.
*/
public final void setValue(final String _value) {
this.value = _value;
}
};

View File

@ -1,87 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.Tools;
/**
* Comment node: lt;!-- ... --gt;
*/
public class Comment extends Node {
public Comment() {
super();
}
public Comment(final Comment obj) {
super(obj.value);
}
/**
* Constructor
* @param[in] _value comment value
*/
public Comment(final String _value) {
super(_value);
}
@Override
public Comment clone() {
return new Comment(this);
}
@Override
public NodeType getType() {
return NodeType.COMMENT;
}
@Override
public boolean iGenerate(final StringBuilder _data, final int _indent) {
Tools.addIndent(_data, _indent);
_data.append("<!--");
_data.append(this.value);
_data.append("-->\n");
return true;
}
@Override
protected boolean iParse(final String _data, final PositionParsing _pos, final boolean _caseSensitive, final FilePos _filePos, final Document _doc) {
Log.verbose("start parse : 'comment'");
this.pos = _filePos;
final FilePos tmpPos = new FilePos();
final int white = Tools.countWhiteChar(_data, _pos.value, tmpPos);
_filePos.add(tmpPos);
// search end of the comment :
for (int iii = _pos.value + white; iii + 2 < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
continue;
}
if (_data.charAt(iii) == '-' && _data.charAt(iii + 1) == '-' && _data.charAt(iii + 2) == '>') {
_filePos.add(2);
// search whitespace :
int newEnd = iii;
for (int jjj = iii - 1; jjj > _pos.value; jjj--) {
if (Tools.isWhiteChar(_data.charAt(jjj)) == true) {
newEnd = jjj;
} else {
break;
}
}
// find end of value:
this.value = _data.substring(_pos.value + white, newEnd);
Log.verbose(" find comment '" + this.value + "'");
_pos.value = iii + 2;
return true;
}
}
_pos.value = _data.length();
_doc.createError(_data, _pos.value, _filePos, "comment got end of file without finding end node");
return false;
}
};

View File

@ -1,93 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.Tools;
/**
* Declaration node: lt;?XXXXXX ... gt;
*/
public class Declaration extends AttributeList {
public Declaration() {
super("");
};
public Declaration(final Declaration obj) {
super(obj.value);
for (final Attribute elem : obj.listAttribute) {
this.listAttribute.add(elem.clone());
}
};
/**
* Constructor
* @param[in] _name name of the declaration (xml, xml:xxxx ...)
*/
public Declaration(final String _name) {
super(_name);
}
@Override
public Declaration clone() {
return new Declaration(this);
}
@Override
public NodeType getType() {
return NodeType.DECLARATION;
};
@Override
protected boolean iGenerate(final StringBuilder _data, final int _indent) {
Tools.addIndent(_data, _indent);
_data.append("<?");
_data.append(this.value);
super.iGenerate(_data, _indent);
_data.append("?>\n");
return true;
}
@Override
protected boolean iParse(final String _data, final PositionParsing _pos, final boolean _caseSensitive, final FilePos _filePos, final Document _doc) {
Log.verbose("start parse : 'declaration' : '" + this.value + "'");
this.pos = _filePos;
// search end of the comment :
for (int iii = _pos.value; iii + 1 < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
continue;
}
if (_data.charAt(iii) == '>' || _data.charAt(iii) == '<') {
// an error occured :
_doc.createError(_data, _pos.value, _filePos, " find '>' or '<' instead of '?>'");
return false;
}
if (_data.charAt(iii) == '?' && _data.charAt(iii + 1) == '>') {
_filePos.increment();
// find end of declaration:
_pos.value = iii + 1;
return true;
}
if (Tools.checkAvaillable(_data.charAt(iii), true) == true) {
// we find an attibute == > create an element and parse it:
final Attribute attribute = new Attribute();
_pos.value = iii;
if (attribute.iParse(_data, _pos, _caseSensitive, _filePos, _doc) == false) {
return false;
}
iii = _pos.value;
this.listAttribute.add(attribute);
continue;
}
}
_doc.createError(_data, _pos.value, _filePos, "Text got end of file without finding end node");
_pos.value = _data.length();
return false;
}
}

View File

@ -1,41 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Log;
public class DeclarationXML extends Declaration {
public DeclarationXML(final DeclarationXML obj) {
super(obj.value);
for (final Attribute elem : obj.listAttribute) {
this.listAttribute.add(elem.clone());
}
}
public DeclarationXML(final String _version, final String _format, final boolean _standalone) {
super("xml");
if (_version.isEmpty() != true) {
setAttribute("version", _version);
}
if (_format.contentEquals("UTF-8")) {
setAttribute("encoding", "UTF-8");
} else {
Log.error("Actually does not supported other charset than UTF8");
setAttribute("encoding", "UTF-8");
}
if (_standalone == true) {
setAttribute("standalone", "true");
} else {
setAttribute("standalone", "true");
}
}
@Override
public DeclarationXML clone() {
return new DeclarationXML(this);
}
}

View File

@ -1,243 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.Tools;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
/**
* Basic document element of a document
*/
public class Document extends Element {
private boolean caseSensitive; //!< check the case sensitive of the nodes and attribute
private boolean writeErrorWhenDetexted; //!< Request print error in parsing just when detected
private String comment; //!< Comment on the error;
private String Line; //!< Parse line error (copy);
private FilePos filePos; //!< position of the error
/**
* Constructor
*/
public Document() {
this.caseSensitive = false;
this.writeErrorWhenDetexted = true;
this.comment = "";
this.Line = "";
this.filePos = new FilePos(0, 0);
}
@Override
public void clear() {
// TODO Auto-generated method stub
}
/**
* Create an error in the parsing (call by the syetm for error management)
* @param[in] _data string of chat is wrong
* @param[in] _pos Position in the file
* @param[in] _filePos human position of the error
* @param[in] _comment Error string to display
*/
public void createError(final String _data, final int _pos, final FilePos _filePos, final String _comment) {
this.comment = _comment;
this.Line = extract_line(_data, _pos);
this.filePos = _filePos;
if (this.writeErrorWhenDetexted == true) {
displayError();
}
}
/**
* Display the Document on console
*/
public void display() {
final StringBuilder tmpp = new StringBuilder();
iGenerate(tmpp, 0);
Log.info("Generated XML : \n" + tmpp.toString());
}
/**
* Request display in log of the error
*/
public void displayError() {
if (this.comment.length() == 0) {
Log.error("No error detected ???");
return;
}
Log.error(this.filePos + " " + this.comment + "\n" + this.Line + "\n" + Tools.createPosPointer(this.Line, this.filePos.getCol()));
//Log.critical("detect error");
}
String extract_line(final String data, final int _pos) {
// search back : '\n'
int startPos = data.lastIndexOf('\n', _pos);
if (startPos == _pos) {
startPos = 0;
} else {
startPos++;
}
// search forward : '\n'
int stopPos = _pos;
if (data.length() == _pos) {
stopPos = _pos;
} else if (data.charAt(_pos) != '\n') {
stopPos = data.indexOf('\n', _pos);
if (stopPos == _pos) {
stopPos = data.length();
}
}
if (startPos == -1) {
startPos = 0;
} else if (startPos >= data.length()) {
return "";
}
if (stopPos == -1) {
return "";
} else if (stopPos >= data.length()) {
stopPos = data.length();
}
return data.substring(startPos, stopPos);
}
/**
* generate a string that contain the created XML
* @param[out] _data Data where the xml is stored
* @return false : An error occured
* @return true : Parsing is OK
*/
public boolean generate(final StringBuilder _data) {
return iGenerate(_data, 0);
}
/**
* Load the file that might contain the xml
* @param[in] _uri URI of the xml
* @return false : An error occured
* @return true : Parsing is OK
*/
/*
public boolean load( Uri _uri){
// Start loading the XML :
EXML_VERBOSE("open file (xml) " + _uri);
clear();
auto fileIo = uri::get(_uri);
if (fileIo == null) {
Log.error("File Does not exist : " + _uri);
return false;
}
if (fileIo->open(io::OpenMode::Read) == false) {
Log.error("Can not open (r) the file : " + _uri);
return false;
}
// load data from the file:
String tmpDataUnicode = fileIo->readAllString();
// close the file:
fileIo->close();
// parse the data:
boolean ret = parse(tmpDataUnicode);
//Display();
return ret;
}
*/
/**
* Store the Xml in the file
* @param[in] _uri URI of the xml
* @return false : An error occured
* @return true : Parsing is OK
*/
/*
public boolean store( Uri _uri){
String createData;
if (generate(createData) == false) {
Log.error("Error while creating the XML: " + _uri);
return false;
}
auto fileIo = uri::get(_uri);
if (fileIo == null) {
Log.error("Can not create the uri: " + _uri);
return false;
}
if (fileIo->open(io::OpenMode::Write) == false) {
Log.error("Can not open (r) the file : " + _uri);
return false;
}
fileIo->writeAll(createData);
fileIo->close();
return true;
}
*/
/**
* get the status of case sensitive mode.
* @return true if case sensitive is active
*/
public boolean getCaseSensitive() {
return this.caseSensitive;
}
/**
* Get the display of the error status.
* @return true Display error
* @return false Does not display error (get it at end)
*/
public boolean getDisplayError() {
return this.writeErrorWhenDetexted;
}
@Override
public NodeType getType() {
return NodeType.DOCUMENT;
}
@Override
public boolean iGenerate(final StringBuilder _data, final int _indent) {
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null) {
this.listSub.get(iii).iGenerate(_data, _indent);
}
}
return true;
}
/**
* parse a string that contain an XML
* @param[in] _data Data to parse
* @return false : An error occured
* @return true : Parsing is OK
*/
public boolean parse(final String _data) {
Log.verbose("Start parsing document (type: string) size=" + _data.length());
clear();
// came from char == > force in utf8 ...
this.pos = new FilePos(1, 0);
final PositionParsing parsePos = new PositionParsing();
return subParse(_data, parsePos, this.caseSensitive, this.pos, this, true);
}
/**
* Enable or diasable the case sensitive (must be done before the call of parsing)
* @param[in] _val true if enable; false else.
*/
// TODO: Naming error, it is insensitive ...
public void setCaseSensitive(final boolean _val) {
this.caseSensitive = _val;
}
/**
* Set the display of the error when detected.
* @param[in] _value true: display error, false not display error (get it at end)
*/
public void setDisplayError(final boolean _value) {
this.writeErrorWhenDetexted = _value;
}
}

View File

@ -1,536 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import org.atriasoft.exml.exception.ExmlNodeDoesNotExist;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.Tools;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
/**
* Basic element Node of an XML document lt;YYYYYgt;
*/
public class Element extends AttributeList {
protected List<Node> listSub = new ArrayList<>(); //!< List of subNodes;
/**
* Constructor
*/
public Element() {
super();
};
public Element(final Element obj) throws CloneNotSupportedException {
super(obj.value);
for (final Attribute elem : obj.listAttribute) {
this.listAttribute.add(elem.clone());
}
for (final Node elem : obj.listSub) {
this.listSub.add(elem.clone());
}
}
/**
* Constructor
* @param[in] _value Element name;
*/
public Element(final String _value) {
super(_value);
};
/**
* add a node at the element (not Attribute (move in the attribute automaticly).
* @param[in] _node Pointer of the node to add.
*/
public void append(final Node _node) {
if (_node == null) {
Log.error("Try to set an empty node");
return;
}
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) == _node) {
Log.error("Try to add a node that is already added before !!!");
return;
}
}
this.listSub.add(_node);
}
@Override
public void clear() {
super.clear();
this.listSub.clear();
};
@Override
public Element clone() throws CloneNotSupportedException {
return new Element(this);
}
/**
* get the Node pointer of the element id.
* @param[in] _id Id of the element.
* @return true if the Node exist.
*/
public boolean existNode(final int _id) {
if (_id < 0 || _id >= this.listSub.size()) {
return false;
}
return true;
}
/**
* get an element with his name (work only with Element)
* @param[in] _name Name of the element that is requested
* @return true if the Node exist.
*/
public boolean existNode(final String _name) {
if (_name.isEmpty() == true) {
return false;
}
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null && this.listSub.get(iii).getValue().contentEquals(_name) == true) {
if (this.listSub.get(iii) == null) {
return false;
}
return true;
}
}
return false;
}
/**
* get the Node pointer of the element id.
* @param[in] _id Id of the element.
* @return Pointer on node.
* @throws ExmlNodeDoesNotExist The Node does not exist
*/
public Node getNode(final int _id) throws ExmlNodeDoesNotExist {
if (_id < 0 || _id >= this.listSub.size()) {
throw new ExmlNodeDoesNotExist("Node does not exist: " + _id + "/" + this.listSub.size());
}
return this.listSub.get(_id);
}
/**
* get an element with his name (work only with Element)
* @param[in] _name Name of the element that is requested
* @return Pointer on the node.
* @throws ExmlNodeDoesNotExist The Node does not exist
*/
public Node getNode(final String _name) throws ExmlNodeDoesNotExist {
if (_name.isEmpty() == true) {
throw new ExmlNodeDoesNotExist("Node can not have empty name in " + this.listAttribute.size() + " nodes");
}
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null && this.listSub.get(iii).getValue().contentEquals(_name) == true) {
return this.listSub.get(iii);
}
}
throw new ExmlNodeDoesNotExist("Node does not exist: '" + _name + "' in " + this.listAttribute.size());
}
/**
* Get the list of the sub-nodes.
* @return List of current nodes.
*/
public List<Node> getNodes() {
return this.listSub;
}
/**
* get the internal data of the element (if the element has some sub node they are converted in xml string == > like this it is not needed to use <![CDATA[...]]>
* @return the curent data string. if Only one text node, then we get the parssed data (no amp; ...) if more than one node, then we transform ,",',<,> in xml normal text...
*/
public String getText() {
final StringBuilder res = new StringBuilder();
if (this.listSub.size() == 1) {
if (this.listSub.get(0).getType() == NodeType.TEXT) {
res.append(this.listSub.get(0).getValue());
} else {
this.listSub.get(0).iGenerate(res, 0);
}
} else {
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null) {
this.listSub.get(iii).iGenerate(res, 0);
}
}
}
return res.toString();
}
@Override
public NodeType getType() {
return NodeType.ELEMENT;
}
/**
* get the type of the element id.
* @param[in] _id Id of the element.
* @return the Current type of the element or typeUnknow.
* @throws ExmlNodeDoesNotExist The Node does not exist
*/
public NodeType getType(final int _id) throws ExmlNodeDoesNotExist {
if (_id < 0 || _id >= this.listSub.size()) {
throw new ExmlNodeDoesNotExist("Node does not exist: " + _id + "/" + this.listSub.size());
}
return this.listSub.get(_id).getType();
}
@Override
protected boolean iGenerate(final StringBuilder _data, final int _indent) {
Tools.addIndent(_data, _indent);
_data.append("<");
_data.append(this.value);
super.iGenerate(_data, _indent);
if (this.listSub.size() > 0) {
if (this.listSub.size() == 1 && this.listSub.get(0) != null && this.listSub.get(0).getType() == NodeType.TEXT && ((Text) this.listSub.get(0)).countLines() == 1) {
_data.append(">");
this.listSub.get(0).iGenerate(_data, 0);
Log.verbose(" generate : '" + _data + "'");
} else {
_data.append(">\n");
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null) {
this.listSub.get(iii).iGenerate(_data, _indent + 1);
}
}
Tools.addIndent(_data, _indent);
}
_data.append("</");
_data.append(this.value);
_data.append(">\n");
} else {
_data.append("/>\n");
}
return true;
}
@Override
protected boolean iParse(final String _data, final PositionParsing _pos, final boolean _caseSensitive, final FilePos _filePos, final Document _doc) {
//EXML_PARSE_ELEMENT("start parse : 'element' named='" + value + "'");
// note : When start parsing the upper element must have set the value of the element and set the position after this one
this.pos = _filePos.clone();
// find a normal node ...
for (int iii = _pos.value; iii < _data.length(); iii++) {
_filePos.check(_data.charAt(iii));
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_data.charAt(iii) == '>') {
// we find the end ...
_pos.value = iii + 1;
return subParse(_data, _pos, _caseSensitive, _filePos, _doc, false);
}
if (_data.charAt(iii) == '/') {
// standalone node or error...
if (iii + 1 >= _data.length()) {
_doc.createError(_data, _pos.value, _filePos, "Find end of files ... == > bad case");
return false;
}
// TODO : Can have white spaces ....
if (_data.charAt(iii + 1) == '>') {
_pos.value = iii + 1;
return true;
}
// error
_doc.createError(_data, _pos.value, _filePos, "Find / without > char ...");
return false;
}
if (Tools.checkAvaillable(_data.charAt(iii), true) == true) {
// we find an attibute == > create an element and parse it:
final Attribute attribute = new Attribute();
_pos.value = iii;
if (attribute.iParse(_data, _pos, _caseSensitive, _filePos, _doc) == false) {
return false;
}
iii = _pos.value;
this.listAttribute.add(attribute);
continue;
}
if (Tools.isWhiteChar(_data.charAt(iii)) == false) {
_doc.createError(_data, iii, _filePos, "Find an unknow element : '" + _data.charAt(iii) + "'");
return false;
}
}
_doc.createError(_data, _pos.value, _filePos, "Unexpecting end of parsing exml::internal::Element : '" + this.value + "' == > check if the '/>' is set or the end of element");
return false;
}
/**
* Remove all element with this name
* @param[in] _nodeName Name of nodes to remove.
*/
public void remove(final String _nodeName) {
if (_nodeName == "") {
return;
}
for (final ListIterator<Node> iter = this.listSub.listIterator(); iter.hasNext();) {
final Node element = iter.next();
if (element == null) {
iter.remove();
continue;
}
if (element.getValue().contentEquals(_nodeName) == true) {
iter.remove();
}
}
}
/**
* get the number of sub element in the node (can be Comment ; Element ; Text :Declaration).
* @return a number >=0.
*/
public int size() {
return this.listSub.size();
}
/**
* Parse sub node string
* @param[in] _data all file string data
* @param[in,out] _pos Position to start parsing in the file and return the end of parsing
* @param[in] _caseSensitive Case sensitive parsing (usefull for html)
* @param[in] _filePos Current File position of the parsing
* @param[in] _doc Document base reference
* @param[in] _mainNode if true, this is the first root node
* @return true parsing is done OK
* @return false An error appear in the parsing
*/
protected boolean subParse(final String _data, final PositionParsing _pos, final boolean _caseSensitive, final FilePos _filePos, final Document _doc) {
return subParse(_data, _pos, _caseSensitive, _filePos, _doc, false);
}
protected boolean subParse(final String _data, final PositionParsing _pos, final boolean _caseSensitive, final FilePos _filePos, final Document _doc, final boolean _mainNode) {
//EXML_PARSE_ELEMENT(" start subParse ... " << _pos << " " << _filePos);
for (int iii = _pos.value; iii < _data.length(); iii++) {
_filePos.check(_data.charAt(iii));
Tools.drawElementParsed(_data.charAt(iii), _filePos);
final FilePos tmpPos = new FilePos();
if (_data.charAt(iii) == '<') {
final int white = Tools.countWhiteChar(_data, iii + 1, tmpPos);
if (iii + white + 1 >= _data.length()) {
_filePos.add(tmpPos);
_doc.createError(_data, _pos.value, _filePos, "End file with '<' char == > invalide XML");
_pos.value = iii + white;
return false;
}
// Detect type of the element:
if (_data.charAt(iii + white + 1) == '>') {
_filePos.add(tmpPos);
_doc.createError(_data, _pos.value, _filePos, "Find '>' with no element in the element...");
_pos.value = iii + white + 1;
return false;
}
if (_data.charAt(iii + white + 1) == '?') {
tmpPos.increment();
// TODO : white space ...
if (Tools.checkAvaillable(_data.charAt(iii + white + 2), true) == false) {
_doc.createError(_data, _pos.value, _filePos, "Find unavaillable name in the Declaration node...");
_pos.value = iii + white + 1;
return false;
}
//EXML_DEBUG("Generate node name : '" << _data[iii+1] << "'");
int endPosName = iii + white + 1;
// generate element name ...
for (int jjj = iii + white + 2; jjj < _data.length(); jjj++) {
if (Tools.checkAvaillable(_data.charAt(jjj), false) == true) {
// we find the end ...
endPosName = jjj;
} else {
break;
}
tmpPos.check(_data.charAt(jjj));
}
String tmpname = _data.substring(iii + white + 2, endPosName + 1);
if (_caseSensitive == true) {
tmpname = tmpname.toLowerCase();
}
// Find declaration marker
final Declaration declaration = new Declaration(tmpname);
_filePos.add(tmpPos);
_pos.value = endPosName + 1;
if (declaration.iParse(_data, _pos, _caseSensitive, _filePos, _doc) == false) {
return false;
}
iii = _pos.value;
this.listSub.add(declaration);
continue;
}
if (_data.charAt(iii + white + 1) == '!') {
tmpPos.increment();
// Find special block element
if (iii + white + 2 >= _data.length()) {
_doc.createError(_data, _pos.value, _filePos, "End file with '<!' chars == > invalide XML");
return false;
}
if (_data.charAt(iii + white + 2) == '-') {
tmpPos.increment();
if (iii + white + 3 >= _data.length()) {
_doc.createError(_data, _pos.value, _filePos, "End file with '<!-' chars == > invalide XML");
return false;
}
if (_data.charAt(iii + white + 3) != '-') {
_doc.createError(_data, _pos.value, _filePos, "Element parse with '<!-" + _data.charAt(iii + 3) + "' chars == > invalide XML");
return false;
}
tmpPos.increment();
// find comment:
final Comment comment = new Comment();
_pos.value = iii + white + 4;
_filePos.add(tmpPos);
if (comment.iParse(_data, _pos, _caseSensitive, _filePos, _doc) == false) {
return false;
}
iii = _pos.value;
this.listSub.add(comment);
} else if (_data.charAt(iii + white + 2) == '[') {
tmpPos.increment();
if (iii + white + 8 >= _data.length()) {
_doc.createError(_data, _pos.value, _filePos, "End file with '<![' chars == > invalide XML");
return false;
}
if (_data.charAt(iii + white + 3) != 'C' || _data.charAt(iii + white + 4) != 'D' || _data.charAt(iii + white + 5) != 'A' || _data.charAt(iii + white + 6) != 'T'
|| _data.charAt(iii + white + 7) != 'A' || _data.charAt(iii + white + 8) != '[') {
_doc.createError(_data, _pos.value, _filePos, "Element parse with '<![" + _data.charAt(iii + white + 3) + _data.charAt(iii + white + 4) + _data.charAt(iii + white + 5)
+ _data.charAt(iii + white + 6) + _data.charAt(iii + white + 7) + _data.charAt(iii + white + 8) + "' chars == > invalide XML");
return false;
}
tmpPos.add(6);
// find text:
final TextCDATA text = new TextCDATA();
_pos.value = iii + 9 + white;
_filePos.add(tmpPos);
if (text.iParse(_data, _pos, _caseSensitive, _filePos, _doc) == false) {
return false;
}
iii = _pos.value;
this.listSub.add(text);
} else {
_doc.createError(_data, _pos.value, _filePos, "End file with '<!" + _data.charAt(iii + white + 2) + "' chars == > invalide XML");
return false;
}
continue;
}
if (_data.charAt(iii + white + 1) == '/') {
tmpPos.increment();
//EXML_DEBUG("Generate node name : '" << _data[iii+1] << "'");
int endPosName = iii + white + 1;
// generate element name ...
for (int jjj = iii + white + 2; jjj < _data.length(); jjj++) {
if (Tools.checkAvaillable(_data.charAt(jjj), false) == true) {
// we find the end ...
endPosName = jjj;
} else {
break;
}
tmpPos.check(_data.charAt(jjj));
}
String tmpname = _data.substring(iii + white + 2, endPosName + 1);
if (_caseSensitive == true) {
tmpname = tmpname.toLowerCase();
}
if (tmpname.contentEquals(this.value) == true) {
// find end of node :
// find > element ...
for (int jjj = endPosName + 1; jjj < _data.length(); jjj++) {
Tools.drawElementParsed(_data.charAt(jjj), _filePos);
if (tmpPos.check(_data.charAt(jjj)) == true) {
continue;
}
if (_data.charAt(jjj) == '>') {
_pos.value = jjj;
_filePos.add(tmpPos);
return true;
} else if (_data.charAt(jjj) != '\r' && _data.charAt(jjj) != ' ' && _data.charAt(jjj) != '\t') {
_filePos.add(tmpPos);
_doc.createError(_data, jjj, _filePos, "End node error : have data inside end node other than [ \\n\\t\\r] " + this.value + "'");
return false;
}
}
} else {
_doc.createError(_data, _pos.value, _filePos, "End node error : '" + tmpname + "' != '" + this.value + "'");
return false;
}
}
if (_data.charAt(iii + white + 1) == '>') {
// end of something == > this is really bad
_doc.createError(_data, _pos.value, _filePos, "Find '>' chars == > invalide XML");
return false;
}
if (Tools.checkAvaillable(_data.charAt(iii + white + 1), true) == true) {
tmpPos.increment();
Log.debug("Generate node name : '" + _data.charAt(iii + 1) + "'");
int endPosName = iii + white + 1;
// generate element name ...
for (int jjj = iii + white + 2; jjj < _data.length(); jjj++) {
if (Tools.checkAvaillable(_data.charAt(jjj), false) == true) {
// we find the end ...
endPosName = jjj;
} else {
break;
}
tmpPos.check(_data.charAt(jjj));
}
String tmpname = _data.substring(iii + white + 1, endPosName + 1);
if (_caseSensitive == true) {
tmpname = tmpname.toLowerCase();
}
Log.debug("find node named : '" + tmpname + "'");
// find text:
final Element element = new Element(tmpname);
_pos.value = endPosName + 1;
_filePos.add(tmpPos);
if (element.iParse(_data, _pos, _caseSensitive, _filePos, _doc) == false) {
return false;
}
iii = _pos.value;
this.listSub.add(element);
continue;
}
_filePos.add(tmpPos);
// here we have an error :
_doc.createError(_data, _pos.value, _filePos, "Find an ununderstanding element : '" + _data.charAt(iii + white + 1) + "'");
return false;
} else {
if (_data.charAt(iii) == '>') {
_doc.createError(_data, _pos.value, _filePos, "Find elemement '>' == > no reason to be here ...");
return false;
}
// might to be data text ...
if (_data.charAt(iii) == '\n' || _data.charAt(iii) == ' ' || _data.charAt(iii) == '\t' || _data.charAt(iii) == '\r') {
// empty spaces == > nothing to do ....
} else {
// find data == > parse it...
final Text text = new Text();
_pos.value = iii;
_filePos.add(tmpPos);
if (text.iParse(_data, _pos, _caseSensitive, _filePos, _doc) == false) {
return false;
}
iii = _pos.value;
this.listSub.add(text);
}
}
}
if (_mainNode == true) {
return true;
}
_doc.createError(_data, _pos.value, _filePos, "Did not find end of the exml::internal::Element : '" + this.value + "'");
return false;
}
};

View File

@ -0,0 +1,121 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.builder.Builder;
import org.atriasoft.exml.builder.BuilderGeneric;
import org.atriasoft.exml.exception.ExmlBuilderException;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.parser.ParseXml;
public class Exml {
/**
* Display the Document on console
*/
public static void display() {
final StringBuilder tmpp = new StringBuilder();
//iGenerate(tmpp, 0);
Log.info("Generated XML : \n" + tmpp.toString());
}
/**
* generate a string that contain the created XML
* @param[out] _data Data where the xml is stored
* @return false : An error occured
* @return true : Parsing is OK
*/
public static boolean generate(final StringBuilder _data) {
//return iGenerate(_data, 0);
return false;
}
public static boolean iGenerate(final StringBuilder _data, final int _indent) {
/*
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null) {
this.listSub.get(iii).iGenerate(_data, _indent);
}
}
*/
return true;
}
public static XmlNode parse(final String data) {
final Builder builder = new BuilderGeneric();
final ParseXml parser = new ParseXml(builder);
Object out = null;
try {
out = parser.parse(data);
} catch (final ExmlBuilderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (XmlNode) out;
}
/**
* Load the file that might contain the xml
* @param[in] _uri URI of the xml
* @return false : An error occured
* @return true : Parsing is OK
*/
/*
public boolean load( Uri _uri){
// Start loading the XML :
EXML_VERBOSE("open file (xml) " + _uri);
clear();
auto fileIo = uri::get(_uri);
if (fileIo == null) {
Log.error("File Does not exist : " + _uri);
return false;
}
if (fileIo->open(io::OpenMode::Read) == false) {
Log.error("Can not open (r) the file : " + _uri);
return false;
}
// load data from the file:
String tmpDataUnicode = fileIo->readAllString();
// close the file:
fileIo->close();
// parse the data:
boolean ret = parse(tmpDataUnicode);
//Display();
return ret;
}
*/
/**
* Store the Xml in the file
* @param[in] _uri URI of the xml
* @return false : An error occured
* @return true : Parsing is OK
*/
/*
public boolean store( Uri _uri){
String createData;
if (generate(createData) == false) {
Log.error("Error while creating the XML: " + _uri);
return false;
}
auto fileIo = uri::get(_uri);
if (fileIo == null) {
Log.error("Can not create the uri: " + _uri);
return false;
}
if (fileIo->open(io::OpenMode::Write) == false) {
Log.error("Can not open (r) the file : " + _uri);
return false;
}
fileIo->writeAll(createData);
fileIo->close();
return true;
}
*/
private Exml() {}
}

View File

@ -1,116 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.Tools;
/**
* Text node interface (internal data between two Marker: &lt;XXX&gt; ALL here &lt;/XXX&gt;
*/
public class Text extends Node {
// transform the Text with :
// "&lt;" == "<"
// "&gt;" == ">"
// "&amp;" == "&"
// "&apos;" == "'"
// "&quot;" == """
private static String replaceSpecialChar(final String _inval) {
final String out = _inval;
out.replace("&lt;", "<");
out.replace("&gt;", ">");
out.replace("&apos;", "'");
out.replace("&quot;", "\"");
out.replace("&amp;", "&");
//EXML_ERROR("INNN '"<< _inval << "' => '" << out << "'");
return out;
}
private static String replaceSpecialCharOut(final String _inval) {
final String out = _inval;
out.replace("<", "&lt;");
out.replace(">", "&gt;");
out.replace("'", "&apos;");
out.replace("\"", "&quot;");
out.replace("&", "&amp;");
//EXML_ERROR("OUTTT '"<< _inval << "' => '" << out << "'");
return out;
}
/**
* Constructor
*/
public Text() {};
/**
* Constructor
* @param[in] _data String data of the current Text
*/
public Text(final String _data) {
super(_data);
}
/**
* count the number of line in the current text
* @return The number of lines
*/
protected int countLines() {
int count = 1;
for (int iii = 0; iii < this.value.length(); iii++) {
if (this.value.charAt(iii) == '\n') {
count++;
}
}
return count;
}
@Override
public NodeType getType() {
return NodeType.TEXT;
};
@Override
protected boolean iGenerate(final StringBuilder _data, final int _indent) {
_data.append(replaceSpecialCharOut(this.value));
return true;
}
@Override
protected boolean iParse(final String _data, final PositionParsing _pos, final boolean _caseSensitive, final FilePos _filePos, final Document _doc) {
Log.verbose("start parse : 'text'");
this.pos = _filePos.clone();
// search end of the comment :
for (int iii = _pos.value; iii < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
continue;
}
if (_data.charAt(iii) == '>' || _data.charAt(iii) == '<') {
// search whitespace :
int newEnd = iii;
for (int jjj = iii - 1; jjj > _pos.value; --jjj) {
if (Tools.isWhiteChar(_data.charAt(jjj)) == true) {
newEnd = jjj;
} else {
break;
}
}
// find end of value:
this.value = _data.substring(_pos.value, newEnd);
Log.verbose(" find text '" + this.value + "'");
_pos.value = iii - 1;
this.value = replaceSpecialChar(this.value);
return true;
}
}
_doc.createError(_data, _pos.value, _filePos, "Text got end of file without finding end node");
_pos.value = _data.length();
return false;
}
};

View File

@ -5,11 +5,7 @@
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.Tools;
public class TextCDATA extends Text {
public class TextCDATA extends XmlText {
public TextCDATA() {
super();
}
@ -26,27 +22,4 @@ public class TextCDATA extends Text {
return true;
}
@Override
protected boolean iParse(final String _data, final PositionParsing _pos, final boolean _caseSensitive, final FilePos _filePos, final Document _doc) {
Log.verbose("start parse : 'text::CDATA'");
this.pos = _filePos.clone();
// search end of the comment :
for (int iii = _pos.value; iii + 2 < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
continue;
}
if (_data.charAt(iii) == ']' && _data.charAt(iii + 1) == ']' && _data.charAt(iii + 2) == '>') {
// find end of value:
_filePos.add(2);
this.value = _data.substring(_pos.value, iii);
Log.verbose(" find text CDATA '" + this.value + "'");
_pos.value = iii + 2;
return true;
}
}
_doc.createError(_data, _pos.value, _filePos, "text CDATA got end of file without finding end node");
_pos.value = _data.length();
return false;
}
}

View File

@ -0,0 +1,95 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.FilePos;
/**
* Single attribute element
*/
public class XmlAttribute {
protected FilePos pos; //!< position in the read file (null if the file is not parsed);
protected String value; //!< value of the node (for element this is the name, for text it is the inside text ...);
protected String name; //!< Name of the attribute
public XmlAttribute() {
this.pos = null;
this.value = "";
this.name = "";
}
public XmlAttribute(final String _name) {
this.name = _name;
this.value = "";
}
/**
* Constructor
* @param[in] _name Name of the attribute.
* @param[in] _value Value of the attribute.
*/
public XmlAttribute(final String _name, final String _value) {
this.name = _name;
this.value = _value;
}
public XmlAttribute(final XmlAttribute _obj) {
this.pos = null;
this.value = _obj.value;
this.name = _obj.name;
}
public void clear() {
this.value = "";
}
@Override
public XmlAttribute clone() {
return new XmlAttribute(this.name, this.value);
}
/**
* get the current name of the Attribute
* @return String of the attribute
*/
public String getName() {
return this.name;
};
/**
* get the current element Value.
* @return the reference of the string value.
*/
public String getValue() {
return this.value;
};
protected boolean iGenerate(final StringBuilder _data, final int _indent) {
_data.append(" ");
_data.append(this.name);
_data.append("=\"");
_data.append(this.value);
_data.append("\"");
return true;
};
/**
* set the name of the attribute
* @param[in] _name New name of the attribute
*/
public void setName(final String _name) {
this.name = _name;
}
/**
* set the value of the node.
* @param[in] _value New value of the node.
*/
public final void setValue(final String _value) {
this.value = _value;
}
};

View File

@ -16,10 +16,10 @@ import org.atriasoft.exml.internal.Log;
/**
* List of all attribute element in a node
*/
public abstract class AttributeList extends Node {
protected List<Attribute> listAttribute = new ArrayList<>(); //!< list of all attribute;
public abstract class XmlAttributeList extends XmlNode {
protected List<XmlAttribute> listAttribute = new ArrayList<>(); //!< list of all attribute;
public AttributeList() {
public XmlAttributeList() {
super();
};
@ -27,7 +27,7 @@ public abstract class AttributeList extends Node {
* Constructor
* @param[in] _value Node value;
*/
public AttributeList(final String _value) {
public XmlAttributeList(final String _value) {
super(_value);
}
@ -35,7 +35,7 @@ public abstract class AttributeList extends Node {
* Add attribute on the List
* @param[in] _attr Pointer on the attribute
*/
public void appendAttribute(final Attribute _attr) {
public void appendAttribute(final XmlAttribute _attr) {
if (_attr == null) {
Log.error("Try to set an empty node");
return;
@ -82,7 +82,7 @@ public abstract class AttributeList extends Node {
* @return Pointer on the attribute or NULL
* @throws ExmlAttributeDoesNotExist The attribute does not exist.
*/
public Attribute getAttr(final int _id) throws ExmlAttributeDoesNotExist {
public XmlAttribute getAttr(final int _id) throws ExmlAttributeDoesNotExist {
if (_id < 0 || _id >= this.listAttribute.size()) {
throw new ExmlAttributeDoesNotExist("Attribute does not exist: " + _id + "/" + this.listAttribute.size());
}
@ -107,7 +107,7 @@ public abstract class AttributeList extends Node {
throw new ExmlAttributeDoesNotExist("Attribute does not exist: " + _name + " in " + this.listAttribute.size() + " attributes");
}
public List<Attribute> getAttributes() {
public List<XmlAttribute> getAttributes() {
return this.listAttribute;
}
@ -118,7 +118,7 @@ public abstract class AttributeList extends Node {
* @throws ExmlAttributeDoesNotExist The attribute does not exist.
*/
public Pair<String, String> getAttrPair(final int _id) throws ExmlAttributeDoesNotExist {
final Attribute att = getAttr(_id);
final XmlAttribute att = getAttr(_id);
return new Pair<String, String>(att.getName(), att.getValue());
}
@ -142,8 +142,8 @@ public abstract class AttributeList extends Node {
if (_name.length() == 0) {
return false;
}
for (final ListIterator<Attribute> iter = this.listAttribute.listIterator(); iter.hasNext();) {
final Attribute element = iter.next();
for (final ListIterator<XmlAttribute> iter = this.listAttribute.listIterator(); iter.hasNext();) {
final XmlAttribute element = iter.next();
if (element == null) {
iter.remove();
continue;
@ -170,7 +170,7 @@ public abstract class AttributeList extends Node {
return;
}
}
final Attribute attr = new Attribute(_name, _value);
final XmlAttribute attr = new XmlAttribute(_name, _value);
this.listAttribute.add(attr);
}

View File

@ -0,0 +1,50 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Tools;
/**
* Comment node: lt;!-- ... --gt;
*/
public class XmlComment extends XmlNode {
public XmlComment() {
super();
}
/**
* Constructor
* @param[in] _value comment value
*/
public XmlComment(final String _value) {
super(_value);
}
public XmlComment(final XmlComment obj) {
super(obj.value);
}
@Override
public XmlComment clone() {
return new XmlComment(this);
}
@Override
public XmlNodeType getType() {
return XmlNodeType.COMMENT;
}
@Override
public boolean iGenerate(final StringBuilder _data, final int _indent) {
Tools.addIndent(_data, _indent);
_data.append("<!--");
_data.append(this.value);
_data.append("-->\n");
return true;
}
};

View File

@ -0,0 +1,72 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.Tools;
/**
* Declaration node: lt;?XXXXXX ... gt;
*/
public class XmlDeclaration extends XmlAttributeList {
public XmlDeclaration() {
super("");
};
/**
* Constructor
* @param[in] _name name of the declaration (xml, xml:xxxx ...)
*/
public XmlDeclaration(final String _name) {
super(_name);
}
public XmlDeclaration(final String _version, final String _format, final boolean _standalone) {
super("xml");
if (_version.isEmpty() != true) {
setAttribute("version", _version);
}
if (_format.contentEquals("UTF-8")) {
setAttribute("encoding", "UTF-8");
} else {
Log.error("Actually does not supported other charset than UTF8");
setAttribute("encoding", "UTF-8");
}
if (_standalone == true) {
setAttribute("standalone", "true");
} else {
setAttribute("standalone", "true");
}
};
public XmlDeclaration(final XmlDeclaration obj) {
super(obj.value);
for (final XmlAttribute elem : obj.listAttribute) {
this.listAttribute.add(elem.clone());
}
}
@Override
public XmlDeclaration clone() {
return new XmlDeclaration(this);
}
@Override
public XmlNodeType getType() {
return XmlNodeType.DECLARATION;
};
@Override
protected boolean iGenerate(final StringBuilder _data, final int _indent) {
Tools.addIndent(_data, _indent);
_data.append("<?");
_data.append(this.value);
super.iGenerate(_data, _indent);
_data.append("?>\n");
return true;
}
}

View File

@ -0,0 +1,251 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import org.atriasoft.exml.exception.ExmlNodeDoesNotExist;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.Tools;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
/**
* Basic element Node of an XML document lt;YYYYYgt;
*/
public class XmlElement extends XmlAttributeList {
protected List<XmlNode> listSub = new ArrayList<>(); //!< List of subNodes;
/**
* Constructor
*/
public XmlElement() {
super();
};
/**
* Constructor
* @param[in] _value Element name;
*/
public XmlElement(final String _value) {
super(_value);
}
public XmlElement(final XmlElement obj) throws CloneNotSupportedException {
super(obj.value);
for (final XmlAttribute elem : obj.listAttribute) {
this.listAttribute.add(elem.clone());
}
for (final XmlNode elem : obj.listSub) {
this.listSub.add(elem.clone());
}
};
/**
* add a node at the element (not Attribute (move in the attribute automaticly).
* @param[in] _node Pointer of the node to add.
*/
public void append(final XmlNode _node) {
if (_node == null) {
Log.error("Try to set an empty node");
return;
}
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) == _node) {
Log.error("Try to add a node that is already added before !!!");
return;
}
}
this.listSub.add(_node);
}
@Override
public void clear() {
super.clear();
this.listSub.clear();
};
@Override
public XmlElement clone() throws CloneNotSupportedException {
return new XmlElement(this);
}
/**
* get the Node pointer of the element id.
* @param[in] _id Id of the element.
* @return true if the Node exist.
*/
public boolean existNode(final int _id) {
if (_id < 0 || _id >= this.listSub.size()) {
return false;
}
return true;
}
/**
* get an element with his name (work only with Element)
* @param[in] _name Name of the element that is requested
* @return true if the Node exist.
*/
public boolean existNode(final String _name) {
if (_name.isEmpty() == true) {
return false;
}
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null && this.listSub.get(iii).getValue().contentEquals(_name) == true) {
if (this.listSub.get(iii) == null) {
return false;
}
return true;
}
}
return false;
}
/**
* get the Node pointer of the element id.
* @param[in] _id Id of the element.
* @return Pointer on node.
* @throws ExmlNodeDoesNotExist The Node does not exist
*/
public XmlNode getNode(final int _id) throws ExmlNodeDoesNotExist {
if (_id < 0 || _id >= this.listSub.size()) {
throw new ExmlNodeDoesNotExist("Node does not exist: " + _id + "/" + this.listSub.size());
}
return this.listSub.get(_id);
}
/**
* get an element with his name (work only with Element)
* @param[in] _name Name of the element that is requested
* @return Pointer on the node.
* @throws ExmlNodeDoesNotExist The Node does not exist
*/
public XmlNode getNode(final String _name) throws ExmlNodeDoesNotExist {
if (_name.isEmpty() == true) {
throw new ExmlNodeDoesNotExist("Node can not have empty name in " + this.listAttribute.size() + " nodes");
}
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null && this.listSub.get(iii).getValue().contentEquals(_name) == true) {
return this.listSub.get(iii);
}
}
throw new ExmlNodeDoesNotExist("Node does not exist: '" + _name + "' in " + this.listAttribute.size());
}
/**
* Get the list of the sub-nodes.
* @return List of current nodes.
*/
public List<XmlNode> getNodes() {
return this.listSub;
}
/**
* get the internal data of the element (if the element has some sub node they are converted in xml string == > like this it is not needed to use <![CDATA[...]]>
* @return the curent data string. if Only one text node, then we get the parssed data (no amp; ...) if more than one node, then we transform ,",',<,> in xml normal text...
*/
public String getText() {
final StringBuilder res = new StringBuilder();
if (this.listSub.size() == 1) {
if (this.listSub.get(0).getType() == XmlNodeType.TEXT) {
res.append(this.listSub.get(0).getValue());
} else {
this.listSub.get(0).iGenerate(res, 0);
}
} else {
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null) {
this.listSub.get(iii).iGenerate(res, 0);
}
}
}
return res.toString();
}
@Override
public XmlNodeType getType() {
return XmlNodeType.ELEMENT;
}
/**
* get the type of the element id.
* @param[in] _id Id of the element.
* @return the Current type of the element or typeUnknow.
* @throws ExmlNodeDoesNotExist The Node does not exist
*/
public XmlNodeType getType(final int _id) throws ExmlNodeDoesNotExist {
if (_id < 0 || _id >= this.listSub.size()) {
throw new ExmlNodeDoesNotExist("Node does not exist: " + _id + "/" + this.listSub.size());
}
return this.listSub.get(_id).getType();
}
@Override
protected boolean iGenerate(final StringBuilder _data, final int _indent) {
Tools.addIndent(_data, _indent);
_data.append("<");
_data.append(this.value);
super.iGenerate(_data, _indent);
if (this.listSub.size() > 0) {
if (this.listSub.size() == 1 && this.listSub.get(0) != null && this.listSub.get(0).getType() == XmlNodeType.TEXT && ((XmlText) this.listSub.get(0)).countLines() == 1) {
_data.append(">");
this.listSub.get(0).iGenerate(_data, 0);
Log.verbose(" generate : '" + _data + "'");
} else {
_data.append(">\n");
for (int iii = 0; iii < this.listSub.size(); iii++) {
if (this.listSub.get(iii) != null) {
this.listSub.get(iii).iGenerate(_data, _indent + 1);
}
}
Tools.addIndent(_data, _indent);
}
_data.append("</");
_data.append(this.value);
_data.append(">\n");
} else {
_data.append("/>\n");
}
return true;
}
/**
* Remove all element with this name
* @param[in] _nodeName Name of nodes to remove.
*/
public void remove(final String _nodeName) {
if (_nodeName == "") {
return;
}
for (final ListIterator<XmlNode> iter = this.listSub.listIterator(); iter.hasNext();) {
final XmlNode element = iter.next();
if (element == null) {
iter.remove();
continue;
}
if (element.getValue().contentEquals(_nodeName) == true) {
iter.remove();
}
}
}
/**
* get the number of sub element in the node (can be Comment ; Element ; Text :Declaration).
* @return a number >=0.
*/
public int size() {
return this.listSub.size();
}
};

View File

@ -5,12 +5,12 @@
*/
package org.atriasoft.exml;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.FilePos;
/**
* Basic main object of all xml elements.
*/
public abstract class Node {
public abstract class XmlNode {
protected FilePos pos; //!< position in the read file (null if the file is not parsed)
protected String value; //!< value of the node (for element this is the name, for text it is the inside text ...);
@ -18,7 +18,7 @@ public abstract class Node {
/**
* basic element of a xml structure
*/
public Node() {
public XmlNode() {
this.pos = null;
}
@ -26,7 +26,7 @@ public abstract class Node {
* basic element of a xml structure
* @param[in] _value value of the node
*/
public Node(final String _value) {
public XmlNode(final String _value) {
this.pos = null;
this.value = _value;
}
@ -40,7 +40,7 @@ public abstract class Node {
}
@Override
protected Node clone() throws CloneNotSupportedException {
protected XmlNode clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Can not clone an abstract class ...");
}
@ -56,7 +56,7 @@ public abstract class Node {
* get the node type.
* @return the type of the Node.
*/
public abstract NodeType getType();
public abstract XmlNodeType getType();
/**
* get the current element Value.
@ -83,14 +83,14 @@ public abstract class Node {
* @param[in,out] _doc Base document reference
* @return false if an error occured.
*/
protected abstract boolean iParse(String _data, PositionParsing _pos, boolean _caseSensitive, FilePos _filePos, Document _doc);
//protected abstract boolean iParse(String _data, PositionParsing _pos, boolean _caseSensitive, FilePos _filePos, Document _doc);
/**
* check if the node is a Comment
* @return true if the node is a Comment
*/
public final boolean isComment() {
return this instanceof Comment;
return this instanceof XmlComment;
}
/**
@ -98,7 +98,7 @@ public abstract class Node {
* @return true if the node is a Declaration
*/
public final boolean isDeclaration() {
return this instanceof Declaration;
return this instanceof XmlDeclaration;
}
/**
@ -114,7 +114,7 @@ public abstract class Node {
* @return true if the node is a Element
*/
public final boolean isElement() {
return this instanceof Element;
return this instanceof XmlElement;
}
/**
@ -122,7 +122,7 @@ public abstract class Node {
* @return true if the node is a Text
*/
public final boolean isText() {
return this instanceof Text;
return this instanceof XmlText;
}
/**
@ -138,16 +138,16 @@ public abstract class Node {
* Cast the element in a Comment if it is possible.
* @return pointer on the class or null.
*/
public final Comment toComment() {
return (Comment) this;
public final XmlComment toComment() {
return (XmlComment) this;
}
/**
* Cast the element in a Declaration if it is possible.
* @return pointer on the class or null.
*/
public final Declaration toDeclaration() {
return (Declaration) this;
public final XmlDeclaration toDeclaration() {
return (XmlDeclaration) this;
}
/**
@ -162,16 +162,16 @@ public abstract class Node {
* Cast the element in a Element if it is possible.
* @return pointer on the class or null.
*/
public final Element toElement() {
return (Element) this;
public final XmlElement toElement() {
return (XmlElement) this;
}
/**
* Cast the element in a Text if it is possible.
* @return pointer on the class or null.
*/
public final Text toText() {
return (Text) this;
public final XmlText toText() {
return (XmlText) this;
}
}

View File

@ -8,7 +8,7 @@ package org.atriasoft.exml;
/**
* Type of the XML elements.
*/
public enum NodeType {
public enum XmlNodeType {
DOCUMENT, //!< all the file main access
DECLARATION, //!< &lt;?xml ... ?&gt;
ELEMENT, //!< the &lt;XXX&gt; ... &lt;/XXX&gt;

View File

@ -0,0 +1,51 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
/**
* Text node interface (internal data between two Marker: &lt;XXX&gt; ALL here &lt;/XXX&gt;
*/
public class XmlText extends XmlNode {
/**
* Constructor
*/
public XmlText() {};
/**
* Constructor
* @param[in] _data String data of the current Text
*/
public XmlText(final String _data) {
super(_data);
}
/**
* count the number of line in the current text
* @return The number of lines
*/
protected int countLines() {
int count = 1;
for (int iii = 0; iii < this.value.length(); iii++) {
if (this.value.charAt(iii) == '\n') {
count++;
}
}
return count;
}
@Override
public XmlNodeType getType() {
return XmlNodeType.TEXT;
};
@Override
protected boolean iGenerate(final StringBuilder _data, final int _indent) {
_data.append(replaceSpecialCharOut(this.value));
return true;
}
};

View File

@ -0,0 +1,65 @@
package org.atriasoft.exml.builder;
import org.atriasoft.exml.exception.ExmlBuilderException;
/**
* @author heero
*
*/
/**
* @author heero
*
*/
public interface Builder {
/**
* New comment added on this Element
* @param element Element representing the node of the Comment is added
* @param comment Comment value
* @throws ExmlBuilderException Error with this node or element.
*/
void newComment(Object element, String comment) throws ExmlBuilderException;
/**
* New comment added on this Element
* @param parent Element representing the node of the Declaration is added
* @param text Name of the declaration
* @return Declaration object value
* @throws ExmlBuilderException Error with this node or element.
*/
Object newDeclaration(Object parent, String text) throws ExmlBuilderException;
/**
* Add a new sub-element on the current parent element
* @param parent Element representing the node of the Element is added
* @param nodeName New element name.
* @return the object representing the Element.
* @throws ExmlBuilderException Error with this node or element.
*/
Object newElement(Object parent, String nodeName) throws ExmlBuilderException;
/**
* Add a property on the Element.
* @param element Element representing the node of the property is added
* @param propertyName Name of the property
* @param propertyValue Value of the property
* @throws ExmlBuilderException Error with this node or element.
*/
void newProperty(Object element, String propertyName, String propertyValue) throws ExmlBuilderException;
/**
* Create or get the root element of the document
* @return An object that id a root element.
* @throws ExmlBuilderException Error with this node or element.
*/
Object newRoot() throws ExmlBuilderException;
/**
* Add a text value on the current Element
* @param parent Parent element where the Text is added
* @param text Test to add.
* @throws ExmlBuilderException Error with this node or element.
*/
void newText(Object parent, String text) throws ExmlBuilderException;
}

View File

@ -0,0 +1,69 @@
package org.atriasoft.exml.builder;
import org.atriasoft.exml.XmlAttribute;
import org.atriasoft.exml.XmlAttributeList;
import org.atriasoft.exml.XmlComment;
import org.atriasoft.exml.XmlDeclaration;
import org.atriasoft.exml.XmlElement;
import org.atriasoft.exml.XmlText;
import org.atriasoft.exml.exception.ExmlBuilderException;
public class BuilderGeneric implements Builder {
@Override
public void newComment(final Object element, final String comment) throws ExmlBuilderException {
if (element instanceof XmlElement) {
final XmlElement elem = (XmlElement) element;
elem.append(new XmlComment(comment));
}
throw new ExmlBuilderException("can not add Comment on something else than Element");
}
@Override
public Object newDeclaration(final Object parent, final String text) throws ExmlBuilderException {
if (parent instanceof XmlElement) {
final XmlElement elem = (XmlElement) parent;
final XmlDeclaration dec = new XmlDeclaration(text);
elem.append(dec);
return dec;
}
throw new ExmlBuilderException("can not add Declaration on something else than Element");
}
@Override
public Object newElement(final Object parent, final String nodeName) throws ExmlBuilderException {
if (parent instanceof XmlElement) {
final XmlElement elem = (XmlElement) parent;
final XmlElement eee = new XmlElement(nodeName);
elem.append(eee);
return eee;
}
throw new ExmlBuilderException("can not add Element on something else than Element");
}
@Override
public void newProperty(final Object element, final String propertyName, final String propertyValue) throws ExmlBuilderException {
if (element instanceof XmlAttributeList) {
final XmlAttributeList attr = (XmlAttributeList) element;
attr.appendAttribute(new XmlAttribute(propertyName, propertyValue));
return;
}
throw new ExmlBuilderException("can not add Attribute on something else than Element or Declaration");
}
@Override
public Object newRoot() throws ExmlBuilderException {
return new XmlElement();
}
@Override
public void newText(final Object parent, final String text) throws ExmlBuilderException {
if (parent instanceof XmlElement) {
final XmlElement attr = (XmlElement) parent;
attr.append(new XmlText(text));
return;
}
throw new ExmlBuilderException("can not add Text on something else than Element or Declaration");
}
}

View File

@ -0,0 +1,18 @@
/** @file
* @author Edouard DUPIN
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml.exception;
public class ExmlBuilderException extends ExmlException {
/**
* Generate Unique ID for serialization
*/
private static final long serialVersionUID = 1L;
public ExmlBuilderException(final String data) {
super(data);
}
}

View File

@ -3,7 +3,7 @@
* @copyright 2021, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
package org.atriasoft.exml;
package org.atriasoft.exml.internal;
/** @file
* @author Edouard DUPIN

View File

@ -1,7 +1,5 @@
package org.atriasoft.exml.internal;
import org.atriasoft.exml.FilePos;
public class Tools {
/**
* add indentation of the string input.
@ -90,6 +88,37 @@ public class Tools {
}
}
public static String extract_line(final String data, final int _pos) {
// search back : '\n'
int startPos = data.lastIndexOf('\n', _pos);
if (startPos == _pos) {
startPos = 0;
} else {
startPos++;
}
// search forward : '\n'
int stopPos = _pos;
if (data.length() == _pos) {
stopPos = _pos;
} else if (data.charAt(_pos) != '\n') {
stopPos = data.indexOf('\n', _pos);
if (stopPos == _pos) {
stopPos = data.length();
}
}
if (startPos == -1) {
startPos = 0;
} else if (startPos >= data.length()) {
return "";
}
if (stopPos == -1) {
return "";
} else if (stopPos >= data.length()) {
stopPos = data.length();
}
return data.substring(startPos, stopPos);
}
public static boolean isWhiteChar(final Character _val) {
if (_val == ' ' || _val == '\t' || _val == '\n' || _val == '\r') {
return true;
@ -97,5 +126,33 @@ public class Tools {
return false;
}
// transform the Text with :
// "&lt;" == "<"
// "&gt;" == ">"
// "&amp;" == "&"
// "&apos;" == "'"
// "&quot;" == """
public static String replaceSpecialChar(final String _inval) {
final String out = _inval;
out.replace("&lt;", "<");
out.replace("&gt;", ">");
out.replace("&apos;", "'");
out.replace("&quot;", "\"");
out.replace("&amp;", "&");
//EXML_ERROR("INNN '"<< _inval << "' => '" << out << "'");
return out;
}
public static String replaceSpecialCharOut(final String _inval) {
final String out = _inval;
out.replace("<", "&lt;");
out.replace(">", "&gt;");
out.replace("'", "&apos;");
out.replace("\"", "&quot;");
out.replace("&", "&amp;");
//EXML_ERROR("OUTTT '"<< _inval << "' => '" << out << "'");
return out;
}
private Tools() {}
}

View File

@ -0,0 +1,517 @@
package org.atriasoft.exml.parser;
import org.atriasoft.exml.builder.Builder;
import org.atriasoft.exml.exception.ExmlBuilderException;
import org.atriasoft.exml.internal.FilePos;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.PositionParsing;
import org.atriasoft.exml.internal.Tools;
public class ParseXml {
// global builder that is generate the final Tree
private final Builder builder;
public ParseXml(final Builder builder) {
this.builder = builder;
}
protected boolean iParseAttribute(final Object parent, final String _data, final PositionParsing _pos, final FilePos _filePos, final ParsingProperty parsingProperty) throws ExmlBuilderException {
Log.verbose("start parse : 'attribute'");
final FilePos pos = _filePos.clone();
// search end of the comment :
int lastElementName = _pos.value;
for (int iii = _pos.value; iii < _data.length(); iii++) {
_filePos.check(_data.charAt(iii));
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (Tools.checkAvaillable(_data.charAt(iii), false) == true) {
lastElementName = iii;
} else {
break;
}
}
String name = _data.substring(_pos.value, lastElementName + 1);
String value = "";
if (parsingProperty.getCaseSensitive() == true) {
name = name.toLowerCase();
}
// count white space :
final FilePos tmpPos = new FilePos();
int white = Tools.countWhiteChar(_data, lastElementName + 1, tmpPos);
_filePos.add(tmpPos);
if (lastElementName + white + 1 >= _data.length()) {
parsingProperty.createError(_data, lastElementName + white + 1, _filePos, " parse an xml end with an attribute parsing...");
return false;
}
if (_data.charAt(lastElementName + white + 1) != '=') {
parsingProperty.createError(_data, lastElementName + white + 1, _filePos, " error attribute parsing == > missing '=' ...");
return false;
}
white += Tools.countWhiteChar(_data, lastElementName + white + 2, tmpPos);
_filePos.add(tmpPos);
if (lastElementName + white + 2 >= _data.length()) {
parsingProperty.createError(_data, lastElementName + white + 2, _filePos, " parse an xml end with an attribute parsing...");
return false;
}
boolean simpleQuoteCase = false;
if (_data.charAt(lastElementName + white + 2) == '\'') { // '
simpleQuoteCase = true;
}
if (_data.charAt(lastElementName + white + 2) != '"' && _data.charAt(lastElementName + white + 2) != '\'') { // '
// parse with no element " == > direct value separate with space ...
_filePos.increment();
int lastAttributePos = lastElementName + white + 2;
for (int iii = lastElementName + white + 2; iii < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
parsingProperty.createError(_data, iii, _filePos, "unexpected '\\n' in an attribute parsing");
return false;
}
if (_data.charAt(iii) != ' ' && _data.charAt(iii) != '/' && _data.charAt(iii) != '?' && _data.charAt(iii) != '>') {
lastAttributePos = iii + 1;
} else {
break;
}
}
value = _data.substring(lastElementName + white + 2, lastAttributePos);
//EXML_PARSE_ATTRIBUTE(pos << " attribute : " << name << "=\"" << value << "\"");
_pos.value = lastAttributePos - 1;
this.builder.newProperty(parent, name, value);
return true;
}
int lastAttributePos = lastElementName + white + 3;
for (int iii = lastElementName + white + 3; iii < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
_filePos.check(_data.charAt(iii));
if ((_data.charAt(iii) != '"' && simpleQuoteCase == false) || (_data.charAt(iii) != '\'' && simpleQuoteCase == true)) { // '
lastAttributePos = iii + 1;
} else {
break;
}
}
value = _data.substring(lastElementName + white + 3, lastAttributePos);
//EXML_PARSE_ATTRIBUTE(pos << " attribute : " << name << "=\"" << value << "\"");
_pos.value = lastAttributePos;
this.builder.newProperty(parent, name, value);
return true;
}
protected boolean iParseCDATA(final Object parent, final String _data, final PositionParsing _pos, final FilePos _filePos, final ParsingProperty parsingProperty) throws ExmlBuilderException {
Log.verbose("start parse : 'text::CDATA'");
final FilePos pos = _filePos.clone();
// search end of the comment :
for (int iii = _pos.value; iii + 2 < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
continue;
}
if (_data.charAt(iii) == ']' && _data.charAt(iii + 1) == ']' && _data.charAt(iii + 2) == '>') {
// find end of value:
_filePos.add(2);
final String valueCData = _data.substring(_pos.value, iii);
Log.verbose(" find text CDATA '" + valueCData + "'");
_pos.value = iii + 2;
this.builder.newText(parent, valueCData);
return true;
}
}
parsingProperty.createError(_data, _pos.value, _filePos, "text CDATA got end of file without finding end node");
_pos.value = _data.length();
return false;
}
protected boolean iParseComment(final Object parent, final String _data, final PositionParsing _pos, final FilePos _filePos, final ParsingProperty parsingProperty) throws ExmlBuilderException {
Log.verbose("start parse : 'comment'");
final FilePos pos = _filePos;
final FilePos tmpPos = new FilePos();
final int white = Tools.countWhiteChar(_data, _pos.value, tmpPos);
_filePos.add(tmpPos);
// search end of the comment :
for (int iii = _pos.value + white; iii + 2 < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
continue;
}
if (_data.charAt(iii) == '-' && _data.charAt(iii + 1) == '-' && _data.charAt(iii + 2) == '>') {
_filePos.add(2);
// search whitespace :
int newEnd = iii;
for (int jjj = iii - 1; jjj > _pos.value; jjj--) {
if (Tools.isWhiteChar(_data.charAt(jjj)) == true) {
newEnd = jjj;
} else {
break;
}
}
// find end of value:
final String value2 = _data.substring(_pos.value + white, newEnd);
Log.verbose(" find comment '" + value2 + "'");
this.builder.newComment(parent, value2);
_pos.value = iii + 2;
return true;
}
}
_pos.value = _data.length();
parsingProperty.createError(_data, _pos.value, _filePos, "comment got end of file without finding end node");
return false;
}
protected boolean iParseDeclaration(final Object parent, final String _data, final PositionParsing _pos, final FilePos _filePos, final ParsingProperty parsingProperty)
throws ExmlBuilderException {
final FilePos pos = _filePos;
// search end of the comment :
for (int iii = _pos.value; iii + 1 < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
continue;
}
if (_data.charAt(iii) == '>' || _data.charAt(iii) == '<') {
// an error occured :
parsingProperty.createError(_data, _pos.value, _filePos, " find '>' or '<' instead of '?>'");
return false;
}
if (_data.charAt(iii) == '?' && _data.charAt(iii + 1) == '>') {
_filePos.increment();
// find end of declaration:
_pos.value = iii + 1;
return true;
}
if (Tools.checkAvaillable(_data.charAt(iii), true) == true) {
// we find an attibute ==> parse it:
_pos.value = iii;
if (iParseAttribute(parent, _data, _pos, _filePos, parsingProperty) == false) {
return false;
}
iii = _pos.value;
continue;
}
}
parsingProperty.createError(_data, _pos.value, _filePos, "Text got end of file without finding end node");
_pos.value = _data.length();
return false;
}
protected boolean iParseElement(final Object parent, final String nameElement, final String _data, final PositionParsing _pos, final FilePos _filePos, final ParsingProperty parsingProperty)
throws ExmlBuilderException {
// note : When start parsing the upper element must have set the value of the element and set the position after this one
final FilePos pos = _filePos.clone();
// find a normal node ...
for (int iii = _pos.value; iii < _data.length(); iii++) {
_filePos.check(_data.charAt(iii));
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_data.charAt(iii) == '>') {
// we find the end ...
_pos.value = iii + 1;
return subParseElement(parent, nameElement, _data, _pos, _filePos, parsingProperty);
}
if (_data.charAt(iii) == '/') {
// standalone node or error...
if (iii + 1 >= _data.length()) {
parsingProperty.createError(_data, _pos.value, _filePos, "Find end of files ... == > bad case");
return false;
}
// TODO : Can have white spaces ....
if (_data.charAt(iii + 1) == '>') {
_pos.value = iii + 1;
return true;
}
// error
parsingProperty.createError(_data, _pos.value, _filePos, "Find / without > char ...");
return false;
}
if (Tools.checkAvaillable(_data.charAt(iii), true) == true) {
// we find an attibute ==> parse it:
_pos.value = iii;
if (iParseAttribute(parent, _data, _pos, _filePos, parsingProperty) == false) {
return false;
}
iii = _pos.value;
continue;
}
if (Tools.isWhiteChar(_data.charAt(iii)) == false) {
parsingProperty.createError(_data, iii, _filePos, "Find an unknow element : '" + _data.charAt(iii) + "'");
return false;
}
}
parsingProperty.createError(_data, _pos.value, _filePos, "Unexpecting end of parsing exml::internal::Element : '" + nameElement + "' == > check if the '/>' is set or the end of element");
return false;
}
protected boolean iParseText(final Object parent, final String _data, final PositionParsing _pos, final FilePos _filePos, final ParsingProperty parsingProperty) throws ExmlBuilderException {
Log.verbose("start parse : 'text'");
final FilePos pos = _filePos.clone();
// search end of the comment :
for (int iii = _pos.value; iii < _data.length(); iii++) {
Tools.drawElementParsed(_data.charAt(iii), _filePos);
if (_filePos.check(_data.charAt(iii)) == true) {
continue;
}
if (_data.charAt(iii) == '>' || _data.charAt(iii) == '<') {
// search whitespace :
int newEnd = iii;
for (int jjj = iii - 1; jjj > _pos.value; --jjj) {
if (Tools.isWhiteChar(_data.charAt(jjj)) == true) {
newEnd = jjj;
} else {
break;
}
}
// find end of value:
String valueText = _data.substring(_pos.value, newEnd);
Log.verbose("find text '" + valueText + "'");
_pos.value = iii - 1;
valueText = Tools.replaceSpecialChar(valueText);
this.builder.newText(parent, valueText);
return true;
}
}
parsingProperty.createError(_data, _pos.value, _filePos, "Text got end of file without finding end node");
_pos.value = _data.length();
return false;
}
public Object parse(final String data) throws ExmlBuilderException {
Log.verbose("Start parsing document (type: string) size=" + data.length());
// came from char == > force in utf8 ...
final FilePos pos = new FilePos(1, 0);
final PositionParsing parsePos = new PositionParsing();
final ParsingProperty property = new ParsingProperty();
final Object rootNode = this.builder.newRoot();
if (subParseElement(rootNode, null, data, parsePos, pos, property) == true) {
return rootNode;
}
return null;
}
/**
* Parse sub node string
* @param[in] _data all file string data
* @param[in,out] _pos Position to start parsing in the file and return the end of parsing
* @param[in] _caseSensitive Case sensitive parsing (usefull for html)
* @param[in] _filePos Current File position of the parsing
* @param[in] _doc Document base reference
* @param[in] _mainNode if true, this is the first root node
* @return true parsing is done OK
* @return false An error appear in the parsing
*/
protected boolean subParseElement(final Object parent, final String nameElement, final String _data, final PositionParsing _pos, final FilePos _filePos, final ParsingProperty parsingProperty)
throws ExmlBuilderException {
//EXML_PARSE_ELEMENT(" start subParse ... " << _pos << " " << _filePos);
for (int iii = _pos.value; iii < _data.length(); iii++) {
_filePos.check(_data.charAt(iii));
Tools.drawElementParsed(_data.charAt(iii), _filePos);
final FilePos tmpPos = new FilePos();
if (_data.charAt(iii) == '<') {
final int white = Tools.countWhiteChar(_data, iii + 1, tmpPos);
if (iii + white + 1 >= _data.length()) {
_filePos.add(tmpPos);
parsingProperty.createError(_data, _pos.value, _filePos, "End file with '<' char == > invalide XML");
_pos.value = iii + white;
return false;
}
// Detect type of the element:
if (_data.charAt(iii + white + 1) == '>') {
_filePos.add(tmpPos);
parsingProperty.createError(_data, _pos.value, _filePos, "Find '>' with no element in the element...");
_pos.value = iii + white + 1;
return false;
}
if (_data.charAt(iii + white + 1) == '?') {
tmpPos.increment();
// TODO : white space ...
if (Tools.checkAvaillable(_data.charAt(iii + white + 2), true) == false) {
parsingProperty.createError(_data, _pos.value, _filePos, "Find unavaillable name in the Declaration node...");
_pos.value = iii + white + 1;
return false;
}
//EXML_DEBUG("Generate node name : '" << _data[iii+1] << "'");
int endPosName = iii + white + 1;
// generate element name ...
for (int jjj = iii + white + 2; jjj < _data.length(); jjj++) {
if (Tools.checkAvaillable(_data.charAt(jjj), false) == true) {
// we find the end ...
endPosName = jjj;
} else {
break;
}
tmpPos.check(_data.charAt(jjj));
}
String tmpname = _data.substring(iii + white + 2, endPosName + 1);
if (parsingProperty.getCaseSensitive() == true) {
tmpname = tmpname.toLowerCase();
}
// Find declaration marker
final Object declaration = this.builder.newDeclaration(parent, tmpname);
_filePos.add(tmpPos);
_pos.value = endPosName + 1;
Log.verbose("start parse : 'declaration' : '" + tmpname + "'");
if (iParseDeclaration(declaration, _data, _pos, _filePos, parsingProperty) == false) {
return false;
}
iii = _pos.value;
continue;
}
if (_data.charAt(iii + white + 1) == '!') {
tmpPos.increment();
// Find special block element
if (iii + white + 2 >= _data.length()) {
parsingProperty.createError(_data, _pos.value, _filePos, "End file with '<!' chars == > invalide XML");
return false;
}
if (_data.charAt(iii + white + 2) == '-') {
tmpPos.increment();
if (iii + white + 3 >= _data.length()) {
parsingProperty.createError(_data, _pos.value, _filePos, "End file with '<!-' chars == > invalide XML");
return false;
}
if (_data.charAt(iii + white + 3) != '-') {
parsingProperty.createError(_data, _pos.value, _filePos, "Element parse with '<!-" + _data.charAt(iii + 3) + "' chars == > invalide XML");
return false;
}
tmpPos.increment();
// find comment:
_pos.value = iii + white + 4;
_filePos.add(tmpPos);
if (iParseComment(parent, _data, _pos, _filePos, parsingProperty) == false) {
return false;
}
iii = _pos.value;
} else if (_data.charAt(iii + white + 2) == '[') {
tmpPos.increment();
if (iii + white + 8 >= _data.length()) {
parsingProperty.createError(_data, _pos.value, _filePos, "End file with '<![' chars == > invalide XML");
return false;
}
if (_data.charAt(iii + white + 3) != 'C' || _data.charAt(iii + white + 4) != 'D' || _data.charAt(iii + white + 5) != 'A' || _data.charAt(iii + white + 6) != 'T'
|| _data.charAt(iii + white + 7) != 'A' || _data.charAt(iii + white + 8) != '[') {
parsingProperty.createError(_data, _pos.value, _filePos, "Element parse with '<![" + _data.charAt(iii + white + 3) + _data.charAt(iii + white + 4)
+ _data.charAt(iii + white + 5) + _data.charAt(iii + white + 6) + _data.charAt(iii + white + 7) + _data.charAt(iii + white + 8) + "' chars == > invalide XML");
return false;
}
tmpPos.add(6);
// find text:
_pos.value = iii + 9 + white;
_filePos.add(tmpPos);
if (iParseCDATA(parent, _data, _pos, _filePos, parsingProperty) == false) {
return false;
}
iii = _pos.value;
} else {
parsingProperty.createError(_data, _pos.value, _filePos, "End file with '<!" + _data.charAt(iii + white + 2) + "' chars == > invalide XML");
return false;
}
continue;
}
if (_data.charAt(iii + white + 1) == '/') {
tmpPos.increment();
//EXML_DEBUG("Generate node name : '" << _data[iii+1] << "'");
int endPosName = iii + white + 1;
// generate element name ...
for (int jjj = iii + white + 2; jjj < _data.length(); jjj++) {
if (Tools.checkAvaillable(_data.charAt(jjj), false) == true) {
// we find the end ...
endPosName = jjj;
} else {
break;
}
tmpPos.check(_data.charAt(jjj));
}
String tmpname = _data.substring(iii + white + 2, endPosName + 1);
if (parsingProperty.getCaseSensitive() == true) {
tmpname = tmpname.toLowerCase();
}
if (tmpname.contentEquals(nameElement) == true) {
// find end of node :
// find > element ...
for (int jjj = endPosName + 1; jjj < _data.length(); jjj++) {
Tools.drawElementParsed(_data.charAt(jjj), _filePos);
if (tmpPos.check(_data.charAt(jjj)) == true) {
continue;
}
if (_data.charAt(jjj) == '>') {
_pos.value = jjj;
_filePos.add(tmpPos);
return true;
} else if (_data.charAt(jjj) != '\r' && _data.charAt(jjj) != ' ' && _data.charAt(jjj) != '\t') {
_filePos.add(tmpPos);
parsingProperty.createError(_data, jjj, _filePos, "End node error : have data inside end node other than [ \\n\\t\\r] " + nameElement + "'");
return false;
}
}
} else {
parsingProperty.createError(_data, _pos.value, _filePos, "End node error : '" + tmpname + "' != '" + nameElement + "'");
return false;
}
}
if (_data.charAt(iii + white + 1) == '>') {
// end of something == > this is really bad
parsingProperty.createError(_data, _pos.value, _filePos, "Find '>' chars == > invalide XML");
return false;
}
if (Tools.checkAvaillable(_data.charAt(iii + white + 1), true) == true) {
tmpPos.increment();
Log.debug("Generate node name : '" + _data.charAt(iii + 1) + "'");
int endPosName = iii + white + 1;
// generate element name ...
for (int jjj = iii + white + 2; jjj < _data.length(); jjj++) {
if (Tools.checkAvaillable(_data.charAt(jjj), false) == true) {
// we find the end ...
endPosName = jjj;
} else {
break;
}
tmpPos.check(_data.charAt(jjj));
}
String tmpname = _data.substring(iii + white + 1, endPosName + 1);
if (parsingProperty.getCaseSensitive() == true) {
tmpname = tmpname.toLowerCase();
}
Log.debug("find node named : '" + tmpname + "'");
// find text:
final Object element = this.builder.newElement(parent, tmpname);
_pos.value = endPosName + 1;
_filePos.add(tmpPos);
Log.verbose("start parse : 'element' named='" + tmpname + "'");
if (iParseElement(element, tmpname, _data, _pos, _filePos, parsingProperty) == false) {
return false;
}
iii = _pos.value;
continue;
}
_filePos.add(tmpPos);
// here we have an error :
parsingProperty.createError(_data, _pos.value, _filePos, "Find an ununderstanding element : '" + _data.charAt(iii + white + 1) + "'");
return false;
} else {
if (_data.charAt(iii) == '>') {
parsingProperty.createError(_data, _pos.value, _filePos, "Find elemement '>' == > no reason to be here ...");
return false;
}
// might to be data text ...
if (_data.charAt(iii) == '\n' || _data.charAt(iii) == ' ' || _data.charAt(iii) == '\t' || _data.charAt(iii) == '\r') {
// empty spaces == > nothing to do ....
} else {
// find data == > parse it...
_pos.value = iii;
_filePos.add(tmpPos);
if (iParseText(parent, _data, _pos, _filePos, parsingProperty) == false) {
return false;
}
iii = _pos.value;
}
}
}
if (nameElement == null) {
return true;
}
parsingProperty.createError(_data, _pos.value, _filePos, "Did not find end of the exml::internal::Element : '" + nameElement + "'");
return false;
}
}

View File

@ -0,0 +1,87 @@
package org.atriasoft.exml.parser;
import org.atriasoft.exml.internal.FilePos;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.internal.Tools;
public class ParsingProperty {
private boolean caseSensitive; //!< check the case sensitive of the nodes and attribute
private boolean writeErrorWhenDetexted; //!< Request print error in parsing just when detected
private String comment; //!< Comment on the error;
private String Line; //!< Parse line error (copy);
private FilePos filePos; //!< position of the error
/**
* Constructor
*/
public ParsingProperty() {
this.caseSensitive = false;
this.writeErrorWhenDetexted = true;
this.comment = "";
this.Line = "";
this.filePos = new FilePos(0, 0);
}
/**
* Create an error in the parsing (call by the syetm for error management)
* @param[in] _data string of chat is wrong
* @param[in] _pos Position in the file
* @param[in] _filePos human position of the error
* @param[in] _comment Error string to display
*/
public void createError(final String _data, final int _pos, final FilePos _filePos, final String _comment) {
this.comment = _comment;
this.Line = Tools.extract_line(_data, _pos);
this.filePos = _filePos;
if (this.writeErrorWhenDetexted == true) {
displayError();
}
}
/**
* Request display in log of the error
*/
public void displayError() {
if (this.comment.length() == 0) {
Log.error("No error detected ???");
return;
}
Log.error(this.filePos + " " + this.comment + "\n" + this.Line + "\n" + Tools.createPosPointer(this.Line, this.filePos.getCol()));
//Log.critical("detect error");
}
/**
* get the status of case sensitive mode.
* @return true if case sensitive is active
*/
public boolean getCaseSensitive() {
return this.caseSensitive;
}
/**
* Get the display of the error status.
* @return true Display error
* @return false Does not display error (get it at end)
*/
public boolean getDisplayError() {
return this.writeErrorWhenDetexted;
}
/**
* Enable or diasable the case sensitive (must be done before the call of parsing)
* @param[in] _val true if enable; false else.
*/
// TODO: Naming error, it is insensitive ...
public void setCaseSensitive(final boolean _val) {
this.caseSensitive = _val;
}
/**
* Set the display of the error when detected.
* @param[in] _value true: display error, false not display error (get it at end)
*/
public void setDisplayError(final boolean _value) {
this.writeErrorWhenDetexted = _value;
}
}

View File

@ -6,6 +6,7 @@
package test.atriasoft.exml;
import org.atriasoft.exml.Document;
import org.atriasoft.exml.Exml;
import org.junit.jupiter.api.Assertions;
class ExmlLocal {
@ -18,7 +19,7 @@ class ExmlLocal {
final Document doc = new Document();
//doc.setCaseSensitive(!_caseInSensitive);
Log.verbose("parse : \n" + _input);
final boolean retParse = doc.parse(_input);
final boolean retParse = Exml.parse(_input);
if (_errorPos == 1) {
Assertions.assertEquals(retParse, false);
return;

View File

@ -5,9 +5,9 @@
*/
package test.atriasoft.exml;
import org.atriasoft.exml.Attribute;
import org.atriasoft.exml.XmlAttribute;
import org.atriasoft.exml.Document;
import org.atriasoft.exml.Element;
import org.atriasoft.exml.XmlElement;
import org.atriasoft.exml.exception.ExmlAttributeDoesNotExist;
import org.atriasoft.exml.exception.ExmlNodeDoesNotExist;
import org.junit.jupiter.api.Assertions;
@ -22,29 +22,29 @@ public class ExmlTestAttribute {
@Test
public void AttributeElementNotExist() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
Assertions.assertThrows(ExmlAttributeDoesNotExist.class, () -> myElement.getAttr(65465465));
}
@Test
public void clear() {
final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute");
final XmlAttribute myAttribute = new XmlAttribute("nameAttribute", "valueAttribute");
myAttribute.clear();
}
@Test
public void createAssignement() {
final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute");
final Attribute myOtherAttribute = myAttribute.clone();
final XmlAttribute myAttribute = new XmlAttribute("nameAttribute", "valueAttribute");
final XmlAttribute myOtherAttribute = myAttribute.clone();
Assertions.assertEquals(myAttribute.getValue(), myOtherAttribute.getValue());
Assertions.assertEquals(myAttribute.getName(), myOtherAttribute.getName());
}
@Test
public void createCopy() {
final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute");
final Attribute myOtherAttribute = new Attribute(myAttribute);
final XmlAttribute myAttribute = new XmlAttribute("nameAttribute", "valueAttribute");
final XmlAttribute myOtherAttribute = new XmlAttribute(myAttribute);
Assertions.assertEquals(myAttribute.getValue(), myOtherAttribute.getValue());
Assertions.assertEquals(myAttribute.getName(), myOtherAttribute.getName());
}
@ -52,7 +52,7 @@ public class ExmlTestAttribute {
@Test
public void exist() {
final Element elem = new Element("elem");
final XmlElement elem = new XmlElement("elem");
elem.setAttribute("valA", "plop");
Assertions.assertEquals(elem.existAttribute("valA"), true);
Assertions.assertEquals(elem.existAttribute("qsdfsdf"), false);
@ -61,7 +61,7 @@ public class ExmlTestAttribute {
@Test
public void get() {
final Element elem = new Element("elem");
final XmlElement elem = new XmlElement("elem");
elem.setAttribute("valA", "plop");
try {
Assertions.assertEquals(elem.getAttribute("valA"), "plop");
@ -74,7 +74,7 @@ public class ExmlTestAttribute {
@Test
public void getpair() {
final Element elem = new Element("elem");
final XmlElement elem = new XmlElement("elem");
elem.setAttribute("valA", "coucou");
try {
Assertions.assertEquals(elem.getAttrPair(0).first, "valA");
@ -90,14 +90,14 @@ public class ExmlTestAttribute {
public void moveInAllElement() {
final Document doc = new Document();
doc.parse("<elem valA=\"plop\"/>");
Element elem;
XmlElement elem;
try {
elem = (Element) doc.getNode("elem");
elem = (XmlElement) doc.getNode("elem");
} catch (final ExmlNodeDoesNotExist e) {
Assertions.fail("Should Not have thrown an exception");
return;
}
for (final Attribute it : elem.getAttributes()) {
for (final XmlAttribute it : elem.getAttributes()) {
Assertions.assertEquals(it.getName(), "valA");
Assertions.assertEquals(it.getValue(), "plop");
}
@ -105,7 +105,7 @@ public class ExmlTestAttribute {
@Test
public void remove() {
final Element elem = new Element("elem");
final XmlElement elem = new XmlElement("elem");
elem.setAttribute("valA", "plop");
Assertions.assertEquals(elem.existAttribute("valA"), true);
elem.removeAttribute("valA");
@ -115,7 +115,7 @@ public class ExmlTestAttribute {
@Test
public void setGetName() {
final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute");
final XmlAttribute myAttribute = new XmlAttribute("nameAttribute", "valueAttribute");
Assertions.assertEquals(myAttribute.getName(), "nameAttribute");
myAttribute.setName("newName");
Assertions.assertEquals(myAttribute.getName(), "newName");
@ -124,7 +124,7 @@ public class ExmlTestAttribute {
@Test
public void setGetValue() {
final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute");
final XmlAttribute myAttribute = new XmlAttribute("nameAttribute", "valueAttribute");
Assertions.assertEquals(myAttribute.getValue(), "valueAttribute");
myAttribute.setValue("new value");
Assertions.assertEquals(myAttribute.getValue(), "new value");
@ -133,7 +133,7 @@ public class ExmlTestAttribute {
@Test
public void setterNew() {
final Element elem = new Element("elem");
final XmlElement elem = new XmlElement("elem");
elem.setAttribute("valA", "coucou");
try {
Assertions.assertEquals(elem.getAttribute("valA"), "coucou");
@ -145,7 +145,7 @@ public class ExmlTestAttribute {
@Test
public void setterRewrite() {
final Element elem = new Element("elem");
final XmlElement elem = new XmlElement("elem");
elem.setAttribute("valA", "coucou");
try {
Assertions.assertEquals(elem.getAttribute("valA"), "coucou");

View File

@ -6,7 +6,7 @@
package test.atriasoft.exml;
import org.atriasoft.exml.Document;
import org.atriasoft.exml.Element;
import org.atriasoft.exml.XmlElement;
import org.atriasoft.exml.TextCDATA;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@ -32,8 +32,8 @@ public class ExmlTestCData {
public void parseCDATA() {
final Document doc = new Document();
doc.parse("<elem><![CDATA[Text &é<>examp]le]] ...]]></elem>");
final Element elem = Assertions.assertDoesNotThrow(() -> {
return (Element) doc.getNode("elem");
final XmlElement elem = Assertions.assertDoesNotThrow(() -> {
return (XmlElement) doc.getNode("elem");
});
Assertions.assertEquals("Text &é<>examp]le]] ...", elem.getText());
}

View File

@ -5,9 +5,9 @@
*/
package test.atriasoft.exml;
import org.atriasoft.exml.Comment;
import org.atriasoft.exml.Node;
import org.atriasoft.exml.NodeType;
import org.atriasoft.exml.XmlComment;
import org.atriasoft.exml.XmlNode;
import org.atriasoft.exml.XmlNodeType;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -20,28 +20,28 @@ public class ExmlTestComment {
@Test
public void create() {
final Comment myComment = new Comment("my Comment");
Assertions.assertEquals(myComment.getType(), NodeType.COMMENT);
final XmlComment myComment = new XmlComment("my Comment");
Assertions.assertEquals(myComment.getType(), XmlNodeType.COMMENT);
}
@Test
public void createAssignement() {
final Comment myComment = new Comment("my comment");
final Comment myOtherComment = myComment.clone();
final XmlComment myComment = new XmlComment("my comment");
final XmlComment myOtherComment = myComment.clone();
Assertions.assertEquals(myComment.getValue(), myOtherComment.getValue());
}
@Test
public void createCopy() {
final Comment myComment = new Comment("my Comment");
final Comment myOtherComment = new Comment(myComment);
final XmlComment myComment = new XmlComment("my Comment");
final XmlComment myOtherComment = new XmlComment(myComment);
Assertions.assertEquals(myComment.getValue(), myOtherComment.getValue());
}
@Test
public void transform() {
Comment myComment = new Comment("my comment");
final Node myNode = myComment;
XmlComment myComment = new XmlComment("my comment");
final XmlNode myNode = myComment;
myComment = myNode.toComment();
Assertions.assertEquals(myComment.getValue(), "my comment");
}

View File

@ -6,7 +6,7 @@
package test.atriasoft.exml;
import org.atriasoft.exml.DeclarationXML;
import org.atriasoft.exml.NodeType;
import org.atriasoft.exml.XmlNodeType;
import org.atriasoft.exml.exception.ExmlAttributeDoesNotExist;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@ -21,7 +21,7 @@ public class ExmlTestDeclarationXML {
@Test
public void create() {
final DeclarationXML myDeclarationXML = new DeclarationXML("1.0", "UTF-8", true);
Assertions.assertEquals(myDeclarationXML.getType(), NodeType.DECLARATION);
Assertions.assertEquals(myDeclarationXML.getType(), XmlNodeType.DECLARATION);
try {
Assertions.assertEquals(myDeclarationXML.getAttribute("version"), "1.0");
Assertions.assertEquals(myDeclarationXML.getAttribute("encoding"), "UTF-8");

View File

@ -6,9 +6,9 @@
package test.atriasoft.exml;
import org.atriasoft.exml.Document;
import org.atriasoft.exml.Element;
import org.atriasoft.exml.Node;
import org.atriasoft.exml.NodeType;
import org.atriasoft.exml.XmlElement;
import org.atriasoft.exml.XmlNode;
import org.atriasoft.exml.XmlNodeType;
import org.atriasoft.exml.exception.ExmlNodeDoesNotExist;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@ -22,9 +22,9 @@ public class ExmlTestElement {
@Test
public void append() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
Assertions.assertEquals(myElement.getNodes().size(), 0);
myElement.append(new Element("jkjhkjhkh"));
myElement.append(new XmlElement("jkjhkjhkh"));
Assertions.assertEquals(myElement.getNodes().size(), 1);
try {
myElement.getNode("jkjhkjhkh");
@ -36,9 +36,9 @@ public class ExmlTestElement {
@Test
public void clear() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
Assertions.assertEquals(myElement.getNodes().size(), 0);
myElement.append(new Element("jkjhkjhkh"));
myElement.append(new XmlElement("jkjhkjhkh"));
Assertions.assertEquals(myElement.getNodes().size(), 1);
try {
myElement.getNode("jkjhkjhkh");
@ -52,15 +52,15 @@ public class ExmlTestElement {
@Test
public void create() {
final Element myElement = new Element("NodeName");
Assertions.assertEquals(myElement.getType(), NodeType.ELEMENT);
final XmlElement myElement = new XmlElement("NodeName");
Assertions.assertEquals(myElement.getType(), XmlNodeType.ELEMENT);
}
@Test
public void createAssignement() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
try {
final Element myOtherElement = myElement.clone();
final XmlElement myOtherElement = myElement.clone();
Assertions.assertEquals(myElement.getValue(), myOtherElement.getValue());
} catch (final CloneNotSupportedException e) {
Assertions.fail("Should Not have thrown an exception");
@ -69,9 +69,9 @@ public class ExmlTestElement {
@Test
public void createCopy() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
try {
final Element myOtherElement = new Element(myElement);
final XmlElement myOtherElement = new XmlElement(myElement);
Assertions.assertEquals(myElement.getValue(), myOtherElement.getValue());
} catch (final CloneNotSupportedException e) {
Assertions.fail("Should Not have thrown an exception");
@ -81,34 +81,34 @@ public class ExmlTestElement {
@Test
public void getNamed() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
Assertions.assertEquals(myElement.existNode("jkjhkjhkh"), false);
}
@Test
public void getNodeId() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
Assertions.assertEquals(false, myElement.existNode(465));
}
@Test
public void getText1() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
Assertions.assertEquals("", myElement.getText());
}
@Test
public void getText2() {
final Element myElement = new Element("NodeName");
myElement.append(new Element("jkjhkjhkh"));
final XmlElement myElement = new XmlElement("NodeName");
myElement.append(new XmlElement("jkjhkjhkh"));
Assertions.assertEquals("<jkjhkjhkh/>\n", myElement.getText());
}
@Test
public void getTypeId() {
final Element myElement = new Element("NodeName");
final XmlElement myElement = new XmlElement("NodeName");
Assertions.assertThrows(ExmlNodeDoesNotExist.class, () -> myElement.getType(1));
}
@ -116,8 +116,8 @@ public class ExmlTestElement {
public void moveInAllElement() {
final Document doc = new Document();
doc.parse("<elem><elem1/><elem2/></elem>");
for (final Node it : doc.getNodes()) {
final Element elem = (Element) it;
for (final XmlNode it : doc.getNodes()) {
final XmlElement elem = (XmlElement) it;
Assertions.assertEquals("elem", elem.getValue());
Assertions.assertEquals(2, elem.getNodes().size());
Assertions.assertEquals(2, elem.size());