001/* 002 * Copyright 2017 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.odfsync.cdmfr.transformers; 017 018import java.io.IOException; 019import java.util.Map; 020 021import org.apache.avalon.framework.parameters.Parameters; 022import org.apache.cocoon.ProcessingException; 023import org.apache.cocoon.environment.SourceResolver; 024import org.apache.cocoon.transformation.AbstractTransformer; 025import org.apache.commons.lang.ArrayUtils; 026import org.apache.commons.lang.StringUtils; 027import org.xml.sax.Attributes; 028import org.xml.sax.SAXException; 029import org.xml.sax.helpers.AttributesImpl; 030 031/** 032 * This transformer provides a valid docbook output for rich-text issued from CDM-fr: 033 * <ul> 034 * <li>- no character (break line, bold, text, ...) outside a <code>para</code> element</li> 035 * <li>- no <code>title</code> outside a <code>section</code> element</li> 036 * </ul> 037 */ 038public class CDMRichTextTransformer extends AbstractTransformer 039{ 040 private static final String __TAG_ARTICLE = "article"; 041 private static final String __TAG_SECTION = "section"; 042 private static final String __TAG_TITLE = "title"; 043 044 private static final String[] __CHARACTER_TYPES = new String[] {"emphasis", "phrase", "link"}; 045 private static final String[] __BLOC_TYPES = new String[] {"itemizedlist", "para", "orderedlist", "table"}; 046 047 int _sectionCount; 048 int _titleCount; 049 050 boolean _inDocbook; 051 boolean _inBlock; 052 boolean _inSection; 053 boolean _inTitle; 054 055 boolean _startPara; 056 057 private void _init () 058 { 059 _sectionCount = 0; 060 _titleCount = 0; 061 062 _inDocbook = true; 063 _inBlock = false; 064 _inSection = false; 065 _inTitle = false; 066 067 _startPara = false; 068 } 069 070 @Override 071 public void startElement(String uri, String localName, String raw, Attributes attrs) throws SAXException 072 { 073 if (__TAG_ARTICLE.equals(localName)) 074 { 075 _init(); 076 } 077 078 if (_inDocbook && __TAG_SECTION.equals(localName)) 079 { 080 _sectionCount++; 081 082 if (_startPara) 083 { 084 // End <para> 085 _endParaElement(); 086 } 087 } 088 089 if (_inDocbook && __TAG_TITLE.equals(localName)) 090 { 091 _titleCount++; 092 _inTitle = true; 093 094 if (_titleCount > _sectionCount) 095 { 096 if (_startPara) 097 { 098 // End <para> 099 _endParaElement(); 100 } 101 102 _sectionCount++; 103 super.startElement("", "section", "section", new AttributesImpl()); 104 } 105 } 106 107 if (ArrayUtils.contains(__BLOC_TYPES, localName)) 108 { 109 if (_startPara) 110 { 111 // End <para> 112 _endParaElement(); 113 } 114 _inBlock = true; 115 } 116 117 // Find <emphasis>, <phrase> or <link> without outside a <listItem> or <para> parent 118 if (ArrayUtils.contains(__CHARACTER_TYPES, localName) && !_inBlock) 119 { 120 // Insert <para> element 121 _startParaElement(); 122 } 123 124 super.startElement(uri, localName, raw, attrs); 125 } 126 127 @Override 128 public void endElement(String uri, String localName, String raw) throws SAXException 129 { 130 if (__TAG_ARTICLE.equals(localName)) 131 { 132 _inDocbook = false; 133 134 if (_startPara) 135 { 136 // End <para> 137 _endParaElement(); 138 } 139 140 while (_sectionCount != 0) 141 { 142 contentHandler.endElement("", "section", "section"); 143 _sectionCount--; 144 _titleCount--; 145 } 146 } 147 148 if (__TAG_TITLE.equals(localName)) 149 { 150 _inTitle = false; 151 } 152 153 if (__TAG_SECTION.equals(localName)) 154 { 155 _sectionCount--; 156 _titleCount--; 157 158 if (_startPara) 159 { 160 // End <para> 161 _endParaElement(); 162 } 163 } 164 165 if (_inDocbook && ArrayUtils.contains(__BLOC_TYPES, localName)) 166 { 167 _inBlock = false; 168 } 169 170 super.endElement(uri, localName, raw); 171 } 172 173 @Override 174 public void characters(char[] c, int start, int len) throws SAXException 175 { 176 boolean isBlank = StringUtils.isBlank(new String (c, start, len)); 177 178 if (!isBlank && _inDocbook && !_inBlock && !_inTitle) 179 { 180 _startParaElement(); 181 } 182 super.characters(c, start, len); 183 } 184 185 private void _startParaElement () throws SAXException 186 { 187 _startPara = true; 188 _inBlock = true; 189 contentHandler.startElement("", "para", "para", new AttributesImpl()); 190 } 191 192 private void _endParaElement () throws SAXException 193 { 194 _startPara = false; 195 _inBlock = false; 196 contentHandler.endElement("", "para", "para"); 197 } 198 199 @Override 200 public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException 201 { 202 // Nothing 203 } 204}