When i read the xml file it reads duplicates of the node - c#

When i try read my xml file it seems to reads it twice and im unsure on how to fix such an error. I thought i can have some sort of loop but im still lost. Any help would be appreciated ty. - It writes the xml file correctly but the duplicate occurs when it reads it.
String workingDir = Directory.GetCurrentDirectory();
XmlTextReader textReader = new XmlTextReader(workingDir + #"\xmldoc.xml");
Console.WriteLine("BaseURI:" + textReader.BaseURI);
textReader.Read();
while (textReader.Read())
{
if (textReader.Name == "test")
{
textReader.Read();
XmlNodeType nType = textReader.NodeType;
if (nType == XmlNodeType.Text)
{
// label.Text = textReader.Value.ToString();
Label l = new Label();
System.Drawing.Point l1 = new System.Drawing.Point(15, 13 + a);
l.Location = l1;
l.Text = textReader.Value.ToString();
a += 20;
}

What makes you think some entries are read twice? If it is the case, also check if this method is not called twice (shift + F12 in Visual Studio to find usage).
Also, it seems that the piece of code you joined here is not complete (no declaration of variable 'a'). Do you have some code executed under the if (textReader.Name == "test") that would do the same operations?

I have no idea what you are REALLY trying to do, and no visibility of you XML, but here is roughly how I would do it.
Notes:
I'm using an XmlReader <- Better IMHO (base class, so there's less waffle)
I'm using "reader.Value" without the ToString() as it's already a string type.
I changed it to be a switch as I think they are cleaner, but there are A LOT of XmlNodeTypes out there and you don't want to have to if/else to much!!!
Code:
XmlReader reader = XmlReader.Create("books.xml");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
//DO NOTHING
break;
case XmlNodeType.Text: //Display the text in each element.
//label.Text = reader.Value;
Label l = new Label();
System.Drawing.Point l1 = new System.Drawing.Point(15, 13 + a);
l.Location = l1;
l.Text = reader.Value;
a += 20;
break;
case XmlNodeType.EndElement: //Display the end of the element.
//DO NOTHING
break;
}
}

Related

Creating a dictionary of Func

I have a method which writes a DataGridView into a text file:
private void textToolStripMenuItem_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
saveFileDialog1.FilterIndex = 2;
saveFileDialog1.RestoreDirectory = true;
saveFileDialog1.FileName = DateTime.Now.ToString("yyyyMMddhhmm") + "_icmquery_" + GetTabName() + ".txt";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
using (FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.OpenOrCreate))
{
switch (mainTabGroup.SelectedTab.Name.ToString())
{
case "findScriptsTab":
WriteTextFile(fs, findScriptsDataGrid);
break;
case "dialNumberAuditTab":
WriteTextFile(fs, findScriptsDataGrid);
break;
case "calltypeRequalificationTab":
WriteTextFile(fs, ctrDataGrid);
break;
case "targetAuditTab":
WriteTextFile(fs, targetAuditDataGrid);
break;
}
}
}
}
public void WriteTextFile(FileStream fs, DataGridView dataGrid)
{
using (TextWriter tw = new StreamWriter(fs))
{
foreach (DataGridViewRow row in dataGrid.Rows)
{
string line = string.Empty;
foreach (DataGridViewCell cell in row.Cells)
{
line = line + cell.Value + ",";
}
line = line.TrimEnd(',');
tw.WriteLine(line);
}
}
}
But instead of using the large switch statement in textToolStripMenuItem_Click() I would like to define a dictionary in my form. I have tried:
private Dictionary<TabPage, Func<FileStream, DataGridView>> WriteTextFileByTab(FileStream fs) = new Dictionary<TabPage, Func<FileStream, DataGridView>>()
{
{findScriptsTab, WriteTextFile(fs, findScriptsDataGrid)}
};
But visual studios won't even register this as a valid thing. I typed this in manually but none of the intense would fill anything in. When I hover over "findScriptsTab" it says its a field by used like a type, and WriteTextFile says the same thing. Any idea on how I could properly convert the switch statement to a dictionary so I can just say: WriteTextFileByTab[mainTabGroup.SelectedTab];?
You cannot define the parameter to the method for each item in the dictionary before you define the dictionary itself. You need to declare the parameter's identifier when constructing each value of the dictionary:
private Dictionary<TabPage, Func<FileStream, DataGridView>> WriteTextFileByTab
= new Dictionary<TabPage, Func<FileStream, DataGridView>>()
{
{findScriptsTab, fs => WriteTextFile(fs, findScriptsDataGrid)}
};
Of course if findScriptsTab and findScriptsDataGrid are instance fields, as I suspect that they are, you won't be able to use them when initializing another instance field. As such, you'll need to initialize this dictionary in the constructor, not when declaring it.
It also looks like the delegates in your dictionary (based on your implementation of WriteTextFile) don't actually need to return a DataGridView so the appropriate delegate to use is actually an Action<FileStream>, not a Func<FileStream, DataGridView>.

