| /* |
| * 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; |
| } |
| } |