Project

General

Profile

1 87 jones
/**
2 203 jones
 *  '$RCSfile$'
3
 *    Purpose: A Class that transforms an XML text document
4
 *             into a another type using XSL
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones
8 87 jones
 *
9 1929 brooke
 * '$Author$'
10
 * '$Date$'
11 203 jones
 * '$Revision$'
12 669 jones
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 87 jones
 */
27
28
package edu.ucsb.nceas.metacat;
29
30
import java.io.*;
31
import java.net.URL;
32
import java.net.MalformedURLException;
33
import java.sql.*;
34 1688 tao
import java.util.Enumeration;
35 1664 tao
import java.util.Hashtable;
36 3675 barteau
import java.util.Iterator;
37
import java.util.Map;
38
import java.util.Map.Entry;
39 87 jones
import java.util.Stack;
40
41 906 berkley
import javax.xml.transform.TransformerFactory;
42
import javax.xml.transform.Transformer;
43
import javax.xml.transform.stream.StreamSource;
44
import javax.xml.transform.stream.StreamResult;
45
import javax.xml.transform.TransformerException;
46
import javax.xml.transform.TransformerConfigurationException;
47
48 2663 sgarg
import org.apache.log4j.Logger;
49 906 berkley
import org.apache.xerces.parsers.DOMParser;
50
import org.w3c.dom.Attr;
51
import org.w3c.dom.NamedNodeMap;
52
import org.w3c.dom.NodeList;
53
import org.w3c.dom.Document;
54
import org.w3c.dom.Node;
55
import org.w3c.dom.DocumentType;
56
import org.xml.sax.SAXException;
57
import org.xml.sax.InputSource;
58
import org.apache.xerces.dom.DocumentTypeImpl;
59
import org.apache.xpath.XPathAPI;
60
61
/*
62 87 jones
import oracle.xml.parser.v2.XSLStylesheet;
63
import oracle.xml.parser.v2.XSLException;
64 832 jones
import oracle.xml.parser.v2.XMLParseException;
65 87 jones
import oracle.xml.parser.v2.XSLProcessor;
66
import oracle.xml.parser.v2.XMLDocument;
67
import oracle.xml.parser.v2.DOMParser;
68 906 berkley
*/
69 832 jones
import org.w3c.dom.Document;
70
import org.w3c.dom.Node;
71
import org.w3c.dom.Element;
72
import org.xml.sax.SAXException;
73 87 jones
74 4080 daigle
import edu.ucsb.nceas.metacat.service.PropertyService;
75
import edu.ucsb.nceas.metacat.util.MetaCatUtil;
76
import edu.ucsb.nceas.metacat.util.SystemUtil;
77
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
78
79 2896 sgarg
import java.util.Properties;
80 2893 sgarg
81 2912 harris
82 1716 berkley
/**
83 87 jones
 * A Class that transforms XML documents utitlizing XSL style sheets
84
 */
