1

I have this example code in my c# win form...

List<string> listFurniture = new List<string>();
XDocument xml = XDocument.Load(Application.StartupPath + @"\Furniture.xml");
foreach (XElement quality in xml.Descendants("Quality"))
    listFurniture.Add(quality.Value);

maintextbox.Text = listFurniture[0];

... And this example xml

<Furniture>
  <Table>
    <Quality>textbox1.Text + "and" + textbox2.Text + "but" + textbox3.Text</Quality>   
    ...
  </Table>  
</Furniture>

My dilemma is, the maintextbox is producing the actual string "textbox1.Text", instead of the value of textbox1.

I want the xml value to be read as:

maintextbox.Text = textbox1.Text + "and" + textbox2.Text + "but" + textbox3.Text;

not as:

maintextbox.Text = "textbox1.Text + "and" + textbox2.Text + "but" + textbox3.Text";

I tried using a text file as well with StreamReader and I got the same result.

The reason for coding my project this way is because the sequence of the textboxes changes and so does the "and" and the "but". When that change happens, I wouldn't have to rewrite the code and recompile the program. I would just make the changes in xml.

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459

2 Answers2

2

There is all OK with xml parsing in your solution. What you need is processing of Quality strings.

string[] parts = quality.Split('+');
Regex regex = new Regex(@"^""(.*)""$");
var textBoxes = Controls.OfType<TextBox>().ToList();

for (int i = 0; i < parts.Length; i++)
{
    string part = parts[i].Trim();

    var match = regex.Match(part);
    if (match.Success)
    {
        parts[i] = match.Groups[1].Value;
        continue;
    }

    var textBox = textBoxes.FirstOrDefault(tb => tb.Name + ".Text" == part);
    if (textBox != null) // possibly its an error if textbox not found
        parts[i] = textBox.Text; 
}    

mainTextBox.Text = String.Join(" ", parts);

What happened here:

  • We split quality string by + chars to get array of string parts
  • With regular expression we verify if part looks like something in quotes "something". If yes, then it will be or, and or other connective word
  • And last, we check all textboxes for matching name of textbox in quality string part. If it matches, then we replace part with text from textbox
  • We join parts to get result string

BTW you can parse Xml in one line:

var listFurniture = xml.Descendants("Quality") 
                       .Select(q => (string)q)
                       .ToList();
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • This is brilliant! I do understand your logic, and thank you for pointing me to the right direction... Thanks for the xml parsing tip as well. What puzzles me though is, the variable textbox in your code is not recognizing the similarity between tb and part, thus making textbox == null, and the textboxes in parts still output the textboxes names like "textbox1.Text" instead of the value. – John Smith Optional Jan 18 '13 at 17:44
  • @JohnSmithOptional possibly your textbox have name `textBox1`, which does not match case of `textbox1` – Sergey Berezovskiy Jan 18 '13 at 18:00
  • Thanks lazyberezovsky. I may have a lead on what's happening. When I check the textboxes in the var textBoxes, I only see the textboxes placed directly on the form. The textboxes I am processing are inside their respective GroupBoxes, and they are not showing in the var textBoxes. I'm gonna pull a little bit more hair and work on keeping the textboxes in their home - feel free to help ;) . Thank you again. – John Smith Optional Jan 18 '13 at 18:27
  • 1
    ok I got it to work I just added the group name: var textBoxes = grpBox.Controls.OfType().ToList(); . You pulled me out of a trap sir. I thank you. – John Smith Optional Jan 18 '13 at 18:44
  • @JohnSmithOptional sorry, was AFK :) Glad that you found solution! BTW [here is simple solution how to look through all controls](http://stackoverflow.com/questions/3419159/how-to-get-all-child-controls-of-a-winform-of-a-specific-type-button-textbox) – Sergey Berezovskiy Jan 18 '13 at 19:01
  • 1
    Nice example, nice use of expressions to provide read and write capability in the method. Nice parse example Lazy. – Greg Jan 18 '13 at 19:43
  • 1
    @lazyberezovsky excellent! That's a lot better than my way.Thank you once again. – John Smith Optional Jan 18 '13 at 21:14
1

Update:

Since I received a comment to explain the code a bit; I'll explain it a bit.

First, XML as a language is designed for structure. That structure and ease; provides the flexibility and power to quickly parse data between languages or applications seamless. Your original question states that your textbox is producing a string value of your code textbox.text.

The XML need to be structured; an example structure would be:

<Furniture>
     <Table>
         <Color> Red </Color>
         <Quality> 10 </Quality>
         <Material> Wood </Material>
      </Table>
</Furniture>

So if you were to read your XML it would be finding the root tag. All other components would be nodes. These nodes need to be index, or siphoned through to attain the proper correlation you would like represented into your textbox.

That is what this code is doing; I'll break it down through each step.

// String you will format with the XML Structure.
StringBuilder output = new StringBuilder();

The next part will be as follows:

// Create an XML Reader, by wrapping it in the 'using' it will ensure once your done the object is disposed of.  Rather then leaving the connection to your document open.
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
       // We will read our document to the following; hold to that attribute.  The attribute is identifying the node and all of the child elements that reside within it: So in our case Table.
       reader.ReadToFollowing("Table");
       reader.MoveToFirstAttribute();
       string color = reader.Value;
       output.AppendLine("The color of the table " + color);

       // As you can see there isn't anything fancy here, it reads to our root node.  Then moves to the first child element.  Then it creates a string and appends it. Keep in mind we are using our StringBuilder so we are just appending to that structure.
       reader.ReadToFollowing("Material");
       output.AppendLine("The material: " + reader.ReadElementContentAsString());

       // Same result as we used earlier; just a different method to attain our value.
}

