001    package fi.iki.hsivonen.xml;
002    
003    import java.util.Arrays;
004    
005    import org.xml.sax.Attributes;
006    import org.xml.sax.SAXException;
007    
008    import gnu.xml.pipeline.EventConsumer;
009    import gnu.xml.pipeline.EventFilter;
010    
011    public class HeadingShiftFilter extends EventFilter {
012    
013        /**
014         * The XHTML namespace URI
015         */
016        private final static String XHTML_NS = "http://www.w3.org/1999/xhtml";
017    
018        private static String[] HEADINGS = {
019            "h1",
020            "h2",
021            "h3",
022            "h4",
023            "h5",
024            "h6"
025        };
026        
027        private static String[] HEADING_TARGETS = {
028            "h1",
029            "h1",
030            "h1",
031            "h1",
032            "h1",
033            "h1",
034            "h2",
035            "h3",
036            "h4",
037            "h5",
038            "h6",
039            "h6",
040            "h6",
041            "h6",
042            "h6",
043            "h6"
044        };    
045    
046        private int offset;
047    
048        public HeadingShiftFilter(EventConsumer next, int offset) {
049            super(next);
050            setContentHandler(this);
051            if (offset > 5 || offset < -5) {
052                throw new IllegalArgumentException("Offset out of range.");
053            }
054            this.offset = offset;
055        }
056    
057        private String mapName(String name) {
058            int i = Arrays.binarySearch(HEADINGS, name);
059            if (i < 0) {
060                return name;
061            } else {
062                return HEADING_TARGETS[5 + i + offset];
063            }
064        }
065    
066        /**
067         * @see gnu.xml.pipeline.EventFilter#endElement(java.lang.String, java.lang.String, java.lang.String)
068         */
069        public void endElement(String ns, String local, String q) throws SAXException {
070            if (XHTML_NS.equals(ns)) {
071                local = mapName(local);
072            }
073            super.endElement(ns, local, local);
074        }
075    
076        /**
077         * @see gnu.xml.pipeline.EventFilter#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
078         */
079        public void startElement(String ns, String local, String q, Attributes attrs) throws SAXException {
080            if (XHTML_NS.equals(ns)) {
081                local = mapName(local);
082            }
083            super.startElement(ns, local, local, attrs);
084        }
085        
086    }