001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.markup.transformer; 018 019import java.io.FileNotFoundException; 020import java.io.StringReader; 021import java.io.StringWriter; 022 023import javax.xml.transform.Transformer; 024import javax.xml.transform.TransformerFactory; 025import javax.xml.transform.stream.StreamResult; 026import javax.xml.transform.stream.StreamSource; 027 028import org.apache.wicket.Application; 029import org.apache.wicket.Component; 030import org.apache.wicket.util.resource.IResourceStream; 031import org.apache.wicket.core.util.resource.locator.IResourceStreamLocator; 032 033 034/** 035 * A processor to XSLT transform the output generated by a Component. 036 * 037 * @see org.apache.wicket.markup.transformer.XsltOutputTransformerContainer 038 * @see org.apache.wicket.markup.transformer.XsltTransformerBehavior 039 * 040 * @author Juergen Donnerstag 041 */ 042public class XsltTransformer implements ITransformer 043{ 044 private final static String extension = "xsl"; 045 046 /** an optional XSL file */ 047 private final String xslFile; 048 049 /** 050 * Construct. 051 */ 052 public XsltTransformer() 053 { 054 xslFile = null; 055 } 056 057 /** 058 * Instead of using the default mechanism to determine the associated XSL file, it is given by 059 * the user. 060 * 061 * @param xslFile 062 * XSL input file path relative to the component's package. If the path does not end 063 * with <tt>.xsl</tt>, then it is considered as a basename and will be passed as-is 064 * to 065 * {@link IResourceStreamLocator#locate(Class, String, String, String, java.util.Locale, String, boolean)} 066 * . All stylesheets must have the <tt>.xsl</tt> extension. 067 */ 068 public XsltTransformer(final String xslFile) 069 { 070 if ((xslFile != null) && xslFile.endsWith(extension)) 071 { 072 this.xslFile = xslFile.substring(0, xslFile.length() - extension.length() - 1); 073 } 074 else 075 { 076 this.xslFile = xslFile; 077 } 078 } 079 080 /** 081 * Apply a XSL transformation to the markup generated by a component. The *.xsl resource must be 082 * located in the same path as the nearest parent with an associated markup and must have a 083 * filename equal to the component's id. 084 */ 085 @Override 086 public CharSequence transform(final Component component, final CharSequence output) 087 throws Exception 088 { 089 IResourceStream resourceStream = getResourceStream(component); 090 091 if (resourceStream == null) 092 { 093 throw new FileNotFoundException("Unable to find XSLT resource for " + 094 component.toString()); 095 } 096 097 try 098 { 099 // 1. Instantiate a TransformerFactory. 100 TransformerFactory tFactory = TransformerFactory.newInstance(); 101 102 // 2. Use the TransformerFactory to process the stylesheet Source 103 // and 104 // generate a Transformer. 105 Transformer transformer = tFactory.newTransformer(new StreamSource( 106 resourceStream.getInputStream())); 107 108 // 3. Use the Transformer to transform an XML Source and send the 109 // output to a Result object. 110 StringWriter writer = new StringWriter(); 111 transformer.transform(new StreamSource(new StringReader(output.toString())), 112 new StreamResult(writer)); 113 114 return writer.getBuffer(); 115 } 116 finally 117 { 118 resourceStream.close(); 119 } 120 } 121 122 /** 123 * Get the XSL resource stream 124 * 125 * @param component 126 * 127 * @return The XSLT file resource stream 128 */ 129 private IResourceStream getResourceStream(final Component component) 130 { 131 final IResourceStream resourceStream; 132 133 String filePath = xslFile; 134 if (filePath == null) 135 { 136 filePath = component.findParentWithAssociatedMarkup() 137 .getClass() 138 .getPackage() 139 .getName() 140 .replace('.', '/') + 141 "/" + component.getId(); 142 } 143 144 resourceStream = Application.get() 145 .getResourceSettings() 146 .getResourceStreamLocator() 147 .locate(getClass(), filePath, component.getStyle(), component.getVariation(), 148 component.getLocale(), XsltTransformer.extension, false); 149 150 return resourceStream; 151 } 152}