Commit 6d11931c authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

XmlTokenBuilder can now convert one element into several tokens.

parent f3279375
......@@ -16,6 +16,9 @@
*/
package org.orekit.files.ccsds.ndm.adm;
import java.util.Collections;
import java.util.List;
import org.orekit.files.ccsds.utils.lexical.ParseToken;
import org.orekit.files.ccsds.utils.lexical.TokenType;
import org.orekit.files.ccsds.utils.lexical.XmlTokenBuilder;
......@@ -52,9 +55,9 @@ public class RotationXmlTokenBuilder implements XmlTokenBuilder {
/** {@inheritDoc} */
@Override
public ParseToken buildToken(final boolean startTag, final String qName,
final String content, final Attributes attributes,
final int lineNumber, final String fileName) {
public List<ParseToken> buildTokens(final boolean startTag, final String qName,
final String content, final Attributes attributes,
final int lineNumber, final String fileName) {
// get the token name from the first attribute found
String name = attributes.getValue(ANGLE);
......@@ -69,7 +72,9 @@ public class RotationXmlTokenBuilder implements XmlTokenBuilder {
final Unit units = cache.getUnits(attributes.getValue(UNITS));
// final build
return new ParseToken(type, name, content, units, lineNumber, fileName);
final ParseToken token = new ParseToken(type, name, content, units, lineNumber, fileName);
return Collections.singletonList(token);
}
......
......@@ -16,13 +16,30 @@
*/
package org.orekit.files.ccsds.utils.lexical;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.orekit.utils.units.Unit;
import org.xml.sax.Attributes;
/** Builder for the root element with CCSDS message version.
* <p>
* Instances of this class are immutable.
* All parsers for CCSDS ADM, ODM and TDM messages need to handle the
* root level XML element specially. OPM file for example have a root
* element of the form:
* </p>
* <pre>
* &lt;opm id="CCSDS_OPM_VERS" verion="3.0"&gt;
* </pre>
* <p>
* This {@link XmlTokenBuilder token builder} will generate two
* {@link ParseToken parse tokens} from this root element:
* </p>
* <ol>
* <li>one with name set to "opm", type set to {@link TokenType#START} and no content</li>
* <li>one with name set to "CCSDS_OPM_VERS", type set to {@link TokenType#ENTRY} and content set to "3.0"</li>
* </ol>
* @author Luc Maisonobe
* @since 11.0
*/
......@@ -36,18 +53,19 @@ public class MessageVersionXmlTokenBuilder implements XmlTokenBuilder {
/** {@inheritDoc} */
@Override
public ParseToken buildToken(final boolean startTag, final String qName,
final String content, final Attributes attributes,
final int lineNumber, final String fileName) {
public List<ParseToken> buildTokens(final boolean startTag, final String qName,
final String content, final Attributes attributes,
final int lineNumber, final String fileName) {
if (startTag) {
// we replace the start tag with the message version specification
return new ParseToken(TokenType.ENTRY,
attributes.getValue(ID),
attributes.getValue(VERSION),
Unit.NONE,
lineNumber, fileName);
final String id = attributes.getValue(ID);
final String version = attributes.getValue(VERSION);
final ParseToken start = new ParseToken(TokenType.START, qName, null, Unit.NONE, lineNumber, fileName);
final ParseToken entry = new ParseToken(TokenType.ENTRY, id, version, Unit.NONE, lineNumber, fileName);
return Arrays.asList(start, entry);
} else {
return new ParseToken(TokenType.STOP, qName, null, Unit.NONE, lineNumber, fileName);
final ParseToken stop = new ParseToken(TokenType.STOP, qName, null, Unit.NONE, lineNumber, fileName);
return Collections.singletonList(stop);
}
}
......
......@@ -16,13 +16,18 @@
*/
package org.orekit.files.ccsds.utils.lexical;
import java.util.Collections;
import java.util.List;
import org.orekit.utils.units.Unit;
import org.orekit.utils.units.UnitsCache;
import org.xml.sax.Attributes;
/** Regular builder using XML elements names and content for tokens.
* <p>
* Instances of this class are immutable.
* Each tag generates exactly one token, either a {@link TokenType#START START},
* or {@link TokenType#STOP STOP} token without content for non-leaf elements,
* or a {@link TokenType#ENTRY ENTRY} token with content for leaf elements.
* </p>
* @author Luc Maisonobe
* @since 11.0
......@@ -43,9 +48,9 @@ public class RegularXmlTokenBuilder implements XmlTokenBuilder {
/** {@inheritDoc} */
@Override
public ParseToken buildToken(final boolean startTag, final String qName,
final String content, final Attributes attributes,
final int lineNumber, final String fileName) {
public List<ParseToken> buildTokens(final boolean startTag, final String qName,
final String content, final Attributes attributes,
final int lineNumber, final String fileName) {
// elaborate the token type
final TokenType tokenType = (content == null) ?
......@@ -56,7 +61,9 @@ public class RegularXmlTokenBuilder implements XmlTokenBuilder {
final Unit units = cache.getUnits(attributes.getValue(UNITS));
// final build
return new ParseToken(tokenType, qName, content, units, lineNumber, fileName);
final ParseToken token = new ParseToken(tokenType, qName, content, units, lineNumber, fileName);
return Collections.singletonList(token);
}
......
......@@ -16,13 +16,25 @@
*/
package org.orekit.files.ccsds.utils.lexical;
import java.util.Collections;
import java.util.List;
import org.orekit.files.ccsds.ndm.odm.UserDefined;
import org.orekit.utils.units.Unit;
import org.xml.sax.Attributes;
/** Builder for user-defined parameters.
* <p>
* Instances of this class are immutable.
* User-defined elements are of the form:
* </p>
* <pre>
* &lt;USER_DEFINED parameter="SOME_PARAMETER_NAME"&gt;value&lt;/USER_DEFINED&gt;
* </pre>
* <p>
* This {@link XmlTokenBuilder token builder} will generate a single
* {@link ParseToken parse token} from this root element with name set to
* "SOME_PARAMETER_NAME", type set to {@link TokenType#ENTRY} and content
* set to {@code value}.
* </p>
* @author Luc Maisonobe
* @since 11.0
......@@ -31,9 +43,9 @@ public class UserDefinedXmlTokenBuilder implements XmlTokenBuilder {
/** {@inheritDoc} */
@Override
public ParseToken buildToken(final boolean startTag, final String qName,
final String content, final Attributes attributes,
final int lineNumber, final String fileName) {
public List<ParseToken> buildTokens(final boolean startTag, final String qName,
final String content, final Attributes attributes,
final int lineNumber, final String fileName) {
// elaborate the token type
final TokenType tokenType = (content == null) ?
......@@ -42,10 +54,12 @@ public class UserDefinedXmlTokenBuilder implements XmlTokenBuilder {
// final build
final String name = attributes.getValue(UserDefined.USER_DEFINED_XML_ATTRIBUTE);
return new ParseToken(tokenType,
UserDefined.USER_DEFINED_PREFIX + name,
content, Unit.NONE,
lineNumber, fileName);
final ParseToken token = new ParseToken(tokenType,
UserDefined.USER_DEFINED_PREFIX + name,
content, Unit.NONE,
lineNumber, fileName);
return Collections.singletonList(token);
}
......
......@@ -165,9 +165,11 @@ public class XmlLexicalAnalyzer implements LexicalAnalyzer {
currentLineNumber = locator.getLineNumber();
currentContent = null;
messageParser.process(getBuilder(qName).
buildToken(true, qName, currentContent, currentAttributes,
currentLineNumber, source.getName()));
for (final ParseToken token : getBuilder(qName).
buildTokens(true, qName, currentContent, currentAttributes,
currentLineNumber, source.getName())) {
messageParser.process(token);
}
}
......@@ -179,9 +181,12 @@ public class XmlLexicalAnalyzer implements LexicalAnalyzer {
// for an end tag without content, we keep the line number of the end tag itself
currentLineNumber = locator.getLineNumber();
}
messageParser.process(getBuilder(qName).
buildToken(false, qName, currentContent, currentAttributes,
currentLineNumber, source.getName()));
for (final ParseToken token : getBuilder(qName).
buildTokens(false, qName, currentContent, currentAttributes,
currentLineNumber, source.getName())) {
messageParser.process(token);
}
currentElementName = null;
currentLineNumber = -1;
......
......@@ -16,51 +16,38 @@
*/
package org.orekit.files.ccsds.utils.lexical;
import java.util.List;
import org.xml.sax.Attributes;
/** Builder for building {@link ParseToken} from XML elements.
* <p>
* The regular handling of regular XML elements is to used the element name
* as the token name, the element content as the token content and the
* "units" attribute for the units. In some cases however the token name
* should be extracted from attributes, and sometimes even the content. This
* interface allows to define all these behaviors, by providing special builders
* to the lexical analyzer when it calls their {@link MessageParser#getSpecialXmlElementsBuilders()
* The regular handling of regular XML elements is to used the element
* name as the token name, the element content as the token content and
* the "units" attribute for the units. In some cases however the token
* name should be extracted from attributes, and sometimes even the
* content. This interface allows to define all these behaviors, by
* providing specialized builders to the lexical analyzer when it calls
* their {@link MessageParser#getSpecialXmlElementsBuilders()
* getSpecialXmlElementsHandlers} method.
* </p>
* <p>
* A typical example, needed for all parsers, is to handle the top level XML
* element. The {@link org.orekit.files.ccsds.ndm.odm.opm.OpmParser OPM parser}
* for example would put in this list an {@link XmlTokenBuilder} configured
* with {@code name = "opm"}, {@code nameAttributes= ["id"]} and
* {@code contentAttribute="version"}. With this setting, when the
* lexical analyzer sees the element: {@code <opm id="CCSDS_OPM_VERS" version="3.0">}
* it generates a {@link ParseToken} with name set to "CCSDS_OPM_VERS"
* and content set to "3.0".
* <p>
* <p>
* If multiple attributes can be used to get the token name, they are tested
* in turn and the first match is used. This is useful in ADM files where
* the XML elements {@code rotation1}, {@code rotation2}, and {@code rotation3},
* use attribute {@code angle} in rotation angle sub-section but use attribute
* {@code rate} in rotation rate sub-section.
* @author Luc Maisonobe
* @since 11.0
*/
public interface XmlTokenBuilder {
/** Create a token.
/** Create a list of parse tokens.
* @param startTag if true we are parsing the start tag from an XML element
* @param qName element qualified name
* @param content element content
* @param attributes element attributes
* @param lineNumber number of the line in the CCSDS data message
* @param fileName name of the file
* @return parse token
* @return list of parse tokens
*/
ParseToken buildToken(boolean startTag, String qName,
String content, Attributes attributes,
int lineNumber, String fileName);
List<ParseToken> buildTokens(boolean startTag, String qName,
String content, Attributes attributes,
int lineNumber, String fileName);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment