1 /***
2 * Java DAB EPG API - Serialize/Deserialize To/From POJOs to XML/Binary as per
3 * ETSI specifications TS 102 818 (XML Specification for DAB EPG) and TS 102
4 * 371 (Transportation and Binary Encoding Specification for EPG).
5 *
6 * Copyright (C) 2007 GCap Media PLC
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 package com.gcapmedia.dab.epg.xml;
23
24 import java.io.*;
25 import java.net.URL;
26
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29 import javax.xml.parsers.ParserConfigurationException;
30 import javax.xml.transform.*;
31 import javax.xml.transform.dom.DOMSource;
32 import javax.xml.transform.stream.StreamResult;
33
34 import org.w3c.dom.CDATASection;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37
38 import com.gcapmedia.dab.epg.*;
39
40 /***
41 * Marshalls an EPG to/from XML
42 */
43 public class XmlMarshaller implements Marshaller {
44
45 /***
46 * Serial version
47 */
48 private static final long serialVersionUID = 3823353646420716647L;
49
50
51
52
53
54
55
56 /***
57 * @see com.gcapmedia.dab.epg.Marshaller#marshall(com.gcapmedia.dab.epg.Epg)
58 */
59 public byte[] marshall(Epg epg) throws MarshallException {
60
61 byte[] bytes = null;
62
63
64 Document doc = buildDocument(epg);
65
66
67 try {
68
69 Source source = new DOMSource(doc);
70
71
72 StringWriter writer = new StringWriter();
73 TransformerFactory factory = TransformerFactory.newInstance();
74 factory.setAttribute("indent-number", new Integer(4));
75 Transformer transformer = factory.newTransformer();
76 StreamResult result = new StreamResult(writer);
77 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
78 transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
79 transformer.transform(source, result);
80 String markup = writer.getBuffer().toString();
81 bytes = markup.getBytes();
82
83 } catch (Exception e) {
84 throw new MarshallException("Error marshalling XML data", e);
85 }
86
87 return bytes;
88 }
89
90 /***
91 * Marshalls an EPG to an XML string adherent to the ISO/IEC 10646 character
92 * set and using UTF-8 encoding.
93 * @throws UnsupportedEncodingException
94 * @throws MarshallException
95 */
96 public String marshallToXmlString(Epg epg) throws UnsupportedEncodingException, MarshallException {
97 return new String(marshall(epg), "ISO-8859-2");
98 }
99
100 /***
101 * @see com.gcapmedia.dab.epg.Marshaller#unmarshall(byte[])
102 */
103 public Epg unmarshall(byte[] bytes) {
104
105 return null;
106 }
107
108 /***
109 * Unmarshall a document located at the specified URL. This should use the
110 * ISO/IEC 10646 character set and be encoded in UTF-8.
111 * @throws IOException
112 */
113 public Epg unmarshallFromUrl(URL url) throws IOException {
114 BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
115 String tmp = null;
116 StringBuilder buffer = new StringBuilder();
117 while((tmp = reader.readLine()) != null) {
118 buffer.append(tmp);
119 }
120 return unmarshall(buffer.toString().getBytes());
121 }
122
123 /***
124 * Unmarshall an EPG from a file. This should use the
125 * ISO/IEC 10646 character set and be encoded in UTF-8.
126 * @throws IOException
127 */
128 public Epg unmarshallFromFile(File file) throws IOException {
129 return unmarshallFromUrl(file.toURL());
130 }
131
132 /***
133 * @param epg
134 * @return
135 */
136 private Document buildDocument(Epg epg) {
137
138
139 DocumentBuilder builder = null;
140 try {
141 builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
142 } catch (ParserConfigurationException e1) {
143
144 e1.printStackTrace();
145 }
146 Document doc = builder.newDocument();
147
148
149
150 Element epgElement = doc.createElement("epg");
151 doc.appendChild(epgElement);
152 epgElement.setAttribute("system", epg.getSystemType().name());
153
154
155 if(epg.getSchedule() != null) {
156 Schedule schedule = epg.getSchedule();
157 Element scheduleElement = buildSchedule(schedule, epgElement, doc);
158 epgElement.appendChild(scheduleElement);
159 }
160
161 return doc;
162 }
163
164 /***
165 * builds the <schedule> element
166 */
167 private Element buildSchedule(Schedule schedule, Element parent, Document doc) {
168 Element scheduleElement = doc.createElement("schedule");
169 if(schedule.getVersion() > 0) {
170 scheduleElement.setAttribute("version", "" + schedule.getVersion());
171 }
172 if(schedule.getCreated() != null) {
173 scheduleElement.setAttribute("creationTime", schedule.getCreated().toString());
174 }
175 if(schedule.getOriginator() != null) {
176 scheduleElement.setAttribute("originator", schedule.getOriginator());
177 }
178
179
180 if(schedule.getScope() != null) {
181 Scope scope = schedule.getScope();
182 Element scopeElement = buildScope(scope, scheduleElement, doc);
183 scheduleElement.appendChild(scopeElement);
184 }
185
186
187 for(Programme programme : schedule.getProgrammes()) {
188 Element programmeElement = buildProgramme(programme, scheduleElement, doc);
189 scheduleElement.appendChild(programmeElement);
190 }
191
192 return scheduleElement;
193 }
194
195 /***
196 * builds a <programme> element
197 */
198 private Element buildProgramme(Programme programme, Element scheduleElement, Document doc) {
199
200
201 Element programmeElement = doc.createElement("programme");
202 programmeElement.setAttribute("shortId", "" + programme.getShortId());
203 if(programme.getId() != null) {
204 programmeElement.setAttribute("id", programme.getId().toString());
205 }
206 if(programme.getRecommendation() != null && programme.getRecommendation() != Recommendation.NO) {
207 programmeElement.setAttribute("recommendation", programme.getRecommendation().value());
208 }
209 if(programme.getBroadcastFlag() != null && programme.getBroadcastFlag() != BroadcastFlag.ON_AIR) {
210 programmeElement.setAttribute("broadcast", programme.getBroadcastFlag().value());
211 }
212
213
214 NameGroup names = programme.getNames();
215 for(ShortName shortName : names.getShortNames()) {
216 Element shortNameElement = doc.createElement("shortName");
217 shortNameElement.setAttribute("xml:lang", shortName.getLanguage());
218 shortNameElement.setTextContent(shortName.getText());
219 programmeElement.appendChild(shortNameElement);
220 }
221 for(MediumName mediumName : names.getMediumNames()) {
222 Element mediumNameElement = doc.createElement("mediumName");
223 mediumNameElement.setAttribute("xml:lang", mediumName.getLanguage());
224 mediumNameElement.setTextContent(mediumName.getText());
225 programmeElement.appendChild(mediumNameElement);
226 }
227 for(LongName longName : names.getLongNames()) {
228 Element longNameElement = doc.createElement("longName");
229 longNameElement.setAttribute("xml:lang", longName.getLanguage());
230 longNameElement.setTextContent(longName.getText());
231 programmeElement.appendChild(longNameElement);
232 }
233
234
235 for(Location location : programme.getLocations()) {
236 Element locationElement = buildLocation(location, programmeElement, doc);
237 programmeElement.appendChild(locationElement);
238 }
239
240
241 MediaGroup media = programme.getMedia();
242 Element mediaElement = buildMedia(media, doc);
243 programmeElement.appendChild(mediaElement);
244
245
246 for(Genre genre : programme.getGenres()) {
247 Element genreElement = buildGenre(genre, programmeElement, doc);
248 programmeElement.appendChild(genreElement);
249 }
250
251
252 for(Membership membership : programme.getMemberships()) {
253 Element membershipElement = buildMembership(membership, programmeElement, doc);
254 programmeElement.appendChild(membershipElement);
255 }
256
257
258 for(Link link : programme.getLinks()) {
259 Element linkElement = buildLink(link, programmeElement, doc);
260 programmeElement.appendChild(linkElement);
261 }
262
263
264 for(ProgrammeEvent event : programme.getEvents()) {
265 Element eventElement = buildEvent(event, programmeElement, doc);
266 programmeElement.appendChild(eventElement);
267 }
268
269 return programmeElement;
270 }
271
272 /***
273 * builds the <programmeEvent> element
274 */
275 private Element buildEvent(ProgrammeEvent event, Element programmeElement, Document doc) {
276 Element eventElement = doc.createElement("programmeEvent");
277
278 eventElement.setAttribute("shortId", "" + event.getShortId());
279 if(event.getId() != null) {
280 eventElement.setAttribute("id", event.getId().toString());
281 }
282 if(event.getRecommendation() != null) {
283 eventElement.setAttribute("recommendation", event.getRecommendation().value());
284 }
285
286
287 NameGroup names = event.getNames();
288 for(ShortName shortName : names.getShortNames()) {
289 Element shortNameElement = doc.createElement("shortName");
290 shortNameElement.setAttribute("xml:lang", shortName.getLanguage());
291 shortNameElement.setTextContent(shortName.getText());
292 eventElement.appendChild(shortNameElement);
293 }
294 for(MediumName mediumName : names.getMediumNames()) {
295 Element mediumNameElement = doc.createElement("mediumName");
296 mediumNameElement.setAttribute("xml:lang", mediumName.getLanguage());
297 mediumNameElement.setTextContent(mediumName.getText());
298 eventElement.appendChild(mediumNameElement);
299 }
300 for(LongName longName : names.getLongNames()) {
301 Element longNameElement = doc.createElement("longName");
302 longNameElement.setAttribute("xml:lang", longName.getLanguage());
303 longNameElement.setTextContent(longName.getText());
304 eventElement.appendChild(longNameElement);
305 }
306
307
308 for(Location location : event.getLocations()) {
309 Element locationElement = buildLocation(location, programmeElement, doc);
310 eventElement.appendChild(locationElement);
311 }
312
313
314 MediaGroup media = event.getMedia();
315 Element mediaElement = buildMedia(media, doc);
316 eventElement.appendChild(mediaElement);
317
318
319
320 for(Genre genre : event.getGenres()) {
321 Element genreElement = buildGenre(genre, programmeElement, doc);
322 eventElement.appendChild(genreElement);
323 }
324
325
326 for(Membership membership : event.getMemberships()) {
327 Element membershipElement = buildMembership(membership, programmeElement, doc);
328 eventElement.appendChild(membershipElement);
329 }
330
331
332 for(Link link : event.getLinks()) {
333 Element linkElement = buildLink(link, programmeElement, doc);
334 eventElement.appendChild(linkElement);
335 }
336
337 return eventElement;
338 }
339
340 /***
341 * builds the <link> element
342 */
343 private Element buildLink(Link link, Element programmeElement, Document doc) {
344 Element linkElement = doc.createElement("link");
345 linkElement.setAttribute("url", link.getUrl().toString());
346 linkElement.setAttribute("description", link.getDescription());
347 return linkElement;
348 }
349
350 /***
351 * builds the <memberOf> element
352 */
353 private Element buildMembership(Membership membership, Element programmeElement, Document doc) {
354 Element memberOfElement = doc.createElement("memberOf");
355 memberOfElement.setAttribute("shortId", "" + membership.getShortId());
356 if(membership.getCrid() != null) {
357 memberOfElement.setAttribute("id", membership.getCrid().toString());
358 }
359 if(membership.getIndex() > 0) {
360 memberOfElement.setAttribute("shortId", "" + membership.getIndex());
361 }
362 return memberOfElement;
363 }
364
365 /***
366 * builds the <genre> element
367 */
368 private Element buildGenre(Genre genre, Element programmeElement, Document doc) {
369 Element genreElement = doc.createElement("genre");
370 genreElement.setAttribute("href", genre.toString());
371 if(genre.getType() != null && genre.getType() != Genre.Type.MAIN) {
372 genreElement.setAttribute("type", genre.getType().toString());
373 }
374 if(genre.getDefinition() != null) {
375 Element nameElement = doc.createElement("doc");
376 CDATASection data = doc.createCDATASection(genre.getDefinition());
377 nameElement.appendChild(data);
378 genreElement.appendChild(nameElement);
379 }
380 return genreElement;
381 }
382
383 /***
384 * builds the <mediaDescription> element
385 */
386 private Element buildMedia(MediaGroup media, Document doc) {
387
388 Element mediaElement = doc.createElement("mediaDescription");
389
390
391 for(ShortDescription shortDescription : media.getShortDescriptions()) {
392 Element shortDescriptionElement = doc.createElement("shortDescription");
393 shortDescriptionElement.setAttribute("xml:lang", shortDescription.getLanguage());
394 CDATASection data = doc.createCDATASection(shortDescription.getText());
395 shortDescriptionElement.appendChild(data);
396 mediaElement.appendChild(shortDescriptionElement);
397 }
398
399
400 for(LongDescription longDescription : media.getLongDescriptions()) {
401 Element longDescriptionElement = doc.createElement("longDescription");
402 longDescriptionElement.setAttribute("xml:lang", longDescription.getLanguage());
403 CDATASection data = doc.createCDATASection(longDescription.getText());
404 longDescriptionElement.appendChild(data);
405 mediaElement.appendChild(longDescriptionElement);
406 }
407
408
409 for(Multimedia multimedia : media.getMultimedia()) {
410 Element multimediaElement = doc.createElement("multimedia");
411 multimediaElement.setAttribute("url", multimedia.getUrl().toString());
412 if(multimedia.getType() != null) {
413 multimediaElement.setAttribute("type", multimedia.getType().toString());
414 }
415 if(multimedia.getMimeType() != null) {
416 multimediaElement.setAttribute("mimeValue", multimedia.getMimeType());
417 }
418 if(multimedia.getHeight() > 0) {
419 multimediaElement.setAttribute("height", "" + multimedia.getHeight());
420 }
421 if(multimedia.getWidth() > 0) {
422 multimediaElement.setAttribute("width", "" + multimedia.getWidth());
423 }
424 mediaElement.appendChild(multimediaElement);
425 }
426
427 return mediaElement;
428 }
429
430 /***
431 * builds the <location> element
432 */
433 private Element buildLocation(Location location, Element parent, Document doc) {
434 Element locationElement = doc.createElement("location");
435
436
437 for(Time time : location.getTimes()) {
438 Element timeElement = doc.createElement("time");
439 timeElement.setAttribute("time", time.getBilledTime().toString());
440 timeElement.setAttribute("duration", time.getBilledDuration().toString());
441 if(time.getActualTime() != null) {
442 timeElement.setAttribute("actualTime", time.getActualTime().toString());
443 }
444 if(time.getActualDuration() != null) {
445 timeElement.setAttribute("actualDuration", time.getActualDuration().toString());
446 }
447 locationElement.appendChild(timeElement);
448 }
449
450
451 for(RelativeTime time : location.getRelativeTimes()) {
452 Element timeElement = doc.createElement("relativeTime");
453 timeElement.setAttribute("time", time.getBilledTime().toString());
454 timeElement.setAttribute("duration", time.getBilledDuration().toString());
455 if(time.getActualTime() != null) {
456 timeElement.setAttribute("actualTime", time.getActualTime().toString());
457 }
458 if(time.getActualDuration() != null) {
459 timeElement.setAttribute("actualDuration", time.getActualDuration().toString());
460 }
461 locationElement.appendChild(timeElement);
462 }
463
464
465 for(Bearer bearer : location.getBearers()) {
466 Element bearerElement = doc.createElement("bearer");
467 bearerElement.setAttribute("id", bearer.getId().toString());
468 locationElement.appendChild(bearerElement);
469 }
470
471 return locationElement;
472 }
473
474 /***
475 * builds the <scope> element
476 */
477 private Element buildScope(Scope scope, Element parent, Document doc) {
478 Element scopeElement = doc.createElement("scope");
479 scopeElement.setAttribute("startTime", scope.getStartTime().toString());
480 scopeElement.setAttribute("stopTime", scope.getStopTime().toString());
481 for(ContentId id : scope.getServices()) {
482 Element serviceElement = doc.createElement("serviceScope");
483 serviceElement.setAttribute("id", id.toString());
484 scopeElement.appendChild(serviceElement);
485 }
486 return scopeElement;
487 }
488
489 }