473,245 Members | 1,770 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,245 software developers and data experts.

XmlTextReader Hack

I am trying to use an XmlTextReader to retrieve data. I need to use an
XmlTextReader because it is faster than using an XmlDocument.

I have found an inelegant way of retrieving each item's title and
description using string methods. See my code below. I would like to know how
I can retrieve the <title> and <description> nodes more directly using the
methods of the XmlTextReader.

My xml file looks somthing like:
<items>
<item><title>Title 1</title><description>Description 1</description></item>
<item><title>Title 2</title><description>Description 2</description></item>
</items>

My Hack:
XmlTextReader xmlTextReader = new XmlTextReader(myXmlUrl);

while(xmlTextReader.Read())
{
if(xmlTextReader.NodeType == XmlNodeType.Element && xmlTextReader.Name ==
"item" )
{
string itemContent = xmlTextReader.ReadOuterXml();
int headlineStart = itemContent.IndexOf("<title>") + "<title>".Length;
headlineLength = itemContent.IndexOf("</title>") - headlineStart;
descriptStart = itemContent.IndexOf("<description>") +
"<description>".Length;
int descriptLength = itemContent.IndexOf("</description>") - descriptStart;
string headline = itemContent.Substring(headlineStart,
headlineLength);
string description = itemContent.Substring(descriptStart, descriptLength);

Response.Write(headline + "<br>" + description + "<br><br>");
}

Many thanks,

CR
Mar 14 '06 #1
4 5978
String manipulation here is a bit messy, but works (I guess);

Personally, I use a bespoke XmlReader-based approach for this that uses a
custom iterator (so only has one "row" in memory at once); I tell it the
name of the parent nodes ("item" in this case) and each *direct* child
("title" and "description"), and it returns each row as an array matching
what I passed it. It copes with parents at different levels, children in any
order, and elements and attributes (children) - e.g.

foreach(string[] fields in reader.ReadElements("item", "title",
"description")) {
// title is fields[0], description is fields[1]
}

I can post / e-mail the source if you are interested, but it is a bit
long... but it shows a different way to do it (without the strings).

Or you can do it manually in about 20 ways...

Let me know if you want me to post it

Marc

"CodeRazor" <Co*******@discussions.microsoft.com> wrote in message
news:E9**********************************@microsof t.com...
I am trying to use an XmlTextReader to retrieve data. I need to use an
XmlTextReader because it is faster than using an XmlDocument.

I have found an inelegant way of retrieving each item's title and
description using string methods. See my code below. I would like to know
how
I can retrieve the <title> and <description> nodes more directly using the
methods of the XmlTextReader.

My xml file looks somthing like:
<items>
<item><title>Title 1</title><description>Description
1</description></item>
<item><title>Title 2</title><description>Description
2</description></item>
</items>

My Hack:
XmlTextReader xmlTextReader = new XmlTextReader(myXmlUrl);

while(xmlTextReader.Read())
{
if(xmlTextReader.NodeType == XmlNodeType.Element && xmlTextReader.Name ==
"item" )
{
string itemContent = xmlTextReader.ReadOuterXml();
int headlineStart = itemContent.IndexOf("<title>") + "<title>".Length;
headlineLength = itemContent.IndexOf("</title>") - headlineStart;
descriptStart = itemContent.IndexOf("<description>") +
"<description>".Length;
int descriptLength = itemContent.IndexOf("</description>") -
descriptStart;
string headline = itemContent.Substring(headlineStart,
headlineLength);
string description = itemContent.Substring(descriptStart, descriptLength);

Response.Write(headline + "<br>" + description + "<br><br>");
}

Many thanks,

CR

Mar 14 '06 #2
Hi Marc, thanks for your help.

When i tried what you suggested though, i get the error,
"'System.Xml.XmlTextReader' does not contain a definition for 'ReadElements'"

Are you using an XmlTextReader?

I've sent you an email to your posted address.

Mar 14 '06 #3
no; this is (as stated) using a bespoke class - SimpleXmlReader; copied
below - use it something like:

using(SimpleXmlReader reader = new SimpleXmlReader({your chosen ctor})) {
// the code from before
}

Let me know if you have any problems,

Marc
using System;
using System.Xml;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace Your.Namespace.Xml {
/// <summary>
/// Provides a simple but efficient way of reading typical
/// Xml structures with named (field) attributes or elements
<b>immediately</b> underneath
/// named (row) elements
/// </summary>
public sealed class SimpleXmlReader : IDisposable {
private static Dictionary<string, int> GetDictionary(string[]
nodeNames) {
int index = 0;
Dictionary<string, int> requiredValues = new Dictionary<string,
int>(nodeNames.Length);
foreach (string nodeName in nodeNames) {
if (!string.IsNullOrEmpty(nodeName)) {
// deliberately breaks if duplicated key requested;
value represents
// position in out array
requiredValues.Add(nodeName, index++);
}
}
return requiredValues;
}
/// <summary>
/// Returns the cited node values underneath the current element in
the reader
/// </summary>
/// <param name="reader">The reader to investigate</param>
/// <param name="nodeNames">The fields required (prefix attributes
with @)</param>
/// <returns>Array of strings, with each value in the corresponding
position to the requested fields</returns>
public static string[] ReadValues(XmlReader reader, params string[]
nodeNames) {
return ReadValues(reader, GetDictionary(nodeNames));
}
private static string[] ReadValues(XmlReader reader,
Dictionary<string, int> requiredValues) {
string[] result = new string[requiredValues.Count];
string name;
int index, targetDepth = reader.Depth + 1;
bool isEmpty = reader.IsEmptyElement;
if(reader.HasAttributes) {
if (reader.MoveToFirstAttribute()) { // read attributes
do {
name = "@" + reader.Name;
if (requiredValues.TryGetValue(name, out index) &&
result[index] == null) {
result[index] = reader.Value;
}
} while (reader.MoveToNextAttribute());
}
}
if (!isEmpty && reader.Read()) {// read sub-elements (note this
progresses the cursor)
while (true) {
int currentDepth = reader.Depth;
if (reader.Depth < targetDepth) {
break; // too shallow: reached end of element
} else if (currentDepth > targetDepth) { // too deep:
only interested in first descendents
reader.Skip();
} else if (reader.NodeType == XmlNodeType.Element) { //
right depth; is it an element?
name = reader.Name;
if (requiredValues.TryGetValue(name, out index) &&
result[index] == null) {
result[index] =
reader.ReadElementContentAsString(); // progresses cursor
} else { // not interested
reader.Skip(); // progresses cursor
}
} else if (!reader.Read()) { // progresses cursor
break; // end of the xml (somehow!)
}
}
}
return result;
}

private Stream _stream;
private readonly bool _leaveStreamOpen, _leaveReaderOpen;

/// <summary>
/// Create a SimpleXmlReader from a string
/// </summary>
/// <param name="xmlString">The xml to load</param>
/// <returns>A new SimpleXmlReader object</returns>
public static SimpleXmlReader Create(string xmlString) {
return new SimpleXmlReader(Encoding.UTF8.GetBytes(xmlString)) ;
}

public SimpleXmlReader(string path) : this(new FileStream(path,
FileMode.Open), false) { }
public SimpleXmlReader(byte[] data) : this(new MemoryStream(data),
false) { }
public SimpleXmlReader(Stream stream) : this(stream, false) { }
public SimpleXmlReader(Stream stream, bool leaveOpen) {
_leaveStreamOpen = leaveOpen;
_leaveReaderOpen = false;
_stream = stream;
}
public SimpleXmlReader(XmlReader reader) : this(reader, false) { }
public SimpleXmlReader(XmlReader reader, bool leaveOpen) {
_leaveStreamOpen = false;
_leaveReaderOpen = leaveOpen;
_reader = reader;
}
/// <summary>
/// Reads the stream, returning an XmlDocument
/// </summary>
/// <returns>The XmlDocument of the data</returns>
/// <remarks>This will read to the end of the stream, and
/// cannot be repeated</remarks>
public XmlDocument GetDocument() {
XmlDocument doc = new XmlDocument();
if (_stream != null)
doc.Load(_stream);
else if (_reader != null)
doc.Load(_reader);
else
throw new InvalidOperationException("No stream/reader to
load from");
return doc;
}

private XmlReader _reader;
public XmlReader Reader {
get {
if (_reader == null) {
XmlReaderSettings readerSettings = new
XmlReaderSettings();
readerSettings.CloseInput = !_leaveStreamOpen;
readerSettings.IgnoreComments = true;
_reader = XmlReader.Create(_stream, readerSettings);
}
return _reader;
}
}
/// <summary>
/// Searches through the xml (forwards only) looking for the cited
row-element;
/// for each such found, the requested fields are returned to the
caller
/// </summary>
/// <param name="rowElementName">The element to search for (at any
level) </param>
/// <param name="nodeNames">The fields required (prefix attributes
with @)</param>
/// <returns></returns>
/// <remarks>Note that this searches the xml *while* enumerating -
so only one row
/// is ever in memory at once; this makes for highly efficient
processing</remarks>
public System.Collections.Generic.IEnumerable<string[]>
ReadElements(string rowElementName, params string[] valueNodeNames) {
XmlReader reader = Reader; // creates if not already there
Dictionary<string, int> requiredValues =
GetDictionary(valueNodeNames);
while (reader.ReadToFollowing(rowElementName)) {
yield return ReadValues(reader, requiredValues);
}

}

public void Close() {
if (_reader != null) {
if (!_leaveReaderOpen) {
_reader.Close();
}
_reader = null;
}
if (_stream != null) {
if (!_leaveStreamOpen) {
_stream.Close();
_stream.Dispose();
}
_stream = null;
}
}
public void Dispose() {
Close();
}
}
}

