Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/nwalsh/saxon/UnwrapLinksEmitter.java


1   package com.nwalsh.saxon;
2   
3   import java.util.Stack;
4   import org.xml.sax.*;
5   import org.w3c.dom.*;
6   import javax.xml.transform.TransformerException;
7   import com.icl.saxon.output.*;
8   import com.icl.saxon.om.*;
9   import com.icl.saxon.Controller;
10  import com.icl.saxon.tree.AttributeCollection;
11  
12  /**
13   * <p>Saxon extension to unwrap links in a result tree fragment.</p>
14   *
15   * <p>$Id: UnwrapLinksEmitter.java,v 1.1 2002/06/26 11:02:05 nwalsh Exp $</p>
16   *
17   * <p>Copyright (C) 2000, 2002 Norman Walsh.</p>
18   *
19   * <p>This class provides the guts of a
20   * <a href="http://saxon.sf.net/">Saxon 6.*</a>
21   * implementation of a link unwrapper.</p>
22   *
23   * <p>The general design is this: the stylesheets construct a result tree
24   * fragment for some environment. Then the result tree fragment
25   * is "replayed" through the UnwrapLinksEmitter; the UnwrapLinksEmitter
26   * builds a
27   * new result tree fragment from this event stream with top-level links unwrapped.
28   * That RTF is returned. Note that only a <i>single</i> level of unwrapping
29   * is performed. This is clearly a crude implementation.
30   * </p>
31   *
32   * <p><b>Change Log:</b></p>
33   * <dl>
34   * <dt>1.0</dt>
35   * <dd><p>Initial release.</p></dd>
36   * </dl>
37   *
38   * @author Norman Walsh
39   * <a href="mailto:ndw@nwalsh.com">ndw@nwalsh.com</a>
40   *
41   * @version $Id: UnwrapLinksEmitter.java,v 1.1 2002/06/26 11:02:05 nwalsh Exp $
42   *
43   */
44  public class UnwrapLinksEmitter extends CopyEmitter {
45    /** A stack for the preserving information about open elements. */
46    protected Stack elementStack = null;
47    protected Stack saveStack = null;
48  
49    /** The FO namespace name. */
50    protected static String foURI = "http://www.w3.org/1999/XSL/Format";
51  
52    /** The XHTML namespace name. */
53    protected static String xhURI = "http://www.w3.org/1999/xhtml";
54  
55    /** Is the stylesheet currently running an FO stylesheet? */
56    protected boolean foStylesheet = false;
57  
58    /** Are we currently in a link? How deep? */
59    protected int linkDepth = 0;
60    protected int skipDepth = 0;
61  
62    protected int htmlAFingerprint  = 0;
63    protected int xhtmlAFingerprint = 0;
64    protected boolean inSkip = false;
65    protected boolean tryAgain = false;
66  
67  
68    /** <p>Constructor for the UnwrapLinksEmitter.</p>
69     *
70     * @param namePool The name pool to use for constructing elements and attributes.
71     * @param foStylesheet Is this an FO stylesheet?
72     */
73    public UnwrapLinksEmitter(Controller controller,
74            NamePool namePool,
75            boolean foStylesheet) {
76      super(controller,namePool);
77      elementStack = new Stack();
78      this.foStylesheet = foStylesheet;
79  
80      htmlAFingerprint  = namePool.getFingerprint("", "a");
81      xhtmlAFingerprint = namePool.getFingerprint(xhURI, "a");
82    }
83  
84    /** Process start element events. */
85    public void startElement(int nameCode,
86           org.xml.sax.Attributes attributes,
87           int[] namespaces,
88           int nscount)
89      throws TransformerException {
90  
91      int thisFingerprint = namePool.getFingerprint(nameCode);
92      boolean isLink = (thisFingerprint == htmlAFingerprint
93            || thisFingerprint == xhtmlAFingerprint);
94  
95      if (isLink) {
96        linkDepth++;
97        tryAgain = tryAgain || inSkip;
98      }
99  
100     if (isLink && linkDepth > 1 && !inSkip) {
101       inSkip = true;
102 
103       // Close all the open elements
104       saveStack = new Stack();
105       Stack tempStack = new Stack();
106       while (!elementStack.empty()) {
107   StartElementInfo elem = (StartElementInfo) elementStack.pop();
108   rtfEmitter.endElement(elem.getNameCode());
109   saveStack.push(elem);
110   tempStack.push(elem);
111       }
112 
113       while (!tempStack.empty()) {
114   StartElementInfo elem = (StartElementInfo) tempStack.pop();
115   elementStack.push(elem);
116       }
117     }
118 
119     if (inSkip) {
120       skipDepth++;
121     } else {
122     }
123 
124     rtfEmitter.startElement(nameCode,attributes,namespaces,nscount);
125 
126     StartElementInfo sei = new StartElementInfo(nameCode, attributes,
127             namespaces, nscount);
128     elementStack.push(sei);
129   }
130 
131   /** Process end element events. */
132   public void endElement(int nameCode) throws TransformerException {
133     int thisFingerprint   = namePool.getFingerprint(nameCode);
134     boolean isLink = (thisFingerprint == htmlAFingerprint
135           || thisFingerprint == xhtmlAFingerprint);
136 
137     rtfEmitter.endElement(nameCode);
138     elementStack.pop();
139 
140     if (isLink) {
141       linkDepth--;
142     }
143 
144     if (inSkip) {
145       skipDepth--;
146       inSkip = (skipDepth > 0);
147       if (!inSkip) {
148   // Reopen all the ones we closed before...
149   while (!saveStack.empty()) {
150     StartElementInfo elem = (StartElementInfo) saveStack.pop();
151 
152     AttributeCollection attr = (AttributeCollection)elem.getAttributes();
153     AttributeCollection newAttr = new AttributeCollection(namePool);
154 
155     for (int acount = 0; acount < attr.getLength(); acount++) {
156       String localName = attr.getLocalName(acount);
157       String type = attr.getType(acount);
158       String value = attr.getValue(acount);
159       String uri = attr.getURI(acount);
160       String prefix = "";
161 
162       if (localName.indexOf(':') > 0) {
163         prefix = localName.substring(0, localName.indexOf(':'));
164         localName = localName.substring(localName.indexOf(':')+1);
165       }
166 
167       if (uri.equals("")
168     && ((foStylesheet
169          && localName.equals("id"))
170         || (!foStylesheet
171       && (localName.equals("id")
172           || localName.equals("name"))))) {
173         // skip this attribute
174       } else {
175         newAttr.addAttribute(prefix, uri, localName, type, value);
176       }
177     }
178 
179     rtfEmitter.startElement(elem.getNameCode(),
180           newAttr,
181           elem.getNamespaces(),
182           elem.getNSCount());
183   }
184       }
185     }
186   }
187 
188   public boolean tryAgain()
189     throws TransformerException {
190     return tryAgain;
191   }
192 
193   /**
194    * <p>A private class for maintaining the information required to call
195    * the startElement method.</p>
196    *
197    * <p>In order to close and reopen elements, information about those
198    * elements has to be maintained. This class is just the little record
199    * that we push on the stack to keep track of that info.</p>
200    */
201   private class StartElementInfo {
202     private int _nameCode;
203     org.xml.sax.Attributes _attributes;
204     int[] _namespaces;
205     int _nscount;
206 
207     public StartElementInfo(int nameCode,
208           org.xml.sax.Attributes attributes,
209           int[] namespaces,
210           int nscount) {
211       _nameCode = nameCode;
212       _attributes = attributes;
213       _namespaces = namespaces;
214       _nscount = nscount;
215     }
216 
217     public int getNameCode() {
218       return _nameCode;
219     }
220 
221     public org.xml.sax.Attributes getAttributes() {
222       return _attributes;
223     }
224 
225     public int[] getNamespaces() {
226       return _namespaces;
227     }
228 
229     public int getNSCount() {
230       return _nscount;
231     }
232   }
233 }