1   package org.daisy.pipeline.tts;
2   
3   import java.net.URI;
4   import java.net.URISyntaxException;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.List;
8   
9   import net.sf.saxon.om.NodeInfo;
10  import net.sf.saxon.s9api.Axis;
11  import net.sf.saxon.s9api.Processor;
12  import net.sf.saxon.s9api.QName;
13  import net.sf.saxon.s9api.XdmNode;
14  import net.sf.saxon.s9api.XdmNodeKind;
15  import net.sf.saxon.s9api.XdmSequenceIterator;
16  
17  import org.slf4j.Logger;
18  import org.slf4j.LoggerFactory;
19  
20  import com.google.common.collect.HashMultimap;
21  import com.google.common.collect.Multimap;
22  import com.xmlcalabash.util.TreeWriter;
23  
24  public class DefaultSSMLMarkSplitter implements SSMLMarkSplitter {
25  
26  	private static Logger ServerLogger = LoggerFactory
27  	        .getLogger(DefaultSSMLMarkSplitter.class);
28  
29  	private Processor mProc;
30  
31  	public DefaultSSMLMarkSplitter(Processor proc) {
32  		mProc = proc;
33  	}
34  
35  	@Override
36  	public Collection<Chunk> split(XdmNode ssml) {
37  		List<String> sortedMarkNames = new ArrayList<String>();
38  		Multimap<NodeInfo, String> marksScope = HashMultimap.create();
39  		sortedMarkNames.add(null); //null means 'no mark'
40  		findMarks(ssml, marksScope, sortedMarkNames);
41  
42  		Collection<Chunk> chunks = new ArrayList<Chunk>();
43  
44  		if (ssml.getNodeKind() == XdmNodeKind.DOCUMENT) {
45  			XdmSequenceIterator iter = ssml.axisIterator(Axis.CHILD);
46  			while (ssml.getNodeKind() != XdmNodeKind.ELEMENT && iter.hasNext()) {
47  				ssml = (XdmNode) iter.next();
48  			}
49  		}
50  		URI docURI = null;
51  		try {
52  			docURI = new URI("http://tmp");
53  		} catch (URISyntaxException e) {
54  		}
55  
56  		for (String markName : sortedMarkNames) {
57  			TreeWriter tw = new TreeWriter(mProc);
58  			tw.startDocument(docURI);
59  			tw.startContent();
60  			toXML(ssml, tw, markName, marksScope);
61  			tw.endDocument();
62  			chunks.add(new Chunk(tw.getResult(), markName));
63  		}
64  
65  		return chunks;
66  	}
67  
68  	private static void findMarks(XdmNode ssml, Multimap<NodeInfo, String> marksScope,
69  	        List<String> sortedMarkNames) {
70  		String markName = sortedMarkNames.get(sortedMarkNames.size() - 1);
71  		marksScope.put(ssml.getUnderlyingNode(), markName);
72  		XdmSequenceIterator iter = ssml.axisIterator(Axis.ANCESTOR);
73  		while (iter.hasNext()) {
74  			XdmNode parent = (XdmNode) iter.next();
75  			marksScope.put(parent.getUnderlyingNode(), markName);
76  		}
77  		if (ssml.getNodeName() != null
78  		        && markNode.getLocalName().equals(ssml.getNodeName().getLocalName())) {
79  			sortedMarkNames.add(ssml.getAttributeValue(markNameAttr));
80  		}
81  		iter = ssml.axisIterator(Axis.CHILD);
82  		while (iter.hasNext()) {
83  			findMarks((XdmNode) iter.next(), marksScope, sortedMarkNames);
84  		}
85  	}
86  
87  	private static void toXML(XdmNode ssml, TreeWriter tw, String markName,
88  	        Multimap<NodeInfo, String> marksScope) {
89  		if (!marksScope.containsEntry(ssml.getUnderlyingNode(), markName)) {
90  			return;
91  		}
92  		if (ssml.getNodeKind() == XdmNodeKind.TEXT) {
93  			tw.addText(ssml.getStringValue());
94  		} else if (ssml.getNodeKind() == XdmNodeKind.ELEMENT
95  		        && !markNode.getLocalName().equals(ssml.getNodeName().getLocalName())) {
96  			QName elementName = ssml.getNodeName();
97  			if (elementName != null) {
98  				tw.addStartElement(ssml);
99  				tw.addAttributes(ssml);
100 			}
101 
102 			XdmSequenceIterator iter = ssml.axisIterator(Axis.CHILD);
103 			while (iter.hasNext()) {
104 				toXML((XdmNode) iter.next(), tw, markName, marksScope);
105 			}
106 
107 			if (elementName != null) {
108 				tw.addEndElement();
109 			}
110 		}
111 	}
112 
113 	private static final QName markNode = new QName("mark");
114 	private static final QName markNameAttr = new QName("name");
115 }