"CodeRazor" <Co*******@discussions.microsoft.com> wrote in message
news:9C**********************************@microsof t.com...
Hi Marc, thanks for your help.

When i tried what you suggested though, i get the error,
"'System.Xml.XmlTextReader' does not contain a definition for
'ReadElements'"

Are you using an XmlTextReader?

I've sent you an email to your posted address.

Mar 14 '06 #4
thanks Marc, but this is too complex for what I need.
All I want to do is just read the values from the title and description
nodes in my xml file using XmlTextReader methods.

How can i do that? -- thanks

<items>
<item><title>Title 1</title><description>Description 1</description></item>
<item><title>Title 2</title><description>Description 2</description></item>
</items>
Mar 15 '06 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Andy Neilson | last post by:
I've run across a strange behaviour with XmlSerializer that I'm unable to explain. I came across this while trying to use XmlSerializer to deserialize from a the details of a SoapException. This...
5
by: Geoff Bennett | last post by:
While parsing an XML document, my TextReader instance skips nodes. For example, in this fragment: <Person Sex="Male" FirstHomeBuyer="No" YearsInCurrentProfession="14"> <RelatedEntityRef...
2
by: Yuriy | last post by:
Hi, any ideas how to read XML fragment from TextReader? XmlTextReader constructor accepts only Stream or string as source Do I miss something? thanks Yuriy
1
by: RJN | last post by:
Hi I'm using XMLTextReader to parse the contents of XML. I have issues when the xml content itself has some special characters like & ,> etc. <CompanyName>Johnson & Jhonson</CompanyName>...
1
by: SHC | last post by:
Hi all, I did the "Build" on the attached code in my VC++ .NET 2003 - Windows XP Pro PC. On the c:\ screen, I got the following: Microsoft Development Environment An unhandled exception of type...
3
by: Kjeld | last post by:
My scenario: I'm using an XmlTextReader to Deserialize serveral classes from a single xml document. Every class i pass the source stream, containing the xml. Each class subsequently creates an...
2
by: XML reading with XMLTextReader | last post by:
im trying to read an xml file which is in the wwwroot folder.im using IIS on XP Prof. my code is...
4
by: CodeRazor | last post by:
I am reading an xml file from a URL. I was originally doing this using the XmlDocument class. But this was very slow. The XmlTextReader is meant to be much quicker for forward only retrieval of...
1
by: Steve | last post by:
For some reason, the schema seems to be empty every time it's loaded. Does anyone have any ideas?? Thanks! Here's the code: Dim xsd As System.Xml.Schema.XmlSchema Dim io As New...
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.