org.xerial.silk.SilkUtil Maven / Gradle / Ivy
/*--------------------------------------------------------------------------
* Copyright 2009 Taro L. Saito
*
* Licensed 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.
*--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// SilkUtil.java
// Since: 2009/02/13 21:15:32
//
// $URL$
// $Author$
//--------------------------------------
package org.xerial.silk;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import org.xerial.core.XerialError;
import org.xerial.core.XerialException;
import org.xerial.json.JSONArray;
import org.xerial.json.JSONObject;
import org.xerial.json.JSONValue;
import org.xerial.lens.tree.TreeEvent;
import org.xerial.util.ArrayDeque;
import org.xerial.util.Deque;
import org.xerial.util.bean.impl.BeanUtilImpl;
import org.xerial.util.tree.TreeVisitor;
import org.xerial.util.tree.TreeVisitorBase;
import org.xerial.util.tree.TreeWalker;
import org.xerial.util.xml.XMLAttribute;
import org.xerial.util.xml.XMLErrorCode;
import org.xerial.util.xml.XMLGenerator;
/**
* Utilities for handling Silk file format.
*
* @author leo
*
*/
public class SilkUtil
{
/**
* Silk to Object mapping. Create a bean object from a given Silk file. The
* parameter values of the specified bean class will be populated with the
* content of the Silk file.
*
*
* @param
* @param beanType
* object type to generate
* @param silkSource
* Silk file address
* @return object generated from the Silk source file
* @throws XerialException
* @throws IOException
* when failed to open the specified Silk file.
*/
public static E createBean(Class beanType, URL silkSource) throws XerialException, IOException
{
return BeanUtilImpl.createBeanFromSilk(beanType, silkSource);
}
/**
* Populate the parameter values of the given bean using the content of the
* Silk file.
*
* @param
* @param bean
* object to populate
* @param silkSource
* Silk file address
* @return
* @throws XerialException
* @throws IOException
* when failed to open the specified Silk file
*/
public static E populateBean(E bean, URL silkSource) throws XerialException, IOException
{
return BeanUtilImpl.populateBeanWithSilk(bean, silkSource);
}
/**
* Convert the given Silk file into XML data. Since Silk's data model is
* forest, while XML is tree, the root element (<silk> tag) for the
* XML data will be generated.
*
* @param silkSource
* @return
* @throws IOException
* @throws XerialException
*/
public static String toXML(URL silkSource) throws IOException, XerialException
{
StringWriter buf = new StringWriter();
toXML(silkSource, buf);
return buf.toString();
}
/**
* Convert the silk file into XML
*
* @param silkSource
* @param out
* @throws IOException
* @throws XerialException
*/
public static void toXML(URL silkSource, Writer out) throws IOException, XerialException
{
SilkWalker walker = new SilkWalker(silkSource);
XMLBuilder builder = new XMLBuilder(out);
walker.walk(builder);
}
/**
*
*
* 1:visit -> 2:visit : pop(1), startTag(1, value=".."), push(2:visit)
* 1:visit -> 2:text : pop(1), startTag(1, value=".."), text(2:text)
* 1:visit -> 2:leave : pop(1), selfCloseTag(1, value="..")
*
*
* @author leo
*
*/
private static class XMLBuilder extends TreeVisitorBase
{
final XMLGenerator xout;
final Deque eventQueue = new ArrayDeque();
public XMLBuilder(Writer out)
{
xout = new XMLGenerator(out);
}
private void popQueue()
{
if (!eventQueue.isEmpty())
{
TreeEvent prev = eventQueue.removeLast();
switch (prev.event)
{
case VISIT:
if (prev.nodeValue == null)
xout.startTag(prev.nodeName);
else
xout.startTag(prev.nodeName, new XMLAttribute("value", prev.nodeValue));
break;
default:
throw new XerialError(XMLErrorCode.INVALID_XML_STRUCTURE);
}
}
}
@Override
public void visitNode(String nodeName, String immediateNodeValue, TreeWalker walker) throws XerialException
{
popQueue();
eventQueue.addLast(new TreeEvent(TreeEvent.EventType.VISIT, nodeName, immediateNodeValue));
}
@Override
public void text(String nodeName, String textDataFragment, TreeWalker walker) throws XerialException
{
popQueue();
xout.text(textDataFragment);
}
@Override
public void leaveNode(String nodeName, TreeWalker walker) throws XerialException
{
if (!eventQueue.isEmpty())
{
TreeEvent prev = eventQueue.removeLast();
switch (prev.event)
{
case VISIT:
if (prev.nodeValue == null)
xout.selfCloseTag(prev.nodeName);
else
xout.element(prev.nodeName, prev.nodeValue);
}
}
else
xout.endTag();
}
@Override
public void init(TreeWalker walker) throws XerialException
{
visitNode("silk", null, walker);
}
@Override
public void finish(TreeWalker walker) throws XerialException
{
leaveNode("silk", walker);
xout.endDocument();
}
}
/**
* Convert the Silk data into JSON.
*
* TODO implementation
*
* @param silkSource
* @param out
* @throws IOException
* @throws XerialException
*/
public static Writer toJSON(URL silkSource, Writer out) throws IOException, XerialException
{
SilkWalker walker = new SilkWalker(silkSource);
JSONBuilder jsonBuilder = new JSONBuilder();
walker.walk(jsonBuilder);
JSONArray root = jsonBuilder.getRoot();
out.append(root.toJSONString());
return out;
}
private static class JSONBuilder implements TreeVisitor
{
JSONArray root = new JSONArray();
Deque contextStack = new ArrayDeque();
Deque textStack = new ArrayDeque();
final StringBuilder ZERO_CAPACITY_BUFFER = new StringBuilder(0);
public JSONBuilder()
{
}
public JSONArray getRoot()
{
return root;
}
private JSONObject getContext()
{
return contextStack.peekLast();
}
private StringBuilder getTextBuilder()
{
if (textStack.peekLast() == ZERO_CAPACITY_BUFFER)
{
textStack.removeLast();
textStack.addLast(new StringBuilder());
}
return textStack.peekLast();
}
public void finish(TreeWalker walker) throws XerialException
{}
public void init(TreeWalker walker) throws XerialException
{}
public void leaveNode(String nodeName, TreeWalker walker) throws XerialException
{
JSONObject node = getContext();
contextStack.removeLast();
if (node.keys().size() == 0)
{
// flatten object into single key:value pair
JSONObject parent = getContext();
if (textStack.peekLast() != ZERO_CAPACITY_BUFFER)
parent.put(nodeName, textStack.peekLast().toString());
if (contextStack.size() == 1)
{
contextStack.removeLast(); // remove additional object
textStack.removeLast();
return;
}
}
else
{
if (contextStack.size() == 1)
{
contextStack.removeLast(); // remove additional object
textStack.removeLast();
return;
}
JSONObject parent = getContext();
if (!parent.hasKey(nodeName))
parent.put(nodeName, node);
else
{
// use array to handle multiple occurrences of the same name node
JSONValue elderBrother = parent.get(nodeName);
JSONArray array = elderBrother.getJSONArray();
if (array != null)
{
array.add(node);
}
else
{
parent.remove(nodeName);
array = new JSONArray();
array.add(elderBrother);
array.add(node);
parent.put(nodeName, array);
}
}
}
textStack.removeLast();
}
public void text(String nodeName, String textDataFragment, TreeWalker walker) throws XerialException
{
getTextBuilder().append(textDataFragment);
}
public void visitNode(String nodeName, String immediateNodeValue, TreeWalker walker) throws XerialException
{
JSONObject newContext = new JSONObject();
if (contextStack.isEmpty())
{
JSONObject childOfRoot = new JSONObject();
childOfRoot.put(nodeName, newContext);
root.add(childOfRoot);
contextStack.addLast(childOfRoot); // additional object
}
contextStack.addLast(newContext);
textStack.addLast(ZERO_CAPACITY_BUFFER);
if (immediateNodeValue != null)
getTextBuilder().append(immediateNodeValue);
}
}
/**
* Forbid construction
*/
protected SilkUtil()
{}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy