473,385 Members | 1,506 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,385 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 5988
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...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

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.