001package org.apache.maven.doxia.sink.impl; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.util.Enumeration; 023import java.util.Arrays; 024 025import javax.swing.text.AttributeSet; 026import javax.swing.text.MutableAttributeSet; 027 028import org.apache.maven.doxia.markup.Markup; 029import org.apache.maven.doxia.sink.SinkEventAttributes; 030 031/** 032 * Collection of common utility methods for sinks. 033 * 034 * @author ltheussl 035 * @version $Id$ 036 * @since 1.1 037 */ 038public class SinkUtils 039{ 040 041 /** Do not instantiate. */ 042 private SinkUtils() 043 { 044 // Utility class 045 } 046 047 /** 048 * The set of base attributes. 049 */ 050 public static final String[] SINK_BASE_ATTRIBUTES = 051 { 052 SinkEventAttributes.CLASS, SinkEventAttributes.ID, SinkEventAttributes.LANG, 053 SinkEventAttributes.STYLE, SinkEventAttributes.TITLE 054 }; 055 056 /** 057 * The attributes that are supported for the br tag. 058 */ 059 public static final String[] SINK_BR_ATTRIBUTES = 060 { 061 SinkEventAttributes.CLASS, SinkEventAttributes.ID, 062 SinkEventAttributes.STYLE, SinkEventAttributes.TITLE 063 }; 064 065 /** 066 * The attributes that are supported for the <img> tag. 067 */ 068 public static final String[] SINK_IMG_ATTRIBUTES; 069 070 /** 071 * The attributes that are supported for the section tags, like <p>, <h2>, <div>. 072 */ 073 public static final String[] SINK_SECTION_ATTRIBUTES; 074 075 /** 076 * The attributes that are supported for the <div> and <pre> tags. 077 */ 078 public static final String[] SINK_VERBATIM_ATTRIBUTES; 079 080 /** 081 * The attributes that are supported for the <hr> tag. 082 */ 083 public static final String[] SINK_HR_ATTRIBUTES; 084 085 /** 086 * The attributes that are supported for the <a> tag. 087 */ 088 public static final String[] SINK_LINK_ATTRIBUTES; 089 090 /** 091 * The attributes that are supported for the <table> tag. 092 */ 093 public static final String[] SINK_TABLE_ATTRIBUTES; 094 095 /** 096 * The attributes that are supported for the <td> and <th> tags. 097 */ 098 public static final String[] SINK_TD_ATTRIBUTES; 099 100 /** 101 * The attributes that are supported for the <tr> tag. 102 */ 103 public static final String[] SINK_TR_ATTRIBUTES; 104 105 private static final String[] IMG_ATTRIBUTES = 106 { 107 SinkEventAttributes.ALIGN, SinkEventAttributes.ALT, SinkEventAttributes.BORDER, 108 SinkEventAttributes.HEIGHT, SinkEventAttributes.HSPACE, SinkEventAttributes.ISMAP, 109 SinkEventAttributes.SRC, SinkEventAttributes.USEMAP, SinkEventAttributes.VSPACE, 110 SinkEventAttributes.WIDTH 111 }; 112 113 private static final String[] HR_ATTRIBUTES = 114 { 115 SinkEventAttributes.ALIGN, SinkEventAttributes.NOSHADE, SinkEventAttributes.SIZE, 116 SinkEventAttributes.WIDTH 117 }; 118 119 private static final String[] LINK_ATTRIBUTES = 120 { 121 SinkEventAttributes.CHARSET, SinkEventAttributes.COORDS, SinkEventAttributes.HREF, 122 SinkEventAttributes.HREFLANG, SinkEventAttributes.REL, SinkEventAttributes.REV, 123 SinkEventAttributes.SHAPE, SinkEventAttributes.TARGET, SinkEventAttributes.TYPE 124 }; 125 126 private static final String[] TABLE_ATTRIBUTES = 127 { 128 SinkEventAttributes.ALIGN, SinkEventAttributes.BGCOLOR, SinkEventAttributes.BORDER, 129 SinkEventAttributes.CELLPADDING, SinkEventAttributes.CELLSPACING, SinkEventAttributes.FRAME, 130 SinkEventAttributes.RULES, SinkEventAttributes.SUMMARY, SinkEventAttributes.WIDTH 131 }; 132 133 private static final String[] TABLE_CELL_ATTRIBUTES = 134 { 135 SinkEventAttributes.ABBRV, SinkEventAttributes.ALIGN, SinkEventAttributes.AXIS, 136 SinkEventAttributes.BGCOLOR, SinkEventAttributes.COLSPAN, SinkEventAttributes.HEADERS, 137 SinkEventAttributes.HEIGHT, SinkEventAttributes.NOWRAP, SinkEventAttributes.ROWSPAN, 138 SinkEventAttributes.SCOPE, SinkEventAttributes.VALIGN, SinkEventAttributes.WIDTH 139 }; 140 141 static 142 { 143 SINK_IMG_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, IMG_ATTRIBUTES ); 144 SINK_SECTION_ATTRIBUTES = 145 join( SINK_BASE_ATTRIBUTES, new String[] {SinkEventAttributes.ALIGN} ); 146 SINK_VERBATIM_ATTRIBUTES = 147 join( SINK_BASE_ATTRIBUTES, 148 new String[] {SinkEventAttributes.ALIGN, SinkEventAttributes.DECORATION, SinkEventAttributes.WIDTH} ); 149 SINK_HR_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, HR_ATTRIBUTES ); 150 SINK_LINK_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, LINK_ATTRIBUTES ); 151 SINK_TABLE_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, TABLE_ATTRIBUTES ); 152 SINK_TR_ATTRIBUTES = 153 join( SINK_BASE_ATTRIBUTES, 154 new String[] {SinkEventAttributes.ALIGN, SinkEventAttributes.BGCOLOR, SinkEventAttributes.VALIGN} ); 155 SINK_TD_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, TABLE_CELL_ATTRIBUTES ); 156 } 157 158 private static String[] join( String[] a, String[] b ) 159 { 160 String[] temp = new String[a.length + b.length]; 161 System.arraycopy( a, 0, temp, 0, a.length ); 162 System.arraycopy( b, 0, temp, a.length, b.length ); 163 164 Arrays.sort( temp ); // necessary for binary searches in filterAttributes() 165 166 return temp; 167 } 168 169 /** 170 * Utility method to get an AttributeSet as a String. 171 * The resulting String is in the form ' name1="value1" name2="value2" ...', 172 * ie it can be appended directly to an xml start tag. Attribute values that are itself 173 * AttributeSets are ignored unless the Attribute name is SinkEventAttributeSet.STYLE, 174 * in which case they are written as outlined at 175 * {@link org.apache.maven.doxia.sink.SinkEventAttributes#STYLE SinkEventAttributes.STYLE}. 176 * All other keys and values are written as Strings. 177 * 178 * @param att The AttributeSet. May be null, in which case an empty String is returned. 179 * @return the AttributeSet as a String in a form that can be appended to an xml start tag. 180 */ 181 public static String getAttributeString( AttributeSet att ) 182 { 183 if ( att == null ) 184 { 185 return ""; 186 } 187 188 StringBuilder sb = new StringBuilder(); 189 190 Enumeration<?> names = att.getAttributeNames(); 191 192 while ( names.hasMoreElements() ) 193 { 194 Object key = names.nextElement(); 195 Object value = att.getAttribute( key ); 196 197 if ( value instanceof AttributeSet ) 198 { 199 // Other AttributeSets are ignored 200 if ( SinkEventAttributes.STYLE.equals( key.toString() ) ) 201 { 202 sb.append( Markup.SPACE ).append( key.toString() ).append( Markup.EQUAL ) 203 .append( Markup.QUOTE ).append( asCssString( (AttributeSet) value ) ) 204 .append( Markup.QUOTE ); 205 } 206 } 207 else 208 { 209 sb.append( Markup.SPACE ).append( key.toString() ).append( Markup.EQUAL ) 210 .append( Markup.QUOTE ).append( value.toString() ).append( Markup.QUOTE ); 211 } 212 } 213 214 return sb.toString(); 215 } 216 217 private static String asCssString( AttributeSet att ) 218 { 219 StringBuilder sb = new StringBuilder(); 220 221 Enumeration<?> names = att.getAttributeNames(); 222 223 while ( names.hasMoreElements() ) 224 { 225 Object key = names.nextElement(); 226 Object value = att.getAttribute( key ); 227 228 // don't go recursive 229 if ( !( value instanceof AttributeSet ) ) 230 { 231 sb.append( key.toString() ).append( Markup.COLON ) 232 .append( Markup.SPACE ).append( value.toString() ); 233 234 if ( names.hasMoreElements() ) 235 { 236 sb.append( Markup.SEMICOLON ).append( Markup.SPACE ); 237 } 238 } 239 } 240 241 return sb.toString(); 242 } 243 244 /** 245 * Filters the given AttributeSet. 246 * Removes all attributes whose name (key) is not contained in the sorted array valids. 247 * 248 * @param attributes The AttributeSet to filter. The String values of Attribute names 249 * are compared to the elements of the valids array. 250 * @param valids a sorted array of attribute names that are to be kept in the resulting AttributeSet. 251 * <b>Note:</b> a binary search is employed, so the array has to be sorted for correct results. 252 * @return A filtered MutableAttributeSet object. Returns null if the input AttributeSet is null. 253 * If the array of valids is either null or empty, an empty AttributeSet is returned. 254 */ 255 public static MutableAttributeSet filterAttributes( AttributeSet attributes, String[] valids ) 256 { 257 if ( attributes == null ) 258 { 259 return null; 260 } 261 262 if ( valids == null || valids.length == 0 ) 263 { 264 return new SinkEventAttributeSet( 0 ); 265 } 266 267 MutableAttributeSet atts = new SinkEventAttributeSet( attributes.getAttributeCount() ); 268 269 Enumeration<?> names = attributes.getAttributeNames(); 270 271 while ( names.hasMoreElements() ) 272 { 273 String key = names.nextElement().toString(); 274 275 if ( Arrays.binarySearch( valids, key ) >= 0 ) 276 { 277 atts.addAttribute( key, attributes.getAttribute( key ) ); 278 } 279 } 280 281 return atts; 282 } 283}