public static XmlDocument BuildRamsellXmlDocForFormResult(int formResultId, IFormsRepository formsRepo) { string xsdFilePath = HttpContext.Current.Server.MapPath(xsdPath); XmlSchemaSet schemaSet = Utilities.GetXsdSchemaSet(xsdFilePath); // Extract the schema sets from the XSD (microsoft actually does it this way) // https://msdn.microsoft.com/en-us/library/ms255932(v=vs.110).aspx XmlSchema schema = null; foreach (XmlSchema xs in schemaSet.Schemas()) { schema = xs; } // convert schema heirarchy into custom types. See "SchemaElement" and subclasses below. // (the ResponseElement subclass will be used to link "leaf" nodes with item variables) List <RamsellExport.DefSchemaElement> defElements = RamsellExport.ParseSchemaElements(schema.Elements.Values); // build response xml document based on schema XmlDocument outputXmlDoc = new XmlDocument(); // Removed schemaSet from top level tag per Ramsell // outputXmlDoc.Schemas.Add(schemaSet); //outputXmlDoc.AppendChild(outputXmlDoc.CreateComment("Responses taken from formResult " + formResultId)); foreach (RamsellExport.DefSchemaElement elem in defElements) { RamsellExport.BuildResponseXml(null, outputXmlDoc, elem, formResultId, formsRepo); } // Validate response xml based on schema // resultDoc.Validate((object sender, ValidationEventArgs args) => { throw new Exception(args.Message); } ); try { Debug.WriteLine("XSD resultDoc.Schemas.Count: " + outputXmlDoc.Schemas.Count.ToString()); /* * foreach (System.Xml.Schema.XmlSchemaSet xss in resultDoc.Schemas.Schemas()) * { * Debug.WriteLine("XSD Schemas NameTable: " + xss.NameTable.ToString()); * } */ ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler); outputXmlDoc.Validate(eventHandler); Debug.WriteLine("*** Validation is complete."); } catch (Exception xcptn) { Debug.WriteLine("Validate exception: " + xcptn.Message); } return(outputXmlDoc); }
/// <summary> /// Process a single node from an XML improted from Ramsell, modifying the specified formResult as applicable. /// Noramlly this will only be called from within a loop to iterate over xml nodes, however this function will recurse to handle Ramsell's "income" structures /// </summary> /// <param name="fromReader">XmlReader where Read() has already been called</param> /// <param name="checkedBoxes">this should ba appended to with itemVariable identifiers for each checked checkbox. Used to uncheck excluded boxes at the end of the import</param> /// <param name="specialCaseValuesByTagname">this will be used to run special-case transformations that may involve multiple ramsell tags</param> private void ImportXmlNodeFromRamsell( XmlReader fromReader, List <string> checkedBoxes, Dictionary <string, string> specialCaseValuesByTagname) { if (fromReader.NodeType != XmlNodeType.Element) { throw new Exception("Expecting NodeType \"" + XmlNodeType.Element + "\", found \"" + fromReader.NodeType + "\""); } string ramellTagName = fromReader.Name; //the "Income_Item" tag is a one-off structure with multiple occurances if (ramellTagName == "Income_Item") { ImportIncomeStructureFromRamsell(fromReader); return; } //get the nodes contents string ramsellVal = String.Empty; if (!fromReader.IsEmptyElement) { fromReader.Read(); if (fromReader.NodeType == XmlNodeType.EndElement) { return; } if (fromReader.NodeType != XmlNodeType.Text) { throw new Exception("Inside of node \"" + ramellTagName + "\", found NodeType \"" + fromReader.NodeType + "\", expecting NodeType \"" + XmlNodeType.Text + "\", or \"" + XmlNodeType.EndElement + "\""); } ramsellVal = fromReader.Value; } //based on tagName, check if this a simple case (no transformation necessary) List <string> ivIdentifiers = RamsellExport.GetItemVariableIdentifiersForRamsellTagName(ramellTagName); if (ivIdentifiers.Count == 1) { //one-to-one case: this ramsell tagName corresponds with exactly one itemVariable //so just save the text contents as a response to that itemVariable // RRB 4/18/16 Ramsell seems to be sending a default date of 1900-01-01 // This should be tested more. If doesn't fix, maybe our date converter is causing an empty DOB to be this date. if (ramellTagName.Equals("DOB") && (string.IsNullOrEmpty(ramsellVal) || ramsellVal.StartsWith("1900"))) { ; } else { UpdateResponse(ivIdentifiers[0], ramsellVal); } } else if (ivIdentifiers.Count > 1) { //checkbox case: this ramsell tagName corresponds to a set of itemVariables (representing checkboxes in the application) //so pick the checkbox based on this node's text contents, and save the response "1" for that checkbox #region checkbox case //based on lookups, pick the inidividual itemvariable (matchIv) that matches the node contents (ramsellVal) def_ItemVariables matchIv = null; foreach (string ivIdent in ivIdentifiers) { def_ItemVariables iv = formsRepo.GetItemVariableByIdentifier(ivIdent); if (iv.baseTypeId == 1) { def_LookupMaster lm = formsRepo.GetLookupMastersByLookupCode(iv.identifier); if (lm != null) { List <def_LookupDetail> ld = formsRepo.GetLookupDetailsByLookupMasterEnterprise(lm.lookupMasterId, SessionHelper.LoginStatus.EnterpriseID); if (ld.Where(ldt => ramsellVal == ldt.dataValue).Any()) { matchIv = iv; break; } } } } //save the respones "1" to the single matched itemVariable, and add it to the "checkedBoxes" list //at the end of the import, any grouped checkboxes that haven't been added to that list will be unchecked if (matchIv == null) { Debug.WriteLine("* * * RamsellImport: Could not find matching itemVariable for ramsell tag/value \"" + ramellTagName + "/" + ramsellVal + "\", skipping..."); } else { def_ItemResults ir = userData.SaveItemResult(toFormResultId, matchIv.itemId); userData.SaveResponseVariable(ir, matchIv, "1"); checkedBoxes.Add(matchIv.identifier); } #endregion } else { //this tagname must be either ignorable or handled by a special one-off transformation, //so just record the tagname/value pair to be handled later on. //the special-cases can involve multiple ramsell tags so there is no way to handle them one tag at a time. specialCaseValuesByTagname.Add(ramellTagName, ramsellVal); } }