View Javadoc

1   package org.apache.maven.doxia.sink;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Enumeration;
23  import java.util.Arrays;
24  
25  import javax.swing.text.AttributeSet;
26  import javax.swing.text.MutableAttributeSet;
27  
28  import org.apache.maven.doxia.markup.Markup;
29  
30  /**
31   * Collection of common utility methods for sinks.
32   *
33   * @author ltheussl
34   * @version $Id: SinkUtils.java 1185112 2011-10-17 11:33:00Z ltheussl $
35   * @since 1.1
36   */
37  public class SinkUtils
38  {
39  
40      /** Do not instantiate. */
41      private SinkUtils()
42      {
43          // Utility class
44      }
45  
46      /**
47       * The set of base attributes.
48       */
49      public static final String[] SINK_BASE_ATTRIBUTES =
50      {
51          SinkEventAttributes.CLASS, SinkEventAttributes.ID, SinkEventAttributes.LANG,
52          SinkEventAttributes.STYLE, SinkEventAttributes.TITLE
53      };
54  
55      /**
56       * The attributes that are supported for the br tag.
57       */
58      public static final String[] SINK_BR_ATTRIBUTES =
59      {
60          SinkEventAttributes.CLASS, SinkEventAttributes.ID,
61          SinkEventAttributes.STYLE, SinkEventAttributes.TITLE
62      };
63  
64      /**
65       * The attributes that are supported for the <img> tag.
66       */
67      public static final String[] SINK_IMG_ATTRIBUTES;
68  
69      /**
70       * The attributes that are supported for the section tags, like <p>, <h2>, <div>.
71       */
72      public static final String[] SINK_SECTION_ATTRIBUTES;
73  
74      /**
75       * The attributes that are supported for the <div> and <pre> tags.
76       */
77      public static final String[] SINK_VERBATIM_ATTRIBUTES;
78  
79      /**
80       * The attributes that are supported for the <hr> tag.
81       */
82      public static final String[] SINK_HR_ATTRIBUTES;
83  
84      /**
85       * The attributes that are supported for the <a> tag.
86       */
87      public static final String[] SINK_LINK_ATTRIBUTES;
88  
89      /**
90       * The attributes that are supported for the <table> tag.
91       */
92      public static final String[] SINK_TABLE_ATTRIBUTES;
93  
94      /**
95       * The attributes that are supported for the <td> and <th> tags.
96       */
97      public static final String[] SINK_TD_ATTRIBUTES;
98  
99      /**
100      * The attributes that are supported for the <tr> tag.
101      */
102     public static final String[] SINK_TR_ATTRIBUTES;
103 
104     private static final String[] IMG_ATTRIBUTES =
105     {
106         SinkEventAttributes.ALIGN, SinkEventAttributes.ALT, SinkEventAttributes.BORDER,
107         SinkEventAttributes.HEIGHT, SinkEventAttributes.HSPACE, SinkEventAttributes.ISMAP,
108         SinkEventAttributes.SRC, SinkEventAttributes.USEMAP, SinkEventAttributes.VSPACE,
109         SinkEventAttributes.WIDTH
110     };
111 
112     private static final String[] HR_ATTRIBUTES =
113     {
114         SinkEventAttributes.ALIGN, SinkEventAttributes.NOSHADE, SinkEventAttributes.SIZE,
115         SinkEventAttributes.WIDTH
116     };
117 
118     private static final String[] LINK_ATTRIBUTES =
119     {
120         SinkEventAttributes.CHARSET, SinkEventAttributes.COORDS, SinkEventAttributes.HREF,
121         SinkEventAttributes.HREFLANG, SinkEventAttributes.REL, SinkEventAttributes.REV,
122         SinkEventAttributes.SHAPE, SinkEventAttributes.TARGET, SinkEventAttributes.TYPE
123     };
124 
125     private static final String[] TABLE_ATTRIBUTES =
126     {
127         SinkEventAttributes.ALIGN, SinkEventAttributes.BGCOLOR, SinkEventAttributes.BORDER,
128         SinkEventAttributes.CELLPADDING, SinkEventAttributes.CELLSPACING, SinkEventAttributes.FRAME,
129         SinkEventAttributes.RULES, SinkEventAttributes.SUMMARY, SinkEventAttributes.WIDTH
130     };
131 
132     private static final String[] TABLE_CELL_ATTRIBUTES =
133     {
134         SinkEventAttributes.ABBRV, SinkEventAttributes.ALIGN, SinkEventAttributes.AXIS,
135         SinkEventAttributes.BGCOLOR, SinkEventAttributes.COLSPAN, SinkEventAttributes.HEADERS,
136         SinkEventAttributes.HEIGHT, SinkEventAttributes.NOWRAP, SinkEventAttributes.ROWSPAN,
137         SinkEventAttributes.SCOPE, SinkEventAttributes.VALIGN, SinkEventAttributes.WIDTH
138     };
139 
140     static
141     {
142         SINK_IMG_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, IMG_ATTRIBUTES );
143         SINK_SECTION_ATTRIBUTES =
144                 join( SINK_BASE_ATTRIBUTES, new String[] {SinkEventAttributes.ALIGN} );
145         SINK_VERBATIM_ATTRIBUTES =
146                 join( SINK_BASE_ATTRIBUTES,
147                 new String[] {SinkEventAttributes.ALIGN, SinkEventAttributes.DECORATION, SinkEventAttributes.WIDTH} );
148         SINK_HR_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, HR_ATTRIBUTES );
149         SINK_LINK_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, LINK_ATTRIBUTES );
150         SINK_TABLE_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, TABLE_ATTRIBUTES );
151         SINK_TR_ATTRIBUTES =
152                 join( SINK_BASE_ATTRIBUTES,
153                 new String[] {SinkEventAttributes.ALIGN, SinkEventAttributes.BGCOLOR, SinkEventAttributes.VALIGN} );
154         SINK_TD_ATTRIBUTES = join( SINK_BASE_ATTRIBUTES, TABLE_CELL_ATTRIBUTES );
155     }
156 
157     private static String[] join( String[] a, String[] b )
158     {
159         String[] temp = new String[a.length + b.length];
160         System.arraycopy( a, 0, temp, 0, a.length );
161         System.arraycopy( b, 0, temp, a.length, b.length );
162 
163         Arrays.sort( temp ); // necessary for binary searches in filterAttributes()
164 
165         return temp;
166     }
167 
168     /**
169      * Utility method to get an AttributeSet as a String.
170      * The resulting String is in the form ' name1="value1" name2="value2" ...',
171      * ie it can be appended directly to an xml start tag. Attribute values that are itself
172      * AttributeSets are ignored unless the Attribute name is SinkEventAttributeSet.STYLE,
173      * in which case they are written as outlined at
174      * {@link org.apache.maven.doxia.sink.SinkEventAttributes#STYLE SinkEventAttributes.STYLE}.
175      * All other keys and values are written as Strings.
176      *
177      * @param att The AttributeSet. May be null, in which case an empty String is returned.
178      * @return the AttributeSet as a String in a form that can be appended to an xml start tag.
179      */
180     public static String getAttributeString( AttributeSet att )
181     {
182         if ( att == null )
183         {
184             return "";
185         }
186 
187         StringBuilder sb = new StringBuilder();
188 
189         Enumeration<?> names = att.getAttributeNames();
190 
191         while ( names.hasMoreElements() )
192         {
193             Object key = names.nextElement();
194             Object value = att.getAttribute( key );
195 
196             if ( value instanceof AttributeSet )
197             {
198                 // Other AttributeSets are ignored
199                 if ( SinkEventAttributes.STYLE.equals( key.toString() ) )
200                 {
201                     sb.append( Markup.SPACE ).append( key.toString() ).append( Markup.EQUAL )
202                         .append( Markup.QUOTE ).append( asCssString( (AttributeSet) value ) )
203                         .append( Markup.QUOTE );
204                 }
205             }
206             else
207             {
208                 sb.append( Markup.SPACE ).append( key.toString() ).append( Markup.EQUAL )
209                     .append( Markup.QUOTE ).append( value.toString() ).append( Markup.QUOTE );
210             }
211         }
212 
213         return sb.toString();
214     }
215 
216     private static String asCssString( AttributeSet att )
217     {
218         StringBuilder sb = new StringBuilder();
219 
220         Enumeration<?> names = att.getAttributeNames();
221 
222         while ( names.hasMoreElements() )
223         {
224             Object key = names.nextElement();
225             Object value = att.getAttribute( key );
226 
227             // don't go recursive
228             if ( !( value instanceof AttributeSet ) )
229             {
230                 sb.append( key.toString() ).append( Markup.COLON )
231                     .append( Markup.SPACE ).append( value.toString() );
232 
233                 if ( names.hasMoreElements() )
234                 {
235                     sb.append( Markup.SEMICOLON ).append( Markup.SPACE );
236                 }
237             }
238         }
239 
240         return sb.toString();
241     }
242 
243     /**
244      * Filters the given AttributeSet.
245      * Removes all attributes whose name (key) is not contained in the sorted array valids.
246      *
247      * @param attributes The AttributeSet to filter. The String values of Attribute names
248      * are compared to the elements of the valids array.
249      * @param valids a sorted array of attribute names that are to be kept in the resulting AttributeSet.
250      *      <b>Note:</b> a binary search is employed, so the array has to be sorted for correct results.
251      * @return A filtered MutableAttributeSet object. Returns null if the input AttributeSet is null.
252      *      If the array of valids is either null or empty, an empty AttributeSet is returned.
253      */
254     public static MutableAttributeSet filterAttributes( AttributeSet attributes, String[] valids )
255     {
256         if ( attributes == null )
257         {
258             return null;
259         }
260 
261         if ( valids == null || valids.length == 0 )
262         {
263             return new SinkEventAttributeSet( 0 );
264         }
265 
266         MutableAttributeSet atts = new SinkEventAttributeSet( attributes.getAttributeCount() );
267 
268         Enumeration<?> names = attributes.getAttributeNames();
269 
270         while ( names.hasMoreElements() )
271         {
272             String key = names.nextElement().toString();
273 
274             if ( Arrays.binarySearch( valids, key ) >= 0 )
275             {
276                 atts.addAttribute( key, attributes.getAttribute( key ) );
277             }
278         }
279 
280         return atts;
281     }
282 }