1   package org.daisy.pipeline.braille.css.saxon.impl;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import javax.xml.namespace.QName;
7   
8   import net.sf.saxon.expr.XPathContext;
9   import net.sf.saxon.lib.ExtensionFunctionCall;
10  import net.sf.saxon.lib.ExtensionFunctionDefinition;
11  import net.sf.saxon.om.Item;
12  import net.sf.saxon.om.NodeInfo;
13  import net.sf.saxon.om.Sequence;
14  import net.sf.saxon.om.StructuredQName;
15  import net.sf.saxon.s9api.XdmNode;
16  import net.sf.saxon.trans.XPathException;
17  import net.sf.saxon.value.BooleanValue;
18  import net.sf.saxon.value.EmptySequence;
19  import net.sf.saxon.value.QNameValue;
20  import net.sf.saxon.value.SequenceExtent;
21  import net.sf.saxon.value.SequenceType;
22  
23  import org.daisy.braille.css.BrailleCSSParserFactory.Context;
24  import org.daisy.braille.css.InlineStyle;
25  import org.daisy.common.saxon.SaxonOutputValue;
26  import org.daisy.pipeline.braille.css.impl.BrailleCssSerializer;
27  import org.daisy.pipeline.braille.css.impl.BrailleCssTreeBuilder.Style;
28  
29  import org.osgi.service.component.annotations.Component;
30  
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  @Component(
35  	name = "css:parse-stylesheet",
36  	service = { ExtensionFunctionDefinition.class }
37  )
38  public class ParseStylesheetDefinition extends ExtensionFunctionDefinition {
39  	
40  	private static final String XMLNS_CSS = "http://www.daisy.org/ns/pipeline/braille-css";
41  	
42  	private static final StructuredQName funcname = new StructuredQName("css", XMLNS_CSS, "parse-stylesheet");
43  	
44  	private static final QName PAGE = new QName("page");
45  	private static final QName VOLUME = new QName("volume");
46  	private static final QName HYPHENATION_RESOURCE = new QName("hyphenation-resource");
47  	private static final QName VENDOR_RULE = new QName("vendor-rule");
48  	
49  	public StructuredQName getFunctionQName() {
50  		return funcname;
51  	}
52  	
53  	@Override
54  	public int getMinimumNumberOfArguments() {
55  		return 1;
56  	}
57  	
58  	@Override
59  	public int getMaximumNumberOfArguments() {
60  		return 3;
61  	}
62  	
63  	public SequenceType[] getArgumentTypes() {
64  		return new SequenceType[] {
65  			SequenceType.OPTIONAL_STRING,
66  			SequenceType.SINGLE_BOOLEAN,
67  			SequenceType.OPTIONAL_QNAME,
68  		};
69  	}
70  	
71  	public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
72  		return SequenceType.NODE_SEQUENCE;
73  	}
74  	
75  	public ExtensionFunctionCall makeCallExpression() {
76  		return new ExtensionFunctionCall() {
77  			public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
78  				if (arguments.length == 0)
79  					return EmptySequence.getInstance();
80  				Item arg = arguments[0].head();
81  				if (arg == null)
82  					return EmptySequence.getInstance();
83  				boolean deep = arguments.length > 1
84  					? ((BooleanValue)arguments[1]).getBooleanValue()
85  					: false;
86  				Context styleCtxt = Context.ELEMENT; {
87  					if (arguments.length > 2) {
88  						Item i = arguments[2].head();
89  						if (i != null) {
90  							QName qn = ((QNameValue)i).toJaxpQName();
91  							if (qn.equals(PAGE))
92  								styleCtxt = Context.PAGE;
93  							else if (qn.equals(VOLUME))
94  								styleCtxt = Context.VOLUME;
95  							else if (qn.equals(HYPHENATION_RESOURCE))
96  								styleCtxt = Context.HYPHENATION_RESOURCE;
97  							else if (qn.equals(VENDOR_RULE))
98  								styleCtxt = Context.VENDOR_RULE;
99  							else
100 								throw new RuntimeException(); }}}
101 				List<NodeInfo> result = new ArrayList<>();
102 				try {
103 					Style style = Style.of(new InlineStyle(arg.getStringValue(), styleCtxt));
104 					BrailleCssSerializer.toXml(
105 						style,
106 						new SaxonOutputValue(
107 							item -> {
108 								if (item instanceof XdmNode)
109 									result.add(((XdmNode)item).getUnderlyingNode());
110 								else
111 									throw new RuntimeException(); // should not happen
112 							},
113 							context.getConfiguration()
114 						).asXMLStreamWriter(),
115 						deep);
116 				} catch (Exception e) {
117 					logger.error("Error happened while parsing " + arg, e);
118 				}
119 				return new SequenceExtent(result);
120 			}
121 		};
122 	}
123 	
124 	private static final Logger logger = LoggerFactory.getLogger(ParseStylesheetDefinition.class);
125 	
126 }