11 Mayıs 2007 Cuma

XML Validation

XML veri doğrulaması nedir? XML veri doğrulamasını koddan bağımsız olarak nasıl yaparız? DataRow nesnesini nasıl Serialise Deserialise yaparız?


Farklı platformlar arasında veriyi taşımak için taşınan verinin modelini de bilmek gerekmektedir. XML veriyi ve veri modelini bir arada saklanması ve taşınması mantığından ortaya cıkmış bir standarttır. XML veri modelleme ve doğrulama için iki geçerli yolumuz var. Biri çok eski bir standart olan DTD standardıdır. Diğeri web servisler ile adını duyuran XSD standardıdır.
XSD (XML Shema Definition) XML veri modelin doğrulanma ihtiyacından doğmuş olan ve ilk Microsoft tarafından duyurulan bir standarttır. Bilindiği üzere Typed DataSet sınıfları TypedDataSetGenerator sınıfı ile XSD dosyaları kullanılarak üretilen nesnelerdir.
DTD (Data Type Definition) XSD benzeri bir XML tanımlama standardıdır. Avantajı XSD ye göre çok basit olması.  Eğer hız her şey ise sizin sisteminizde DTD veri doğrulamak için uygun bir  seçim olabilir. Özellikle eski sistemlerde (web servislerden önce) sıkça kullanılırdı. Eski platformlarda sadece DTD verisini test eden sınıflarımız vardı.  Eğer sizde benim gibi işiniz gereği eski platformları kullanan sistemler ile haberleşmek zorunda kalırsanız DTD doğrulama için Dispatcher sınıfı size yardımcı olacaktır.
XML veriyi kontrol etmek için önce XmlResolver nesnesine veri doğrulama kaynağını vermemiz gerekmektedir. Bu uygulamada veri doğrulama kaynağını koddan bağımsız hale getirmek için veri doğrulama bilgisini dosyadan okuyacağız. Dosyadan okunan veri doğrulama bilgisi için önce XmlResolver sınıfından türetilene ve veri doğrulama şablonunu yerel dosyadan okuyacak bir sınıf yazmalıyız.
[cs]
#region local document type resolver
/// 
/// XML Resolver için uygulama sınıfı
/// 
internal class LocalDocumentTypeResolver : XmlUrlResolver,IDisposable {
 FileStream stream = null;
 public LocalDocumentTypeResolver(String systemEntry) {
  stream = new FileStream(systemEntry,
   FileMode.Open,
   FileAccess.Read,
   FileShare.Read);
 }
 override public object GetEntity(Uri absoluteUri, 
  string role, Type ofObjectToReturn) 
 {
  return stream;
 }
 
