001: package com.xoetrope.template;
002:
003: import java.io.File;
004: import java.io.FileOutputStream;
005: import java.io.FileReader;
006: import java.io.FileWriter;
007: import java.io.IOException;
008: import java.util.Enumeration;
009: import java.util.Vector;
010: import net.xoetrope.xml.XmlElement;
011: import net.xoetrope.xml.XmlSource;
012: import net.xoetrope.xml.jaxp.JaxpXmlWriter;
013: import net.xoetrope.xml.nanoxml.NanoXmlElement;
014: import net.xoetrope.xml.nanoxml.NanoXmlWriter;
015: import net.xoetrope.xui.XProject;
016:
017: /**
018: * <p>A template processor for parameterized XML files.</p>
019: * <p>Individual elements can be
020: * excludes/included in the copy of the template file by adding the 'te_include'
021: * attribute to those elements. The attribute value is then used to query the
022: * template engine's includes method. The method's return value dictates whether
023: * or not the element is included.</p>
024: * <p>
025: * A <code><Repeat></code> element can be included so that elements can be
026: * repeated. The element is repeated while the <code>while</code> attribute
027: * evaluates to <code>true</code>. The same evaluation mechansim as is used
028: * within XUI's page is employed and the <code>XTemplateEngine</code>'s
029: * subclasses can implement the callback methods. As each item is included the
030: * loop counter is processed and this value can be used with expressoions as the
031: * value <code>{N}</code>. Each attribute is evaluated so that the necessary
032: * substitutions can be made. This a field name by be coded as
033: * <code>name="addressEdit{N}"</code> such that the name is different for each
034: * element included.
035: * </p>
036: *
037: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
038: * the GNU Public License (GPL), please see license.txt for more details. If
039: * you make commercial use of this software you must purchase a commercial
040: * license from Xoetrope.</p>
041: * <p> $Revision: 1.6 $</p>
042: */
043: public class XXmlTemplateProcessor extends XTemplateProcessor {
044: private XmlElement xml;
045:
046: public XXmlTemplateProcessor(XProject proj, XTemplateEngine te) {
047: super (proj, te);
048: }
049:
050: public boolean process(String sourceName, String targetName,
051: int processingType) {
052: sourceFile = new File(sourceFileName = sourceName);
053: targetFile = new File(targetFileName = targetName);
054:
055: boolean rc = loadFile();
056: if (rc) {
057: rc &= includeElements(xml);
058: rc &= excludeElements(xml);
059: rc &= repeatElements(null, xml);
060: rc &= insertAttribute(xml);
061: rc &= copyResources(xml);
062:
063: if (rc)
064: rc = saveFile();
065: }
066:
067: return rc;
068: }
069:
070: /**
071: * Read the XML template
072: * @return true if the processing completed successfully, otherwise false is returned
073: */
074: protected boolean loadFile() {
075: try {
076: xml = XmlSource.read(new FileReader(sourceFileName));
077: } catch (Exception ex) {
078: ex.printStackTrace();
079: return false;
080: }
081:
082: return true;
083: }
084:
085: /**
086: * Save the XML template
087: * @return true if the processing completed successfully, otherwise false is returned
088: */
089: protected boolean saveFile() {
090: FileWriter fw = null;
091: FileOutputStream fos = null;
092: try {
093: targetFile.getParentFile().mkdirs();
094:
095: if (xml instanceof NanoXmlElement) {
096: fw = new FileWriter(targetFile);
097: NanoXmlWriter xmlWriter = new NanoXmlWriter(fw);
098: xmlWriter.write(xml, true, 4);
099:
100: fw.flush();
101: fw.close();
102: } else {
103: fos = new FileOutputStream(targetFile);
104: JaxpXmlWriter xmlWriter = new JaxpXmlWriter();
105: xmlWriter.setOutputStream(fos);
106: xmlWriter.write(xml, true, 4);
107:
108: fos.close();
109: }
110:
111: return true;
112: } catch (Exception ex) {
113: ex.printStackTrace();
114: } finally {
115: if (fw != null) {
116: try {
117: fw.close();
118: } catch (IOException ex) {
119: ex.printStackTrace();
120: }
121: } else if (fos != null) {
122: try {
123: fos.close();
124: } catch (IOException ex) {
125: ex.printStackTrace();
126: }
127: }
128: }
129:
130: return false;
131: }
132:
133: /**
134: * Include the xml fragements referenced by the include elements
135: * @param xe the element being processed
136: * @return true if the processing completed successfully, otherwise false is returned
137: */
138: protected boolean includeElements(XmlElement xe) {
139: return true;
140: }
141:
142: /**
143: * Exclude those elements that are marked as being optional.
144: * Calls back to the isIncluded method of the template engine
145: * @param xe the element being processed
146: * @return true if the processing completed successfully, otherwise false is returned
147: */
148: protected boolean excludeElements(XmlElement xe) {
149: Vector children = xe.getChildren();
150: int numChildren = children.size();
151: for (int i = numChildren - 1; i >= 0; i--) {
152: XmlElement child = (XmlElement) children.elementAt(i);
153: String include = child.getAttribute("te_include");
154: if (include != null) {
155: if (!engine.includes(include)) {
156: xe.remove(child);
157: child.removeAttribute("te_include");
158: continue;
159: }
160: }
161: excludeElements(child);
162: }
163: return true;
164: }
165:
166: /**
167: * Repeat those elements that are within a repeat element.
168: * The while clause of the repeat element is used to determine the number of
169: * times the element is repeated. When done, the repeat element is removed.
170: * @param parent the parent of the element being processed
171: * @param xe the element being processed
172: * @return true if the processing completed successfully, otherwise false is returned
173: */
174: protected boolean repeatElements(XmlElement parent, XmlElement xe) {
175: String tag = xe.getName();
176:
177: Vector children = xe.getChildren();
178: int numChildren = children.size();
179: for (int i = 0; i < numChildren; i++) {
180: boolean repeatElement = false;
181:
182: XmlElement child = (XmlElement) children.elementAt(i);
183:
184: // Preserve a copy of the original node
185: XmlElement clone = (XmlElement) child.clone();
186:
187: if ("Repeat".equals(tag)) {
188: String repeatReference = child.getAttribute("while");
189:
190: int loopCounter = 0;
191: do {
192: // Replace the loop counter
193: Enumeration attribNames = clone
194: .enumerateAttributeNames();
195: while (attribNames.hasMoreElements()) {
196: String attribName = (String) attribNames
197: .nextElement();
198: String attribValue = clone
199: .getAttribute(attribName);
200: int counterPos = attribName.indexOf("{N}");
201: if (counterPos >= 0)
202: attribValue.replace("{N}", Integer
203: .toString(loopCounter));
204:
205: attribValue = engine.evaluateAttribute(
206: attribValue).toString();
207: child.setAttribute(attribName, attribValue);
208: }
209:
210: if ((loopCounter > 0) && tag.equals("Repeat")) {
211: // Repeat the child addition.
212: repeatElement = ((Boolean) engine
213: .evaluateAttribute(repeatReference))
214: .booleanValue();
215: if (repeatElement) {
216: child = (XmlElement) child.clone();
217: parent.addChild(child);
218: repeatElements(xe, child);
219: }
220: }
221: loopCounter++;
222: } while (repeatElement);
223:
224: parent.remove(xe);
225: }
226: repeatElements(xe, child);
227: }
228: return true;
229: }
230:
231: /**
232: * Sustitute any content, field values etc described in the template
233: * @param xe the element being processed
234: * @return true if the processing completed successfully, otherwise false is returned
235: */
236: protected boolean insertAttribute(XmlElement xe) {
237: Vector children = xe.getChildren();
238: int numChildren = children.size();
239: for (int i = numChildren - 1; i >= 0; i--) {
240: XmlElement child = (XmlElement) children.elementAt(i);
241: String custom = child.getAttribute("te_content");
242: if (custom != null) {
243: String content = engine.getContent(custom);
244: if (content != null) {
245: child.setAttribute("content", content);
246: }
247: }
248: String style = child.getAttribute("te_style");
249: if (style != null) {
250: String content = engine.getContent(style);
251: if (content != null) {
252: child.setAttribute("style", content);
253: }
254: }
255: String tooltip = child.getAttribute("te_hint");
256: if (tooltip != null) {
257: String content = engine.getContent(tooltip);
258: if (content != null) {
259: child.removeAttribute("tooltip");
260: }
261: }
262:
263: insertAttribute(child);
264: }
265: return true;
266: }
267:
268: /**
269: * Attempt to copy the resources specified in XML template
270: * @param xe the element being processed
271: * @return true if the processing completed successfully, otherwise false is returned
272: */
273: protected boolean copyResources(XmlElement xe) {
274: return true;
275: }
276: }
|