// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.library.tools.xpath; import java.util.ArrayList; import java.util.Collections; import java.util.List; import openadk.library.*; import openadk.library.impl.surrogates.RenderSurrogate; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.JXPathException; import org.apache.commons.jxpath.ri.NamespaceResolver; import org.apache.commons.jxpath.ri.QName; import org.apache.commons.jxpath.ri.compiler.NodeNameTest; import org.apache.commons.jxpath.ri.compiler.NodeTest; import org.apache.commons.jxpath.ri.model.NodeIterator; import org.apache.commons.jxpath.ri.model.NodePointer; import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer; import org.apache.commons.jxpath.ri.model.beans.PropertyPointer; /** * Represents a NodePointer for a SIFElement * * @author Andrew Elmhorst * @version ADK 2.0 */ public class SIFElementPointer extends ADKElementPointer { /** * */ private static final long serialVersionUID = -2805505553878070975L; protected SIFElement fSIFElement; /** * @param parentpointer * @param element * @param version */ public SIFElementPointer(NodePointer parentpointer, SIFElement element, SIFVersion version) { super(parentpointer, element, version); fSIFElement = element; } /* (non-Javadoc) * @see org.apache.commons.jxpath.ri.model.NodePointer#getDefaultNamespaceURI() */ @Override protected String getDefaultNamespaceURI() { String sifNSURI = getVersion().getXmlns(); return sifNSURI; } /** * @param parentPointer * @param element * @param version * @return A NodePointer pointing to a SIFElement */ public static NodePointer create( NodePointer parentPointer, SIFElement element, SIFVersion version ) { if( version.getMajor() < 2 ){ ElementDef fieldDef = element.getElementDef(); RenderSurrogate rs = fieldDef.getVersionInfo( version ).getSurrogate(); if( rs != null ){ return rs.createNodePointer( parentPointer, element, version ); } } if ( "SIF_ExtendedElement".equals(element.tag()) ) return new SIFExtendedElementPointer( parentPointer, (openadk.library.common.SIF_ExtendedElement)element, version ); else return new SIFElementPointer( parentPointer, element, version ); } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.ri.model.NodePointer#isLeaf() */ @Override public boolean isLeaf() { return false; } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.ri.model.NodePointer#isCollection() */ @Override public boolean isCollection() { return false; } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.ri.model.NodePointer#getLength() */ @Override public int getLength() { return 1; } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.Pointer#setValue(java.lang.Object) */ @Override public void setValue(Object rawValue) { SIFSimpleType sst = getSIFSimpleTypeValue( fElementDef, rawValue ); fSIFElement.setSIFValue( sst ); } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.ri.model.NodePointer#attributeIterator(org.apache.commons.jxpath.ri.QName) */ @Override public NodeIterator attributeIterator(QName name) { // SIFVersion version = getVersion(); // if( version.getMajor() < 2 ){ // // Look for a surrogate pointer if the SIF Version < 2 // ElementDef def = ADK.DTD().lookupElementDef( fElementDef, name.getName() ); // if( def != null ){ // ElementVersionInfo evi = def.getVersionInfo( version ); // if( evi != null ){ // // Determine if a RenderSurrogate handles this path // RenderSurrogate surrogate = evi.getSurrogate(); // if( surrogate != null ){ // return surrogate.childIterator( this, name ); // } // } // } // } return new ADKAttributeIterator(this, name); } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.ri.model.NodePointer#childIterator(org.apache.commons.jxpath.ri.compiler.NodeTest, * boolean, org.apache.commons.jxpath.ri.model.NodePointer) */ @Override public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith) { ArrayList<Element> alist = new ArrayList<Element>(); SIFVersion version = getVersion(); // Do a cursory speed check if (test != null && test instanceof NodeNameTest) { NodeNameTest nnt = (NodeNameTest) test; if (!nnt.isWildcard()) { QName name = nnt.getNodeName(); String localName = name.getName(); // Look for a surrogate pointer if the SIF Version < 2 ElementDef def = ADK.DTD().lookupElementDef( fElementDef, localName ); if( def != null ){ // Check to see if this ElementDef represents a field or complex type (SIFElement) if( def.isField() ){ SimpleField sf = this.fSIFElement.getField(localName); if( sf != null ) { return new SingleNodeIterator( SimpleFieldPointer.create(this, sf) ); } } else { List<SIFElement> children = this.fSIFElement.getChildList(localName); if (children.size() > 0) { alist.addAll(children); } } } } } if (alist.size() == 0) { // Get all of the Element fields and children that match the // NodeTest into a list SIFFormatter formatter = ADK.DTD().getFormatter( version ); List<Element> elements = formatter.getContent(fSIFElement, version); for (Element e : elements) { if (testElement(e, test)) { alist.add(e); } } } if (alist.size() == 1) { Element singleChild = alist.get( 0 ); if( singleChild instanceof SimpleField ){ return new SingleNodeIterator( SimpleFieldPointer.create( this, (SimpleField)singleChild ) ); } else { return new SingleNodeIterator( SIFElementPointer.create( this, (SIFElement)singleChild, version ) ); } } int start = -1; if (startWith != null) { start = alist.indexOf(startWith.getNode()); } if (start == -1) { if (reverse) { start = alist.size() - 1; } else { start = 0; } } if (reverse) { Collections.reverse(alist); } return new ADKElementIterator(this, alist); } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.ri.model.NodePointer#createChild(org.apache.commons.jxpath.JXPathContext, * org.apache.commons.jxpath.ri.QName, int) */ @Override public NodePointer createChild(JXPathContext context, QName name, int childIndex) { ElementDef subEleDef = getChildDef(name); SIFVersion version = getVersion(); SIFFormatter formatter = ADK.DTD().getFormatter(version); // Check to see if this child has a render surrogate defined RenderSurrogate rs = subEleDef.getVersionInfo( version ).getSurrogate(); if( rs != null ){ return rs.createChild( this, formatter, version, context ); } return createChildPointer(subEleDef, version, formatter); } /** * Creates a NodePointer representing the specified child * @param childDef * @param version * @param formatter * @return */ public NodePointer createChildPointer(ElementDef childDef, SIFVersion version, SIFFormatter formatter) { if (childDef.isField()) { SIFSimpleType ssf = childDef.getTypeConverter().getSIFSimpleType( null ); SimpleField sf = formatter.setField(fSIFElement, childDef, ssf, version);// fSIFElement.setField(sf); return SimpleFieldPointer.create( this, sf ); } else { try { SIFElement newEle = SIFElement.create( this.fSIFElement, childDef ); formatter.addChild(fSIFElement, newEle, version); if ( "SIF_ExtendedElement".equals(newEle.tag()) ) return new SIFExtendedElementPointer( this, (openadk.library.common.SIF_ExtendedElement)newEle, version ); else return new SIFElementPointer( this, newEle, version ); } catch (ADKSchemaException adkse) { throw new JXPathException(adkse.getMessage(), adkse); } } } /** * Reutrns a child def with the requested name * @param name The name to look up * @return The ElementDef representing the requested name */ private ElementDef getChildDef(QName name) { String localName = name.getName(); ElementDef subEleDef = ADK.DTD().lookupElementDef( fElementDef, localName ); if (subEleDef == null) { subEleDef = ADK.DTD().lookupElementDef(localName); if (subEleDef == null) throw new JXPathException(localName + " is not a recognized element of " + fElementDef.tag(getVersion())); } return subEleDef; } /** * Use by SIFXPathContext when determining if it can add a child * or not. * @param childName * @return True if a child should be added, false if it already exists */ public AddChildDirective getAddChildDirective( QName childName ){ if( fSIFElement.getChildCount() == 0 ){ // There are no children. Don't even check for repeatability. // This child can be added. return AddChildDirective.ADD; } ElementDef candidate = getChildDef( childName ); if( candidate.isField() ){ // Don't evaluate repeatability return AddChildDirective.ADD; } SIFElement instance = fSIFElement.getChild( candidate ); if( instance == null ){ // There are no siblings of this type. This child can be // added return AddChildDirective.ADD; } if( candidate.isRepeatable( getVersion() ) ){ // This element is repeatable. This child can be added return AddChildDirective.ADD; } // A sibling exists, and the element is not repeatable return AddChildDirective.DONT_ADD_NOT_REPEATABLE; } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.ri.model.NodePointer#createChild(org.apache.commons.jxpath.JXPathContext, * org.apache.commons.jxpath.ri.QName, int, java.lang.Object) */ @Override public NodePointer createChild(JXPathContext context, QName name, int childIndex, Object value) { NodePointer ptr = createChild(context, name, childIndex); ptr.setValue(value); return ptr; } /* * (non-Javadoc) * * @see org.apache.commons.jxpath.ri.model.NodePointer#createAttribute(org.apache.commons.jxpath.JXPathContext, * org.apache.commons.jxpath.ri.QName) */ @Override public NodePointer createAttribute(JXPathContext context, QName name) { ElementDef subEleDef = getChildDef(name); if (subEleDef.isField()) { SIFSimpleType ssf = subEleDef.getTypeConverter().getSIFSimpleType( null); SimpleField sf = ssf.createField(fSIFElement, subEleDef); fSIFElement.setField(sf); return SimpleFieldPointer.create(this, sf); } throw new JXPathException( "Factory could not create a child node for path: " + asPath() + "/" + name + "[" + (index + 1) + "]"); } /** * The set of values that can be returned from the <code>getChildAddDirective<code> * method * */ public enum AddChildDirective { /** * It is OK to add this child */ ADD, /** * Don't add this child because the element is not repeatable and * another already exists as a child of this element */ DONT_ADD_NOT_REPEATABLE } }