From b1ea27a01ab5544b8abed0deb25e02ad62f1b380 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Wed, 24 Feb 2021 18:56:14 +0100 Subject: [PATCH] [DEV] port work but not rally compatible with java phylosophie ==> need update.. --- .checkstyle | 7 + .classpath | 35 ++ .gitignore | 17 + .project | 24 + CheckStyle.xml | 66 +++ CleanUp.xml | 106 ++++ Formatter.xml | 390 +++++++++++++ LICENSE | 373 ++++++++++++ src/module-info.java | 10 + src/org/atriasoft/exml/Attribute.java | 166 ++++++ src/org/atriasoft/exml/AttributeList.java | 184 ++++++ src/org/atriasoft/exml/Comment.java | 85 +++ src/org/atriasoft/exml/Declaration.java | 91 +++ src/org/atriasoft/exml/DeclarationXML.java | 36 ++ src/org/atriasoft/exml/Document.java | 252 +++++++++ src/org/atriasoft/exml/Element.java | 532 ++++++++++++++++++ src/org/atriasoft/exml/FilePos.java | 180 ++++++ src/org/atriasoft/exml/Node.java | 275 +++++++++ src/org/atriasoft/exml/NodeType.java | 20 + src/org/atriasoft/exml/Text.java | 114 ++++ src/org/atriasoft/exml/TextCDATA.java | 45 ++ .../exception/ExmlAttributeDoesNotExist.java | 13 + .../exml/exception/ExmlException.java | 12 + .../exml/exception/ExmlNodeDoesNotExist.java | 13 + src/org/atriasoft/exml/internal/Log.java | 68 +++ test/.gitignore | 1 + test/src/test/atriasoft/exml/ExmlLocal.java | 44 ++ test/src/test/atriasoft/exml/ExmlTestAll.java | 73 +++ .../atriasoft/exml/ExmlTestAttribute.java | 170 ++++++ .../test/atriasoft/exml/ExmlTestCData.java | 35 ++ .../test/atriasoft/exml/ExmlTestComment.java | 48 ++ .../exml/ExmlTestDeclarationXML.java | 62 ++ .../test/atriasoft/exml/ExmlTestElement.java | 127 +++++ .../exml/ExmlTestParseAttribute.java | 115 ++++ .../atriasoft/exml/ExmlTestParseComment.java | 60 ++ .../exml/ExmlTestParseDeclaration.java | 56 ++ .../atriasoft/exml/ExmlTestParseElement.java | 84 +++ test/src/test/atriasoft/exml/Log.java | 68 +++ version.txt | 1 + 39 files changed, 4058 insertions(+) create mode 100644 .checkstyle create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100755 CheckStyle.xml create mode 100644 CleanUp.xml create mode 100644 Formatter.xml create mode 100644 LICENSE create mode 100644 src/module-info.java create mode 100644 src/org/atriasoft/exml/Attribute.java create mode 100644 src/org/atriasoft/exml/AttributeList.java create mode 100644 src/org/atriasoft/exml/Comment.java create mode 100644 src/org/atriasoft/exml/Declaration.java create mode 100644 src/org/atriasoft/exml/DeclarationXML.java create mode 100644 src/org/atriasoft/exml/Document.java create mode 100644 src/org/atriasoft/exml/Element.java create mode 100644 src/org/atriasoft/exml/FilePos.java create mode 100644 src/org/atriasoft/exml/Node.java create mode 100644 src/org/atriasoft/exml/NodeType.java create mode 100644 src/org/atriasoft/exml/Text.java create mode 100644 src/org/atriasoft/exml/TextCDATA.java create mode 100644 src/org/atriasoft/exml/exception/ExmlAttributeDoesNotExist.java create mode 100644 src/org/atriasoft/exml/exception/ExmlException.java create mode 100644 src/org/atriasoft/exml/exception/ExmlNodeDoesNotExist.java create mode 100644 src/org/atriasoft/exml/internal/Log.java create mode 100644 test/.gitignore create mode 100644 test/src/test/atriasoft/exml/ExmlLocal.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestAll.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestAttribute.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestCData.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestComment.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestDeclarationXML.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestElement.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestParseAttribute.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestParseComment.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestParseDeclaration.java create mode 100644 test/src/test/atriasoft/exml/ExmlTestParseElement.java create mode 100644 test/src/test/atriasoft/exml/Log.java create mode 100644 version.txt diff --git a/.checkstyle b/.checkstyle new file mode 100644 index 0000000..34ed486 --- /dev/null +++ b/.checkstyle @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..5c16154 --- /dev/null +++ b/.classpath @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d075be7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +/bin/ +/Operator/ +/DrawerProperties/ +*.pdfd +*.dbc +SchedulerConfig.txt +scenicView.properties +ScenariumConfig.txt +*.class +*~ +*.bck +build.number +/extern/ +/out/ +/.settings/ +/junit/ +/target/ diff --git a/.project b/.project new file mode 100644 index 0000000..d5321e7 --- /dev/null +++ b/.project @@ -0,0 +1,24 @@ + + + atriasoft-exml + + + atriasoft-exml + + + + org.eclipse.jdt.core.javabuilder + + + + + net.sf.eclipsecs.core.CheckstyleBuilder + + + + + + org.eclipse.jdt.core.javanature + net.sf.eclipsecs.core.CheckstyleNature + + diff --git a/CheckStyle.xml b/CheckStyle.xml new file mode 100755 index 0000000..d68aedd --- /dev/null +++ b/CheckStyle.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CleanUp.xml b/CleanUp.xml new file mode 100644 index 0000000..6cf4cba --- /dev/null +++ b/CleanUp.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Formatter.xml b/Formatter.xml new file mode 100644 index 0000000..14a5d6c --- /dev/null +++ b/Formatter.xml @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/src/module-info.java b/src/module-info.java new file mode 100644 index 0000000..767e633 --- /dev/null +++ b/src/module-info.java @@ -0,0 +1,10 @@ +/** Basic module interface. + * + * @author Edouard DUPIN */ + +open module org.atriasoft.exml { + exports org.atriasoft.exml; + + requires transitive org.atriasoft.etk; + requires transitive io.scenarium.logger; +} diff --git a/src/org/atriasoft/exml/Attribute.java b/src/org/atriasoft/exml/Attribute.java new file mode 100644 index 0000000..d905a23 --- /dev/null +++ b/src/org/atriasoft/exml/Attribute.java @@ -0,0 +1,166 @@ +package org.atriasoft.exml; + +import org.atriasoft.exml.internal.Log; + +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +/** + * @brief Single attribute element + */ +public class Attribute extends Node { + + protected String m_name; //!< Name of the attribute + + public Attribute() { + super(""); + this.m_name = ""; + } + + public Attribute(final Attribute _obj) { + super(_obj.m_value); + this.m_pos = _obj.getPos().clone(); + this.m_name = _obj.m_name; + } + + public Attribute(final String _name) { + super(""); + this.m_name = _name; + } + + /** + * @brief Constructor + * @param[in] _name Name of the attribute. + * @param[in] _value Value of the attribute. + */ + public Attribute(final String _name, final String _value) { + super(_value); + this.m_name = _name; + } + + @Override + public void clear() { + this.m_name = ""; + }; + + @Override + public Attribute clone() { + return new Attribute(this); + }; + + /** + * @brief get the current name of the Attribute + * @return String of the attribute + */ + public String getName() { + return this.m_name; + }; + + @Override + public NodeType getType() { + return NodeType.attribute; + } + + @Override + protected boolean iGenerate(final StringBuilder _data, final int _indent) { + _data.append(" "); + _data.append(this.m_name); + _data.append("=\""); + _data.append(this.m_value); + _data.append("\""); + 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 : 'attribute'"); + this.m_pos.set(_filePos); + // search end of the comment : + int lastElementName = _pos.value; + for (int iii = _pos.value; iii < _data.length(); iii++) { + _filePos.check(_data.charAt(iii)); + drawElementParsed(_data.charAt(iii), _filePos); + if (checkAvaillable(_data.charAt(iii), false) == true) { + lastElementName = iii; + } else { + break; + } + } + this.m_name = _data.substring(_pos.value, lastElementName + 1); + if (_caseSensitive == true) { + this.m_name = this.m_name.toLowerCase(); + } + // count white space : + final FilePos tmpPos = new FilePos(); + int white = 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 += 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++) { + 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.m_value = _data.substring(lastElementName + white + 2, lastAttributePos); + + //EXML_PARSE_ATTRIBUTE(m_pos << " attribute : " << m_name << "=\"" << m_value << "\""); + + _pos.value = lastAttributePos - 1; + return true; + } + int lastAttributePos = lastElementName + white + 3; + for (int iii = lastElementName + white + 3; iii < _data.length(); iii++) { + 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.m_value = _data.substring(lastElementName + white + 3, lastAttributePos); + + //EXML_PARSE_ATTRIBUTE(m_pos << " attribute : " << m_name << "=\"" << m_value << "\""); + + _pos.value = lastAttributePos; + return true; + } + + /** + * @brief set the name of the attribute + * @param[in] _name New name of the attribute + */ + public void setName(final String _name) { + this.m_name = _name; + } +}; \ No newline at end of file diff --git a/src/org/atriasoft/exml/AttributeList.java b/src/org/atriasoft/exml/AttributeList.java new file mode 100644 index 0000000..5427432 --- /dev/null +++ b/src/org/atriasoft/exml/AttributeList.java @@ -0,0 +1,184 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, 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.etk.util.Pair; +import org.atriasoft.exml.exception.ExmlAttributeDoesNotExist; +import org.atriasoft.exml.internal.Log; + +/** + * @brief List of all attribute element in a node + */ +public abstract class AttributeList extends Node { + protected List m_listAttribute = new ArrayList<>(); //!< list of all attribute; + + public AttributeList() { + super(); + }; + + /** + * @brief Constructor + * @param[in] _value Node value; + */ + public AttributeList(final String _value) { + super(_value); + } + + /** + * @brief add attribute on the List + * @param[in] _attr Pointer on the attribute + */ + public void appendAttribute(final Attribute _attr) { + if (_attr == null) { + Log.error("Try to set an empty node"); + return; + } + for (int iii = 0; iii < this.m_listAttribute.size(); iii++) { + if (this.m_listAttribute.get(iii) == _attr) { + Log.error("Try to add a node that is already added before !!!"); + return; + } + if (this.m_listAttribute.get(iii).getName().contentEquals(_attr.getName()) == true) { + Log.error("Try to add a node that is already added before (same name)"); + return; + } + } + this.m_listAttribute.add(_attr); + } + + @Override + public void clear() { + super.clear(); + this.m_listAttribute.clear(); + }; + + /** + * @brief check if an attribute exist or not with his name. + * @param[in] _name Attribute Name. + * @return true if the attribute exist or False + */ + public boolean existAttribute(final String _name) { + if (_name.length() == 0) { + return false; + } + for (int iii = 0; iii < this.m_listAttribute.size(); ++iii) { + if (this.m_listAttribute.get(iii) != null && this.m_listAttribute.get(iii).getName().contentEquals(_name) == true) { + return true; + } + } + return false; + } + + /** + * @brief get attribute whith his ID + * @param[in] _id Identifier of the attribute 0<= _id < sizeAttribute() + * @return Pointer on the attribute or NULL + * @throws ExmlAttributeDoesNotExist The attribute does not exist. + */ + public Attribute getAttr(final int _id) throws ExmlAttributeDoesNotExist { + if (_id < 0 || _id >= this.m_listAttribute.size()) { + throw new ExmlAttributeDoesNotExist("Attribute does not exist: " + _id + "/" + this.m_listAttribute.size()); + } + return this.m_listAttribute.get(_id); + } + + /** + * @brief get the attribute value with searching in the List with his name + * @param[in] _name Attribute Name. + * @return Value of the attribute or no data in the string + * @throws ExmlAttributeDoesNotExist The attribute does not exist. + */ + public String getAttribute(final String _name) throws ExmlAttributeDoesNotExist { + if (_name.length() == 0) { + throw new ExmlAttributeDoesNotExist("Attribute can not have empty name"); + } + for (int iii = 0; iii < this.m_listAttribute.size(); iii++) { + if (this.m_listAttribute.get(iii) != null && this.m_listAttribute.get(iii).getName().contentEquals(_name) == true) { + return this.m_listAttribute.get(iii).getValue(); + } + } + throw new ExmlAttributeDoesNotExist("Attribute does not exist: " + _name + " in " + this.m_listAttribute.size() + " attributes"); + } + + public List getAttributes() { + return this.m_listAttribute; + } + + /** + * @brief get attribute whith his ID + * @param[in] _id Identifier of the attribute 0<= _id < sizeAttribute() + * @return Name and value of the attribute + * @throws ExmlAttributeDoesNotExist The attribute does not exist. + */ + public Pair getAttrPair(final int _id) throws ExmlAttributeDoesNotExist { + final Attribute att = getAttr(_id); + return new Pair(att.getName(), att.getValue()); + } + + @Override + protected boolean iGenerate(final StringBuilder _data, final int _indent) { + for (int iii = 0; iii < this.m_listAttribute.size(); iii++) { + if (this.m_listAttribute.get(iii) != null) { + this.m_listAttribute.get(iii).iGenerate(_data, _indent); + } + } + return true; + } + + /** + * @brief Remove an attribute form the list + * @param[in] _name Name of the attribute + * @return true The attribute has been removed + * @return false An error occured. + */ + public boolean removeAttribute(final String _name) { + if (_name.length() == 0) { + return false; + } + for (final ListIterator iter = this.m_listAttribute.listIterator(); iter.hasNext();) { + final Attribute element = iter.next(); + if (element == null) { + iter.remove(); + continue; + } + if (element.getName().contentEquals(_name) == true) { + iter.remove(); + return true; + } + } + return false; + } + + /** + * @brief Set A new attribute or replace data of the previous one + * @param[in] _name Name of the attribute + * @param[in] _value Value of the attribute + */ + public void setAttribute(final String _name, final String _value) { + // check if attribute already det : + for (int iii = 0; iii < this.m_listAttribute.size(); ++iii) { + if (this.m_listAttribute.get(iii) != null && this.m_listAttribute.get(iii).getName().contentEquals(_name) == true) { + // update the value : + this.m_listAttribute.get(iii).setValue(_value); + return; + } + } + final Attribute attr = new Attribute(_name, _value); + this.m_listAttribute.add(attr); + } + + /** + * @brief get the number of attribute in the Node + * @return Nulber of attribute >=0 + */ + public int sizeAttribute() { + return this.m_listAttribute.size(); + } +} \ No newline at end of file diff --git a/src/org/atriasoft/exml/Comment.java b/src/org/atriasoft/exml/Comment.java new file mode 100644 index 0000000..3f0e5e4 --- /dev/null +++ b/src/org/atriasoft/exml/Comment.java @@ -0,0 +1,85 @@ +package org.atriasoft.exml; + +import org.atriasoft.exml.internal.Log; + +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +/** + * @brief Comment node: lt;!-- ... --gt; + */ +public class Comment extends Node { + + public Comment() { + super(); + } + + public Comment(final Comment obj) { + super(obj.m_value); + } + + /** + * @brief 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) { + addIndent(_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 : 'comment'"); + this.m_pos = _filePos; + final FilePos tmpPos = new FilePos(); + final int white = countWhiteChar(_data, _pos.value, tmpPos); + _filePos.add(tmpPos); + // search end of the comment : + for (int iii = _pos.value + white; iii + 2 < _data.length(); iii++) { + 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 (isWhiteChar(_data.charAt(jjj)) == true) { + newEnd = jjj; + } else { + break; + } + } + // find end of value: + this.m_value = _data.substring(_pos.value + white, newEnd); + Log.verbose(" find comment '" + this.m_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; + } +}; \ No newline at end of file diff --git a/src/org/atriasoft/exml/Declaration.java b/src/org/atriasoft/exml/Declaration.java new file mode 100644 index 0000000..59f3cb4 --- /dev/null +++ b/src/org/atriasoft/exml/Declaration.java @@ -0,0 +1,91 @@ +package org.atriasoft.exml; + +import org.atriasoft.exml.internal.Log; + +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +/** + * @brief Declaration node: lt;?XXXXXX ... gt; + */ +public class Declaration extends AttributeList { + public Declaration() { + super(""); + }; + + public Declaration(final Declaration obj) { + super(obj.m_value); + for (final Attribute elem : obj.m_listAttribute) { + this.m_listAttribute.add(elem.clone()); + } + }; + + /** + * @brief 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) { + addIndent(_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.m_value + "'"); + this.m_pos = _filePos; + // search end of the comment : + for (int iii = _pos.value; iii + 1 < _data.length(); iii++) { + 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 (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.m_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; + } + +} diff --git a/src/org/atriasoft/exml/DeclarationXML.java b/src/org/atriasoft/exml/DeclarationXML.java new file mode 100644 index 0000000..55ba699 --- /dev/null +++ b/src/org/atriasoft/exml/DeclarationXML.java @@ -0,0 +1,36 @@ +package org.atriasoft.exml; + +import org.atriasoft.exml.internal.Log; + +public class DeclarationXML extends Declaration { + public DeclarationXML(final DeclarationXML obj) { + super(obj.m_value); + for (final Attribute elem : obj.m_listAttribute) { + this.m_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); + } + +} diff --git a/src/org/atriasoft/exml/Document.java b/src/org/atriasoft/exml/Document.java new file mode 100644 index 0000000..7729d8c --- /dev/null +++ b/src/org/atriasoft/exml/Document.java @@ -0,0 +1,252 @@ +package org.atriasoft.exml; + +import org.atriasoft.exml.internal.Log; + +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +/** + * @brief Basic document element of a document + */ +public class Document extends Element { + private static String createPosPointer(final String _line, final int _pos) { + String out = ""; + int iii; + for (iii = 0; iii < _pos && iii < _line.length(); iii++) { + if (_line.charAt(iii) == '\t') { + out += "\t"; + } else { + out += " "; + } + } + for (; iii < _pos; iii++) { + out += " "; + } + out += "^"; + return out; + } + + private boolean m_caseSensitive; //!< check the case sensitive of the nodes and attribute + private boolean m_writeErrorWhenDetexted; //!< Request print error in parsing just when detected + private String m_comment; //!< Comment on the error; + private String m_Line; //!< Parse line error (copy); + private FilePos m_filePos; //!< position of the error + + /** + * @brief Constructor + */ + public Document() { + this.m_caseSensitive = false; + this.m_writeErrorWhenDetexted = true; + this.m_comment = ""; + this.m_Line = ""; + this.m_filePos = new FilePos(0, 0); + } + + @Override + public void clear() { + // TODO Auto-generated method stub + + } + + /** + * @brief 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.m_comment = _comment; + this.m_Line = extract_line(_data, _pos); + this.m_filePos = _filePos; + if (this.m_writeErrorWhenDetexted == true) { + displayError(); + } + } + + /** + * @brief Display the Document on console + */ + public void display() { + final StringBuilder tmpp = new StringBuilder(); + iGenerate(tmpp, 0); + Log.info("Generated XML : \n" + tmpp.toString()); + } + + /** + * @brief Request display in log of the error + */ + public void displayError() { + if (this.m_comment.length() == 0) { + Log.error("No error detected ???"); + return; + } + Log.error(this.m_filePos + " " + this.m_comment + "\n" + this.m_Line + "\n" + createPosPointer(this.m_Line, this.m_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); + } + + /** + * @brief 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); + } + /** + * @brief 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; + } + */ + /** + * @brief 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; + } + */ + /** + * @brief get the status of case sensitive mode. + * @return true if case sensitive is active + */ + public boolean getCaseSensitive() { + return this.m_caseSensitive; + } + + /** + * @brief 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.m_writeErrorWhenDetexted; + } + + @Override + public NodeType getType() { + return NodeType.document; + } + + @Override + public boolean iGenerate(final StringBuilder _data, final int _indent) { + for (int iii = 0; iii < this.m_listSub.size(); iii++) { + if (this.m_listSub.get(iii) != null) { + this.m_listSub.get(iii).iGenerate(_data, _indent); + } + } + return true; + } + + /** + * @brief 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.m_pos = new FilePos(1, 0); + final PositionParsing parsePos = new PositionParsing(); + return subParse(_data, parsePos, this.m_caseSensitive, this.m_pos, this, true); + } + + /** + * @brief 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.m_caseSensitive = _val; + } + + /** + * @brief 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.m_writeErrorWhenDetexted = _value; + } +} diff --git a/src/org/atriasoft/exml/Element.java b/src/org/atriasoft/exml/Element.java new file mode 100644 index 0000000..ccecb4a --- /dev/null +++ b/src/org/atriasoft/exml/Element.java @@ -0,0 +1,532 @@ +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; + +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +/** + * @brief Basic element Node of an XML document lt;YYYYYgt; + */ +public class Element extends AttributeList { + protected List m_listSub = new ArrayList<>(); //!< List of subNodes; + + /** + * @brief Constructor + */ + public Element() { + super(); + }; + + public Element(final Element obj) throws CloneNotSupportedException { + super(obj.m_value); + for (final Attribute elem : obj.m_listAttribute) { + this.m_listAttribute.add(elem.clone()); + } + for (final Node elem : obj.m_listSub) { + this.m_listSub.add(elem.clone()); + } + } + + /** + * @brief Constructor + * @param[in] _value Element name; + */ + public Element(final String _value) { + super(_value); + + }; + + /** + * @brief 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; + } + if (_node.getType() == NodeType.attribute) { + appendAttribute(_node.toAttribute()); + return; + } + for (int iii = 0; iii < this.m_listSub.size(); iii++) { + if (this.m_listSub.get(iii) == _node) { + Log.error("Try to add a node that is already added before !!!"); + return; + } + } + this.m_listSub.add(_node); + } + + @Override + public void clear() { + super.clear(); + this.m_listSub.clear(); + }; + + @Override + public Element clone() throws CloneNotSupportedException { + return new Element(this); + } + + /** + * @brief 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.m_listSub.size()) { + return false; + } + return true; + } + + /** + * @brief 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.m_listSub.size(); iii++) { + if (this.m_listSub.get(iii) != null && this.m_listSub.get(iii).getValue().contentEquals(_name) == true) { + if (this.m_listSub.get(iii) == null) { + return false; + } + return true; + } + } + return false; + } + + /** + * @brief 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.m_listSub.size()) { + throw new ExmlNodeDoesNotExist("Node does not exist: " + _id + "/" + this.m_listAttribute.size()); + } + return this.m_listSub.get(_id); + } + + /** + * @brief 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.m_listAttribute.size() + " nodes"); + } + for (int iii = 0; iii < this.m_listSub.size(); iii++) { + if (this.m_listSub.get(iii) != null && this.m_listSub.get(iii).getValue().contentEquals(_name) == true) { + return this.m_listSub.get(iii); + } + } + throw new ExmlNodeDoesNotExist("Node does not exist: '" + _name + "' in " + this.m_listAttribute.size()); + } + + /** + * @brief Get the list of the sub-nodes. + * @return List of current nodes. + */ + public List getNodes() { + return this.m_listSub; + } + + /** + * @brief 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 + * @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.m_listSub.size() == 1) { + if (this.m_listSub.get(0).getType() == NodeType.text) { + res.append(this.m_listSub.get(0).getValue()); + } else { + this.m_listSub.get(0).iGenerate(res, 0); + } + } else { + for (int iii = 0; iii < this.m_listSub.size(); iii++) { + if (this.m_listSub.get(iii) != null) { + this.m_listSub.get(iii).iGenerate(res, 0); + } + } + } + return res.toString(); + } + + @Override + public NodeType getType() { + return NodeType.element; + } + + /** + * @brief get the type of the element id. + * @param[in] _id Id of the element. + * @return the Current type of the element or typeUnknow. + */ + public NodeType getType(final int _id) { + if (_id < 0 || _id >= this.m_listSub.size()) { + return NodeType.unknow; + } + return this.m_listSub.get(_id).getType(); + } + + @Override + protected boolean iGenerate(final StringBuilder _data, final int _indent) { + addIndent(_data, _indent); + _data.append("<"); + _data.append(this.m_value); + super.iGenerate(_data, _indent); + + if (this.m_listSub.size() > 0) { + if (this.m_listSub.size() == 1 && this.m_listSub.get(0) != null && this.m_listSub.get(0).getType() == NodeType.text && ((Text) this.m_listSub.get(0)).countLines() == 1) { + _data.append(">"); + this.m_listSub.get(0).iGenerate(_data, 0); + Log.verbose(" generate : '" + _data + "'"); + } else { + _data.append(">\n"); + for (int iii = 0; iii < this.m_listSub.size(); iii++) { + if (this.m_listSub.get(iii) != null) { + this.m_listSub.get(iii).iGenerate(_data, _indent + 1); + } + } + addIndent(_data, _indent); + } + _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='" + m_value + "'"); + // note : When start parsing the upper element must have set the value of the element and set the position after this one + this.m_pos = _filePos.clone(); + // find a normal node ... + for (int iii = _pos.value; iii < _data.length(); iii++) { + _filePos.check(_data.charAt(iii)); + 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 (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.m_listAttribute.add(attribute); + continue; + } + if (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.m_value + "' == > check if the '/>' is set or the end of element"); + return false; + } + + /** + * @brief 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 iter = this.m_listSub.listIterator(); iter.hasNext();) { + final Node element = iter.next(); + if (element == null) { + iter.remove(); + continue; + } + if (element.getValue().contentEquals(_nodeName) == true) { + iter.remove(); + } + } + } + + /** + * @brief get the number of sub element in the node (can be Comment ; Element ; Text :Declaration). + * @return a number >=0. + */ + public int size() { + return this.m_listSub.size(); + } + + /** + * @brief 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)); + drawElementParsed(_data.charAt(iii), _filePos); + final FilePos tmpPos = new FilePos(); + if (_data.charAt(iii) == '<') { + final int white = 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 (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 (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.m_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 ' 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 ' invalide XML"); + return false; + } + if (_data.charAt(iii + white + 3) != '-') { + _doc.createError(_data, _pos.value, _filePos, "Element parse with ' 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.m_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 ' 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 ' 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.m_listSub.add(text); + } else { + _doc.createError(_data, _pos.value, _filePos, "End file with ' 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 (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.m_value) == true) { + // find end of node : + // find > element ... + for (int jjj = endPosName + 1; jjj < _data.length(); jjj++) { + 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.m_value + "'"); + return false; + } + } + } else { + _doc.createError(_data, _pos.value, _filePos, "End node error : '" + tmpname + "' != '" + this.m_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 (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 (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.m_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.m_listSub.add(text); + } + } + } + if (_mainNode == true) { + return true; + } + _doc.createError(_data, _pos.value, _filePos, "Did not find end of the exml::internal::Element : '" + this.m_value + "'"); + return false; + } + +}; \ No newline at end of file diff --git a/src/org/atriasoft/exml/FilePos.java b/src/org/atriasoft/exml/FilePos.java new file mode 100644 index 0000000..4425e2e --- /dev/null +++ b/src/org/atriasoft/exml/FilePos.java @@ -0,0 +1,180 @@ +package org.atriasoft.exml; + +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +/** + * @brief Position in the file of the original data. + */ +public class FilePos { + private int m_col; //!< source text colomn + private int m_line; //!< source Line colomn + + /** + * @brief default contructor (set line and col at 0) + */ + public FilePos() { + this.m_col = 0; + this.m_line = 0; + } + + /** + * @brief initialize constructor + * @param[in] _line Line in the file + * @param[in] _col Colomn in the file + */ + public FilePos(final int _line, final int _col) { + this.m_col = _col; + this.m_line = _line; + } + + /** + * @brief Addition operator + * @param[in] _obj Addition object.. + * @return Reference on this + */ + public FilePos add(final FilePos _obj) { + if (_obj.m_line == 0) { + this.m_col += _obj.m_col; + } else { + this.m_col = _obj.m_col; + this.m_line += _obj.m_line; + } + return this; + } + + /** + * @brief Colomn addition operator + * @param[in] _col Number of colomn to add + * @return Reference on this + */ + public FilePos add(final int _col) { + this.m_col += _col; + return this; + } + + /** + * @brief Check if the value is a new line and update internal property + * @param[in] _val Char value to check + * @return true We find a new line + * @return false We NOT find a new line + */ + public boolean check(final Character _val) { + this.m_col++; + if (_val == '\n') { + newLine(); + return true; + } + return false; + } + + /** + * @brief Reset position at 0,0 + */ + public void clear() { + this.m_col = 0; + this.m_line = 0; + } + + @Override + public FilePos clone() { + final FilePos out = new FilePos(); + out.m_col = this.m_col; + out.m_line = this.m_line; + return out; + } + + /** + * @brief Decrement the colomn position + * @return Reference on this + */ + public FilePos decrement() { + this.m_col--; + return this; + } + + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof FilePos)) { + return false; + } + final FilePos other = (FilePos) obj; + return this.m_col == other.m_col && this.m_line == other.m_line; + } + + /** + * @brief Get the colomn position + * @return Colomn in number of utf8-char + */ + public int getCol() { + return this.m_col; + } + + /** + * @brief Get the line number position + * @return line ID (start at 0) + */ + public int getLine() { + return this.m_line; + } + + @Override + public int hashCode() { + return super.hashCode() + this.m_line + this.m_col; + } + + /** + * @brief Increment the colomn position + * @return Reference on this + */ + public FilePos increment() { + this.m_col++; + return this; + } + + /** + * @brief Find a new line & reset colomn at 0 + */ + public void newLine() { + this.m_col = 0; + this.m_line++; + } + + /** + * @brief Asignment operator + * @param[in] _obj Object to copy + * @return Reference on this + */ + public FilePos set(final FilePos _obj) { + this.m_col = _obj.m_col; + this.m_line = _obj.m_line; + return this; + } + + /** + * @brief Setter of specific data + * @param[in] _line Line in the file + * @param[in] _col Colomn in the file + */ + public void set(final int _line, final int _col) { + this.m_col = _col; + this.m_line = _line; + } + + @Override + public String toString() { + String out = "(l="; + out += this.m_line; + out += ",c="; + out += this.m_col; + out += ")"; + return out; + } + +}; diff --git a/src/org/atriasoft/exml/Node.java b/src/org/atriasoft/exml/Node.java new file mode 100644 index 0000000..86a0dad --- /dev/null +++ b/src/org/atriasoft/exml/Node.java @@ -0,0 +1,275 @@ +package org.atriasoft.exml; + +import org.atriasoft.exml.internal.Log; + +/** + * @brief Basic main object of all xml elements. + */ +public abstract class Node { + + protected class PositionParsing { + public int value = 0; + } + + protected static boolean isWhiteChar(final Character _val) { + if (_val == ' ' || _val == '\t' || _val == '\n' || _val == '\r') { + return true; + } + return false; + } + + protected FilePos m_pos; //!< position in the readed file == > not correct when the file is generated; + + protected String m_value; //!< value of the node (for element this is the name, for text it is the inside text ...); + + /** + * @brief basic element of a xml structure + */ + public Node() { + this.m_pos = new FilePos(0, 0); + + } + + /** + * @brief basic element of a xml structure + * @param[in] _value value of the node + */ + public Node(final String _value) { + this.m_pos = new FilePos(0, 0); + this.m_value = _value; + } + + /** + * @brief add indentation of the string input. + * @param[in,out] _data String where the indentation is done. + * @param[in] _indent Number of tab to add at the string. + */ + protected void addIndent(final StringBuilder _data, final int _indent) { + for (int iii = 0; iii < _indent; iii++) { + _data.append("\t"); + } + } + + /** + * @brief check if an element or attribute is availlable (not : !"#$%&'()*+,/;<=>?@[\]^`{|}~ \\n\\t\\r and for first char : not -.0123456789). + * @param[in] _val Value to check the conformity. + * @param[in] _firstChar True if the element check is the first char. + * @return true The value can be a part of attribute name + * @return false The value can NOT be a part of attribute name + */ + protected boolean checkAvaillable(final Character _val, final boolean _firstChar) { + if (_val == '!' || _val == '"' || _val == '#' || _val == '$' || _val == '%' || _val == '&' || _val == '\'' // ' + || _val == '(' || _val == ')' || _val == '*' || _val == '+' || _val == ',' || _val == '/' || _val == ';' || _val == '<' || _val == '=' || _val == '>' || _val == '?' || _val == '@' + || _val == '[' || _val == '\\' || _val == ']' || _val == '^' || _val == '`' || _val == '{' || _val == '|' || _val == '}' || _val == '~' || _val == ' ' || _val == '\n' || _val == '\t' + || _val == '\r') { + return false; + } + if (_firstChar == true) { + if (_val == '-' || _val == '.' || (_val >= '0' && _val <= '9')) { + return false; + } + } + return true; + } + + /** + * @brief clear the Node + */ + public void clear() { + this.m_value = ""; + this.m_pos.clear(); + } + + @Override + protected Node clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException("Can not clone an abstract class ..."); + } + + /** + * @brief count the number of white char in the string from the specify position (stop at the first element that is not a white char) + * @param[in] _data Data to parse. + * @param[in] _pos Start position in the string. + * @param[out] _filePos new poistion of te file to add. + * @return number of white element. + */ + protected int countWhiteChar(final String _data, final int _pos, final FilePos _filePos) { + _filePos.clear(); + int white = 0; + for (int iii = _pos; iii < _data.length(); iii++) { + _filePos.check(_data.charAt(iii)); + if (isWhiteChar(_data.charAt(iii)) == true) { + white++; + } else { + break; + } + } + _filePos.decrement(); + return white; + } + + /** + * @brief Display the cuurent element that is curently parse. + * @param[in] _val Char that is parsed. + * @param[in] _filePos Position of the char in the file. + */ + protected void drawElementParsed(final Character _val, final FilePos _filePos) { + if (_val == '\n') { + Log.debug(_filePos + " parse '\\n'"); + } else if (_val == '\t') { + Log.debug(_filePos + " parse '\\t'"); + } else { + Log.debug(_filePos + " parse '" + _val + "'"); + } + } + + /** + * @brief get the current position where the element is in the file + * @return The file position reference + */ + public FilePos getPos() { + return this.m_pos; + } + + /** + * @brief get the node type. + * @return the type of the Node. + */ + NodeType getType() { + return NodeType.node; + } + + /** + * @brief get the current element Value. + * @return the reference of the string value. + */ + public String getValue() { + return this.m_value; + } + + /** + * @brief generate a string with the tree of the xml + * @param[in,out] _data string where to add the elements + * @param[in] _indent current indentation of the file + * @return false if an error occured. + */ + protected boolean iGenerate(final StringBuilder _data, final int _indent) { + return true; + } + + /** + * @brief parse the Current node [pure VIRUAL] + * @param[in] _data data string to parse. + * @param[in,out] _pos position in the string to start parse, return the position end of parsing. + * @param[in] _caseSensitive Request a parsion of element that is not case sensitive (all element is in low case) + * @param[in,out] _filePos file parsing position (line x col x) + * @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); + + /** + * @brief check if the node is a exml::Attribute + * @return true if the node is a exml::Attribute + */ + public boolean isAttribute() { + return this instanceof Attribute; + } + + /** + * @brief check if the node is a exml::Comment + * @return true if the node is a exml::Comment + */ + public boolean isComment() { + return this instanceof Comment; + } + + /** + * @brief check if the node is a exml::Declaration + * @return true if the node is a exml::Declaration + */ + public boolean isDeclaration() { + return this instanceof Declaration; + } + + /** + * @brief check if the node is a exml::Document + * @return true if the node is a exml::Document + */ + public boolean isDocument() { + return this instanceof Document; + } + + /** + * @brief check if the node is a exml::Element + * @return true if the node is a exml::Element + */ + public boolean isElement() { + return this instanceof Element; + } + + /** + * @brief check if the node is a exml::Text + * @return true if the node is a exml::Text + */ + public boolean isText() { + return this instanceof Text; + } + + /** + * @brief set the value of the node. + * @param[in] _value New value of the node. + */ + + public void setValue(final String _value) { + this.m_value = _value; + } + + /** + * @brief Cast the element in a Attribute if it is possible. + * @return pointer on the class or null. + */ + public Attribute toAttribute() { + return (Attribute) this; + } + + /** + * @brief Cast the element in a Comment if it is possible. + * @return pointer on the class or null. + */ + public Comment toComment() { + return (Comment) this; + } + + /** + * @brief Cast the element in a Declaration if it is possible. + * @return pointer on the class or null. + */ + public Declaration toDeclaration() { + return (Declaration) this; + } + + /** + * @brief Cast the element in a Document if it is possible. + * @return pointer on the class or null. + */ + public Document toDocument() { + return (Document) this; + } + + /** + * @brief Cast the element in a Element if it is possible. + * @return pointer on the class or null. + */ + public Element toElement() { + return (Element) this; + } + + /** + * @brief Cast the element in a Text if it is possible. + * @return pointer on the class or null. + */ + public Text toText() { + return (Text) this; + } + +} diff --git a/src/org/atriasoft/exml/NodeType.java b/src/org/atriasoft/exml/NodeType.java new file mode 100644 index 0000000..9d0dd76 --- /dev/null +++ b/src/org/atriasoft/exml/NodeType.java @@ -0,0 +1,20 @@ +package org.atriasoft.exml; +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +/** + * @brief Type of the XML elements. + */ +public enum NodeType { + unknow, //!< might be an error ... + node, //!< might be an error ... + document, //!< all the file main access + declaration, //!< <?xml ... ?> + attribute, //!< the <Element ATTRIBUTE="ATTRIBUTE_VALUE" /> + element, //!< the <XXX> ... </XXX> + comment, //!< comment node : <!-- --> + text, //!< <XXX> InsideText </XXX> +} diff --git a/src/org/atriasoft/exml/Text.java b/src/org/atriasoft/exml/Text.java new file mode 100644 index 0000000..bbaf128 --- /dev/null +++ b/src/org/atriasoft/exml/Text.java @@ -0,0 +1,114 @@ +package org.atriasoft.exml; + +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +import org.atriasoft.exml.internal.Log; + +/** + * @brief Text node interface (internal data between two Marker: <XXX> ALL here </XXX> + */ +public class Text extends Node { + + // transform the Text with : + // "<" == "<" + // ">" == ">" + // "&" == "&" + // "'" == "'" + // """ == """ + private static String replaceSpecialChar(final String _inval) { + final String out = _inval; + out.replace("<", "<"); + out.replace(">", ">"); + out.replace("'", "'"); + out.replace(""", "\""); + out.replace("&", "&"); + //EXML_ERROR("INNN '"<< _inval << "' => '" << out << "'"); + return out; + } + + private static String replaceSpecialCharOut(final String _inval) { + final String out = _inval; + out.replace("<", "<"); + out.replace(">", ">"); + out.replace("'", "'"); + out.replace("\"", """); + out.replace("&", "&"); + //EXML_ERROR("OUTTT '"<< _inval << "' => '" << out << "'"); + return out; + } + + /** + * @brief Constructor + */ + public Text() {}; + + /** + * @brief Constructor + * @param[in] _data String data of the current Text + */ + public Text(final String _data) { + super(_data); + } + + /** + * @brief 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.m_value.length(); iii++) { + if (this.m_value.charAt(iii) == '\n') { + count++; + } + } + return count; + } + + @Override + NodeType getType() { + return NodeType.text; + }; + + @Override + protected boolean iGenerate(final StringBuilder _data, final int _indent) { + _data.append(replaceSpecialCharOut(this.m_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.m_pos = _filePos; + // search end of the comment : + for (int iii = _pos.value; iii < _data.length(); iii++) { + 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 (isWhiteChar(_data.charAt(jjj)) == true) { + newEnd = jjj; + } else { + break; + } + } + // find end of value: + this.m_value = _data.substring(_pos.value, newEnd); + Log.verbose(" find text '" + this.m_value + "'"); + _pos.value = iii - 1; + this.m_value = replaceSpecialChar(this.m_value); + return true; + } + } + _doc.createError(_data, _pos.value, _filePos, "Text got end of file without finding end node"); + _pos.value = _data.length(); + return false; + } + +}; \ No newline at end of file diff --git a/src/org/atriasoft/exml/TextCDATA.java b/src/org/atriasoft/exml/TextCDATA.java new file mode 100644 index 0000000..204e486 --- /dev/null +++ b/src/org/atriasoft/exml/TextCDATA.java @@ -0,0 +1,45 @@ +package org.atriasoft.exml; + +import org.atriasoft.exml.internal.Log; + +public class TextCDATA extends Text { + public TextCDATA() { + super(); + } + + public TextCDATA(final String data) { + super(data); + } + + @Override + protected boolean iGenerate(final StringBuilder _data, final int _indent) { + _data.append(""); + 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.m_pos = _filePos; + // search end of the comment : + for (int iii = _pos.value; iii + 2 < _data.length(); iii++) { + 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.m_value = _data.substring(_pos.value, iii); + Log.verbose(" find text CDATA '" + this.m_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; + } +} diff --git a/src/org/atriasoft/exml/exception/ExmlAttributeDoesNotExist.java b/src/org/atriasoft/exml/exception/ExmlAttributeDoesNotExist.java new file mode 100644 index 0000000..e5d9471 --- /dev/null +++ b/src/org/atriasoft/exml/exception/ExmlAttributeDoesNotExist.java @@ -0,0 +1,13 @@ +package org.atriasoft.exml.exception; + +public class ExmlAttributeDoesNotExist extends ExmlException { + /** + * Generate Unique ID for serialization + */ + private static final long serialVersionUID = 1L; + + public ExmlAttributeDoesNotExist(final String data) { + super(data); + } + +} diff --git a/src/org/atriasoft/exml/exception/ExmlException.java b/src/org/atriasoft/exml/exception/ExmlException.java new file mode 100644 index 0000000..3cb1fdf --- /dev/null +++ b/src/org/atriasoft/exml/exception/ExmlException.java @@ -0,0 +1,12 @@ +package org.atriasoft.exml.exception; + +public class ExmlException extends Exception { + /** + * Generate Unique ID for serialization + */ + private static final long serialVersionUID = 1L; + + public ExmlException(final String data) { + super(data); + } +} diff --git a/src/org/atriasoft/exml/exception/ExmlNodeDoesNotExist.java b/src/org/atriasoft/exml/exception/ExmlNodeDoesNotExist.java new file mode 100644 index 0000000..ca2f1d0 --- /dev/null +++ b/src/org/atriasoft/exml/exception/ExmlNodeDoesNotExist.java @@ -0,0 +1,13 @@ +package org.atriasoft.exml.exception; + +public class ExmlNodeDoesNotExist extends ExmlException { + /** + * Generate Unique ID for serialization + */ + private static final long serialVersionUID = 1L; + + public ExmlNodeDoesNotExist(final String data) { + super(data); + } + +} diff --git a/src/org/atriasoft/exml/internal/Log.java b/src/org/atriasoft/exml/internal/Log.java new file mode 100644 index 0000000..682494d --- /dev/null +++ b/src/org/atriasoft/exml/internal/Log.java @@ -0,0 +1,68 @@ +package org.atriasoft.exml.internal; + +import io.scenarium.logger.LogLevel; +import io.scenarium.logger.Logger; + +public class Log { + private static final String LIB_NAME = "exml"; + private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); + private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL); + private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR); + private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING); + private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO); + private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG); + private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE); + private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO); + private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT); + + public static void critical(final String data) { + if (PRINT_CRITICAL) { + Logger.critical(LIB_NAME_DRAW, data); + } + } + + public static void debug(final String data) { + if (PRINT_DEBUG) { + Logger.debug(LIB_NAME_DRAW, data); + } + } + + public static void error(final String data) { + if (PRINT_ERROR) { + Logger.error(LIB_NAME_DRAW, data); + } + } + + public static void info(final String data) { + if (PRINT_INFO) { + Logger.info(LIB_NAME_DRAW, data); + } + } + + public static void print(final String data) { + if (PRINT_PRINT) { + Logger.print(LIB_NAME_DRAW, data); + } + } + + public static void todo(final String data) { + if (PRINT_TODO) { + Logger.todo(LIB_NAME_DRAW, data); + } + } + + public static void verbose(final String data) { + if (PRINT_VERBOSE) { + Logger.verbose(LIB_NAME_DRAW, data); + } + } + + public static void warning(final String data) { + if (PRINT_WARNING) { + Logger.warning(LIB_NAME_DRAW, data); + } + } + + private Log() {} + +} diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/test/src/test/atriasoft/exml/ExmlLocal.java b/test/src/test/atriasoft/exml/ExmlLocal.java new file mode 100644 index 0000000..8c5a3ab --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlLocal.java @@ -0,0 +1,44 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package test.atriasoft.exml; + +import org.atriasoft.exml.Document; +import org.junit.jupiter.api.Assertions; + +class ExmlLocal { + // _errorPos : -1 : no error , 1 : parsing error, 2 generation error, 3 comparaison error ???? + public static void test(final String _ref, final String _input, final int _errorPos) { + test(_ref, _input, _errorPos, false); + } + + public static void test(final String _ref, final String _input, final int _errorPos, final boolean _caseInSensitive) { + final Document doc = new Document(); + //doc.setCaseSensitive(!_caseInSensitive); + Log.verbose("parse : \n" + _input); + final boolean retParse = doc.parse(_input); + if (_errorPos == 1) { + Assertions.assertEquals(retParse, false); + return; + } else { + Assertions.assertEquals(retParse, true); + } + final StringBuilder out = new StringBuilder(); + final boolean retGenerate = doc.generate(out); + if (_errorPos == 2) { + Assertions.assertEquals(retGenerate, false); + return; + } else { + Assertions.assertEquals(retGenerate, true); + } + final String data = out.toString(); + if (_errorPos == 3) { + Assertions.assertNotEquals(_ref, data); + return; + } else { + Assertions.assertEquals(_ref, data); + } + } +} diff --git a/test/src/test/atriasoft/exml/ExmlTestAll.java b/test/src/test/atriasoft/exml/ExmlTestAll.java new file mode 100644 index 0000000..fdaaa11 --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestAll.java @@ -0,0 +1,73 @@ +package test.atriasoft.exml; + +import org.junit.jupiter.api.BeforeAll; + +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +import org.junit.jupiter.api.Test; + +public class ExmlTestAll { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void testBase() { + //@formatter:off + ExmlLocal.test( "\n" + + " \n" + + " \n" + + " Text example ...\n" + + "\n", + "< exemple\n >\n" + + " \n" + + " \n" + + " \n" + + " Text example ...\n" + + " \n" + + "\n", + -1); + //@formatter:on + } + + @Test + public void testCaseSensitive() { + //@formatter:off + ExmlLocal.test( "\n" + +" \n" + +" \n" + +" Text example ...\n" + +"\n", + "< exemple\n >\n" + +" \n" + +" \n" + +" \n" + +" Text example ...\n" + +" \n" + +"\n", + -1, + false); + //@formatter:on + } + + @Test + public void testError() { + //@formatter:off + ExmlLocal.test( "", + "< exemple\n >\n" + +" \n" + +" >\n" + +" \n" + +" Text example ...\n" + +" \n" + +"\n", + 1); + //@formatter:on + } + +} diff --git a/test/src/test/atriasoft/exml/ExmlTestAttribute.java b/test/src/test/atriasoft/exml/ExmlTestAttribute.java new file mode 100644 index 0000000..edb0919 --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestAttribute.java @@ -0,0 +1,170 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2021, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package test.atriasoft.exml; + +import org.atriasoft.exml.Attribute; +import org.atriasoft.exml.Document; +import org.atriasoft.exml.Element; +import org.atriasoft.exml.NodeType; +import org.atriasoft.exml.exception.ExmlAttributeDoesNotExist; +import org.atriasoft.exml.exception.ExmlNodeDoesNotExist; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestAttribute { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void AttributeElementNotExist() { + final Element myElement = new Element("NodeName"); + Assertions.assertThrows(ExmlAttributeDoesNotExist.class, () -> myElement.getAttr(65465465)); + } + + @Test + public void clear() { + + final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute"); + myAttribute.clear(); + } + + @Test + public void create() { + + final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute"); + Assertions.assertEquals(myAttribute.getType(), NodeType.attribute); + } + + @Test + public void createAssignement() { + final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute"); + final Attribute 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); + Assertions.assertEquals(myAttribute.getValue(), myOtherAttribute.getValue()); + Assertions.assertEquals(myAttribute.getName(), myOtherAttribute.getName()); + } + + @Test + public void exist() { + + final Element elem = new Element("elem"); + elem.setAttribute("valA", "plop"); + Assertions.assertEquals(elem.existAttribute("valA"), true); + Assertions.assertEquals(elem.existAttribute("qsdfsdf"), false); + } + + @Test + public void get() { + + final Element elem = new Element("elem"); + elem.setAttribute("valA", "plop"); + try { + Assertions.assertEquals(elem.getAttribute("valA"), "plop"); + } catch (final ExmlAttributeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + Assertions.assertThrows(ExmlAttributeDoesNotExist.class, () -> elem.getAttribute("qsdfsdf")); + } + + @Test + public void getpair() { + + final Element elem = new Element("elem"); + elem.setAttribute("valA", "coucou"); + try { + Assertions.assertEquals(elem.getAttrPair(0).first, "valA"); + Assertions.assertEquals(elem.getAttrPair(0).second, "coucou"); + } catch (final ExmlAttributeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + Assertions.assertThrows(ExmlAttributeDoesNotExist.class, () -> elem.getAttrPair(1)); + Assertions.assertThrows(ExmlAttributeDoesNotExist.class, () -> elem.getAttrPair(-1)); + } + + @Test + public void moveInAllElement() { + final Document doc = new Document(); + doc.parse(""); + Element elem; + try { + elem = (Element) doc.getNode("elem"); + } catch (final ExmlNodeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + return; + } + for (final Attribute it : elem.getAttributes()) { + Assertions.assertEquals(it.getName(), "valA"); + Assertions.assertEquals(it.getValue(), "plop"); + } + } + + @Test + public void remove() { + final Element elem = new Element("elem"); + elem.setAttribute("valA", "plop"); + Assertions.assertEquals(elem.existAttribute("valA"), true); + elem.removeAttribute("valA"); + Assertions.assertEquals(elem.existAttribute("valA"), false); + } + + @Test + public void setGetName() { + + final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute"); + Assertions.assertEquals(myAttribute.getName(), "nameAttribute"); + myAttribute.setName("newName"); + Assertions.assertEquals(myAttribute.getName(), "newName"); + } + + @Test + public void setGetValue() { + + final Attribute myAttribute = new Attribute("nameAttribute", "valueAttribute"); + Assertions.assertEquals(myAttribute.getValue(), "valueAttribute"); + myAttribute.setValue("new value"); + Assertions.assertEquals(myAttribute.getValue(), "new value"); + } + + @Test + public void setterNew() { + + final Element elem = new Element("elem"); + elem.setAttribute("valA", "coucou"); + try { + Assertions.assertEquals(elem.getAttribute("valA"), "coucou"); + } catch (final ExmlAttributeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + } + + @Test + public void setterRewrite() { + + final Element elem = new Element("elem"); + elem.setAttribute("valA", "coucou"); + try { + Assertions.assertEquals(elem.getAttribute("valA"), "coucou"); + } catch (final ExmlAttributeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + elem.setAttribute("valA", "coucou2"); + try { + Assertions.assertEquals(elem.getAttribute("valA"), "coucou2"); + } catch (final ExmlAttributeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + } +} diff --git a/test/src/test/atriasoft/exml/ExmlTestCData.java b/test/src/test/atriasoft/exml/ExmlTestCData.java new file mode 100644 index 0000000..bf7a2e4 --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestCData.java @@ -0,0 +1,35 @@ +package test.atriasoft.exml; + +import org.atriasoft.exml.Document; +import org.atriasoft.exml.Element; +import org.atriasoft.exml.TextCDATA; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestCData { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void generate() { + final Document doc = new Document(); + doc.append(new TextCDATA("Text &é<>examp]le]] ...")); + doc.append(new TextCDATA("Text &é<>examp]le]] ...")); + final String out = doc.getText(); + doc.parse("examp]le]] ...]]>"); + Assertions.assertEquals("examp]le]] ...]]>examp]le]] ...]]>", out); + } + + @Test + public void parseCDATA() { + final Document doc = new Document(); + doc.parse("examp]le]] ...]]>"); + final Element elem = Assertions.assertDoesNotThrow(() -> { + return (Element) doc.getNode("elem"); + }); + Assertions.assertEquals("Text &é<>examp]le]] ...", elem.getText()); + } +} diff --git a/test/src/test/atriasoft/exml/ExmlTestComment.java b/test/src/test/atriasoft/exml/ExmlTestComment.java new file mode 100644 index 0000000..150af97 --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestComment.java @@ -0,0 +1,48 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package test.atriasoft.exml; + +import org.atriasoft.exml.Comment; +import org.atriasoft.exml.Node; +import org.atriasoft.exml.NodeType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestComment { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void create() { + final Comment myComment = new Comment("my Comment"); + Assertions.assertEquals(myComment.getType(), NodeType.comment); + } + + @Test + public void createAssignement() { + final Comment myComment = new Comment("my comment"); + final Comment 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); + Assertions.assertEquals(myComment.getValue(), myOtherComment.getValue()); + } + + @Test + public void transform() { + Comment myComment = new Comment("my comment"); + final Node myNode = myComment; + myComment = myNode.toComment(); + Assertions.assertEquals(myComment.getValue(), "my comment"); + } +} \ No newline at end of file diff --git a/test/src/test/atriasoft/exml/ExmlTestDeclarationXML.java b/test/src/test/atriasoft/exml/ExmlTestDeclarationXML.java new file mode 100644 index 0000000..6e3eadd --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestDeclarationXML.java @@ -0,0 +1,62 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package test.atriasoft.exml; + +import org.atriasoft.exml.DeclarationXML; +import org.atriasoft.exml.NodeType; +import org.atriasoft.exml.exception.ExmlAttributeDoesNotExist; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestDeclarationXML { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void create() { + final DeclarationXML myDeclarationXML = new DeclarationXML("1.0", "UTF-8", true); + Assertions.assertEquals(myDeclarationXML.getType(), NodeType.declaration); + try { + Assertions.assertEquals(myDeclarationXML.getAttribute("version"), "1.0"); + Assertions.assertEquals(myDeclarationXML.getAttribute("encoding"), "UTF-8"); + Assertions.assertEquals(myDeclarationXML.getAttribute("standalone"), "true"); + } catch (final ExmlAttributeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + } + + @Test + public void createAssignement() { + + final DeclarationXML myDeclarationXML = new DeclarationXML("1.0", "UTF-8", true); + final DeclarationXML myOtherDeclarationXML = myDeclarationXML.clone(); + Assertions.assertEquals(myDeclarationXML.getValue(), myOtherDeclarationXML.getValue()); + try { + Assertions.assertEquals(myDeclarationXML.getAttribute("version"), myOtherDeclarationXML.getAttribute("version")); + Assertions.assertEquals(myDeclarationXML.getAttribute("encoding"), myOtherDeclarationXML.getAttribute("encoding")); + Assertions.assertEquals(myDeclarationXML.getAttribute("standalone"), myOtherDeclarationXML.getAttribute("standalone")); + } catch (final ExmlAttributeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + } + + @Test + public void createCopy() { + final DeclarationXML myDeclarationXML = new DeclarationXML("1.0", "UTF-8", true); + final DeclarationXML myOtherDeclarationXML = new DeclarationXML(myDeclarationXML); + Assertions.assertEquals(myDeclarationXML.getValue(), myOtherDeclarationXML.getValue()); + try { + Assertions.assertEquals(myDeclarationXML.getAttribute("version"), myOtherDeclarationXML.getAttribute("version")); + Assertions.assertEquals(myDeclarationXML.getAttribute("encoding"), myOtherDeclarationXML.getAttribute("encoding")); + Assertions.assertEquals(myDeclarationXML.getAttribute("standalone"), myOtherDeclarationXML.getAttribute("standalone")); + } catch (final ExmlAttributeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + } +} \ No newline at end of file diff --git a/test/src/test/atriasoft/exml/ExmlTestElement.java b/test/src/test/atriasoft/exml/ExmlTestElement.java new file mode 100644 index 0000000..7daea80 --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestElement.java @@ -0,0 +1,127 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +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.exception.ExmlNodeDoesNotExist; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestElement { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void append() { + final Element myElement = new Element("NodeName"); + Assertions.assertEquals(myElement.getNodes().size(), 0); + myElement.append(new Element("jkjhkjhkh")); + Assertions.assertEquals(myElement.getNodes().size(), 1); + try { + myElement.getNode("jkjhkjhkh"); + } catch (final ExmlNodeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + Assertions.assertEquals(myElement.getNodes().size(), 1); + } + + @Test + public void clear() { + final Element myElement = new Element("NodeName"); + Assertions.assertEquals(myElement.getNodes().size(), 0); + myElement.append(new Element("jkjhkjhkh")); + Assertions.assertEquals(myElement.getNodes().size(), 1); + try { + myElement.getNode("jkjhkjhkh"); + } catch (final ExmlNodeDoesNotExist e) { + Assertions.fail("Should Not have thrown an exception"); + } + Assertions.assertEquals(myElement.getNodes().size(), 1); + myElement.clear(); + Assertions.assertEquals(myElement.getNodes().size(), 0); + } + + @Test + public void create() { + final Element myElement = new Element("NodeName"); + Assertions.assertEquals(myElement.getType(), NodeType.element); + } + + @Test + public void createAssignement() { + final Element myElement = new Element("NodeName"); + try { + final Element myOtherElement = myElement.clone(); + Assertions.assertEquals(myElement.getValue(), myOtherElement.getValue()); + } catch (final CloneNotSupportedException e) { + Assertions.fail("Should Not have thrown an exception"); + } + } + + @Test + public void createCopy() { + final Element myElement = new Element("NodeName"); + try { + final Element myOtherElement = new Element(myElement); + Assertions.assertEquals(myElement.getValue(), myOtherElement.getValue()); + } catch (final CloneNotSupportedException e) { + Assertions.fail("Should Not have thrown an exception"); + } + } + + @Test + public void getNamed() { + + final Element myElement = new Element("NodeName"); + Assertions.assertEquals(myElement.existNode("jkjhkjhkh"), false); + } + + @Test + public void getNodeId() { + final Element myElement = new Element("NodeName"); + Assertions.assertEquals(false, myElement.existNode(465)); + } + + @Test + public void getText1() { + + final Element myElement = new Element("NodeName"); + Assertions.assertEquals("", myElement.getText()); + } + + @Test + public void getText2() { + + final Element myElement = new Element("NodeName"); + myElement.append(new Element("jkjhkjhkh")); + Assertions.assertEquals("\n", myElement.getText()); + } + + @Test + public void getTypeId() { + final Element myElement = new Element("NodeName"); + Assertions.assertEquals(NodeType.unknow, myElement.getType(1)); + } + + @Test + public void moveInAllElement() { + final Document doc = new Document(); + doc.parse(""); + for (final Node it : doc.getNodes()) { + final Element elem = (Element) it; + Assertions.assertEquals("elem", elem.getValue()); + Assertions.assertEquals(2, elem.getNodes().size()); + Assertions.assertEquals(2, elem.size()); + } + } + +} diff --git a/test/src/test/atriasoft/exml/ExmlTestParseAttribute.java b/test/src/test/atriasoft/exml/ExmlTestParseAttribute.java new file mode 100644 index 0000000..60ae06a --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestParseAttribute.java @@ -0,0 +1,115 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package test.atriasoft.exml; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestParseAttribute { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void testBase() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testEmptyAttribute() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testEmptyAttributeNoQuote() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testEndAttributeError() { + //@formatter:off + ExmlLocal.test("", + "\n", + 1); + //@formatter:on + } + + @Test + public void testMultiline() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testMultilineNoQuote() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testNoQuote() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testNoQuoteNumber() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testSpace1() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testSpace2() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } +} diff --git a/test/src/test/atriasoft/exml/ExmlTestParseComment.java b/test/src/test/atriasoft/exml/ExmlTestParseComment.java new file mode 100644 index 0000000..59b510c --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestParseComment.java @@ -0,0 +1,60 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package test.atriasoft.exml; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestParseComment { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void testAll() { + //@formatter:off + ExmlLocal.test("\n", + "\n", + -1); + //@formatter:on + } + + @Test + public void testBase() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testEndError() { + ExmlLocal.test("\n", "\n", "\n", -1); + } + + @Test + public void testMultipleEnd() { + ExmlLocal.test("\n", " exemple -->\n", 1); + } + + @Test + public void testNoCharInComment() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testTiretInComment() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testWrongEndParsing() { + ExmlLocal.test(" exemple-->\n", " exemple -->\n", -1); + } +} diff --git a/test/src/test/atriasoft/exml/ExmlTestParseDeclaration.java b/test/src/test/atriasoft/exml/ExmlTestParseDeclaration.java new file mode 100644 index 0000000..9777f4d --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestParseDeclaration.java @@ -0,0 +1,56 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package test.atriasoft.exml; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestParseDeclaration { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void testAll() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testAttribute() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testBase() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testMultiline() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testNoQuote() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testNumberNoQuote() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testSpace1() { + ExmlLocal.test("\n", "\n", -1); + } + + @Test + public void testSpace2() { + ExmlLocal.test("\n", "\n", -1); + } +} diff --git a/test/src/test/atriasoft/exml/ExmlTestParseElement.java b/test/src/test/atriasoft/exml/ExmlTestParseElement.java new file mode 100644 index 0000000..d81c827 --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestParseElement.java @@ -0,0 +1,84 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2014, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +package test.atriasoft.exml; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExmlTestParseElement { + static String refOutputElement = "\n"; + + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void testBase() { + ExmlLocal.test(refOutputElement, "\n", -1); + } + + @Test + public void testBase2() { + ExmlLocal.test("\n", "\n", 1); + } + + @Test + public void testBase3() { + ExmlLocal.test("\n", "\n\n", 1); + } + + @Test + public void testDotPresent() { + ExmlLocal.test(refOutputElement, "< . exemple < />\n", 1); + } + + @Test + public void testExclamationPresence() { + ExmlLocal.test(refOutputElement, "< exemple ? />\n", 1); + } + + @Test + public void testMultiline() { + ExmlLocal.test(refOutputElement, "< \t\r exemple/>\n", -1); + } + + @Test + public void testMultilineMultiTabbed() { + ExmlLocal.test(refOutputElement, "< \t\r exemple \t\r\r\r\n \t\t />\n", -1); + } + + @Test + public void testMultipleSlash() { + ExmlLocal.test(refOutputElement, "< exemple / />\n", 1); + } + + @Test + public void testStarPresence() { + ExmlLocal.test(refOutputElement, "< exemple * />\n", 1); + } + + @Test + public void testWrong1() { + ExmlLocal.test(refOutputElement, "\n", 1); + } + + @Test + public void testWrong2() { + ExmlLocal.test(refOutputElement, "\n", 1); + } + + @Test + public void testWrong3() { + ExmlLocal.test(refOutputElement, "< exemple < />\n", 1); + } + + @Test + public void testWrongStart() { + ExmlLocal.test(refOutputElement, "< exemple < >\n", 1); + } +} diff --git a/test/src/test/atriasoft/exml/Log.java b/test/src/test/atriasoft/exml/Log.java new file mode 100644 index 0000000..8cece3c --- /dev/null +++ b/test/src/test/atriasoft/exml/Log.java @@ -0,0 +1,68 @@ +package test.atriasoft.exml; + +import io.scenarium.logger.LogLevel; +import io.scenarium.logger.Logger; + +public class Log { + private static final String LIB_NAME = "exml-test"; + private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); + private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL); + private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR); + private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING); + private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO); + private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG); + private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE); + private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO); + private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT); + + public static void critical(final String data) { + if (PRINT_CRITICAL) { + Logger.critical(LIB_NAME_DRAW, data); + } + } + + public static void debug(final String data) { + if (PRINT_DEBUG) { + Logger.debug(LIB_NAME_DRAW, data); + } + } + + public static void error(final String data) { + if (PRINT_ERROR) { + Logger.error(LIB_NAME_DRAW, data); + } + } + + public static void info(final String data) { + if (PRINT_INFO) { + Logger.info(LIB_NAME_DRAW, data); + } + } + + public static void print(final String data) { + if (PRINT_PRINT) { + Logger.print(LIB_NAME_DRAW, data); + } + } + + public static void todo(final String data) { + if (PRINT_TODO) { + Logger.todo(LIB_NAME_DRAW, data); + } + } + + public static void verbose(final String data) { + if (PRINT_VERBOSE) { + Logger.verbose(LIB_NAME_DRAW, data); + } + } + + public static void warning(final String data) { + if (PRINT_WARNING) { + Logger.warning(LIB_NAME_DRAW, data); + } + } + + private Log() {} + +} diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..6c6aa7c --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.1.0 \ No newline at end of file