1 13 package mondrian.web.taglib; 14 15 import mondrian.olap.*; 16 17 import org.apache.log4j.Logger; 18 import org.w3c.dom.CDATASection ; 19 import org.w3c.dom.Document ; 20 import org.w3c.dom.Element ; 21 22 import javax.xml.parsers.DocumentBuilder ; 23 import javax.xml.parsers.DocumentBuilderFactory ; 24 import javax.xml.parsers.ParserConfigurationException ; 25 import javax.xml.transform.Templates ; 26 import javax.xml.transform.TransformerFactory ; 27 import javax.xml.transform.dom.DOMSource ; 28 import javax.xml.transform.stream.StreamResult ; 29 import javax.xml.transform.stream.StreamSource ; 30 31 import java.io.ByteArrayOutputStream ; 32 import java.io.OutputStream ; 33 import java.io.StringReader ; 34 import java.util.List ; 35 36 39 public class DOMBuilder { 40 private static final Logger LOGGER = Logger.getLogger(DOMBuilder.class); 41 42 Document factory; 43 Result result; 44 int dimCount; 45 46 protected DOMBuilder(Document factory, Result result) { 47 this.factory = factory; 48 this.result = result; 49 } 50 51 public static Document build(Result result) throws ParserConfigurationException { 52 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 53 dbf.setValidating(false); 54 dbf.setExpandEntityReferences(true); 55 DocumentBuilder db = dbf.newDocumentBuilder(); 56 Document doc = db.newDocument(); 57 Element table = build(doc, result); 58 doc.appendChild(table); 59 return doc; 61 } 62 63 public static Element build(Document factory, Result result) { 64 return new DOMBuilder(factory, result).build(); 65 } 66 67 private Element build() { 68 dimCount = result.getAxes().length; 69 Element mdxtable = factory.createElement("mdxtable"); 70 Element query = elem("query", mdxtable); 71 cdata(Util.unparse(result.getQuery()), query); 72 Element head = elem("head", mdxtable); 73 Element body = elem("body", mdxtable); 74 switch (dimCount) { 75 case 0: 76 buildRows0Dim(body); 77 break; 78 case 1: 79 buildColumns(head, result.getAxes()[0]); 80 buildRows1Dim(body); 81 break; 82 case 2: 83 buildColumns(head, result.getAxes()[0]); 84 buildRows2Dim(body, result.getAxes()[1]); 85 break; 86 default: 87 throw new IllegalArgumentException ("DOMBuilder requires 0, 1 or 2 dimensional result"); 88 } 89 Element slicers = elem("slicers", mdxtable); 90 buildSlicer(slicers); 91 return mdxtable; 92 } 93 94 abstract class AxisBuilder { 95 Member[] prevMembers; 96 Element [] prevElems; 97 int [] prevSpan; 98 99 Element parent; 100 List <Position> positions; 101 int levels; 102 103 AxisBuilder(Element parent, Axis axis) { 104 this.parent = parent; 105 106 positions = axis.getPositions(); 107 levels = positions.get(0).size(); 108 prevMembers = new Member[levels]; 109 prevElems = new Element [levels]; 110 prevSpan = new int[levels]; 111 } 112 113 abstract int getRowCount(); 114 abstract Element build(int rowIndex); 115 } 116 117 class RowBuilder extends AxisBuilder { 118 RowBuilder(Element parent, Axis axis) { 119 super(parent, axis); 120 } 121 122 Element build(int rowIndex) { 123 boolean even = (rowIndex % 2 != 0); Element row = elem("row", parent); 125 build(row, positions.get(rowIndex), even); 126 return row; 127 } 128 129 int getRowCount() { 130 return positions.size(); 131 } 132 133 private void build(Element row, List <Member> currentMembers, boolean even) { 134 for (int i = 0; i < levels; i++) { 135 Member currentMember = currentMembers.get(i); 136 Member prevMember = prevMembers[i]; 137 if (prevMember == null || !prevMember.equals(currentMember)) { 138 Element currentElem = createMemberElem("row-heading", row, currentMember); 139 if (even) 140 currentElem.setAttribute("style", "even"); 141 else 142 currentElem.setAttribute("style", "odd"); 143 prevMembers[i] = currentMember; 144 prevElems[i] = currentElem; 145 prevSpan[i] = 1; 146 for (int j = i + 1; j < levels; j++) 147 prevMembers[j] = null; 148 } 149 else { 150 Element prevElem = prevElems[i]; 151 prevElem.setAttribute("style", "span"); 152 prevSpan[i] += 1; 153 prevElem.setAttribute("rowspan", Integer.toString(prevSpan[i])); 154 } 155 } 156 } 157 } 158 159 160 class ColumnBuilder extends AxisBuilder { 161 ColumnBuilder(Element parent, Axis axis) { 162 super(parent, axis); 163 } 164 165 int getRowCount() { 166 return levels; 167 } 168 169 Element build(int rowIndex) { 170 Element row = elem("row", parent); 171 if (dimCount > 1 && rowIndex == 0) 172 buildCornerElement(row); 173 build(row, rowIndex); 174 return row; 175 } 176 177 private void build(Element row, int rowIndex) { 178 for (int i = 0; i < levels; i++) 179 prevMembers[i] = null; 180 181 for (int i = 0; i < positions.size(); i++) { 182 Position position = positions.get(i); 183 185 for (int j = 0; j < rowIndex - 1; j++) { 186 Member currentMember = position.get(j); 187 if (prevMembers[j] == null || !prevMembers[j].equals(currentMember)) { 188 prevMembers[j] = currentMember; 189 for (int k = j + 1; k < levels; k++) 190 prevMembers[j] = null; 191 } 192 } 193 194 Member currentMember = position.get(rowIndex); 195 Member prevMember = prevMembers[rowIndex]; 196 if (prevMember == null || !prevMember.equals(currentMember)) { 197 Element currentElem = createMemberElem("column-heading", row, currentMember); 198 prevMembers[rowIndex] = currentMember; 199 prevElems[rowIndex] = currentElem; 200 prevSpan[rowIndex] = 1; 201 for (int j = rowIndex + 1; j < levels; j++) 202 prevMembers[j] = null; 203 } 204 else { 205 Element prevElem = prevElems[rowIndex]; 206 prevElem.setAttribute("style", "span"); 207 prevSpan[rowIndex] += 1; 208 prevElem.setAttribute("colspan", Integer.toString(prevSpan[rowIndex])); 209 } 210 } 211 } 212 213 void buildCornerElement(Element row) { 214 Element corner = elem("corner", row); 215 corner.setAttribute("rowspan", Integer.toString(result.getAxes()[0].getPositions().get(0).size())); 216 corner.setAttribute("colspan", Integer.toString(result.getAxes()[1].getPositions().get(0).size())); 217 } 218 } 219 220 221 private void buildRows2Dim(Element parent, Axis axis) { 222 RowBuilder rb = new RowBuilder(parent, axis); 223 final int N = rb.getRowCount(); 224 int[] cellIndex = new int[2]; 225 for (int i = 0; i < N; i++) { 226 Element row = rb.build(i); 227 boolean even = (i % 2 != 0); cellIndex[1] = i; 229 buildCells(row, cellIndex, even); 230 } 231 } 232 233 private void buildRows1Dim(Element parent) { 234 int[] cellIndex = new int[1]; 235 Element row = elem("row", parent); 236 buildCells(row, cellIndex, false); 237 } 238 239 private void buildColumns(Element parent, Axis axis) { 240 ColumnBuilder cb = new ColumnBuilder(parent, axis); 241 final int N = cb.getRowCount(); 242 for (int i = 0; i < N; i++) { 243 Element row = cb.build(i); 244 } 245 } 246 247 248 private void buildCells(Element row, int[] cellIndex, boolean even) { 249 int columns = result.getAxes()[0].getPositions().size(); 250 for (int i = 0; i < columns; i++) { 251 cellIndex[0] = i; 252 Cell cell = result.getCell(cellIndex); 253 buildCell(cell, row, even); 254 } 255 } 256 257 private void buildCell(Cell cell, Element row, boolean even) { 258 Element cellElem = elem("cell", row); 259 String s = cell.getFormattedValue(); 260 if (s == null || s.length() == 0 || s.equals("(null)")) 261 s = "\u00a0"; cellElem.setAttribute("value", s); 263 cellElem.setAttribute("style", even ? "even" : "odd"); 264 } 265 266 private void buildRows0Dim(Element parent) { 267 int[] cellIndex = new int[0]; 268 Element row = elem("row", parent); 269 Cell cell = result.getCell(cellIndex); 270 buildCell(cell, row, false); 271 } 272 273 private void buildSlicer(Element parent) { 274 List <Position> positions = result.getSlicerAxis().getPositions(); 275 for (int i = 0; i < positions.size(); i++) { 276 Position position = positions.get(i); 277 if (position.size() > 0) { 278 Element el = elem("position", parent); 279 for (int j = 0; j < position.size(); j++) { 280 createMemberElem("member", el, position.get(j)); 281 } 282 } 283 } 284 } 285 286 private Element createMemberElem(String name, Element parent, Member m) { 287 Element e = elem(name, parent); 288 e.setAttribute("caption", m.getCaption()); 289 e.setAttribute("depth", Integer.toString(m.getLevel().getDepth())); 290 e.setAttribute("uname", m.getUniqueName()); 293 e.setAttribute("colspan", "1"); 294 e.setAttribute("rowspan", "1"); 295 296 addMemberProperties(m, e); 298 299 return e; 300 } 301 302 private void addMemberProperties(Member m, Element e) { 303 Property[] props = m.getLevel().getProperties(); 304 if (props != null) { 305 for (int i = 0; i < props.length; i++) { 306 String propName = props[i].getName(); 307 String propValue = "" + m.getPropertyValue(propName); 308 Element propElem = elem("property", e); 309 propElem.setAttribute("name", propName); 310 propElem.setAttribute("value", propValue); 311 } 312 } 313 } 314 315 private Element elem(String name, Element parent) { 316 Element elem = factory.createElement(name); 317 parent.appendChild(elem); 318 return elem; 319 } 320 321 private Object cdata(String content, Element parent) { 322 CDATASection section = factory.createCDATASection(content); 323 parent.appendChild(section); 324 return section; 325 } 326 327 private static final String PRETTY_PRINTER = "" 328 + "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" 329 + "<xsl:output method=\"xml\" indent=\"yes\"/>\n" 330 + "<xsl:template match=\"*|@*\">\n" 331 + " <xsl:copy>\n" 332 + " <xsl:apply-templates select=\"*|@*\"/>\n" 333 + " </xsl:copy>\n" 334 + "</xsl:template>\n" 335 + "</xsl:stylesheet>\n"; 336 337 public static void debug(Document doc) { 338 try { 339 TransformerFactory tf = TransformerFactory.newInstance(); 340 StringReader input = new StringReader (PRETTY_PRINTER); 341 Templates templates = tf.newTemplates(new StreamSource (input)); 343 OutputStream result = new ByteArrayOutputStream (); 344 templates.newTransformer().transform(new DOMSource (doc), new StreamResult (result)); 345 LOGGER.debug(result.toString()); 346 } 347 catch (Exception e) { 348 e.printStackTrace(); 349 } 350 } 351 352 } 353 354 | Popular Tags |