Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / New Users / March 2006

Tip: Looking for answers? Try searching our database.

XmlBookmarkReader bug using ReadSubtree

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
eric.olstad@gmail.com - 17 Mar 2006 16:45 GMT
I have discovered a bug in XmlBookmarkReader (code provided by MSDN,
but not necessarily supported by Microsoft).  The article is found
here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnxmlnet/html/X
mlBkMkRead.asp


Consider the following code to print xml.   This code assumes that the
xml text given in the reader will be of a certain form -- basically
having a root node, which is not a crazy assumption at all.  It just
makes the code simpler to demonstrate the bug.

public static void PrintXml(XmlReader reader)
{
  bool inElement = false;
  string elementName="";

  XmlBookmarkReader bReader = new XmlBookmarkReader(reader);

  bReader.Read();
  if (bReader.HasAttributes)
  {
     Console.Write("<"+bReader.Name);
     for (int i=0; i < bReader.AttributeCount; i++)
     {
        Console.Write(" ");
        bReader.MoveToAttribute(i);
        Console.Write("{0}=\"{1}\"", bReader.Name, bReader.Value);
     }
     bReader.MoveToElement();
     Console.WriteLine(">");
  }
  else
  {
     Console.WriteLine("<"+bReader.Name+">");
  }

  while (bReader.Read())
  {
     switch (reader.NodeType)
     {
        case XmlNodeType.Element:
           if (inElement)
           {
              bReader.ReturnToBookmark(elementName);
              PrintXml(bReader.ReadSubtree());
              inElement = false;
           }
           else
           {
              inElement = true;
              elementName = bReader.Name;
              bReader.SetBookmark(elementName);
              if (!bReader.HasAttributes)
                 Console.Write("<" + bReader.Name + ">");
              else
              {
                 Console.Write("<" + bReader.Name);
                 for (int i = 0; i < bReader.AttributeCount; i++)
                 {
                    Console.Write(" ");
                    bReader.MoveToAttribute(i);
                    Console.Write("{0}=\"{1}\"", bReader.Name,
bReader.Value);
                 }
                 bReader.MoveToElement();
                 Console.Write(">");
              }
           }
           break;
           case XmlNodeType.EndElement:
              Console.WriteLine("</" + bReader.Name + ">");
              inElement = false;
              bReader.RemoveBookmark(elementName);
              break;
           case XmlNodeType.Text:
              Console.Write(bReader.Value);
              break;
     }
  }
  reader.Close();
}

Now pass the code above this XML text:
<Config>
 <Id attrib="false">12345-6789-12364</Id>
 <DisplayName attrib="true">Computer</DisplayName>
 <ServerList count="4">
   <Server0 checkedin="true">https://web1.com</Server0>
   <Server1 checkedin="false">https://web2.com</Server1>
   <Server2 checkedin="false">https://web3.com</Server2>
   <Server3 checkedin="false">https://web4.com</Server3>
 </ServerList>
</Config>

Code to turn that text into an XmlReader:
string xml = [XML text above];
XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
nsmgr.AddNamespace("", "");
XmlParserContext parseContext =
  new XmlParserContext(null, nsmgr, null, XmlSpace.None);
XmlTextReader reader =
  new XmlTextReader(xml, XmlNodeType.Document, parseContext);
reader.WhitespaceHandling = WhitespaceHandling.None;
PrintXml(reader);

You get this result:
<Config>
<Id attrib="false">12345-6789-12364</Id>
<DisplayName attrib="true">Computer</DisplayName>
<ServerList count="4"><ServerList count="4">
<Server0 checkedin="true">https://web1.com</Server0>
<Server0 checkedin="true">https://web2.com</Server1>
<Server0 checkedin="true">https://web3.com</Server2>
<Server0 checkedin="true">https://web4.com</Server3>
</ServerList>
</Config>

Notice the Server1, Server2 and Server3 start elements all are Server0,
but the end elements are correct.  Notice they all share the same
'checkedin' attribute values as Server0 as well.  ServerList appearing
twice is a side effect of having to go back using the bookmark.  That
can be dealt with, but for simplicity, I didn't bother to correct it
here.

I've pinned this bug down to an issue with XmlBookmarkReader and
ReadSubtree.  There are some strange effects going on that I don't
understand.  For example, removing the "checkedin="true"" from the
Server0 element in the original XML doesn't result in this behavior.
You get the results you would expect.  In fact, adding any
non-attributed element before Server0 gives you the results you would
expect even an empty element.

The only bit of insight I have with this problem is that the original
reader, before the recursive call to PrintXml, is positioned on Server0
while the bookmark reader is positioned on the cached ServerList node
when the call to ReadSubtree is executed.

Any help pinning down the problem would be greatly appreciated.

My conclusion is that a call to ReadSubtree on CachedXmlNode in the
XmlBookmarkReader may have unexpected results," but I would still like
to solve this problem.
eric.olstad@gmail.com - 17 Mar 2006 19:25 GMT
A solution, though not as elegant, is to forget about using
ReadSubtree.  Instead you assume either the first node read or the
current node is the root node and you read until you encouter the
EndElement with the same name as the root node.  You call PrintXml
recursively like above, but you must remove all bookmarks (because
you're working with the same XmlBookmarkReader).

It works, but has a lot more potential for error.  If anyone is
interested, I can post the code.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.