// Now we output our block.
OutputTextBlock.Text = output.ToString();

Now all the data is pushed into a string, obviously you can use the above code with a textbox to retrieve those values as well.

That is how you correctly receive XML into your application; but you mentioned two things earlier. So it sounds like your trying to use the textbox to physically write to the document, which can be done through the XmlWriter.

But the reason you also keep receiving your textbox because as far as the textbox is concerned textbox.text is associated to the value. Your structure is stating this string is the value.

In order to achieve your goal; you would have a method to write the value to the document. Then another to read it; so that it properly transitions the data in and out of your document and is represented correctly.

<Quality>Textbox1.Text</Quality> That doesn't allow the textbox value to automatically be read into your document and textbox. Your assigning a string value into the node. You would physically have to write to the document the values before it can be read.

The MSDN has examples of how to properly parse the data; hopefully I've clarified some of the reasons in which you are having your issue.


More code; straight from MSDN: Right off the MSDN:

StringBuilder output = new StringBuilder();

String xmlString =
        @"<?xml version='1.0'?>
        <!-- This is a sample XML document -->
        <Items>
          <Item>test with a child element <more/> stuff</Item>
        </Items>";
// Create an XmlReader
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
    XmlWriterSettings ws = new XmlWriterSettings();
    ws.Indent = true;
    using (XmlWriter writer = XmlWriter.Create(output, ws))
    {

        // Parse the file and display each of the nodes.
        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element:
                    writer.WriteStartElement(reader.Name);
                    break;
                case XmlNodeType.Text:
                    writer.WriteString(reader.Value);
                    break;
                case XmlNodeType.XmlDeclaration:
                case XmlNodeType.ProcessingInstruction:
                    writer.WriteProcessingInstruction(reader.Name, reader.Value);
                    break;
                case XmlNodeType.Comment:
                    writer.WriteComment(reader.Value);
                    break;
                case XmlNodeType.EndElement:
                    writer.WriteFullEndElement();
                    break;
            }
        }

    }
}
OutputTextBlock.Text = output.ToString();

or

StringBuilder output = new StringBuilder();

String xmlString =
    @"<bookstore>
        <book genre='autobiography' publicationdate='1981-03-22' ISBN='1-861003-11-0'>
            <title>The Autobiography of Benjamin Franklin</title>
            <author>
                <first-name>Benjamin</first-name>
                <last-name>Franklin</last-name>
            </author>
            <price>8.99</price>
        </book>
    </bookstore>";

// Create an XmlReader
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
    reader.ReadToFollowing("book");
    reader.MoveToFirstAttribute();
    string genre = reader.Value;
    output.AppendLine("The genre value: " + genre);

    reader.ReadToFollowing("title");
    output.AppendLine("Content of the title element: " + reader.ReadElementContentAsString());
}

OutputTextBlock.Text = output.ToString();
Greg
  • 11,302
  • 2
  • 48
  • 79
  • This provides no explanation as to what his issue was originally and why this resolves it (so no learning occurs!). Can you add an explanation? – Nashibukasan Jan 18 '13 at 00:49
  • 1
    Per your request I've modified the answer; I'm assuming you didn't answer or assist him either because you wanted to know how it was solved. So hopefully that helps. – Greg Jan 18 '13 at 06:41