"Chris Fink" <ch********@gmail.com> wrote in message news:%2****************@TK2MSFTNGP10.phx.gbl...
I am receiving xml documents from a customer without a reference to a
doctype. I know what the Doctype DTD should be need to insert the
declaration as follows
<?xml version="1.0" encoding="UTF-8"?>
<!-- start of add validation tag -->
<!DOCTYPE D1XML SYSTEM "http://url/myDTD.DTD">
<!-- end of add validation tag -->
<XML.....>
Using one of the provided framework classes such as XmlValidatingReader,
etc.... is there a method to dynamically add a doctype reference?
While streaming it through an XmlValidatingReader, one possibility
is to subclass one of the Reader classes from the System.IO name-
space to insert the additional line(s) you seek for the reference to
an external DTD.
Here is an example of such a class that could do this (I only impl'd
the Read(char[],int,int) method because in a quick test, that's what
was used when loading an XmlDocument as you may if you wrap
this Reader in an XmlTextReader -- so your mileage may vary.)
- - - InsertLineStreamReader.cs (partial)
using System;
using System.Collections;
using System.IO;
namespace Derek.IO
{
public class InsertLineStreamReader : System.IO.StreamReader
{
private delegate int ReadMethod(char[] buffer, int index, int count);
string insertStr;
int lineNo, readNo, overflowIndex;
char[] overflow;
ReadMethod[] fnRead;
public InsertLineStreamReader(Stream source, string insertStr, int lineNo) : base( source)
{
this.insertStr = insertStr;
this.lineNo = lineNo;
this.readNo = 0;
this.fnRead = new ReadMethod[] {
new ReadMethod( this.ReadBefore),
new ReadMethod( this.ReadOverflow),
new ReadMethod( this.ReadAfter)
};
this.overflowIndex = 0;
}
//
// . . . Override other methods here (may not be necessary depending on the consumer).
//
public override int Read(char[] buffer, int index, int count)
{
// Use dispatch table of delegates to get the complex override(s)
// out of the way asap.
return this.fnRead[this.readNo](buffer, index, count);
}
public int ReadBefore(char[] buffer, int index, int count)
{
char[] scan = new char[count];
int cchRead = base.Read(scan, 0, count);
if (cchRead > -1)
{
int insOfs, lineCnt = 0;
for (insOfs = 0; insOfs < cchRead && this.lineNo != lineCnt; ++insOfs)
{
if (scan[insOfs] == '\n') ++lineCnt;
}
if (this.lineNo == lineCnt)
{
char[] insertBuf = this.insertStr.ToCharArray( );
if ((insOfs + this.insertStr.Length) > count)
{
int fragmentLen = (insOfs + insertBuf.Length - count);
Array.Copy(scan, 0, buffer, index, insOfs);
Array.Copy(insertBuf, 0, buffer, index + insOfs, fragmentLen);
this.overflow = new char[insertBuf.Length - fragmentLen];
Array.Copy(insertBuf, fragmentLen, this.overflow, 0, this.overflow.Length);
this.readNo = 1;
cchRead = count;
}
else
{
Array.Copy(scan, 0, buffer, index, insOfs);
Array.Copy(insertBuf, 0, buffer, index + insOfs, insertBuf.Length);
int destSpaceRemaining = count - insOfs - insertBuf.Length;
int srcSpaceRemaining = cchRead - insOfs;
if (srcSpaceRemaining > destSpaceRemaining)
{
Array.Copy(scan, insOfs, buffer, index + insOfs + insertBuf.Length, destSpaceRemaining);
this.overflow = new char[srcSpaceRemaining - destSpaceRemaining];
Array.Copy(scan, insOfs + destSpaceRemaining, this.overflow, 0, this.overflow.Length);
this.readNo = 1;
cchRead = count;
}
else
{
Array.Copy(scan, insOfs, buffer, index + insOfs + insertBuf.Length, srcSpaceRemaining);
this.readNo = 2;
cchRead = cchRead + insertBuf.Length;
}
}
}
else
{
Array.Copy(scan, 0, buffer, index, cchRead);
}
}
return cchRead;
}
public int ReadOverflow(char[] buffer, int index, int count)
{
int cchRead;
int overflowLen = this.overflow.Length - this.overflowIndex;
if (count > overflowLen)
{
Array.Copy(this.overflow, this.overflowIndex, buffer, index, overflowLen);
this.overflowIndex = this.overflow.Length;
this.readNo = 2;
cchRead = overflowLen;
int nextCchRead = this.Read( buffer, index + overflowLen, count - overflowLen);
return ( -1 == nextCchRead ) ? cchRead : ( cchRead + nextCchRead );
}
Array.Copy(this.overflow, this.overflowIndex, buffer, index, count);
this.overflowIndex += count;
cchRead = count;
return cchRead;
}
public int ReadAfter(char[] buffer, int index, int count)
{
return base.Read(buffer, index, count);
}
}
}
- - -
Now you might use this to insert an arbitrary line into the beginning of
your XML instance document like this,
FileStream stream = new FileStream("doc.xml", FileMode.Open, FileAccess.Read);
string dtd = "<!-- Ref to your DTD can go here. -->";
InsertLineStreamReader reader = new InsertLineStreamReader(stream, dtd, 1);
XmlValidatingReader xmlReader = new XmlValidatingReader(new XmlTextReader( reader));
// ... wire-up Schema and ValidationEventHandler here.
XmlDocument doc = new XmlDocument( );
doc.Load( xmlReader);
As far as the XmlValidatingReader is concerned, it will receive,
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Ref to your DTD can go here. -->
<XML ... />
even though your file contained,
<?xml version="1.0" encoding="UTF-8" ?>
<XML ... />
Derek Harmon