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 }