/**
* $Id$
* $Date$
*
*/
package org.xmlsh.internal.commands;
/**
* Command: xsplit
* Usage: xsplit [options] [input]
* Options:
* -p prefix
* -s suffix
* -e extension
* -c num
* Number of child XML elements to output (def 1)
* -n
* Do not wrap in root element (requires -c=1)
* -w elem
* Wrap in element instead of root element
*
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.xmlsh.core.CoreException;
import org.xmlsh.core.InputPort;
import org.xmlsh.core.InvalidArgumentException;
import org.xmlsh.core.Options;
import org.xmlsh.core.Options.OptionValue;
import org.xmlsh.core.XCommand;
import org.xmlsh.core.XValue;
import org.xmlsh.core.io.OutputPort;
import org.xmlsh.sh.shell.SerializeOpts;
import org.xmlsh.util.Util;
import net.sf.saxon.s9api.SaxonApiException;
public class xsplit extends XCommand {
private XMLOutputFactory mOutputFactory = XMLOutputFactory.newInstance();
private XMLEventFactory mEventFactory = XMLEventFactory.newInstance();
/*
* Runtime data
*/
private XMLEvent mRootNode = null;
private String mPrefix = "x";
private int mSeq = 0;
private String mSuffix = "";
private String mExt = ".xml";
private File mOutputDir = null;
private boolean mNoRoot = false;
private int mNumChildren = 1;
private boolean mNoDTD = false;
private boolean mNoPI = false;
private XValue mList = null;
private List<XMLEvent> mHeader = new ArrayList<XMLEvent>();
private boolean mStream = false;
@Override
public int run(List<XValue> args) throws Exception {
Options opts = new Options(
"c=children:,w=wrap:,n,p=prefix:,e=ext:,s=suffix:,n=nowrap,o=output:,nopi,nodtd,l=list:,stream:",
SerializeOpts.getOptionDefs());
opts.parse(args);
// root node
OptionValue ow = opts.getOpt("w");
XValue wrapper = null;
if(ow != null) {
wrapper = ow.getValue();
mRootNode = mEventFactory
.createStartElement(new QName(null, wrapper.toString()), null, null);
}
mNumChildren = Util.parseInt(opts.getOptString("c", "1"), 1);
mExt = opts.getOptString("e", mExt);
mSuffix = opts.getOptString("s", mSuffix);
mPrefix = opts.getOptString("p", mPrefix);
if(opts.hasOpt("o"))
mOutputDir = getFile(opts.getOptValue("o"));
mNoDTD = opts.hasOpt("nodtd");
mNoPI = opts.hasOpt("nopi");
mList = opts.getOptValue("list");
mStream = opts.hasOpt("stream");
/*
* If not adding a root then must add only 1 child
*/
if(opts.hasOpt("n")) {
mNumChildren = 1;
mNoRoot = true;
}
List<XValue> xvargs = opts.getRemainingArgs();
if(xvargs.size() > 1) {
usage();
return 1;
}
InputPort in = xvargs.size() == 1 ? getInput(xvargs.get(0)) : getStdin();
OutputPort streamOut = null;
setSerializeOpts(opts);
if(mStream)
streamOut = getEnv().getOutputPort(opts.getOptStringRequired("stream"));
try (
InputStream is = in.asInputStream(getSerializeOpts());
PrintWriter listWriter = mList == null ? null
: (getOutput(mList, false)).asPrintWriter(getSerializeOpts());) {
split(in.getSystemId(), is, listWriter, streamOut);
}
return 0;
}
private void split(String systemId, InputStream is, PrintWriter listWriter,
OutputPort streamOut) throws XMLStreamException, IOException,
InvalidArgumentException, CoreException, SaxonApiException {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(XMLInputFactory.IS_COALESCING,
Boolean.valueOf(true));
XMLEventReader xmlreader = inputFactory.createXMLEventReader(systemId, is);
/*
* Read up to root elem collecting events to repeat on each file
*
*/
List<Namespace> ns = null;
while(xmlreader.hasNext()) {
XMLEvent e = xmlreader.nextEvent();
if(e.getEventType() != XMLStreamConstants.START_ELEMENT) {
if(mNoDTD && e.getEventType() == XMLStreamConstants.DTD)
continue;
if(mNoPI
&& e.getEventType() == XMLStreamConstants.PROCESSING_INSTRUCTION)
continue;
mHeader.add(e);
continue;
}
/*
* If no root then dont add elements to root, but do collect namespaces
*/
if(mNoRoot) {
StartElement se = e.asStartElement();
Iterator<?> nsi = se.getNamespaces();
ns = new ArrayList<Namespace>();
while(nsi.hasNext())
ns.add((Namespace) nsi.next());
}
if(!mNoRoot) {
// Found document root
if(mRootNode == null)
mHeader.add(e);
else
mHeader.add(mRootNode);
}
break;
}
/*
* For each element write it to a new file
*/
while(xmlreader.hasNext()) {
XMLEvent e = xmlreader.nextEvent();
int type = e.getEventType();
if(type == XMLStreamConstants.START_ELEMENT) {
write(xmlreader, e, ns, listWriter, streamOut);
}
else if(type == XMLStreamConstants.END_ELEMENT ||
type == XMLStreamConstants.END_DOCUMENT
) {
// ignore
}
else {
if(type == XMLStreamConstants.CHARACTERS
&& e.asCharacters().isWhiteSpace())
continue;
printErr("Skipping XML node: " + e.toString());
}
}
xmlreader.close();
}
/*
* Write out a single element and all its children to the next file or to a
* stram
*
*/
private void write(XMLEventReader xmlreader, XMLEvent first,
List<Namespace> ns, PrintWriter listWriter, OutputPort streamOut)
throws XMLStreamException, IOException, InvalidArgumentException,
CoreException, SaxonApiException {
XMLEventWriter w;
OutputStream fo = null;
String name = "-";
if(streamOut != null)
w = streamOut.asXMLEventWriter(getSerializeOpts());
else {
File fout = nextFile();
name = fout.getName();
fo = new FileOutputStream(fout); // need to close seperately
w = mOutputFactory.createXMLEventWriter(fo);
}
/*
* Write the common header elements
*/
for(XMLEvent e : mHeader)
w.add(e);
w.add(first);
/*
* Add namespaces if needed
*/
if(ns != null)
for(Namespace n : ns)
w.add(n);
int depth = 0;
int nchild = 0;
while(xmlreader.hasNext()) {
XMLEvent e = xmlreader.nextEvent();
w.add(e);
if(e.getEventType() == XMLStreamConstants.START_ELEMENT)
depth++;
else if(e.getEventType() == XMLStreamConstants.END_ELEMENT) {
if(depth-- <= 0) {
if(++nchild == mNumChildren)
break;
}
}
}
/*
* End with end element and end document
*/
// w.add( mEventFactory.createEndElement( first.asStartElement().getName(),
// null));
w.add(mEventFactory.createEndDocument());
w.flush();
w.close();
if(fo != null)
fo.close();
if(streamOut != null)
streamOut.writeSequenceSeperator(getSerializeOpts());
if(listWriter != null) {
listWriter.println(name);
listWriter.flush();
}
}
private File nextFile() throws IOException {
File f = getEnv().getShell().getFile(mOutputDir,
mPrefix + mSeq++ + mSuffix + mExt);
return f;
}
}
//
//
// Copyright (C) 2008-2014 David A. Lee.
//
// The contents of this file are subject to the "Simplified BSD License" (the
// "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the
// License at http://www.opensource.org/licenses/bsd-license.php
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is: all this file.
//
// The Initial Developer of the Original Code is David A. Lee
//
// Portions created by (your name) are Copyright (C) (your legal entity). All
// Rights Reserved.
//
// Contributor(s): none.
//