System.Xml and Delphi.net
see also http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemXmlXmlDocumentClassctorTopic.asp
That example looks in Delphi like this:
unit xmlparser;
interface
uses
System.Xml,
System.Xml.Schema;
{**
This class provides methods for parsing an XML document and assign the contents
to a representation in memory.
*}
type TXMLParser=class
protected
{** The xml file *}
myDoc: XmlDocument;
reader: XmlValidatingReader;
txtReader: XmlTextReader;
....
procedure ValidationCallback(sender: TObject; args: ValidationEventArgs);
end;
implementation
uses System.IO;
constructor TXMLParser.Create(filename: string);
var eventHandler: ValidationEventHandler;
begin
inherited Create();
if not System.IO.File.Exists(filename) then begin
raise Exception.Create('file ' + filename + ' could not be found.');
end;
eventHandler := ValidationCallback;
reader := nil;
try
txtReader := XmlTextReader.Create(filename);
reader := XmlValidatingReader.Create(txtReader);
reader.ValidationType := ValidationType.DTD;
// Set a handler to handle validation errors.
Include(reader.ValidationEventHandler, eventHandler);
myDoc := XmlDocument.Create();
myDoc.Load(reader);
finally
if ( reader <> nil ) then
begin
reader.Close();
end;
end;
end;
procedure TXMLParser.ValidationCallback(sender: TObject; args: ValidationEventArgs);
begin
Console.WriteLine('Validation error loading xml file');
Console.WriteLine(args.Message);
end;
further nice functions:
{** test the given node, if it is a comment or is empty; if it is empty, try the next nodes.
@param cur2 the current node
@return the current or the first next node with actual content
*}
function TXMLParser.nextNotBlank(const cur2: XmlNode): XmlNode;
var
cur: XmlNode;
begin
cur := cur2;
while (true) do
begin
if (cur = nil) then
begin
result := cur;
exit;
end;
if ((cur.NodeType = System.Xml.XmlNodeType.Text) and (Length(cur.toString()) = 0)) then
begin
cur := cur.NextSibling;
continue;
end;
if (cur.name = 'comment') then
begin
cur := cur.NextSibling;
continue;
end;
if (cur.name = '#comment') then
begin
cur := cur.NextSibling;
continue;
end;
result := cur;
exit;
end;
result := nil;
end;
{** get the next code that is a proper entity (i.e. no comment, not empty)
@param cur the current node
@return the next node with actual content
*}
function TXMLParser.getNextEntity(const cur: XmlNode): XmlNode;
begin
if (cur = nil) then
begin
result := nil
end
else
begin
result := nextNotBlank(cur.NextSibling);
end;
end;
{** retrieve the value of an attribute. Does prevent unnecessary exceptions, if the attribute is not existing
@param cur the current node
@param attrib the name of the attribute
@return the value of the attribute, or an empty string if it is not existing
*}
function TXMLParser.getAttribute(cur: XmlNode; attrib: string): string;
var node: XmlNode;
begin
result := '';
node := cur.Attributes.GetNamedItem(attrib);
if (node <> nil) then result := node.Value;
end;
{**
removes line breaks and tabulators and trims spaces, even inside the string
@param s the string that should be cleaned up
@return the clean string, without line breaks, tabulators and groups of spaces
}
function TXMLParser.cleanString(const s: string): string;
// removes \n and \t and trims spaces, even inside the string
var
p: Integer;
s2: string;
ch, prev_ch: char;
begin
s2 := s.Trim();
result := '';
p := 1;
prev_ch := chr(0);
while (p <= Length(s2)) do
begin
ch := s2[p];
if (ch = chr(9)) then
ch := ' ';
if (ch = chr(10)) then
ch := ' ';
if (not ((prev_ch = ' ') and (ch = ' '))) then
begin
result := result + ch;
end;
prev_ch := ch;
inc(p);
end;
end;