blob: 885eea32558641d8ea8a3ddf093cd8dc848a8c86 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.adapter.vinci.util;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.vinci.transport.document.AFrame;
/**
* A SAX content handler that builds a VinciFrame corresponding to the SAX events received.
*
*
*/
public class SaxVinciFrameBuilder extends DefaultHandler implements ContentHandler {
private Stack mOpenFrames;
private String mCurrentFrameName;
private Attributes mCurrentFrameAttrs;
private StringBuffer mCharContentBuffer;
/**
* Sets the parent frame, to which frames built by the object will be added. This MUST be called
* before parsing a document.
*
* @param aParentFrame
* the parent frame
*/
public void setParentFrame(AFrame aParentFrame) {
mOpenFrames = new Stack();
mOpenFrames.push(aParentFrame);
}
/**
* @see org.xml.sax.ContentHandler#startDocument()
*/
public void startDocument() throws SAXException {
mCurrentFrameName = null;
mCurrentFrameAttrs = null;
mCharContentBuffer = new StringBuffer();
}
/**
* Called for each start tag encountered.
*
* @param namespaceURI
* Required if the namespaces property is true.
* @param attributes
* The specified or defaulted attributes.
* @param localName
* The local name (without prefix), or the empty string if Namespace processing is not
* being performed.
* @param qualifiedName
* The qualified name (with prefix), or the empty string if qualified names are not
* available.
*/
public void startElement(String namespaceURI, String localName, String qualifiedName,
org.xml.sax.Attributes attributes) throws SAXException {
// I would like to create a VinciFrame here and put it on the
// mOpenFrames stack, but I don't know whether to create a VinciFrame or
// a FrameLeaf until I see whether there are child elements. So instead
// the element information is stored temporarily until the next call to
// startElement (indicating a non-leaf) or endElement (indicating a leaf)
// first, check to see whether we have a frame for which this temporary info
// was stored from the previous call to startElement.
if (mCurrentFrameName != null) {
// create a non-leaf frame
AFrame frame = new AFrame();
// add this frame to its parent frame
// (the one on top of stack)
AFrame parent = (AFrame) mOpenFrames.peek();
org.apache.vinci.transport.Attributes vinciAttrs = parent.aadd(mCurrentFrameName, frame);
// set attributes
if (mCurrentFrameAttrs != null) {
for (int i = 0; i < mCurrentFrameAttrs.getLength(); i++) {
String attrName = getName(mCurrentFrameAttrs.getLocalName(i), mCurrentFrameAttrs
.getQName(i));
vinciAttrs.fadd(attrName, mCurrentFrameAttrs.getValue(i));
}
}
// put new frame on stack
mOpenFrames.push(frame);
}
// now store the information for the new element
String elemName = getName(localName, qualifiedName);
mCurrentFrameName = elemName;
mCurrentFrameAttrs = attributes;
}
/**
* @see org.xml.sax.ContentHandler#characters(char[],int,int)
*/
public void characters(char[] ch, int start, int length) {
mCharContentBuffer.append(ch, start, length);
}
/**
* @see org.xml.sax.ContentHandler#endElement(String,String,String)
*/
public void endElement(String namespaceURI, String localName, String qualifiedName) {
// if we're ending a leaf frame (which we know because mCurrentFrame is
// non-null), we must create the appropriate FrameLeaf object and add
// it to the top frame on the stack.
if (mCurrentFrameName != null) {
// the getLeafContent method just returns the contents of the
// mCharContentBuffer, but exists so subclasses can override for
// specialized behavior (such as supressing certain content).
String leafContent = getLeafContent(mCurrentFrameName, mCurrentFrameAttrs, mCharContentBuffer);
// add leaf to parent frame
AFrame parent = (AFrame) mOpenFrames.peek();
org.apache.vinci.transport.Attributes vinciAttrs = parent
.aadd(mCurrentFrameName, leafContent);
// set attributes
if (mCurrentFrameAttrs != null) {
for (int i = 0; i < mCurrentFrameAttrs.getLength(); i++) {
String attrName = getName(mCurrentFrameAttrs.getLocalName(i), mCurrentFrameAttrs
.getQName(i));
vinciAttrs.fadd(attrName, mCurrentFrameAttrs.getValue(i));
}
}
mCurrentFrameName = null;
mCurrentFrameAttrs = null;
mCharContentBuffer = new StringBuffer();
} else {
// ending a non-leaf frame; pop the stack
mOpenFrames.pop();
}
}
/**
* Gets the content to be included in a FrameLeaf. This method just returns the contents of the
* provided StringBuffer, but subclasses can override to provide specialized content.
*
* @param aFrameName
* name of the FrameLeaf
* @param aAttributes
* attributes of FrameLeaf
* @param aContentBuf
* StringBuffer containing the character data obtained from the SAX parser
*
* @return the data to be included in the Vinci FrameLeaf
*/
protected String getLeafContent(String aFrameName, Attributes aAttributes,
StringBuffer aContentBuf) {
return aContentBuf.toString();
}
/**
* If the first String parameter is nonempty, return it, else return the second string parameter.
*
* @param s1
* The string to be tested.
* @param s2
* The alternate String.
* @return s1 if it isn't empty, else s2.
*/
protected String getName(String s1, String s2) {
if (s1 == null || "".equals(s1))
return s2;
else
return s1;
}
}