public bool ReadRaw(XmlReader reader, SifVersion version, SifElement parent, SifFormatter formatter) { string name = reader.LocalName; if (name.Equals(fDateElement)) { String dateValue = ConsumeElementTextValue(reader, version); DateTime?date = formatter.ToDate(dateValue); if (date.HasValue) { DateTime tsValue = date.Value; SifDateTime dateTime = new SifDateTime(tsValue); parent.SetField(dateTime.CreateField(parent, fElementDef)); } } else if (name.Equals(fTimeElement)) { String timeValue = ConsumeElementTextValue(reader, version); DateTime?time = formatter.ToTime(timeValue); if (time.HasValue) { DateTime val = time.Value; // See if the Timestamp field already exists on the parent SimpleField timeStampField = parent.GetField(fElementDef); if (timeStampField == null) { // Doesn't exist, create it SifDateTime dateTime = new SifDateTime(val); parent.SetField(dateTime.CreateField(parent, fElementDef)); } else { // Exists, update the time portion of the date SifDateTime sdt = (SifDateTime)timeStampField.SifValue; if (sdt != null && sdt.Value.HasValue) { DateTime tsValue = sdt.Value.Value; tsValue = tsValue.Add(val.TimeOfDay); sdt = new SifDateTime(tsValue); // Overwrite the current value parent.SetField(sdt.CreateField(parent, fElementDef)); } } } } else { return(false); } return(true); }
private void Write(SifElement o, int mode, Boolean isLegacy) { if (!Include(o)) { return; } // "<tag [attr...]>[text]" or "<tag [attr...]/>" string tag = o.ElementDef.Tag(fVersion); fWriter.WriteStartElement(tag); if (!fRootAttributesWritten) { writeRootAttributes(false); } WriteAttributes(o); if (mode == EMPTY) { fWriter.WriteEndElement(); } else { // Check for a text value (or an xs:nil value) SimpleField elementValue = o.GetField(o.ElementDef); if (elementValue != null) { SifSimpleType sst = elementValue.SifValue; if (sst == null || sst.RawValue == null) { // The value of this element has been set and it is // null. This should be rendered as 'xs:nil' in SIF 2.x and greater if (!isLegacy) { fWriter.WriteAttributeString(NIL, XmlSchema.InstanceNamespace, "true"); } } else { if (o.DoNotEncode) { fWriter.WriteRaw(o.TextValue); } else { String xmlValue = sst.ToString(fFormatter); fWriter.WriteString(xmlValue); } } } } }
public bool ReadRaw( XmlReader reader, SifVersion version, SifElement parent, SifFormatter formatter ) { string name = reader.LocalName; if ( name.Equals( fDateElement ) ) { String dateValue = ConsumeElementTextValue( reader, version ); DateTime? date = formatter.ToDate( dateValue ); if ( date.HasValue ) { DateTime tsValue = date.Value; SifDateTime dateTime = new SifDateTime( tsValue ); parent.SetField( dateTime.CreateField( parent, fElementDef ) ); } } else if ( name.Equals( fTimeElement ) ) { String timeValue = ConsumeElementTextValue( reader, version ); DateTime? time = formatter.ToTime( timeValue ); if ( time.HasValue ) { DateTime val = time.Value; // See if the Timestamp field already exists on the parent SimpleField timeStampField = parent.GetField( fElementDef ); if ( timeStampField == null ) { // Doesn't exist, create it SifDateTime dateTime = new SifDateTime( val ); parent.SetField( dateTime.CreateField( parent, fElementDef ) ); } else { // Exists, update the time portion of the date SifDateTime sdt = (SifDateTime) timeStampField.SifValue; if ( sdt != null && sdt.Value.HasValue ) { DateTime tsValue = sdt.Value.Value; tsValue = tsValue.Add( val.TimeOfDay ); sdt = new SifDateTime( tsValue ); // Overwrite the current value parent.SetField( sdt.CreateField( parent, fElementDef ) ); } } } } else { return false; } return true; }
private void Write( SifElement o, int mode, Boolean isLegacy ) { if ( !Include( o ) ) { return; } // "<tag [attr...]>[text]" or "<tag [attr...]/>" string tag = o.ElementDef.Tag( fVersion ); fWriter.WriteStartElement( tag ); if (!fRootAttributesWritten) { writeRootAttributes(false); } WriteAttributes( o ); if ( mode == EMPTY ) { fWriter.WriteEndElement(); } else { // Check for a text value (or an xs:nil value) SimpleField elementValue = o.GetField( o.ElementDef ); if ( elementValue != null ) { SifSimpleType sst = elementValue.SifValue; if ( sst == null || sst.RawValue == null ) { // The value of this element has been set and it is // null. This should be rendered as 'xs:nil' in SIF 2.x and greater if ( !isLegacy ) { fWriter.WriteAttributeString(NIL, XmlSchema.InstanceNamespace, "true"); } } else { if ( o.DoNotEncode ) { fWriter.WriteRaw( o.TextValue ); } else { String xmlValue = sst.ToString( fFormatter ); fWriter.WriteString( xmlValue ); } } } } }
/// <summary> Recursively parse an XPath-like query.</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="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> /// <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>getTextValue</c> method. /// </returns> private Element _xpath(SifElement relativeTo, string curSegment, string nextSegment) { SifElement nextEle = null; int attr = curSegment.IndexOf('@'); int bracket = curSegment.IndexOf('['); if (bracket != -1) { if (attr == -1) { throw new AdkSchemaException("Invalid query: \"" + curSegment + "\" must be in the form [@Attribute='value']"); } string subEleTag = curSegment.Substring(0, (bracket) - (0)); SifElement subEle = relativeTo.GetChild(subEleTag); if (subEle == null) { return null; } int endBracket = curSegment.IndexOf(']', bracket); if (bracket == -1) { throw new AdkSchemaException("Invalid query: \"" + curSegment + "\" must be in the form [@Attribute='value']"); } List<SearchCond> condsList = new List<SearchCond>(10); string conds = curSegment.Substring(bracket + 1, (endBracket) - (bracket + 1)); string[] tokens = conds.Split(','); foreach (string thisTok in tokens) { if (thisTok[0] != '@') { throw new AdkSchemaException("Attribute names must be preceded with the @ character: " + thisTok); } int eq = thisTok.IndexOf('='); if (eq == -1) { throw new AdkSchemaException("Attribute value must be in the form [@Attribute='value']: " + thisTok); } // Lookup the referenced attribute SimpleField attrEle = subEle.GetField(thisTok.Substring(1, (eq) - (1))); if (attrEle == null) { return null; } // Add the attribute/value to the list string aval = _attrValue(thisTok.Substring(eq + 1)); SearchCond sc = new SearchCond(attrEle.ElementDef, aval); condsList.Add(sc); } // Search the parent's subEleTag children for matching attributes. // All attributes in the condsList must match. SifElementList ch = relativeTo.GetChildList(subEleTag); int chLen = ch.Count; for (int i = 0; i < chLen && nextEle == null; i++) { SifElement cmpEle; cmpEle = ch[i]; int matched = 0; // Compare the attributes for (int x = 0; x < condsList.Count; x++) { SearchCond sc = condsList[x]; SimpleField atr = cmpEle.GetField(sc.fAttr); if (atr == null) { break; } if (atr.TextValue.Equals(sc.fValue)) { matched++; } } // If all attributes matched, this is a match if (matched == condsList.Count) { nextEle = cmpEle; // Continue the search if nextSegment has a value if (nextSegment != null && nextSegment.Length > 0) { int ii = nextSegment.IndexOf('/'); Element ee = _xpath(nextEle, ii == -1 ? nextSegment : nextSegment.Substring(0, (ii) - (0)), ii == -1 ? null : nextSegment.Substring(ii + 1)); if (ee != null) { return ee; } else { nextEle = null; } } } } if (nextEle == null) { return null; } } else { // Search for the named attribute/element if (attr != -1) { return relativeTo.GetField(curSegment.Substring(1)); } else { nextEle = relativeTo.GetChild(curSegment); if (nextEle == null) { if (nextSegment == null || (nextSegment.Length > 0 && nextSegment[0] == '@')) { return relativeTo.GetField(curSegment); } return null; } } } // Continue the search if nextSegment has a value if ((nextSegment != null && nextSegment.Length > 0)) { int i = nextSegment.IndexOf('/'); return _xpath(nextEle, i == -1 ? nextSegment : nextSegment.Substring(0, (i) - (0)), i == -1 ? null : nextSegment.Substring(i + 1)); } return nextEle; }
/// <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; }