XmlTextReader C# Problems With Reading and Writing

So, I am trying to make a "Recent Files" feature in my WPF application by use of C#'s XML class.
Basically, the program needs to read each node and get the URI of file to generate menu item.
Problem is, r.Value doesn't give me a string to work with and I'm starting to question whether or not this code is going to work.
XmlTextReader r = new XmlTextReader(this.PathToSpecialFolder + #"\" + Application.CompanyName + #"\" + Application.ProductName + #"\Recent.xml");
int count = 0;
while (r.Read())
{
switch (r.NodeType)
{
case XmlNodeType.Element:
if (r.Name == "Path")
{
count++;
if (count <= 5)
{
MenuItem m = new MenuItem() { Header = r.Value };
openRecentMenuItem.Items.Add(m);
//r.Value populates nothing
}
}
break;
}
}
r.Close();
On a related topic, I'm also trying to get it to where the XML file will only store five nodes. I want to...
Get number of nodes (which I have already accomplished)
Check whether new node + node count > 5 and, if so, prepend new node and remove last node. Otherwise, just add new node
How do you remove the last node? Here is my XML file structure:
<?xml version="1.0" encoding="utf-8"?>
<RecentFiles>
<File>
<Path>Path goes here.</Path>
</File>
</RecentFiles>
UPDATE:
The code below solves my issue with reading (as per advice of John), however, I still cannot figure out how to remove the last node when writing. I prefer not to use Linq in this case, so a solution using XmlReader is preferred, thanks.
XmlReader x = XmlReader.Create(this.PathToSpecialFolder + #"\" + Application.CompanyName + #"\" + Application.ProductName + #"\Recent.xml");
int c = 0;
while (x.Read())
{
if (x.NodeType == XmlNodeType.Element && x.Name == "Path")
{
c++;
if (c <= 10)
{
MenuItem m = new MenuItem() { Header = x.ReadInnerXml() };
m.Click += delegate
{
};
openRecentMenuItem.Items.Add(m);
}
}
}
x.Close();
}

C# how to clear the streamwriter buffer without writing to a txt file?

I am working on C# on Win7.
I need to use Streamwriter to write to a txt file.
StreamWriter outfile = new StreamWriter(MY_PATH, true);
foreach(a line of strings)
{
// process the line
outfile.Write(String.Format(WIDTH + " " + WIDTH, num1Str+"\t", num2Str+"\t"));
}
if all elements in line are "0"
// do not write anything to the file, clear outfile buffer
// WIDTH are constants. num1Str and num2Str are variables.
How to clear the contents written in the stream buffer ?
Flush is not a solution because I do not want to write the file if all elements are 0.
Any help would be appreciated.
I believe you're looking for outfile.Flush();.
UPDATE: so now that the question is clearer, you don't want a StreamWriter, you want to leverage something like a MemoryStream instead. Consider the following snippet:
var writeToDisk = false;
var outfile = new MemoryStream();
foreach(a line of strings)
{
// process the line
// BTW: the `String.Format` you have here is exceptionally confusing
// and may be attributing to why everything is \0
outfile.Write(...);
// set the flag to `true` on some condition to let yourself know
// you DO want to write
if (someCondition) { writeToDisk = true; }
}
if (writeToDisk)
{
var bytes = new byte[outfile.Length];
outfile.Read(bytes, 0, outfile.Length);
File.WriteAllBytes(MY_PATH, bytes);
}
I think what you want is the Any for checking if any is not "0", but also using using would be nice so that you can dispose properly.
if(someString.Any(a=> a != '0')) //if any elements in line are not '0'
{
using(StreamWriter outfile = new StreamWriter(MY_PATH, true))
{
foreach(char a in someString)
{
outfile.Write(WIDTH + " " + WIDTH, num1Str+"\t", num2Str+"\t");
}
}
}
if all elements in line are "0"
// do not write anything to the file, clear outfile buffer
Then why don't you check your line's content, before you write it ?
// process the line
string line = String.Format(WIDTH + " " + WIDTH, num1Str+"\t", num2Str+"\t");
if(!line.Trim().All(c => c == '0'))
outfile.Write(line);

Asp.net FindControl + "Multiple controls with the same ID"

I'm getting a really weird behavior with ASP.Net.
When I run the following code, the exception "Multiple controls with the same ID" is thrown.
The exception is not thrown when adding the control but when using FindControl.
What's really weird is that if I put a breakpoint just before the call and run a FindControl call in the immediate windows where the exception is thrown (so far so consistent) but then when I resume the debugger, everything works fine (!!!). The machine runs the same exact code but, it doesn't throw the exception again.
One last thing about this crazy thing, earlier today the very same code was inside Page_Load and everything was working fine but I reorganized the code and moved it to a separate method (which is called by Page_Load).
I'm getting pretty confident this is a ASP.Net bug...
dlAdvanced.DataSource = dsAdvanced;
dlAdvanced.DataBind();
// Load Advanced Values Controls
#region ADV controls
foreach (DataListItem dli in dlAdvanced.Items)
{
DataRow row = dsAdvanced.Tables[0].Rows[dli.ItemIndex];
switch ((string)row["Type"])
{
default:
TextBox tb = new TextBox();
tb.ID = "Input";
dli.FindControl("InputPlace").Controls.Add(tb);
break;
case "System.Int32":
case "System.Decimal":
TextBox tbn = new TextBox();
tbn.ID = "Input";
Image img = new Image();
img.SkinID = "NumberRequired";
img.ApplyStyleSheetSkin(this);
dli.FindControl("InputPlace").Controls.Add(tbn);
dli.FindControl("InputPlace").Controls.Add(img); // Exception happens here
break;
case "System.DateTime":
golf.golfControls.CalendarBox cal = new golf.golfControls.CalendarBox();
cal.ID = "Input";
cal.SkinID = "Calendar";
cal.ApplyStyleSheetSkin(this);
dli.FindControl("InputPlace").Controls.Add(cal);
break;
case "System.Boolean":
RadioButton rb1 = new RadioButton();
rb1.Text = "True";
rb1.ID = "Input";
rb1.GroupName = "grp" + dli.ItemIndex.ToString();
RadioButton rb2 = new RadioButton();
rb2.Text = "False";
rb2.ID = "Input2";
rb2.GroupName = "grp" + dli.ItemIndex.ToString();
dli.FindControl("InputPlace").Controls.Add(rb1);
dli.FindControl("InputPlace").Controls.Add(rb2);
break;
}
}
#endregion
EDIT :
I just though of something and it worked :
DataRow row = dsAdvanced.Tables[0].Rows[dli.ItemIndex];
var inputPlace = dli.FindControl("InputPlace");
switch ((string)row["Type"])
{
default:
TextBox tb = new TextBox();
tb.ID = "Input";
inputPlace.Controls.Add(tb);
break;
case "System.Int32":
case "System.Decimal":
TextBox tbn = new TextBox();
tbn.ID = "Input";
Image img = new Image();
img.SkinID = "NumberRequired";
img.ApplyStyleSheetSkin(this);
inputPlace.Controls.Add(tbn);
inputPlace.Controls.Add(img);
break;
case "System.DateTime":
golf.golfControls.CalendarBox cal = new golf.golfControls.CalendarBox();
cal.ID = "Input";
cal.SkinID = "Calendar";
cal.ApplyStyleSheetSkin(this);
inputPlace.Controls.Add(cal);
break;
case "System.Boolean":
RadioButton rb1 = new RadioButton();
rb1.Text = "True";
rb1.ID = "Input";
rb1.GroupName = "grp" + dli.ItemIndex.ToString();
RadioButton rb2 = new RadioButton();
rb2.Text = "False";
rb2.ID = "Input2";
rb2.GroupName = "grp" + dli.ItemIndex.ToString();
inputPlace.Controls.Add(rb1);
inputPlace.Controls.Add(rb2);
break;
}
So for the time being, my code works fine, but this issue isn't resolved so if someone knows anything about this bug, please enlighten me.
it is not a bug, all your controls has the same ID tb.ID = "Input"; cal.ID = "Input";, etc
try to add a unique string after each ID like
tb.ID = "input" + dli.ItemIndex.ToString();
The problem actually came for an event that tried to add those controls again elsewhere in the code.
I just answer my own question so it's a closed matter, no rage downvote for this responsible behavior please.

How to prevent XMLReader from unescaping characters

I'd like to create a simple XMLreader which reads a complete node (including subnodes) as text:
string TXML = #"<xml><text>hallöle</text></xml>";
XmlReader r = XmlReader.Create(new StringReader(TXML));
r.Read(); r.Read();
string o = r.ReadOuterXml();
ReadOuterXml does the job but it unescapes the already escaped signs:
"<text>hallöle</text>"
I whish to have the result:
"<text>hallöle</text>"
How can I ommit that 'unescaping'. I want to store this fragments to a db and do need that escaping. Furthermore I dont want to parse and recreate the fragments.
I had a similar problem, I wanted to keep the escaped characters when reading from xml, but in may case when calling ReadOuterXml(), only some of characters were kept and at least oane was transformed (I had " instead of ")
My solution was the following:
string TXML = #"<xml><text>hallöle</text></xml>";
TXML = TXML.Replace("&", "&");
XmlTextReader r = new XmlTextReader(new StringReader(TXML));
r.Read(); r.Read();
// now we are at the text element
r.ReadStartElement()
var content = SecurityElement.Escape(r.ReadContentAsString())
r.ReadEndElement()
I found two solutions. Both not very nice, but maybe you can tell me which has less drawbacks.
Both solutions rely on direcly using the ´XmlTextReader´ instead of ´XmlReader´. It comes with the property ´LinePosition' which lead me to the first solution and with the method ´ReadChars´ as basis for the second one.
Solution (1), get data from original string via indices
Problems:
doesn't work on stream inputs
doesn't work if xml has several lines
Code
string TXML = #"<xml><data></data><rawnode at=""10 4""><text>hallöle</text><z d=""2"">3</z></rawnode><data></data></xml>";
//XmlReader r = XmlReader.Create(new StringReader(TXML));
XmlTextReader r = new XmlTextReader(new StringReader(TXML));
// read to node which shall be retrived "raw"
while ( r.Read() )
{
if ( r.Name.Equals("rawnode") )
break;
}
// here we start
int Begin = r.LinePosition;
r.Skip();
int End = r.LinePosition;
// get it out
string output=TXML.Substring(Begin - 2, End - Begin);
Solution (2), get data with ´ReadChars´
Problems:
I have to parse and recreate the 'outer' markup of my tag which I'd like to read.
This might cost performance.
I might introduce errors.
Code:
// ... again create XmlTextReader and read to rawnode, then:
// here we start
int buflen = 15;
char[] buf = new char[buflen];
StringBuilder sb= new StringBuilder("<",20);
//get start tag and attributes
string tagname=r.Name;
sb.Append(tagname);
bool hasAttributes = r.MoveToFirstAttribute();
while (hasAttributes)
{
sb.Append(" " + r.Name + #"=""" + r.Value + #"""");
hasAttributes = r.MoveToNextAttribute();
}
sb.Append(#">");
r.MoveToContent();
//get raw inner data
int cnt;
while ((cnt = r.ReadChars(buf, 0, buflen)) > 0)
{
if ( cnt<buflen )
buf[cnt]=(char)0;
sb.Append(buf);
}
//append end tag
sb.Append("</" + tagname + ">");
// get it out
string output = sb.ToString();
Have a look on you xml header and verify that it contains something like this: <?xml version="1.0" encoding="ISO-8859-9"?>
For escaping and unescaping you could use the c# functions InnerXml and InnerText :
public static string XmlEscape(string unescaped)
{
XmlDocument doc = new XmlDocument();
var node = doc.CreateElement("root");
node.InnerText = unescaped;
return node.InnerXml;
}
public static string XmlUnescape(string escaped)
{
XmlDocument doc = new XmlDocument();
var node = doc.CreateElement("root");
node.InnerXml = escaped;
return node.InnerText;
}
I understand your desire to not have to parse and recreate the escaped characters, but I can't find a way not to unless you go full on customized with it. Perhaps this isn't so bad?
string TXML = #"<xml><text>hallöle</text></xml>";
TXML = TXML.Replace("&", "&");
XmlTextReader r = new XmlTextReader(new StringReader(TXML));
r.Read(); r.Read();
string o = r.ReadOuterXml();
o = o.Replace("&", "&");

Categories

Resources