public override INodePointer CreateChild(SifXPathContext context, string name, int i) { SifVersion version = Version; IElementDef subEleDef = GetChildDef(name); SifFormatter formatter = Adk.Dtd.GetFormatter(version); SifElement sifElement = (SifElement)fElement; // Check to see if this child has a render surrogate defined IRenderSurrogate rs = subEleDef.GetVersionInfo(version).GetSurrogate(); if (rs != null) { return(rs.CreateChild(this, formatter, version, context)); } if (subEleDef.Field) { SifSimpleType ssf = subEleDef.TypeConverter.GetSifSimpleType(null); SimpleField sf = formatter.SetField(sifElement, subEleDef, ssf, version); return(SimpleFieldPointer.Create(this, sf)); } else { SifElement newEle = SifElement.Create(sifElement, subEleDef); formatter.AddChild(sifElement, newEle, version); return(new SifElementPointer(this, newEle, version)); } }
/// <summary> /// Creates a child element, if supported by this node /// </summary> /// <param name="parentPointer"></param> /// <param name="formatter"></param> /// <param name="version"></param> /// <param name="context"></param> /// <returns></returns> public INodePointer CreateChild(INodePointer parentPointer, SifFormatter formatter, SifVersion version, SifXPathContext context) { // 1) Create an instance of the SimpleField with a null value (It's assigned later) // // STEP 2 // Find the actual field to set the value to // SifElement parent = (SifElement)((SifElementPointer)parentPointer).Element; SifElement targetElement = parent; if (!fElementDef.Field) { // This indicates a child SifElement that needs to be created targetElement = SifElement.Create(parent, fElementDef); formatter.AddChild(parent, targetElement, version); } IElementDef fieldDef = null; if (fValueXpath.Equals(".")) { fieldDef = fElementDef; } else { String fieldName = fValueXpath; if (fValueXpath.StartsWith("@")) { fieldName = fValueXpath.Substring(1); } fieldDef = Adk.Dtd.LookupElementDef(fElementDef, fieldName); } if (fieldDef == null) { throw new ArgumentException("Support for value path {" + fValueXpath + "} is not supported by XPathSurrogate."); } SifSimpleType ssf = fieldDef.TypeConverter.GetSifSimpleType(null); SimpleField sf = ssf.CreateField(targetElement, fieldDef); targetElement.SetField(sf); // 2) built out a fake set of node pointers representing the SIF 1.5r1 path and // return the root pointer from that stack return(BuildLegacyPointers(parentPointer, sf)); }
/// <summary> /// Creates a child element, if supported by this node /// </summary> /// <param name="parentPointer"></param> /// <param name="formatter"></param> /// <param name="version"></param> /// <param name="context"></param> /// <returns></returns> public INodePointer CreateChild( INodePointer parentPointer, SifFormatter formatter, SifVersion version, SifXPathContext context ) { // 1) Create an instance of the SimpleField with a null value (It's assigned later) // // STEP 2 // Find the actual field to set the value to // SifElement parent = (SifElement) ((SifElementPointer) parentPointer).Element; SifElement targetElement = parent; if ( !fElementDef.Field ) { // This indicates a child SifElement that needs to be created targetElement = SifElement.Create( parent, fElementDef ); formatter.AddChild( parent, targetElement, version ); } IElementDef fieldDef = null; if ( fValueXpath.Equals( "." ) ) { fieldDef = fElementDef; } else { String fieldName = fValueXpath; if ( fValueXpath.StartsWith( "@" ) ) { fieldName = fValueXpath.Substring( 1 ); } fieldDef = Adk.Dtd.LookupElementDef( fElementDef, fieldName ); } if ( fieldDef == null ) { throw new ArgumentException( "Support for value path {" + fValueXpath + "} is not supported by XPathSurrogate." ); } SifSimpleType ssf = fieldDef.TypeConverter.GetSifSimpleType( null ); SimpleField sf = ssf.CreateField( targetElement, fieldDef ); targetElement.SetField( sf ); // 2) built out a fake set of node pointers representing the SIF 1.5r1 path and // return the root pointer from that stack return BuildLegacyPointers( parentPointer, sf ); }
/// <summary> /// Creates a child element and sets the text value /// </summary> /// <param name="relativeTo">The parent SIFElement to add the new element to</param> /// <param name="tag">The tag name of the element</param> /// <param name="valueBuilder">The ValueBuilder instance to use to evaluate macros</param> /// <param name="version">The version of SIF for which this mapping operation is being evaluated</param> /// <param name="textFormatter">The SIFFormatter instance used to parse strings into strongly-typed data values. /// For many uses of this API, this formatter is equivalent to Adk.TextFormatter</param> /// <param name="pathFormatter">The SIFFormatter instance used for setting child SIFElements on their parents. /// This formatter may be different than the text formatter. The text formatter is, for /// compatibility's sake defaulted to SIF 1.x. However, the path formatter must be /// correct for the mappings path being evaluated.</param> /// <returns></returns> private SifElement _createChild( SifElement relativeTo, String tag, IValueBuilder valueBuilder, SifVersion version, SifFormatter textFormatter, SifFormatter pathFormatter) { string _tag = tag; string assignValue = null; int eq = tag.IndexOf('='); if (eq != -1) { _tag = tag.Substring(0, (eq) - (0)); string str = tag.Substring(eq + 1); assignValue = valueBuilder == null ? str : valueBuilder.Evaluate(str); } // Lookup the IElementDef IElementDef def = Adk.Dtd.LookupElementDef(relativeTo.ElementDef, _tag); if (def == null) { def = Adk.Dtd.LookupElementDef(_tag); } if (def == null) { throw new AdkSchemaException(_tag + " is not a recognized element or attribute of " + relativeTo.Tag); } try { TypeConverter defConverter = def.TypeConverter; if (defConverter == null) { defConverter = SifTypeConverters.STRING; } if (def.Field) { SimpleField field = defConverter.ParseField(relativeTo, def, textFormatter, assignValue); relativeTo.SetField(field); } else { // Create element instance SifElement ele = (SifElement)ClassFactory.CreateInstance(def.FQClassName); ele.ElementDef = def; pathFormatter.AddChild(relativeTo, ele, version); if (assignValue != null) { // TODO: THis needs to be done using the type converter ele.TextValue = assignValue; } return ele; } } catch (TypeLoadException tle) { throw new SystemException( "The " + def.Package + " Sdo module is not loaded (ensure the Adk is initialized to load this module)", tle); } catch (Exception thr) { throw new SystemException( "Failed to create an instance of the " + def.ClassName + " class from the " + def.Package + " Sdo module: ", thr); } return null; }
/// <summary> Recursively builds elements and attributes relative to a SifElement.</summary> /// <param name="relativeTo">The SifElement this iteration is relative to. For the /// first call to this method, the <i>relativeTo</i> parameter is usually /// a SifDataObject such as StudentPersonal to which the XPath query /// string is relative. With each subsequent call it is the SifElement /// or SimpleField that was previously processed.</param> /// <param name="path">A running path of the segments processed thus far; an empty /// StringBuffer should be passed to this parameter the first time the /// method is called </param> /// <param name="curSegment">The current segment of the path that is being processed. /// For the first call to this method, the <i>curSegment</i> should be /// the portion of the XPath query string up to the first forward slash, /// exclusive.</param> /// <param name="nextSegment">The remaining portion of the path to be processed. /// For the first call to this method, the <i>nextSegment</i> should be /// the portion of the XPath query string following the first forward /// slash.</param> /// <param name="prevAttributes">An optional array of attribute values that were /// used to construct an Element in the processing of the last segment. /// The array is comprised of attribute name and value pairs such that /// element N is an attribute name and N+1 is its value. For the first /// call to this method, the array should be null. For subsequent calls, /// it should be null unless an Element was constructed from attribute /// values.</param> /// <param name="version">The version of SIF for which this mapping operation is being evaluated</param> /// <param name="textFormatter">The SIFFormatter instance used to parse strings into strongly-typed data values. /// For many uses of this API, this formatter is equivalent to ADK.TextFormatter</param> /// <param name="pathFormatter">The SIFFormatter instance used for setting child SIFElements on their parents. /// This formatter may be different than the text formatter. The text formatter is, for /// compatibility's sake defaulted to SIF 1.x. However, the path formatter must be /// correct for the mappings path being evaluated.</param> /// <param name="valueBuilder"></param> /// <returns> The Element satisfying the query, or <c>null</c> if no /// match was found (unless the <i>create</i> parameter is true). If the /// query resolves to an attribute, a SimpleField object is returned. If /// it resolves to an element, a SifElement object is returned. In both /// cases the caller can obtain the text value of the attribute or /// element by calling its <c>TextValue</c> Property. /// </returns> private Element _xpathBuild( SifElement relativeTo, StringBuilder path, string curSegment, string nextSegment, string[] prevAttributes, IValueBuilder valueBuilder, SifVersion version, SifFormatter textFormatter, SifFormatter pathFormatter) { string[] _prevAttributes = null; SifElement nextEle = null; int asgnEq = curSegment.LastIndexOf('='); int attr = curSegment.LastIndexOf('@', asgnEq == -1 ? curSegment.Length - 1 : asgnEq - 1); int bracket = curSegment.IndexOf('['); if (bracket != -1) { if (attr == -1) { throw new AdkSchemaException("Invalid query: \"" + curSegment + "\" must be in the form [@Attr='value1','value2',...]"); } string subEleTag = curSegment.Substring(0, (bracket) - (0)); int lastBracket = curSegment.LastIndexOf(']'); string[] attrList = curSegment.Substring(bracket + 1, (lastBracket) - (bracket + 1)).Split(','); _prevAttributes = new string[attrList.Length * 2]; int _prevI = 0; for (int a = 0; a < attrList.Length; a++) { string _curSegment = attrList[a]; // Determine the value of the attribute int eq = _curSegment.IndexOf("="); string val = _curSegment.Substring(eq + 1); string v = null; if (val[0] == '\'') { int end = val.IndexOf('\'', 1); if (end != -1) { v = valueBuilder == null ? val.Substring(1, (end) - (1)) : valueBuilder.Evaluate(val.Substring(1, (end) - (1))); } } if (v == null) { throw new AdkSchemaException("Attribute value (" + val + ") must be in the form @Attribute='value'"); } string attrName = _curSegment.Substring(1, (eq) - (1)); _prevAttributes[_prevI++] = attrName; _prevAttributes[_prevI++] = v; if (nextEle == null) { // // Look at all of the peer elements to determine if any have the // attribute value set. If so, return it; otherwise create a new // instance of the element with the attribute set. For example, if // curSegment is "Address[@Type='M']", we must look at all of the // Address children of relativeTo in order to determine if any // currently exist with a Type field set to a value of 'M'. If one // does, then it already exists and there is nothing to do; if // not found, however, a new Address child must be added with a // Type field of 'M'. // // Lookup the IElementDef of relativeTo IElementDef subEleDef = Adk.Dtd.LookupElementDef(relativeTo.ElementDef, subEleTag); if (subEleDef == null) { subEleDef = Adk.Dtd.LookupElementDef(subEleTag); if (subEleDef == null) { throw new AdkSchemaException(subEleTag + " is not a recognized attribute of " + relativeTo.Tag); } } bool repeatable = subEleDef.IsRepeatable(relativeTo.SifVersion); SifElementList peers = relativeTo.GetChildList(subEleDef); if (curSegment.IndexOf("+]") == -1) { // // Determine if relatSifElementListiveTo has any children that already // define this attribute/value; if not, create a new instance. // If subEleDef is not repeatable, however, we cannot add // another instance of it regardless. // for (int i = 0; i < peers.Count && nextEle == null; i++) { SimpleField ftest = peers[i].GetField(attrName); if (ftest != null && ftest.TextValue.Equals(v)) { nextEle = peers[i]; } } } if (nextEle == null) { if (!(peers.Count > 0 && !repeatable)) { nextEle = _createChild(relativeTo, subEleTag, valueBuilder, version, textFormatter, pathFormatter); } else { // // subEleDef is not repeatable, so we need to back up // and add this attribute/value to a fresh instance of // relativeTo if possible. First use _xpath(path) to try // to select that instance in case it already exists (otherwise // we'd create a new instance each iteration, which is // not the desired result.) // string _tmp; if (path.Length > 0) { _tmp = path + "/" + curSegment; } else { _tmp = curSegment; } if (XPATH_DEBUG) { Console.Out.Write("Searching for path relative to " + relativeTo.Root.ElementDef.Name + ": " + _tmp); } int _del = _tmp.IndexOf('/'); nextEle = (SifElement) _xpath((SifElement)relativeTo.Root, _tmp.Substring(0, (_del == -1 ? _tmp.Length : _del) - (0)), _del == -1 ? null : _tmp.Substring(_del + 1)); if (XPATH_DEBUG) { if (nextEle == null) { Console.Out.WriteLine("; not found, a new instance will be created"); } else { Console.Out.WriteLine("; found"); } } if (nextEle == null) { if (relativeTo.ElementDef.IsRepeatable(relativeTo.SifVersion)) { // Clone relativeTo SifElement grandParent = (SifElement)relativeTo.Parent; nextEle = SifElement.Create(grandParent, relativeTo.ElementDef); pathFormatter.AddChild(grandParent, nextEle, version); // Clone subEleDef; this now becomes nextEle SifElement newEle = SifElement.Create(nextEle, subEleDef); pathFormatter.AddChild(nextEle, newEle, version); _copyAttributes(nextEle, prevAttributes); nextEle = newEle; } else { throw new AdkSchemaException( "It is not possible to create the element or attribute identified by this path: " + _tmp + (nextSegment == null ? "" : "/" + nextSegment) + ". The element or attribute is either undefined in this version of SIF, " + "or an attempt is being made to create another instance of an element that is not Repeatable."); } } } } } if (nextEle != null) { _createField(nextEle, attrName, v); } if (a == attrList.Length && nextEle == null) { return null; } } } else { // Search for the named attribute/element if (attr != -1) { SimpleField ff = relativeTo.GetField(curSegment.Substring(1)); if (ff == null) { ff = _createField(relativeTo, curSegment.Substring(1), null); } return ff; } else { string _tag = curSegment; int eq = curSegment.IndexOf('='); if (eq != -1) { _tag = curSegment.Substring(0, (eq) - (0)); } nextEle = relativeTo.GetChild(_tag); if (nextEle == null) { // The curSegment element does not exist as a child of the relativeTo // object, so create it. nextEle = _createChild(relativeTo, curSegment, valueBuilder, version, textFormatter, pathFormatter); if (nextEle == null) { if (nextSegment == null) { return relativeTo.GetField(_tag); } return null; } } } } // Continue the search if nextSegment has a value if (nextEle != null && (nextSegment != null && nextSegment.Length > 0)) { int i = nextSegment.IndexOf('/'); if (path.Length > 0) { path.Append("/"); } path.Append(curSegment); return _xpathBuild( nextEle, path, i == -1 ? nextSegment : nextSegment.Substring(0, (i)), i == -1 ? null : nextSegment.Substring(i + 1), _prevAttributes, valueBuilder, version, textFormatter, pathFormatter); } if (nextSegment == null && nextEle != null && (nextEle.TextValue == null || nextEle.TextValue.Length == 0)) { int eq2 = curSegment.LastIndexOf('='); if (eq2 != -1) { if (bracket == -1 || (curSegment.LastIndexOf(']') < eq2)) { // // An equals sign in the final segment indicates there is // a value constant or expression following the XPath // (e.g. "OtherId[@Type='06']=@pad($(PERMNUM),0,5)" ). Use // the user-supplied ValueBuilder to evaluate it. // string str = curSegment.Substring(eq2 + 1); nextEle.TextValue = valueBuilder == null ? str : valueBuilder.Evaluate(str); } } } return nextEle; }
public bool ReadRaw( XmlReader reader, SifVersion version, SifElement parent, SifFormatter formatter ) { String value = null; // // STEP 1 // Determine if this surrogate can handle the parsing of this node. // Retrieve the node value as a string // String[] xPathParts = fLegacyXpath.Split( '/' ); XmlNodeType eventType = reader.NodeType; String localName = reader.LocalName; if ( eventType == XmlNodeType.Element && localName.Equals( xPathParts[0] ) ) { try { int currentSegment = 0; int lastSegment = xPathParts.Length - 1; if ( xPathParts[lastSegment].StartsWith( "@" ) ) { lastSegment--; } while ( currentSegment < lastSegment ) { reader.Read(); currentSegment++; if ( !reader.LocalName.Equals( xPathParts[currentSegment] ) ) { ThrowParseException ( "Element {" + reader.LocalName + "} is not supported by XPathSurrogate path " + fLegacyXpath, version ); } } // New we are at the last segment in the XPath, and the XMLStreamReader // should be positioned on the proper node. The last segment is either // an attribute or an element, which need to be read differently String finalSegment = xPathParts[xPathParts.Length - 1]; if ( finalSegment.StartsWith( "@" ) ) { value = reader.GetAttribute( finalSegment.Substring( 1 ) ); } else { value = ReadElementTextValue( reader ); } // Note: Unlike the Java ADK, Surrogates in the the .NET ADK do not have to worry about // completely consuming the XMLElement and advancing to the next tag. The .NET // Surrogates are handed a reader that only allows reading the current node and // the parent reader is automatically advanced when the surrogate is done. } catch ( Exception xse ) { ThrowParseException( xse, reader.LocalName, version ); } } else { // No match was found return false; } // // STEP 2 // Find the actual field to set the value to // IElementDef fieldDef; SifElement targetElement = parent; if ( fValueXpath.Equals( "." ) && fElementDef.Field ) { fieldDef = fElementDef; } else { // This indicates a child SifElement that needs to be created try { targetElement = SifElement.Create( parent, fElementDef ); } catch ( AdkSchemaException adkse ) { ThrowParseException( adkse, reader.LocalName, version ); } formatter.AddChild( parent, targetElement, version ); if ( fValueXpath.Equals( "." ) ) { fieldDef = fElementDef; } else { String fieldName = fValueXpath; if ( fValueXpath.StartsWith( "@" ) ) { fieldName = fValueXpath.Substring( 1 ); } fieldDef = Adk.Dtd.LookupElementDef( fElementDef, fieldName ); } } if ( fieldDef == null ) { throw new InvalidOperationException ( "Support for value path {" + fValueXpath + "} is not supported by XPathSurrogate." ); } // // STEP 3 // Set the value to the field // TypeConverter converter = fieldDef.TypeConverter; if ( converter == null ) { // TODO: Determine if we should be automatically creating a converter // for elementDefs that don't have one, or whether we should just throw the // spurious data away. converter = SifTypeConverters.STRING; } SifSimpleType data = converter.Parse( formatter, value ); targetElement.SetField( fieldDef, data ); return true; }
public bool ReadRaw( XmlReader reader, SifVersion version, SifElement parent, SifFormatter formatter) { String value = null; // // STEP 1 // Determine if this surrogate can handle the parsing of this node. // Retrieve the node value as a string // String[] xPathParts = fLegacyXpath.Split('/'); XmlNodeType eventType = reader.NodeType; String localName = reader.LocalName; if (eventType == XmlNodeType.Element && localName.Equals(xPathParts[0])) { try { int currentSegment = 0; int lastSegment = xPathParts.Length - 1; if (xPathParts[lastSegment].StartsWith("@")) { lastSegment--; } while (currentSegment < lastSegment) { reader.Read(); currentSegment++; if (!reader.LocalName.Equals(xPathParts[currentSegment])) { ThrowParseException ("Element {" + reader.LocalName + "} is not supported by XPathSurrogate path " + fLegacyXpath, version); } } // New we are at the last segment in the XPath, and the XMLStreamReader // should be positioned on the proper node. The last segment is either // an attribute or an element, which need to be read differently String finalSegment = xPathParts[xPathParts.Length - 1]; if (finalSegment.StartsWith("@")) { value = reader.GetAttribute(finalSegment.Substring(1)); } else { value = ReadElementTextValue(reader); } // Note: Unlike the Java ADK, Surrogates in the the .NET ADK do not have to worry about // completely consuming the XMLElement and advancing to the next tag. The .NET // Surrogates are handed a reader that only allows reading the current node and // the parent reader is automatically advanced when the surrogate is done. } catch (Exception xse) { ThrowParseException(xse, reader.LocalName, version); } } else { // No match was found return(false); } // // STEP 2 // Find the actual field to set the value to // IElementDef fieldDef; SifElement targetElement = parent; if (fValueXpath.Equals(".") && fElementDef.Field) { fieldDef = fElementDef; } else { // This indicates a child SifElement that needs to be created try { targetElement = SifElement.Create(parent, fElementDef); } catch (AdkSchemaException adkse) { ThrowParseException(adkse, reader.LocalName, version); } formatter.AddChild(parent, targetElement, version); if (fValueXpath.Equals(".")) { fieldDef = fElementDef; } else { String fieldName = fValueXpath; if (fValueXpath.StartsWith("@")) { fieldName = fValueXpath.Substring(1); } fieldDef = Adk.Dtd.LookupElementDef(fElementDef, fieldName); } } if (fieldDef == null) { throw new InvalidOperationException ("Support for value path {" + fValueXpath + "} is not supported by XPathSurrogate."); } // // STEP 3 // Set the value to the field // TypeConverter converter = fieldDef.TypeConverter; if (converter == null) { // TODO: Determine if we should be automatically creating a converter // for elementDefs that don't have one, or whether we should just throw the // spurious data away. converter = SifTypeConverters.STRING; } SifSimpleType data = converter.Parse(formatter, value); targetElement.SetField(fieldDef, data); return(true); }