1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.utils.lexical;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.Reader;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Map;
25
26 import javax.xml.parsers.ParserConfigurationException;
27 import javax.xml.parsers.SAXParser;
28 import javax.xml.parsers.SAXParserFactory;
29
30 import org.hipparchus.exception.DummyLocalizable;
31 import org.orekit.data.DataSource;
32 import org.orekit.errors.OrekitException;
33 import org.orekit.errors.OrekitMessages;
34 import org.orekit.files.ccsds.utils.FileFormat;
35 import org.xml.sax.Attributes;
36 import org.xml.sax.InputSource;
37 import org.xml.sax.Locator;
38 import org.xml.sax.SAXException;
39 import org.xml.sax.helpers.DefaultHandler;
40
41
42
43
44
45
46 public class XmlLexicalAnalyzer implements LexicalAnalyzer {
47
48
49 private final DataSource source;
50
51
52
53
54 public XmlLexicalAnalyzer(final DataSource source) {
55 this.source = source;
56 }
57
58
59 @Override
60 public <T> T accept(final MessageParser<T> messageParser) {
61 try {
62
63 final DefaultHandler handler = new XMLHandler(messageParser);
64
65
66 final SAXParserFactory factory = SAXParserFactory.newInstance();
67
68
69 final SAXParser saxParser = factory.newSAXParser();
70
71
72 messageParser.reset(FileFormat.XML);
73 final DataSource.Opener opener = source.getOpener();
74 if (opener.rawDataIsBinary()) {
75 try (InputStream is = opener.openStreamOnce()) {
76 if (is == null) {
77 throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, source.getName());
78 }
79 saxParser.parse(new InputSource(is), handler);
80 }
81 } else {
82 try (Reader reader = opener.openReaderOnce()) {
83 if (reader == null) {
84 throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, source.getName());
85 }
86 saxParser.parse(new InputSource(reader), handler);
87 }
88 }
89
90
91 return messageParser.build();
92
93 } catch (SAXException | ParserConfigurationException | IOException e) {
94
95 throw new OrekitException(e, new DummyLocalizable(e.getMessage()));
96 }
97 }
98
99
100
101 private class XMLHandler extends DefaultHandler {
102
103
104 private final MessageParser<?> messageParser;
105
106
107 private final XmlTokenBuilder regularBuilder;
108
109
110 private Map<String, XmlTokenBuilder> specialElements;
111
112
113 private Locator locator;
114
115
116 private String currentElementName;
117
118
119 private int currentLineNumber;
120
121
122 private String currentContent;
123
124
125 private Map<String, String> currentAttributes;
126
127
128
129
130 private String lastQname;
131
132
133
134
135 private boolean lastWasStart;
136
137
138
139
140 XMLHandler(final MessageParser<?> messageParser) {
141 this.messageParser = messageParser;
142 this.regularBuilder = new RegularXmlTokenBuilder();
143 this.specialElements = messageParser.getSpecialXmlElementsBuilders();
144 this.lastQname = "";
145 this.lastWasStart = false;
146 }
147
148
149
150
151
152 private XmlTokenBuilder getBuilder(final String qName) {
153 final XmlTokenBuilder specialBuilder = specialElements.get(qName);
154 return (specialBuilder != null) ? specialBuilder : regularBuilder;
155 }
156
157
158 @Override
159 public void setDocumentLocator(final Locator documentLocator) {
160 this.locator = documentLocator;
161 }
162
163
164 @Override
165 public void characters(final char[] ch, final int start, final int length) throws SAXException {
166
167
168
169
170
171
172
173
174
175 if (currentElementName != null) {
176
177
178
179
180 currentLineNumber = locator.getLineNumber();
181 this.currentContent = this.currentContent + new String(ch, start, length);
182 }
183 }
184
185
186 @Override
187 public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) {
188
189 currentElementName = qName;
190 currentLineNumber = locator.getLineNumber();
191 currentContent = "";
192
193
194 if (attributes.getLength() == 0) {
195 currentAttributes = Collections.emptyMap();
196 } else {
197 currentAttributes = new HashMap<>(attributes.getLength());
198 for (int i = 0; i < attributes.getLength(); ++i) {
199 currentAttributes.put(attributes.getQName(i), attributes.getValue(i));
200 }
201 }
202
203 for (final ParseToken token : getBuilder(qName).
204 buildTokens(true, false, qName, getContent(), currentAttributes,
205 currentLineNumber, source.getName())) {
206 messageParser.process(token);
207 }
208 lastQname = qName;
209 lastWasStart = true;
210
211 }
212
213 private String getContent() {
214 return currentContent.isEmpty() ? null : currentContent;
215 }
216
217
218 @Override
219 public void endElement(final String uri, final String localName, final String qName) {
220
221 if (currentContent == null || currentContent.isEmpty()) {
222
223 currentLineNumber = locator.getLineNumber();
224 }
225
226
227 final boolean isLeaf = lastWasStart && qName.equals(lastQname);
228
229 for (final ParseToken token : getBuilder(qName).
230 buildTokens(false, isLeaf, qName, getContent(), currentAttributes,
231 currentLineNumber, source.getName())) {
232 messageParser.process(token);
233 }
234 lastQname = qName;
235 lastWasStart = true;
236
237 currentElementName = null;
238 currentAttributes = null;
239 currentLineNumber = -1;
240 currentContent = "";
241
242 }
243
244
245 @Override
246 public InputSource resolveEntity(final String publicId, final String systemId) {
247
248 return new InputSource();
249 }
250
251 }
252
253 }