85
public class DBTransform {
86
87 1217 tao
  //private Connection	conn = null;
88 832 jones
  private MetaCatUtil   util = null;
89
  private String 	configDir = null;
90
  private String	defaultStyle = null;
91 2663 sgarg
  private Logger logMetacat = Logger.getLogger(DBTransform.class);
92 3780 daigle
  private String httpServer = null;
93 3725 tao
  private String contextURL = null;
94 3780 daigle
  private String servletURL = null;
95 2663 sgarg
96 87 jones
  /**
97
   * construct a DBTransform instance.
98
   *
99
   * Generally, one calls transformXMLDocument() after constructing the instance
100
   *
101
   * @param conn the database connection from which to lookup the public ids
102
   */
103 1716 berkley
  public DBTransform()
104
                  throws IOException,
105
                         SQLException,
106 4080 daigle
                         ClassNotFoundException,
107
                         PropertyNotFoundException
108 87 jones
  {
109 4080 daigle
    configDir = SystemUtil.getStyleSkinsDir();
110
    defaultStyle = PropertyService.getProperty("application.default-style");
111
    httpServer = SystemUtil.getServerURL();
112
    contextURL = SystemUtil.getContextURL();
113
    servletURL = SystemUtil.getServletURL();
114 87 jones
  }
115 1716 berkley
116 87 jones
  /**
117 1716 berkley
   * @see transformXMLDocument(String doc, String sourceType,
118
   *            String targetType, String qformat, PrintWriter pw,
119
   *            String sessionid)
120
   */
121
  public void transformXMLDocument(String doc, String sourceType,
122 1717 berkley
                String targetType, String qformat, PrintWriter pw,
123
                Hashtable param)
124 1716 berkley
  {
125 1717 berkley
    transformXMLDocument(doc, sourceType, targetType, qformat, pw, param, null);
126 1716 berkley
  }
127
128 2088 tao
   /**
129
   * @see transformXMLDocument(String doc, String sourceType,
130
   *            String targetType, String qFormat, StringWriter pw
131
   *            String sessionid)
132
   */
133
  public void transformXMLDocument(String doc, String sourceType,
134
                String targetType, String qFormat, StringWriter pw)
135
  {
136
    transformXMLDocument(doc, sourceType, targetType, qFormat, pw, null);
137
  }
138
139
140 1716 berkley
  /**
141 87 jones
   * Transform an XML document using the stylesheet reference from the db
142
   *
143
   * @param doc the document to be transformed
144
   * @param sourcetype the document type of the source
145
   * @param targettype the target document type
146 832 jones
   * @param qformat the name of the style set to use
147
   * @param pw the PrintWriter to which output is printed
148 1664 tao
   * @param params some parameters for eml2 transformation
149 87 jones
   */
150 1716 berkley
  public void transformXMLDocument(String doc, String sourceType,
151
                                   String targetType, String qformat,
152
                                   PrintWriter pw, Hashtable param,
153
                                   String sessionid)
154 1664 tao
 {
155 1716 berkley
156 87 jones
    // Look up the stylesheet for this type combination
157 941 tao
    String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
158 2088 tao
    if (xslSystemId != null)
159
    {
160
      try
161
      {// Create a stylesheet from the system id that was found
162
        doc = removeDOCTYPE(doc);
163
        StringReader xml = new StringReader(doc);
164
        StreamResult result = new StreamResult(pw);
165
        doTransform(xml, result, xslSystemId, param, qformat, sessionid);
166 87 jones
167 2088 tao
      }
168
      catch (Exception e)
169
      {
170 4080 daigle
        pw.println(xslSystemId + ": Error transforming document in " +
171 675 berkley
                   "DBTransform.transformXMLDocument: " +
172 87 jones
                   e.getMessage());
173 1716 berkley
174 87 jones
      }
175 2088 tao
    }
176
    else
177
    {
178 1716 berkley
      // No stylesheet registered form this document type, so just return the
179 87 jones
      // XML stream we were passed
180 100 jones
      pw.print(doc);
181 87 jones
    }
182
  }
183 1716 berkley
184 941 tao
  /**
185 1716 berkley
   * Transform an XML document to StringWriter using the stylesheet reference
186 941 tao
   * from the db
187
   * @param doc the document to be transformed
188
   * @param sourceType the document type of the source
189
   * @param targetType the target document type
190
   * @param qFormat the name of the style set to use
191
   * @param pw the StringWriter to which output will be stored
192
   */
193
  public void transformXMLDocument(String doc, String sourceType,
194 1716 berkley
                String targetType, String qFormat, StringWriter pw,
195 2088 tao
                String sessionid)
196
  {
197 941 tao
198
    // Look up the stylesheet for this type combination
199
    String xslSystemId = getStyleSystemId(qFormat, sourceType, targetType);
200 2088 tao
    if (xslSystemId != null)
201
    {
202 941 tao
      // Create a stylesheet from the system id that was found
203 2088 tao
      try
204
      {
205 1903 tao
        doc = removeDOCTYPE(doc);
206 2088 tao
        StringReader xml = new StringReader(doc);
207
        StreamResult result = new StreamResult(pw);
208
        doTransform(xml, result, xslSystemId, null, qFormat, sessionid);
209
      }
210
      catch (Exception e)
211
      {
212 3780 daigle
        logMetacat.error(xslSystemId + ": Error transforming document in " +
213 941 tao
                   "DBTransform.transformXMLDocument: " +
214 2663 sgarg
                   e.getMessage());
215 1716 berkley
216 941 tao
      }
217 2088 tao
    }
218
    else
219
    {
220 1716 berkley
      // No stylesheet registered form this document type, so just return the
221 941 tao
      // XML stream we were passed
222 950 tao
      pw.write(doc);
223 941 tao
    }
224
  }
225 1716 berkley
226 906 berkley
  /**
227 2088 tao
   * Method to do transform for a string reader
228
   * @param doc the document to be transformed
229
   * @param sourcetype the document type of the source
230
   * @param targettype the target document type
231
   * @param qformat the name of the style set to use
232
   * @param pw the PrintWriter to which output is printed
233
   * @param params some parameters for eml2 transformation
234 1716 berkley
   */
235 2088 tao
   public void transformXMLDocument(StringReader docContent, String sourceType,
236
                                   String targetType, String qformat,
237
                                   PrintWriter pw, Hashtable param,
238
                                   String sessionid)
239
   {
240
     // Look up the stylesheet for this type combination
241
    String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
242
    if (xslSystemId != null)
243
    {
244
      try
245
      {// Create a stylesheet from the system id that was found
246
        StreamResult result = new StreamResult(pw);
247
        doTransform(docContent, result, xslSystemId, param, qformat, sessionid);
248
249
      }
250
      catch (Exception e)
251
      {
252 4080 daigle
        pw.println(xslSystemId + ": Error transforming document in " +
253 2088 tao
                   "DBTransform.transformXMLDocument: " +
254
                   e.getMessage());
255
256
      }
257
    }
258
    else
259
    {
260
      // No stylesheet registered form this document type, so just return the
261
      // XML stream we were passed
262
      pw.print(docContent);
263
    }
264
   }
265
266 3675 barteau
  /**
267
   * Reads skin's config file if it exists, and populates Transformer paramaters
268
   * with its contents.
269
   * It then adds the parameters passed to it via Hashtable param to the Transformer.
270
   * It then calls the Transformer.transform method.
271 2088 tao
   */
272 3675 barteau
  private void doTransform(StringReader docContent,
273
          StreamResult resultOutput,
274
          String xslSystemId,
275
          Hashtable param,
276
          String qformat,
277
          String sessionid)
278
          throws Exception {
279
280
      Properties skinOptions;
281
      TransformerFactory tFactory;
282
      Transformer transformer;
283
      String key, value;
284
      StreamSource xml;
285
      Enumeration en;
286
      Iterator iterIt;
287
      Map.Entry entry;
288
289
      if (xslSystemId != null) {
290
        tFactory = TransformerFactory.newInstance();
291
        transformer = tFactory.newTransformer(new StreamSource(xslSystemId));
292
293 2088 tao
        transformer.setParameter("qformat", qformat);
294 2663 sgarg
        logMetacat.warn("qformat: "+qformat);
295 2893 sgarg
296 3675 barteau
        if (MetaCatUtil.hasSkinConfig(qformat)) {
297
            skinOptions = MetaCatUtil.getSkinConfig(qformat);
298 2897 sgarg
299 3675 barteau
            iterIt = skinOptions.entrySet().iterator();
300
            while (iterIt.hasNext()) {
301
                entry = (Entry) iterIt.next();
302
                key = (String) entry.getKey();
303
                value = (String) entry.getValue();
304
                transformer.setParameter(key, value);
305
            }
306
        }
307 2893 sgarg
308 3675 barteau
        if (sessionid != null && !sessionid.equals("null")) {
309 2088 tao
          transformer.setParameter("sessid", sessionid);
310
        }
311 3675 barteau
312 3733 leinfelder
        //set up the default params (can be overridden by the passed in params)
313 4080 daigle
        String cgiPrefix = SystemUtil.getCGI_URL();
314 3736 leinfelder
        logMetacat.debug("cgi-prefix=" + cgiPrefix);
315 3780 daigle
        logMetacat.debug("httpServer=" + httpServer);
316 3736 leinfelder
        logMetacat.debug("contextURL=" + contextURL);
317 3780 daigle
        logMetacat.debug("serletPath=" + servletURL);
318 3733 leinfelder
        transformer.setParameter("cgi-prefix", cgiPrefix);
319 3780 daigle
        transformer.setParameter("httpServer", httpServer);
320 3733 leinfelder
        transformer.setParameter("contextURL", contextURL);
321 3780 daigle
        transformer.setParameter("servletURL", servletURL);
322 3733 leinfelder
323 2088 tao
        // Set up parameter for transformation
324 3675 barteau
        if ( param != null) {
325
          en = param.keys();
326
          while (en.hasMoreElements()) {
327
            key = (String) en.nextElement();
328
            value = ((String[]) (param.get(key)))[0];
329 2668 sgarg
            logMetacat.info(key+" : "+value);
330 2088 tao
            transformer.setParameter(key, value);
331
          }
332
        }
333 3675 barteau
        xml = new StreamSource(docContent);
334 2088 tao
        transformer.transform(xml,resultOutput);
335
    }
336
  }//doTransform
337
338
339 1716 berkley
  /**
340 906 berkley
   * gets the content of a tag in a given xml file with the given path
341
   * @param f the file to parse
342
   * @param path the path to get the content from
343
   */
344 1716 berkley
  public static NodeList getPathContent(File f, String path)
345 906 berkley
  {
346
    if(f == null)
347
    {
348
      return null;
349
    }
350 1716 berkley
351 906 berkley
    DOMParser parser = new DOMParser();
352
    InputSource in;
353
    FileInputStream fs;
354 1716 berkley
355 906 berkley
    try
356 1716 berkley
    {
357 906 berkley
      fs = new FileInputStream(f);
358
      in = new InputSource(fs);
359
    }
360
    catch(FileNotFoundException fnf)
361
    {
362
      fnf.printStackTrace();
363
      return null;
364
    }
365 1716 berkley
366 906 berkley
    try
367
    {
368
      parser.parse(in);
369
      fs.close();
370
    }
371
    catch(Exception e1)
372
    {
373 1716 berkley
      System.err.println("File: " + f.getPath() + " : parse threw: " +
374 906 berkley
                         e1.toString());
375
      return null;
376
    }
377 1716 berkley
378 906 berkley
    Document doc = parser.getDocument();
379 1716 berkley
380 906 berkley
    try
381
    {
382
      NodeList docNodeList = XPathAPI.selectNodeList(doc, path);
383
      return docNodeList;
384
    }
385
    catch(Exception se)
386
    {
387 1716 berkley
      System.err.println("file: " + f.getPath() + " : parse threw: " +
388 906 berkley
                         se.toString());
389
      return null;
390
    }
391
  }
392 87 jones
393
  /**
394
   * Lookup a stylesheet reference from the db catalog
395
   *
396 832 jones
   * @param qformat    the named style-set format
397
   * @param sourcetype the document type of the source
398
   * @param targettype the document type of the target
399
   */
400 1716 berkley
  public String getStyleSystemId(String qformat, String sourcetype,
401 832 jones
                String targettype) {
402
    String systemId = null;
403
404
    if ((qformat == null) || (qformat.equals("html"))) {
405
      qformat = defaultStyle;
406
    }
407
408
    // Load the style-set map for this qformat into a DOM
409
    try {
410 906 berkley
      boolean breakflag = false;
411 1929 brooke
      String filename = configDir + "/" + qformat + "/" + qformat + ".xml";
412 2663 sgarg
      logMetacat.warn("Trying style-set file: " + filename);
413 906 berkley
      File f = new File(filename);
414
      NodeList nlDoctype = getPathContent(f, "/style-set/doctype");
415
      NodeList nlDefault = getPathContent(f, "/style-set/default-style");
416
      Node nDefault = nlDefault.item(0);
417
      systemId = nDefault.getFirstChild().getNodeValue(); //set the default
418 1716 berkley
419 906 berkley
      for(int i=0; i<nlDoctype.getLength(); i++)
420
      { //look for the right sourcetype
421
        Node nDoctype = nlDoctype.item(i);
422
        NamedNodeMap atts = nDoctype.getAttributes();
423
        Node nAtt = atts.getNamedItem("publicid");
424
        String doctype = nAtt.getFirstChild().getNodeValue();
425
        if(doctype.equals(sourcetype))
426
        { //found the right sourcetype now we need to get the target type
427
          NodeList nlChildren = nDoctype.getChildNodes();
428
          for(int j=0; j<nlChildren.getLength(); j++)
429
          {
430
            Node nChild = nlChildren.item(j);
431
            String childName = nChild.getNodeName();
432
            if(childName.equals("target"))
433
            {
434
              NamedNodeMap childAtts = nChild.getAttributes();
435
              Node nTargetPublicId = childAtts.getNamedItem("publicid");
436
              String target = nTargetPublicId.getFirstChild().getNodeValue();
437
              if(target.equals(targettype))
438
              { //we found the right target type
439
                NodeList nlTarget = nChild.getChildNodes();
440
                for(int k=0; k<nlTarget.getLength(); k++)
441
                {
442
                  Node nChildText = nlTarget.item(k);
443
                  if(nChildText.getNodeType() == Node.TEXT_NODE)
444
                  { //get the text from the target node
445
                    systemId = nChildText.getNodeValue();
446
                    breakflag = true;
447
                    break;
448
                  }
449
                }
450 832 jones
              }
451
            }
452 1716 berkley
453 906 berkley
            if(breakflag)
454
            {
455
              break;
456
            }
457 832 jones
          }
458
        }
459 1716 berkley
460 906 berkley
        if(breakflag)
461
        {
462
          break;
463
        }
464 832 jones
      }
465
    }
466 906 berkley
    catch(Exception e)
467
    {
468
      System.out.println("Error parsing style-set file: " + e.getMessage());
469
      e.printStackTrace();
470
    }
471 3725 tao
472
    //Check if the systemId is relative path, add a postfix - the contextULR to systemID.
473
    if (systemId != null && systemId.indexOf("http://" ) == -1)
474
    {
475
    	systemId = contextURL+systemId;
476
    }
477 832 jones
    // Return the system ID for this particular source document type
478 2663 sgarg
    logMetacat.info("style system id is: "+systemId);
479 832 jones
    return systemId;
480
  }
481
482 1896 tao
 /* Method to modified the system id of xml input -- make sure it
483
    points to system id in xml_catalog table
484
  */
485 2088 tao
  private void modifiedXmlStreamSource(StreamSource xml, String publicId)
486 1896 tao
                                       throws Exception
487
  {
488
    // make sure the xml is not null
489
    if (xml == null || publicId == null)
490
    {
491
      return;
492 87 jones
    }
493 2663 sgarg
    logMetacat.info("public id of input stream is " +publicId);
494 1896 tao
    // Get system id from xml_catalog table
495
    String systemId = DBEntityResolver.getDTDSystemID(publicId);
496 2663 sgarg
    logMetacat.info("system id of input stream from xml_catalog"
497
                               +"table is " +systemId);
498 1896 tao
    //set system id to input stream
499
    xml.setSystemId(systemId);
500 87 jones
  }
501 2088 tao
502 1903 tao
  /*
503
   * removes the DOCTYPE element and its contents from a Sting
504 2088 tao
   * used to avoid problems with incorrect SystemIDs
505 1903 tao
   */
506 2088 tao
  private String removeDOCTYPE(String in) {
507 1903 tao
    String ret = "";
508
    int startpos = in.indexOf("<!DOCTYPE");
509
    if (startpos>-1) {
510 2088 tao
      int stoppos = in.indexOf(">", startpos + 8);
511 1903 tao
      ret = in.substring(0,startpos) + in.substring(stoppos+1,in.length());
512
    } else {
513
      return in;
514
    }
515 2088 tao
    return ret;
516 1903 tao
  }
517 99 jones
518
  /**
519
   * the main routine used to test the transform utility.
520
   *
521 184 jones
   * Usage: java DBTransform
522 99 jones
   */
523
  static public void main(String[] args) {
524 1716 berkley
525 184 jones
     if (args.length > 0)
526 99 jones
     {
527
        System.err.println("Wrong number of arguments!!!");
528 184 jones
        System.err.println("USAGE: java DBTransform");
529 99 jones
        return;
530
     } else {
531
        try {
532 1716 berkley
533 99 jones
          // Create a test document
534
          StringBuffer testdoc = new StringBuffer();
535
          testdoc.append("<?xml version=\"1.0\"?>");
536
          testdoc.append("<eml-dataset><metafile_id>NCEAS-0001</metafile_id>");
537
          testdoc.append("<dataset_id>DS001</dataset_id>");
538
          testdoc.append("<title>My test doc</title></eml-dataset>");
539
540
          // Transform the document to the new doctype
541 1217 tao
          DBTransform dbt = new DBTransform();
542 1716 berkley
          dbt.transformXMLDocument(testdoc.toString(),
543
                                   "-//NCEAS//eml-dataset//EN",
544
                                   "-//W3C//HTML//EN",
545 832 jones
                                   "knb",
546 1664 tao
                                   new PrintWriter(System.out), null);
547 99 jones
548
        } catch (Exception e) {
549
          System.err.println("EXCEPTION HANDLING REQUIRED");
550
          System.err.println(e.getMessage());
551
          e.printStackTrace(System.err);
552
        }
553
     }
554
  }
555 1716 berkley
556 184 jones
  private void dbg(int position) {
557 99 jones
    System.err.println("Debug flag: " + position);
558
  }
559
560 87 jones
}