If you try to programaticaly set/remove values of fields in InfoPath, you might have come across the following error message:
"Schema validation found non-data type errors"
A number of blogs and MSDN articles describe what to do in this case. They work for setting values, however I could not find how to clear values.
The problem
Values that are non-string (DateTime, Time, Date, Boolean, Whole Number, Decimal) cannot be blank (Empty String). If a value is set to the emptry string you will get the error above, because the empty string is considered a string and you are trying to set it to a field that is non-string. When one of these non-string fields is blank, it has an attribute "xsi:nil" that is set to "true". As soon as you type a value in this field in InfoPath the attribute is cleared.
The solution
Therefore, if you are trying to set values programatically you need to clear the "xsi:nil" attribute, or set it to "false". And if you are clearing the value of such a field, then you need to place the "xsi:nil" attribute back in, or set it to "true".
Other blogs on the internet say that clearing the value and setting the xsi:nil attribute to true is very simple, however the snippets of code they offer do not work.
- This is because a nil field looks like so: <my:value />
- After you type something, it looks like so: <my:value>123</my:value>
- If you try and add the nil attribute in <my:value></my:value> you will get the "Schema validation found non-data type errors" error when you load the form.
The solution is to follow the steps below, depending on what you need to do with your field.
Editing a non-string field:
- If you are going to try and programatically edit a field that is non-string, then you have to remove its "nil" attribute
- Now you can change its value
Code (as on all other blogs and articles, this piece was taken from http://blogs.msdn.com/infopath/archive/2006/11/28/the-xsi-nil-attribute.aspx):
//Create a Navigator object for the main data source
XPathNavigator xn = this.MainDataSource.CreateNavigator();
//Create a navigator object for the field (node)
//where we want to set the current date value
XPathNavigator xnfield1 = xn.SelectSingleNode("/my:myFields/my:field1", this.NamespaceManager);
//Check if the "nil" attribute exists on this node
DeleteNil(xnfield1);
//Create a new dateTime object for the current date
DateTime curDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day);
//Set the value of field1 to the current date in the
//correct format: yyyy-mm-dd
xnfield1.SetValue(curDate.GetDateTimeFormats().GetValue(5).ToString());
public void DeleteNil(XPathNavigator node)
{
if (node.MoveToAttribute("nil", http://www.w3.org/2001/XMLSchema-instance))
node.DeleteSelf();
}
Clearing a non-string field:
- If you are going to programatically erase the value of a non-string field, then you have to re-construct the XML node to what InfoPath expects and add the "nil" attribute. This code is slightly different from dooke's Sharepoint place blog.
Code (slight change from dooke's code):
public static void InsertNil(XPathNavigator node)
{
if (!node.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"))
{
string result = string.Empty;
int endIndex = node.OuterXml.IndexOf(">");
result = node.OuterXml.Substring(0, endIndex) + " xsi:nil=\"true\" />";
node.OuterXml = result;
}
}
This code will reconstruct the <my:value>123</my:value> to <my:value xsi:nil="true" /> which will clear the field.
In my particular case, I wanted to clear the field, no matter what it was (string or non-string):
private void ClearAllFields()
{
XPathNavigator node = xNav.SelectSingleNode(xPath, xNameSpace);
if (node == null)
return;
try
{
// try this as a Date, Integer, Boolean node, set the nil value
InsertNil(node);
}
catch
{
// if it is a string, the nil value won't work, so just set it to empty
node.SetValue(string.Empty);
}
}
public static void InsertNil(XPathNavigator node)
{
if (!node.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"))
{
string result = string.Empty;
int endIndex = node.OuterXml.IndexOf(">");
result = node.OuterXml.Substring(0, endIndex) + " xsi:nil=\"true\" />";
node.OuterXml = result;
}
}