我正在开发一个系统,其中所有用户输入都将存储在xml文件中。目前,用户输入由aspx.net Web表单处理。在后面的C#代码中,我将这些值存储在一个对象中,然后序列化回XML。在显示供用户编辑之前,这些值也会从XML序列化为一个对象。
使用以下架构以XML格式表示数据(我为.Net特定前缀表示道歉)
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema id="UserInput-Schema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="urn:UserInput-Schema"
elementFormDefault="qualified">
<xsd:element name="userInputData">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="someTextData" type="xsd:string"
minOccurs="1" maxOccurs="1" />
<xsd:element name="someOtherTextData" type="xsd:string"
minOccurs="1" maxOccurs="1" />
<xsd:element name="yetMoreTextData" type="xsd:string"
minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
但是,我被告知用户应该能够输入空白值,或者根本不输入值。这实际上不是一个问题,除了当输出不在字段之外时,相应的XML元素在序列化发生后没有值。我正在使用.net XML序列化方法将我的对象转换为XML,这个方法似乎在写出之前对值进行修剪(和XML关键字检查)。
例如:
<?xml version="1.0" encoding="utf-8"?>
<userInputData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<someTextData>I love XML!</someTextData>
<someOtherTextData/>
<yetMoreTextData>More text</yetMoreTextData>
</userInputData>
但是,由于元素缺少值,因此在读回时此XML将无法进行架构验证检查。显然,如果我将minOccurs值更改为可以缺少值的元素(根据新提出的要求,那就是一切),那么上面的XML示例将通过模式验证。
但是,我不喜欢这个想法,因为在非常罕见的情况下,用户 COULD 访问应用程序之外的XML文件并进行编辑。如果用户要完全删除元素(无论它是否具有有效值),那么XML仍将通过模式验证,但对于我们的目的而言无效。
我正在考虑为缺少输入的元素(如“未提供输入”)写出内部识别的值,并将值读取为空字符串(如果找到)。例如,这个:
<?xml version="1.0" encoding="utf-8"?>
<userInputData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<someTextData>I love XML!</someTextData>
<someOtherTextData>Input not supplied<someOtherTextData>
<yetMoreTextData>More text</yetMoreTextData>
</userInputData>
然而,由于XML值必须是人类可读的(ish),因此应该从等式中删除应用程序,否则这已被否决。此外,还为读取器和输出文件增加了不必要的复杂性。我查看了nillable标签(在同事的提示下),但我的研究告诉我,这不是什么可用的。 Nillable(如果我是正确的)用于通知XML解析器,而不允许值为NULL,而不是我们可以为它赋值。
除了将minOccurs值设置为0或写出已知的空白值之外,还有更优雅的方法来处理这种特殊情况吗?
是否可以按以下格式写出没有值的元素:
<someTextValue />
让它仍然通过模式验证而不将minOccurs的值设置为0,或者将其传递给已知的(如“this element is blank”)值?
编辑:
算法:
这是我使用的代码块:
private static void ValidateAgainstSchema(Stream schemaToUse, XmlReader documentToValidate)
{
XmlSchema schema;
// Ensure that the stream to the schema is read from the very
// begining of the file.
schemaToUse.Position = 0;
// Read the schema from the stream into the XmlSchema object
using (XmlReader schemaReader = XmlReader.Create(schemaToUse))
{
schema = XmlSchema.Read(schemaReader, ValidationEventHandler);
}
// Add the schema to a set of schemas
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(schema);
// Set up the schema reader settings
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas = schemas;
settings.ValidationFlags = XmlSchemaValidationFlags.ProcessIdentityConstraints | XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += ValidationEventHandler;
// Run through the xml file to be checked, before passing control back
// to the calling method
using (var validationReader = XmlReader.Create(documentToValidate, settings))
{
while (validationReader.Read())
{
// If we fail to read the xml file (badly formed, doesn't match
// the schema, etc.) then we'll fall through to the event handler
// (readerSettings_ValidationEventHandler) automatically.
}
}
}
private static void ValidationEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Warning)
{
/* warning while parsing XML file */
// warnings can be ignored for now. These are not critical
}
else if (e.Severity == XmlSeverityType.Error)
{
/* Error while parsing XML file */
// Errors are problems with the xml file (when checked against
// the schema). These are critical issues with the conents of
// the XML file.
// Possibly throw an exception?
throw new Exception(e.Message);
}
}