1 package org.daisy.pipeline.file.calabash.impl;
2
3 import java.io.IOException;
4 import java.net.URI;
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.Map;
8
9 import com.xmlcalabash.core.XProcConstants;
10 import com.xmlcalabash.core.XProcRuntime;
11 import com.xmlcalabash.io.WritablePipe;
12 import com.xmlcalabash.library.DefaultStep;
13 import com.xmlcalabash.model.RuntimeValue;
14 import com.xmlcalabash.runtime.XAtomicStep;
15
16 import net.sf.saxon.s9api.QName;
17 import net.sf.saxon.s9api.SaxonApiException;
18
19 import static org.daisy.common.saxon.SaxonHelper.jaxpQName;
20 import org.daisy.common.transform.TransformerException;
21 import org.daisy.common.xml.DocumentBuilder;
22 import org.daisy.common.xproc.calabash.XMLCalabashOutputValue;
23 import org.daisy.common.xproc.calabash.XProcStep;
24 import org.daisy.common.xproc.calabash.XProcStepProvider;
25 import org.daisy.common.xproc.XProcMonitor;
26
27 import org.osgi.service.component.annotations.Component;
28 import org.osgi.service.component.annotations.Reference;
29 import org.osgi.service.component.annotations.ReferenceCardinality;
30 import org.osgi.service.component.annotations.ReferencePolicy;
31
32 import org.xml.sax.InputSource;
33 import org.xml.sax.SAXException;
34
35 import org.w3c.dom.Document;
36
37 @Component(
38 name = "px:load",
39 service = { XProcStepProvider.class },
40 property = { "type:String={http://www.daisy.org/ns/pipeline/xproc}load" }
41 )
42 public class LoadProvider implements XProcStepProvider {
43
44 @Override
45 public XProcStep newStep(XProcRuntime runtime, XAtomicStep step, XProcMonitor monitor, Map<String,String> properties) {
46 return new Load(runtime, step);
47 }
48
49 private static final QName _href = new QName("href");
50 private static final QName _content_type = new QName("content-type");
51 private static final QName err_XD0011 = new QName("err", XProcConstants.NS_XPROC_ERROR, "XD0011");
52
53 public class Load extends DefaultStep implements XProcStep {
54
55 private WritablePipe result = null;
56
57 public Load(XProcRuntime runtime, XAtomicStep step) {
58 super(runtime,step);
59 }
60
61 public void setOutput(String port, WritablePipe pipe) {
62 result = pipe;
63 }
64
65 public void reset() {
66 result.resetWriter();
67 }
68
69 public void run() throws SaxonApiException {
70 super.run();
71 try {
72 RuntimeValue href = getOption(_href);
73 URI absoluteHref = href.getBaseURI().resolve(href.getString());
74 InputSource source = new InputSource(absoluteHref.toString());
75 String contentType = getOption(_content_type, "");
76 boolean isXml = "".equals(contentType) || contentType.matches("[^ ]*(/|\\+)xml");
77 Document doc = null;
78 DocumentBuilder xmlParser = null;
79 try {
80 for (DocumentBuilder p : parsers) {
81 if (xmlParser == null && p.supportsContentType("text/xml")) {
82 xmlParser = p;
83 if (isXml) break;
84 }
85 if (!isXml && p.supportsContentType(contentType)) {
86 doc = p.parse(source);
87 break;
88 }
89 }
90 if (doc == null && xmlParser != null) {
91
92
93 doc = xmlParser.parse(source);
94 }
95 } catch (SAXException|IOException e) {
96 throw new TransformerException(
97 jaxpQName(err_XD0011),
98 new IllegalArgumentException("Error parsing " + absoluteHref + " (content-type: " + contentType + ")", e));
99 }
100 if (doc == null) {
101
102 if (xmlParser != null) throw new RuntimeException();
103 throw new TransformerException(new IllegalStateException("No XML parser found"));
104 }
105 new XMLCalabashOutputValue(result, runtime).asNodeConsumer().accept(doc);
106 } catch (Throwable e) {
107 throw XProcStep.raiseError(e, step);
108 }
109 }
110 }
111
112 private final List<DocumentBuilder> parsers = new ArrayList<>();
113
114 @Reference(
115 name = "input-parser",
116 unbind = "-",
117 service = DocumentBuilder.class,
118 cardinality = ReferenceCardinality.MULTIPLE,
119 policy = ReferencePolicy.STATIC
120 )
121 protected void addInputParser(DocumentBuilder parser) {
122 parsers.add(parser);
123 }
124 }