package org.marc4j;\r
\r
import java.io.BufferedWriter;\r
-import java.io.IOException;\r
import java.io.OutputStream;\r
import java.io.OutputStreamWriter;\r
import java.io.UnsupportedEncodingException;\r
-import java.io.Writer;\r
-import java.util.Iterator;\r
\r
-import javax.xml.transform.OutputKeys;\r
import javax.xml.transform.Result;\r
import javax.xml.transform.Source;\r
-import javax.xml.transform.TransformerFactory;\r
-import javax.xml.transform.sax.SAXTransformerFactory;\r
-import javax.xml.transform.sax.TransformerHandler;\r
import javax.xml.transform.stream.StreamResult;\r
import javax.xml.transform.stream.StreamSource;\r
\r
-import org.marc4j.converter.CharConverter;\r
-import org.marc4j.marc.ControlField;\r
-import org.marc4j.marc.DataField;\r
-import org.marc4j.marc.Leader;\r
-import org.marc4j.marc.Record;\r
-import org.marc4j.marc.Subfield;\r
import org.xml.sax.SAXException;\r
-import org.xml.sax.helpers.AttributesImpl;\r
\r
-import com.ibm.icu.text.Normalizer;\r
\r
/**\r
- * Class for writing MARC record objects in MARCXML format. This class outputs a\r
+ * Class for writing MARC record objects in Turbo MARC (XML) format. This class outputs a\r
* SAX event stream to the given {@link java.io.OutputStream} or\r
* {@link javax.xml.transform.Result} object. It can be used in a SAX\r
- * pipeline to postprocess the result. By default this class uses a nulll\r
+ * pipeline to postprocess the result. By default this class uses a null\r
* transform. It is strongly recommended to use a dedicated XML serializer.\r
* \r
* <p>\r
* @version $Revision: 1.9 $\r
* \r
*/\r
-public class TurboMarcXmlWriter implements MarcWriter {\r
+public class TurboMarcXmlWriter extends BaseMarcXmlWriter {\r
+\r
+ /** NS URI */\r
+ public static final String TURBO_MARCXML_NS_URI = "http://www.indexdata.com/turbomarc";\r
\r
protected static final String prefix = "tmarc:";\r
\r
- protected static final String CONTROL_FIELD = "c";\r
- protected static final String Q_CONTROL_FIELD = prefix + CONTROL_FIELD;\r
+ protected static final String CONTROLFIELD = "c";\r
+ protected static final String Q_CONTROL_FIELD = prefix + CONTROLFIELD;\r
\r
- protected static final String DATA_FIELD = "d";\r
- protected static final String Q_DATA_FIELD = prefix + DATA_FIELD;\r
+ protected static final String DATAFIELD = "d";\r
+ protected static final String Q_DATA_FIELD = prefix + DATAFIELD;\r
\r
protected static final String SUBFIELD = "s";\r
protected static final String Q_SUBFIELD = prefix + SUBFIELD;\r
protected static final String LEADER = "l";\r
protected static final String Q_LEADER = prefix + LEADER;\r
\r
- private boolean indent = false;\r
-\r
- private TransformerHandler handler = null;\r
-\r
- private Writer writer = null;\r
- \r
- \r
- /**\r
- * Character encoding. Default is UTF-8.\r
- */\r
- //private String encoding = "UTF8";\r
-\r
- private CharConverter converter = null;\r
-\r
- private boolean normalize = false;\r
-\r
/**\r
* Constructs an instance with the specified output stream.\r
* \r
* @throws MarcException\r
*/\r
public TurboMarcXmlWriter(OutputStream out, String encoding, boolean indent) {\r
+ setup();\r
if (out == null) {\r
throw new NullPointerException("null OutputStream");\r
}\r
writeStartDocument();\r
}\r
\r
+ private void setup() {\r
+ setPrefix(prefix);\r
+ setNamespaceURI(TURBO_MARCXML_NS_URI);\r
+ setCollectionName(COLLECTION);\r
+ setRecordName(RECORD);\r
+ setLeaderName(LEADER);\r
+ setControlfieldTemplate(CONTROLFIELD);\r
+ setDatafieldTemplate(DATAFIELD);\r
+ setSubfieldTemplate(SUBFIELD);\r
+ setUseTurboMarc(true);\r
+ }\r
+\r
/**\r
* Constructs an instance with the specified result.\r
* \r
* @throws SAXException\r
*/\r
public TurboMarcXmlWriter(Result result) {\r
+ setup();\r
if (result == null)\r
throw new NullPointerException("null Result");\r
setHandler(result, null);\r
* @throws SAXException\r
*/\r
public TurboMarcXmlWriter(Result result, Source stylesheet) {\r
+ setup();\r
if (stylesheet == null)\r
throw new NullPointerException("null Source");\r
if (result == null)\r
setHandler(result, stylesheet);\r
writeStartDocument();\r
}\r
-\r
- public void close() {\r
- writeEndDocument();\r
- try {\r
- if (writer != null)\r
- writer.close();\r
- } catch (IOException e) {\r
- throw new MarcException(e.getMessage(), e);\r
- }\r
- }\r
-\r
- /**\r
- * Returns the character converter.\r
- * \r
- * @return CharConverter the character converter\r
- */\r
- public CharConverter getConverter() {\r
- return converter;\r
- }\r
-\r
- /**\r
- * Sets the character converter.\r
- * \r
- * @param converter\r
- * the character converter\r
- */\r
- public void setConverter(CharConverter converter) {\r
- this.converter = converter;\r
- }\r
-\r
- /**\r
- * If set to true this writer will perform Unicode normalization on data\r
- * elements using normalization form C (NFC). The default is false.\r
- * \r
- * The implementation used is ICU4J 2.6. This version is based on Unicode\r
- * 4.0.\r
- * \r
- * @param normalize\r
- * true if this writer performs Unicode normalization, false\r
- * otherwise\r
- */\r
- public void setUnicodeNormalization(boolean normalize) {\r
- this.normalize = normalize;\r
- }\r
-\r
- /**\r
- * Returns true if this writer will perform Unicode normalization, false\r
- * otherwise.\r
- * \r
- * @return boolean - true if this writer performs Unicode normalization,\r
- * false otherwise.\r
- */\r
- public boolean getUnicodeNormalization() {\r
- return normalize;\r
- }\r
-\r
- protected void setHandler(Result result, Source stylesheet)\r
- throws MarcException {\r
- try {\r
- TransformerFactory factory = TransformerFactory.newInstance();\r
- if (!factory.getFeature(SAXTransformerFactory.FEATURE))\r
- throw new UnsupportedOperationException(\r
- "SAXTransformerFactory is not supported");\r
-\r
- SAXTransformerFactory saxFactory = (SAXTransformerFactory) factory;\r
- if (stylesheet == null)\r
- handler = saxFactory.newTransformerHandler();\r
- else\r
- handler = saxFactory.newTransformerHandler(stylesheet);\r
- handler.getTransformer()\r
- .setOutputProperty(OutputKeys.METHOD, "xml");\r
- handler.setResult(result);\r
-\r
- } catch (Exception e) {\r
- throw new MarcException(e.getMessage(), e);\r
- }\r
- }\r
-\r
- /**\r
- * Writes the root start tag to the result.\r
- * \r
- * @throws SAXException\r
- */\r
- protected void writeStartDocument() {\r
- try {\r
- AttributesImpl atts = new AttributesImpl();\r
- handler.startDocument();\r
- // The next line duplicates the namespace declaration for Marc XML\r
- handler.startPrefixMapping("tmarc", Constants.TURBO_MARCXML_NS_URI);\r
- // add namespace declaration using attribute - need better solution\r
- atts.addAttribute(Constants.TURBO_MARCXML_NS_URI, "xmlns", "xmlns:tmarc",\r
- "CDATA", Constants.TURBO_MARCXML_NS_URI); \r
- handler.startElement(Constants.TURBO_MARCXML_NS_URI, COLLECTION, Q_COLLECTION, atts);\r
- } catch (SAXException e) {\r
- throw new MarcException(\r
- "SAX error occured while writing start document", e);\r
- }\r
- }\r
-\r
- /**\r
- * Writes the root end tag to the result.\r
- * \r
- * @throws SAXException\r
- */\r
- protected void writeEndDocument() {\r
- try {\r
- if (indent)\r
- handler.ignorableWhitespace("\n".toCharArray(), 0, 1);\r
-\r
- handler\r
- .endElement(Constants.TURBO_MARCXML_NS_URI, COLLECTION,\r
- Q_COLLECTION);\r
- handler.endPrefixMapping("");\r
- handler.endDocument();\r
- } catch (SAXException e) {\r
- throw new MarcException(\r
- "SAX error occured while writing end document", e);\r
- }\r
- }\r
-\r
- /**\r
- * Writes a Record object to the result.\r
- * \r
- * @param record -\r
- * the <code>Record</code> object\r
- * @throws SAXException\r
- */\r
- public void write(Record record) {\r
- try {\r
- toXml(record);\r
- } catch (SAXException e) {\r
- throw new MarcException("SAX error occured while writing record", e);\r
- }\r
- }\r
-\r
- /**\r
- * Returns true if indentation is active, false otherwise.\r
- * \r
- * @return boolean\r
- */\r
- public boolean hasIndent() {\r
- return indent;\r
- }\r
-\r
- /**\r
- * Activates or deactivates indentation. Default value is false.\r
- * \r
- * @param indent\r
- */\r
- public void setIndent(boolean indent) {\r
- this.indent = indent;\r
- }\r
-\r
- protected void toXml(Record record) throws SAXException {\r
- char temp[];\r
- AttributesImpl atts = new AttributesImpl();\r
- if (indent)\r
- handler.ignorableWhitespace("\n ".toCharArray(), 0, 3);\r
-\r
- handler.startElement(Constants.TURBO_MARCXML_NS_URI, RECORD, Q_RECORD, atts);\r
-\r
- if (indent)\r
- handler.ignorableWhitespace("\n ".toCharArray(), 0, 5);\r
-\r
- handler.startElement(Constants.TURBO_MARCXML_NS_URI, LEADER, Q_LEADER, atts);\r
- Leader leader = record.getLeader();\r
- temp = leader.toString().toCharArray();\r
- handler.characters(temp, 0, temp.length);\r
- handler.endElement(Constants.TURBO_MARCXML_NS_URI, LEADER, Q_LEADER);\r
-\r
- Iterator<ControlField> ci = record.getControlFields().iterator();\r
- while (ci.hasNext()) {\r
- ControlField field = (ControlField) ci.next();\r
- atts = new AttributesImpl();\r
- //atts.addAttribute("", "tag", "tag", "CDATA", field.getTag());\r
-\r
- if (indent)\r
- handler.ignorableWhitespace("\n ".toCharArray(), 0, 5);\r
- String elementName = CONTROL_FIELD + field.getTag();\r
- String qElementName = prefix + elementName;\r
- handler.startElement(Constants.TURBO_MARCXML_NS_URI, elementName, qElementName, atts);\r
- temp = getDataElement(field.getData());\r
- handler.characters(temp, 0, temp.length);\r
- handler.endElement(Constants.TURBO_MARCXML_NS_URI, elementName, qElementName);\r
- }\r
-\r
- Iterator<DataField> di = record.getDataFields().iterator();\r
- while (di.hasNext()) {\r
- DataField field = di.next();\r
- atts = new AttributesImpl();\r
- // atts.addAttribute("", "tag", "tag", "CDATA", field.getTag());\r
- atts.addAttribute("", "ind1", "ind1", "CDATA", String.valueOf(field\r
- .getIndicator1()));\r
- atts.addAttribute("", "ind2", "ind2", "CDATA", String.valueOf(field\r
- .getIndicator2()));\r
-\r
- if (indent)\r
- handler.ignorableWhitespace("\n ".toCharArray(), 0, 5);\r
- StringBuffer elementName = new StringBuffer(DATA_FIELD);\r
- StringBuffer qElementName = new StringBuffer(prefix);\r
- elementName.append(field.getTag());\r
- qElementName.append(elementName);\r
- handler.startElement(Constants.TURBO_MARCXML_NS_URI, elementName.toString(), \r
- qElementName.toString(), atts);\r
-\r
- Iterator<Subfield> si = field.getSubfields().iterator();\r
- while (si.hasNext()) {\r
- Subfield subfield = (Subfield) si.next();\r
- StringBuffer subfieldName = new StringBuffer(SUBFIELD); \r
- StringBuffer qSubfieldName = new StringBuffer(prefix);\r
- qSubfieldName.append(subfieldName);\r
- \r
- char code = subfield.getCode(); \r
- // if [a-zA-Z0-9] append to elementName, otherwise use a attribute\r
- if (code >= '0' && code <= '9' ||\r
- code >= 'a' && code <= 'z' ||\r
- code >= 'A' && code <= 'Z') {\r
- subfieldName.append(code);\r
- qSubfieldName.append(code);\r
- }\r
- else {\r
- atts = new AttributesImpl();\r
- atts.addAttribute("", "code", "code", "CDATA", String\r
- .valueOf(subfield.getCode()));\r
- }\r
- if (indent)\r
- handler.ignorableWhitespace("\n ".toCharArray(), 0, 7);\r
-\r
- handler.startElement(Constants.TURBO_MARCXML_NS_URI, subfieldName.toString(),\r
- qSubfieldName.toString(), atts);\r
- temp = getDataElement(subfield.getData());\r
- handler.characters(temp, 0, temp.length);\r
- handler\r
- .endElement(Constants.TURBO_MARCXML_NS_URI, subfieldName.toString(),\r
- qSubfieldName.toString());\r
- }\r
-\r
- if (indent)\r
- handler.ignorableWhitespace("\n ".toCharArray(), 0, 5);\r
-\r
- handler\r
- .endElement(Constants.TURBO_MARCXML_NS_URI, \r
- elementName.toString(), qElementName.toString());\r
- }\r
-\r
- if (indent)\r
- handler.ignorableWhitespace("\n ".toCharArray(), 0, 3);\r
-\r
- handler.endElement(Constants.TURBO_MARCXML_NS_URI, RECORD, Q_RECORD);\r
- }\r
-\r
- protected char[] getDataElement(String data) {\r
- String dataElement = null;\r
- if (converter == null)\r
- return data.toCharArray();\r
- dataElement = converter.convert(data);\r
- if (normalize)\r
- dataElement = Normalizer.normalize(dataElement, Normalizer.NFC);\r
- return dataElement.toCharArray();\r
- }\r
}
\ No newline at end of file