 #region IDisposable Members
 // xsd kullanırken data source olarak result gösterilirse file used kalıyor
 // onun için LocalDocumentTypeResolver IDispose olmak zorunda
 public void Dispose() {
  stream.Dispose();
  stream = null;
  GC.Collect();
 }
 #endregion
}
#endregion
Artık yerel dosyalardan doğrulama bilgisini okuyabildiğimize göre XML verileni bu dosyalara göre doğrulayabiliriz.
[cs]
/// 
/// verilen mesaja ve tip tanımlama dosyasına gre veri kümesi üretir
/// 
/// ayrıştırılacak mesaj        
/// veri kontrolünü sahlayacak danımlama dosyası tam yolu
/// mesajın root element
/// doğrulama yapılacak dosya uzantısı dtd veya xsd olmalıdır
/// Doğrulama dosyası xsd veya dtd değil
/// tanımlama dosyasına göre oluşturulmuş veri kümesi
public static System.Data.DataSet Dispacth(string message,string validateFilePath,string rootElement){
        if (string.IsNullOrEmpty(rootElement))
                throw new ArgumentException("rootElement", 
                       "XML doğrulaması yapılacak xml root element verilmelidir.");
        if (!Regex.IsMatch(validateFilePath.ToLower(), @"(.)*\.dtd$|(.)*\.xsd$"))
                throw new ArgumentOutOfRangeException("validateFilePath", 
                        "XML doğrulama dosyası 'dtd' veya 'xsd' uzantılı olmalıdır.");
        DataSet result = new DataSet();
        using(LocalDocumentTypeResolver fileResolver =new LocalDocumentTypeResolver(validateFilePath)){ 
                XmlReaderSettings xmlSetting = new XmlReaderSettings();
                if (Regex.IsMatch(validateFilePath.ToLower(), @"(.)*\.dtd$")) {
                        if (message.IndexOf("" + message;
                        xmlSetting.ValidationType = ValidationType.DTD;
                } else if (Regex.IsMatch(validateFilePath, @"(.)*\.xsd$")) {
                        xmlSetting.Schemas.Add(null, XmlTextReader.Create(validateFilePath));
                        xmlSetting.ValidationType = ValidationType.Schema;
                }
                StringReader textReader = new StringReader(message);
                XmlTextReader xmlTextReader = new XmlTextReader(textReader);
                xmlTextReader.XmlResolver = fileResolver;
                xmlSetting.ValidationEventHandler += 
   new ValidationEventHandler(xmlSetting_ValidationEventHandler);
                XmlReader xmlReader = XmlReader.Create(xmlTextReader, xmlSetting);
                isSuccess = true;
                result.ReadXml(xmlReader);
                if (!isSuccess)
                        result = null; 
        } 
        return result;
}
static void xmlSetting_ValidationEventHandler(object sender, ValidationEventArgs e) {
        isSuccess = false;
}
Yukarıda ki kod ne yapıyor: message ile verilen XML verisini validateFilePath konumunda bulunan DTD veya XSD uzantılı dosyayı LocalDocumentTypeResolver sınıfı kullanarak doğruluyor. XmlReader sınıfına XSD için kullanılacak şema eklemek gerekmektedir. DTD için ise şema bilgisi xml verinin en başında tanımlanmalıdır.
Uygulama kodu ise oldukça sadedir.
[cs]
private System.Data.DataTable Dispatch() {
        string xml = txtXML.Text;
        string shemaFile = optDTD.Checked ? DTDFile : XSDFile;
        string rootElement = txtSchema.Text
  .Substring(0, txtSchema.Text.IndexOf(Environment.NewLine))
                .Split(' ')[1];
        SaveSchemaFile(shemaFile);
        System.Data.DataSet result = 
  Framework.Dispatcher.Dispacth(xml, shemaFile, rootElement);
        return result.Tables[0];
}
Dispatch işleminde bize gereken bir diğer işlev ise Serializable DataRow nesnesidir. Yani önce test edilecek veriyi oluşturmak gerekmektedir. DataRow sınıfı varsayılan yapılandırıcıya sahip olmadı için hiçbir şekilde Serialize haline getirilemez. Çözüm DataRow nesnesini DataTable içine alıp serialize edilmektir.
[cs]
/// 
/// DataRow xml olrak serialize eder
/// 
/// 
public static string SerializeRow(DataRow row) {
    Type tableType = row.Table.GetType();
    DataTable table = (DataTable)Activator.CreateInstance(tableType);
    DataRow newRow = table.NewRow();
    newRow.ItemArray = row.ItemArray;
    table.Rows.Add(newRow);
    StringWriter writer = new StringWriter();
    table.WriteXml(writer);
    return writer.ToString().Replace("xml:space=\"preserve\"", "");
}

/// 
/// xml string üzerinden DataRow üretir
/// 
/// xml data source
/// data table type
public static DataRow DeseriazeRow(string xmlDataSource, Type tableType) {
    StringReader reader = new StringReader(xmlDataSource);
    DataTable table = (DataTable)Activator.CreateInstance(tableType);
    table.ReadXml(reader);
    return table.Rows[0];
}
Bir biri ile ayrı uzaylarda çalışan sistemler eğer web servisi gibi bir teknoloji kullanmadan haberleşiyorsa Dispatcher gibi bir çözüme gereksinim duyarlar. DTD ile temel XML doğrulama özellikle eski sistemler ile yapılan çalışmalarda çok fazla karşımıza çıkmaktadır.