DarioSantarelli.Blog("UgiDotNet");

<sharing mode=”On” users=”*” />
posts - 176, comments - 105, trackbacks - 3

My Links

News


This is my personal blog. These postings are provided "AS IS" with no warranties, and confer no rights.




Tag Cloud

Archives

Post Categories

My English Blog

Validare documenti XHTML con XmlPreloadedResolver

Una classe molto interessante che ci fornisce il Framework 4.0 è XmlPreloadedResolver. Come si intuisce dal nome, il suo scopo è quello di risolvere risorse pre-caricate che possono essere referenziate da un’istanza XML. Questa funzionalità è veramente comoda quando non è desiderabile creare chiamate di rete per reperire risorse esterne (es. un DTD) o quando si lavora offline, con evidenti benefici sulle performance. Un esempio concreto di utilizzo di questa classe potrebbe intervenire nella validazione di contenuti XHTML 1.x, magari all’interno di un HttpModule ASP.NET… tipo questo.
Il plus risiede nel fatto che nell’assembly System.Xml.Utils sono già “embeddati” i DTD dello standard XHTML 1.0 Transitional, Strict e Frameset (incluse le entities speciali), nonché dello standard RSS 0.91

Insistendo sul discorso della validazione di contenuti XHTML precaricati, a titolo esemplificativo ho provato a realizzare una semplice classe XhtmlValidator, che espone un metodo Validate() (la validazione del contenuto) ed il relativo Resolver (che deve reperire l’eventuale DOCTYPE esterno da processare nella validazione).
N.B.: Per versioni del Framework precedenti alla 4.0, possiamo ovviamente decidere di svilupparci in casa un Resolver custom (ereditando la classe XmlResolver) che sostanzialmente assolva lo stesso compito.

public class XhtmlValidator

{

   public XmlResolver Resolver { get; set; }

 

   public XhtmlValidator() { }

   public XhtmlValidator(XmlResolver resolver) { Resolver = resolver; }

 

   public bool Validate(string xhtml, out List<XmlValidationError> errors)

   {

      List<XmlValidationError> validationErrors = new List<XmlValidationError>();    

                                                   

      XmlReaderSettings settings = new XmlReaderSettings();

      settings.ValidationType = ValidationType.DTD;

      settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;

      settings.DtdProcessing = DtdProcessing.Parse;

      if (Resolver != null) settings.XmlResolver = Resolver;

      settings.ValidationEventHandler += (s, e) => validationErrors.Add(new XmlValidationError(e.Message,e.Severity));           

 

      Stream xhtmlStream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(xhtml));  

 

      using (XmlReader xmlReader = XmlReader.Create(xhtmlStream, settings))

      {

        try { while (xmlReader.Read()) ; }

        catch (Exception ex) { validationErrors.Add(new XmlValidationError(ex.Message, XmlSeverityType.Error)); }               

      }

 

      errors = validationErrors;

 

      return (validationErrors.Count == 0);

    }     

}

 

public class XmlValidationError

{

   public string Message { get; private set; }

   public XmlSeverityType Severity { get; private set; }

 

   public XmlValidationError(string message, XmlSeverityType severity)

   {

     Message = message;

     Severity = severity;

   }

}

 

La classe XmlValidationError è stata introdotta semplicemente come “astrazione” rispetto a due tipologie di notifiche: quelle derivanti dal parsing della struttura del documento (le Read() dell’XmlReader) e quelle derivanti dal processo di validazione (i ValidationEvent scatenati dalla classe XmlReaderSettings). 
Vediamo quindi come possiamo sfruttare XmlPreloadedResolver in questo contesto tramite una banale applicazione Console…

static void Main(string[] args)

{

   ////GOOD XHTML 1.0 (conformant)

   //string xhtml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" +

   //               "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"it\" lang=\"it\">" +

   //               "<head><title>GOOD XHTML 1.0 Document</title></head><body><p>A paragraph here is OK</p></body></html>";

 

   //// BAD XHTML 1.0 (non conformant)

   string xhtml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" +

                  "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"it\" lang=\"it\">" +

                  "<head><title>BAD XHTML 1.0 Document</title></head><body><span>A span here is NOT OK</span></body></html>";

       

   XmlPreloadedResolver resolver = new XmlPreloadedResolver(XmlKnownDtds.Xhtml10);

   XhtmlValidator validator = new XhtmlValidator(resolver);

 

   List<XmlValidationError> validationErrors = new List<XmlValidationError>();

   bool success = validator.Validate(xhtml, out validationErrors);

 

   if (success) Console.WriteLine("Success");

   else

   {

      Console.WriteLine("Errors: " + validationErrors.Count.ToString());

      foreach (XmlValidationError error in validationErrors) Console.WriteLine(string.Format("- Message: {0} (Severity: {1})", error.Message, error.Severity));               

   }          

}

 

Eseguendo il codice precedente senza essere connessi alla rete, si osserva come il XmlPreloadedResolver faccia il suo lavoro e ci permetta di validare il contenuto XHTML 1.0 Strict di esempio tramite il relativo DTD embeddato nell’assembly System.Xml.Utils.

Domanda: E se volessimo usare XmlPreloadedResolver su documenti XHTML 1.1?
Ebbene, sembra che la strada dello standard XHTML 1.1 non sia stata battuta, forse per la forte modularizzazione della specifica o forse per l'effettiva scarsa adozione dello standard nel web. Fatto sta che in questo contesto non abbiamo "known" DTD pre-caricati (neanche quelli “core” definiti nel DTD principale), quindi dobbiamo pre-caricarceli “a mano” in questo modo…


XmlPreloadedResolver xmlPreloadedResolver = new XmlPreloadedResolver(XmlKnownDtds.Xhtml10);
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"), File.ReadAllBytes("C:\\...\\xhtml11.dtd"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-inlstyle-1.mod"), File.ReadAllBytes("C:\\...\\xhtml-inlstyle-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-text-1.mod"), File.ReadAllBytes("C:\\...\\xhtml-text-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-hypertext-1.mod"), File.ReadAllBytes("C:\\...\\xhtml-hypertext-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-list-1.mod"), File.ReadAllBytes("C:\\...\\xhtml-list-1.mod"));
etc...

 

Tag di Technorati: ,,,

Print | posted on mercoledì 20 aprile 2011 23:23 | Filed Under [ .NET ]

Feedback

Gravatar

# re: Validare documenti XHTML con XmlPreloadedResolver

Grande Dario,
ottima classe! Stavo impazzendo perchè non mi validava l'xml, credevo bastasse lanciare il metodo Create dell'oggetto XmlReader
per far partire la validazione invece dimenticavo il .Read :-(
26/10/2015 17:47 | Marco
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET