com.hfg.xml.xsd.Xsd Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com_hfg Show documentation
Show all versions of com_hfg Show documentation
com.hfg xml, html, svg, and bioinformatics utility library
package com.hfg.xml.xsd;
import java.io.*;
import java.util.*;
import org.xml.sax.*;
import com.hfg.util.StringBuilderPlus;
import com.hfg.util.collection.CollectionUtil;
import com.hfg.util.StringUtil;
import com.hfg.xml.XMLException;
import com.hfg.xml.XMLName;
import com.hfg.xml.XMLNamespace;
import com.hfg.xml.XMLTag;
import com.hfg.xml.parser.SaxyParser;
import com.hfg.xml.parser.XMLTagSAXBroadcaster;
import com.hfg.xml.parser.XMLTagSAXListener;
//------------------------------------------------------------------------------
/**
XML Schema Definition (XSD) specification container.
@author J. Alex Taylor, hairyfatguy.com
*/
//------------------------------------------------------------------------------
// com.hfg XML/HTML Coding Library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
// [email protected]
//------------------------------------------------------------------------------
public class Xsd
{
private final Map mTypeMap = new HashMap<>(2500);
private final Map mGroupMap = new HashMap<>(100);
// We have seen some cases (OfficeOpenXML SpreadsheetML) where the same element name is used with different types.
// Hence, the map allows a Set of elements.
private Map> mElementMap = new HashMap<>(2500);
private SaxyParser mParser;
//###########################################################################
// PUBLIC METHODS
//###########################################################################
//---------------------------------------------------------------------------
public void parse(File inFile)
throws IOException, SAXException
{
BufferedReader reader = null;
try
{
reader = new BufferedReader(new FileReader(inFile));
parse(reader);
}
finally
{
if (reader != null) reader.close();
}
}
//---------------------------------------------------------------------------
public void parse(Reader inReader)
throws IOException, SAXException
{
mParser = new SaxyParser();
XMLTagSAXListenerImpl listener = new XMLTagSAXListenerImpl();
XMLTagSAXBroadcaster contentHandler = new XMLTagSAXBroadcaster()
.addListener(listener, XsdXML.SCHEMA.getLocalName())
.addListener(listener, XsdXML.COMPLEX_TYPE.getLocalName())
.addListener(listener, XsdXML.SIMPLE_TYPE.getLocalName())
.addListener(listener, XsdXML.GROUP.getLocalName())
.addListener(listener, XsdXML.ELEMENT.getLocalName());
mParser.setContentHandler(contentHandler);
mParser.parse(new InputSource(inReader));
}
//---------------------------------------------------------------------------
public Set getElements(XMLName inElementName)
{
return getElements(inElementName.getLocalName());
}
//---------------------------------------------------------------------------
public Set getElements(String inElementName)
{
Set elementSet = mElementMap.get(inElementName);
if (null == elementSet
&& inElementName.indexOf(":") > 0)
{
// Try to look it up w/o the namespace prefix
String baseElementName = inElementName.substring(inElementName.indexOf(":") + 1);
elementSet = mElementMap.get(baseElementName);
}
return elementSet;
}
//---------------------------------------------------------------------------
/**
For debugging/logging purposes.
* @return a summary of the cached XSD information.
*/
public CharSequence getConfigSummary()
{
StringBuilderPlus buffer = new StringBuilderPlus();
buffer.appendln("XSD Type Map Size: " + mTypeMap.size());
buffer.appendln("XSD Group Map Size: " + mGroupMap.size());
buffer.appendln("XSD Element Map Size: " + mElementMap.size());
return buffer;
}
//###########################################################################
// PROTECTED METHODS
//###########################################################################
//---------------------------------------------------------------------------
protected void integrateTypesWithElements()
{
// Not all namespace prefixes may have been set at the time the element was inserted into the Map.
// Hence, we need to rebuild the map so we can lookup elements using their qualified names.
Map> readjustedElementMap = new HashMap<>(mElementMap.size());
for (Set elements : mElementMap.values())
{
for (XsdElement element : elements)
{
Set elementSet = readjustedElementMap.get(element.getQualifiedName());
if (null == elementSet)
{
elementSet = new HashSet<>(4);
readjustedElementMap.put(element.getQualifiedName(), elementSet);
}
elementSet.add(element);
}
}
mElementMap = readjustedElementMap;
// Flesh out the type object for ea. element.
for (Set elements : mElementMap.values())
{
for (XsdElement element : elements)
{
element.setType(mTypeMap.get(element.getQualifiedTypeName()));
}
}
// Flesh out complex types
for (XsdType xsdType : mTypeMap.values())
{
if (xsdType instanceof XsdComplexType)
{
// Is there a base type that needs to be set?
String baseTypeName = ((XsdComplexType) xsdType).getNameOfBaseType();
if (StringUtil.isSet(baseTypeName))
{
((XsdComplexType) xsdType).setBaseType((XsdComplexType) mTypeMap.get(baseTypeName));
}
List contentList = ((XsdComplexType)xsdType).getContent();
if (CollectionUtil.hasValues(contentList))
{
for (XsdContent content : contentList)
{
recursivelyFleshOutContent(content);
}
}
}
}
}
//###########################################################################
// PRIVATE METHODS
//###########################################################################
//---------------------------------------------------------------------------
private void recursivelyFleshOutContent(XsdContent inContent)
{
if (inContent instanceof XsdSequence)
{
List sequenceContentList = ((XsdSequence)inContent).getContent();
if (CollectionUtil.hasValues(sequenceContentList))
{
for (XsdContent sequenceContent : sequenceContentList)
{
recursivelyFleshOutContent(sequenceContent);
}
}
}
else if (inContent instanceof XsdChoice)
{
Set choiceContents = ((XsdChoice)inContent).getOptions();
if (CollectionUtil.hasValues(choiceContents))
{
for (XsdContent choiceContent : choiceContents)
{
recursivelyFleshOutContent(choiceContent);
}
}
}
else if (inContent instanceof XsdGroup)
{
XsdGroup xsdGroup = (XsdGroup) inContent;
if (null == xsdGroup.getContent())
{
XsdGroup groupDef = mGroupMap.get(xsdGroup.getName());
if (groupDef != null
&& CollectionUtil.hasValues(groupDef.getContent()))
{
for (XsdContent groupContent : groupDef.getContent())
{
recursivelyFleshOutContent(groupContent);
((XsdGroup) inContent).addContent(groupContent);
}
}
}
}
else if (inContent instanceof XsdElement
&& ((XsdElement) inContent).getRef() != null)
{
// Flesh out ref elements
XsdElement refElement = ((XsdElement) inContent);
Set elementSet = mElementMap.get(refElement.getRef().getQualifiedName());
if (elementSet != null)
{
// TODO: Not sure what to do if we have multiple elements with the same name.
XsdElement element = elementSet.iterator().next();
refElement.setName(element.getLocalName());
refElement.setType(element.getType());
}
else
{
System.out.println("Dangling xsd ref: " + refElement.getRef().getQualifiedName());
}
}
}
//###########################################################################
// INNER CLASS
//###########################################################################
private class XMLTagSAXListenerImpl implements XMLTagSAXListener
{
//########################################################################
// CONSTRUCTORS
//########################################################################
//------------------------------------------------------------------------
public XMLTagSAXListenerImpl()
{
}
//########################################################################
// PUBLIC METHODS
//########################################################################
//------------------------------------------------------------------------
public void receive(XMLTag inXMLTag)
{
try
{
XMLNamespace namespace = mParser.getCurrentDefaultNamespace();
if (inXMLTag.getTagName().equals(XsdXML.SIMPLE_TYPE.getLocalName()))
{
XsdSimpleType simpleType = new XsdSimpleType(inXMLTag);
simpleType.setNamespace(namespace);
mTypeMap.put(simpleType.getQualifiedName(), simpleType);
}
else if (inXMLTag.getTagName().equals(XsdXML.ELEMENT.getLocalName()))
{
if (inXMLTag.hasAttribute(XsdXML.NAME_ATT.getLocalName())
&& ! mElementMap.containsKey(inXMLTag.getQualifiedTagName()))
{
XsdElement element = new XsdElement(inXMLTag);
element.setNamespace(namespace);
if (StringUtil.isSet(element.getLocalName()))
{
Set elementSet = mElementMap.get(element.getQualifiedName());
if (null == elementSet)
{
elementSet = new HashSet<>(4);
mElementMap.put(element.getQualifiedName(), elementSet);
}
elementSet.add(element);
}
}
}
else if (inXMLTag.getTagName().equals(XsdXML.COMPLEX_TYPE.getLocalName()))
{
XsdComplexType complexType = new XsdComplexType(inXMLTag, namespace);
mTypeMap.put(complexType.getQualifiedName(), complexType);
}
else if (inXMLTag.getTagName().equals(XsdXML.GROUP.getLocalName())
&& inXMLTag.hasAttribute(XsdXML.NAME_ATT.getLocalName()))
{
XsdGroup group = new XsdGroup(inXMLTag, namespace);
mGroupMap.put(group.getName(), group);
}
}
catch (Exception e)
{
throw new XMLException("Problem parsing " + inXMLTag.toXML(), e);
}
}
}
}