I'm working with a 3rd party application that takes input in via XML, and then returns the input back out in XML, I'm looking for a way to format the information to display it nicely in a richtextbox.
<Solution>
<ID>1</ID>
<Property>
<Name>DriverSheave</Name>
<Value>1VP34</Value>
</Property>
<Property>
<Name>DriverBushing</Name>
<Value>
</Value>
</Property>
<Property>
<Name>DrivenSheave</Name>
<Value>AK49</Value>
this is some sample xml that i would receive as an output from the 3rd party app, What I'm currently doing is this.
richTextBox1.Text = Configurator.Results.InnerText.ToString();
which gives me results like this.
1DriverSheave3MVP55B69DriverBushingDrivenSheave3MVB200RDrivenBushingR1BeltB225BeltQty3
essentially id like to know the best way to move these around, and make the output formatted nicely. so im not asking that you format this for me, but rather let me know the proper way to go about formatting this.
id like it to look similar to
Refer to the below code:
using System.XML.Linq;
class XMLParseProgram
{
public DataTable ReadXML(string strXML)
{
XDocument xdoc = XDocument.Load(strXML);
var property= from props in xdoc.Element("Solution").Elements("Property").ToList().ToList();
if (property!= null)
{
DataTable dtItem = new DataTable();
dtItem.Columns.Add("Name");
dtItem.Columns.Add("Value");
foreach (var itemDetail in property.ElementAt(0))
{
dtItem.Rows.Add();
if (itemDetail.Descendants("Name").Any())
dtItem.Rows[count]["Name"] = itemDetail.Element("Name").Value.ToString();
if (itemDetail.Descendants("Value").Any())
dtItem.Rows[count]["Value"] = itemDetail.Element("Value").Value.ToString();
}
}
}
}
You can use the DataTable to generate the string in your program the way you want.
If one of Configurator or Configurator.Results is an XmlDocument or XmlElement you can use one of these converters to an XElement:
richTextBox1.Text = Configurator.Results.ToXElement().ToString();
Related
I've got XML, and would like to get the value of a node using array/data table like notation
<Response>
<Outcome>
<KeyValueOfstringOutcomepQnxSKQu>
<Key>Icon</Key>
<Value>
<DataType>System.String</DataType>
<Field>Icon</Field>
<Value>O</Value>
</Value>
</KeyValueOfstringOutcomepQnxSKQu>
<KeyValueOfstringOutcomepQnxSKQu>
<Key>IconDescription</Key>
<Value>
<DataType>System.String</DataType>
<Field>IconDescription</Field>
<Value>Old</Value>
</Value>
</KeyValueOfstringOutcomepQnxSKQu>
<KeyValueOfstringOutcomepQnxSKQu>
<Key>IconLongDescription</Key>
<Value>
<DataType>System.String</DataType>
<Field>IconLongDescription</Field>
<Value>Older</Value>
</Value>
</KeyValueOfstringOutcomepQnxSKQu>
</Outcome>
</Response>
I want to do something like outcome.Key[IconDescription].Value to give me a value of "Old"
Linq provides access to XML through the XDocumentclass which allows you to run XPath against XML. Whilst it is not exactly in the style of your ideal XPath does provide a handy query language for accessing XML nodes, and your tag suggests you might be interested in an XPath solution!
Here is an example of using an XDocument to query an XML file. For this example I've simply read a file from a stream.
using System.Xml.Linq;
using System.Xml.XPath;
...
static void Main(string[] args)
{
XDocument doc = XDocument.Load(new FileStream(#"C:\path_to\input.xml", FileMode.Open));
string desrcription = doc.XPathSelectElement("/Response/Outcome/KeyValueOfstringOutcomepQnxSKQu[Key='IconDescription']/Value/Value").Value;
Console.WriteLine(desrcription);
Console.ReadLine();
}
I am searching for this for a long time here, but I can't get it working from other codes. I need to find the closest element to "user" (which is "robot") and write its value (it's depending on user's input). I am programming a chat-bot. This is my XML file:
<Answers>
<user>This is a message</user><robot>Here is an answer</robot>
<user>This is another message</user><robot>Here is another answer</robot>
</Answers>
In C# code i am trying something like this:
private static void Main(string[] args)
{
XDocument doc = XDocument.Load("C:\\bot.xml");
var userPms = doc.Descendants("user");
var robotPm = doc.Descendants("robot");
string userInput = Console.ReadLine();
foreach (var pm in userPms.Where(pm => pm.Value == userInput))
{
Console.WriteLine // robotPm.FindNextTo(pm)
}
}
Simply put, I want to compare "user" input in console and in xml and if they are equal write robot's answer from xml which is responsible to specified user input.
Thank you for help
Simply use NextNode
Console.WriteLine(((XElement)pm.NextNode).Value);
But don't forget: Altough I've never seen a counter-example, xml parsers do not guarantee the order of elements. a better approach would be
<item>
<q>qusetion1</q>
<a>answer1</a>
</item>
<item>
<q>qusetion2</q>
<a>answer2</a>
</item>
<Customers>
<Customer1>
<Name>Bobby</Name>
<Age>21</Age>
<Address>Panjim</Address>
</Customer1>
<Customer2>
<Name>Peter</Name>
<Age>32</Age>
<Address>Panjim</Address>
</Customer2>
<Customer4>
<Name>Joel</Name>
<Age>32</Age>
<Address>Mapusa</Address>
</Customer4>
</Customers>
So the thing is I want to delete a particular element and when i delete the first element i.e customer1, I want to update the other elements. I mean I want to make customer3, customer2 and customer2, customer1.
Can anyone please help me achieve this?
What about:
class Program {
static void Main(string[ ] args) {
XDocument doc = XDocument.Load("D:\\file.xml"); //example file
doc.Root.SwitchAndRemove("Customer1");
doc.Save("D:\\file.xml");
}
}
public static class Utilities {
public static void SwitchAndRemove(this XElement customers, XName name) {
var x = customers.Descendants().Where(e => e.Name == name).Select((element, index) => new { element, index }).Single();
int count = 0;
XElement temp = x.element;
foreach (XElement el in customers.Nodes()) {
if (count == x.index + 1) {
temp.RemoveAll();
temp.Add(el.Descendants().ToArray());
temp = el;
}
else
count++;
}
temp.Remove();
}
}
By giving as input your xml the output is the following:
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer1>
<Name>Peter</Name>
<Age>32</Age>
<Address>Panjim</Address>
</Customer1>
<Customer2>
<Name>Joel</Name>
<Age>32</Age>
<Address>Mapusa</Address>
</Customer2>
</Customers>
I'd argue that your problem is not how you could rename your nodes with minimum effort but structure of your XML file.
You said order of customers is not important and apparently customer tag's number is not important, either, since you want to rename the tags upon deletion.
So maybe this structure just creates unnecessary complexity and extra work for you.
Only reason I see you could need the number in tag is to identify the node you are about to remove. Am I right or is there something more to it? If not then you could add random unique identifier (like Guid) to your customer data to remove the right one.
Could save you lot of trouble.
<customers>
<customer>
<guid>07fb-877c-...</guid>
<name>Notch</name>
<age>34</age>
<address>street</address>
</customer>
<customer>
<guid>1435-435a-...</guid>
<name>Sam</name>
<age>23</age>
<address>other</address>
</customer>
<customers>
Say the element you have to delete is Customer1, first of all you can read the complete xml file using one of the XML parsing classes available in c# like XDocument or XmlReader and write to another xml file say "Temp.xml" skipping the Customer1 element completely. This way we have achieved the deletion part.
Next to update, forget the file being XML file and read the entire file to a string, say "xmlstring". Now use the Replace function available with a string data type to replace "Customer2" with "Customer1" and then "Customer3" with "Customer2" and so on.
And now delete your original XML file and write the string "xmlstring" using a stream writer to a file name "YourFileName.xml"
Thats it. Hope this solution works for you. Try this and in case u are unable get this done, share the code which u tried and we shall suggest how to work it out.
taken from your comment that the order does not have to be preserved then you can do this
public static void RemoveCustomer(XElement customers, XElement removeThis){
var last = customeers.Elements().Last();
if(last != removeThis){
foreach(var element in removeThis.Elements()){
element.Value = last.Element(element.Name).Value;
}
}
last.Remove();
}
It effectively substitutes the one to be removed with the last (unless the last should be removed) and thereby eliminates the need for renaming any of the other elements
If I receive a string that is only a list of numbers (e.g. 1,2,3,5), is it possible to convert it to XML format, like this?
<foo>
<id>1</id>
<id>2</id>
<id>3</id>
</foo>
So far I had planned to use something along the lines of this
string s = "example";
XmlDocument xm = new XmlDocument();
xm.LoadXml(string.Format("<foo>{0}</foo>", s));
But I'm unsure as to how I should split the string so that I only get the numbers without using the obvious Split(), which is something my manager doesn't want me to do (otherwise I'd just skip the whole XML format).
Basically, is there a way for me to 'easily' serialize that string into XML format?
Use LINQtoXML
string items="1,4,6,3";
XElement elm = new XElement("foo");
foreach(var item in items.Split(','))
{
elm.Add(new XElement("id",item));
}
Now ele will have the XML you are looking for
You can use the XDocument.Parse(string) method
You can build up the xml string and then pass it to the method
http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument.parse.aspx
I'm serializing a xml string with the following code
StringReader newStringReader = new StringReader(value.Value);
try
{
using (var reader = XmlReader.Create(newStringReader))
{
newStringReader = null;
writer.WriteNode(reader, false);
}
}
finally
{
if (newStringReader != null)
newStringReader.Dispose();
}
but in the written xml file I have
<property i:type="string">
<name>Test</name>
<value>
</value>
</property>
but correct would be
<property i:type="string">
<name>Test</name>
<value></value>
</property>
since the "value" property is an empty string. The way it is serialized not it returns "\r\n ".
Writer:
XmlTextWriter writer = new XmlTextWriter(output);
try { writer.Formatting = System.Xml.Formatting.Indented;
writer.Indentation = 2; // Konfiguration sichern
WriteConfiguration(config, writer);
}
finally { writer.Close(); }
What have I done wrong?
UPDATE:
I write a xml configuration file. The values can either be ints, bools, etc or other xml strings. These xml strings are written with the code above. It works fine except for emtpy string elements in the xml string.
UPDATE 2:
It works if I manually change the xml string I want to write. I replace all
<tag></tag>
by
<tag/>
Unfortunatley it's not really a "proper" solution to modify a string with regexes.
I have always had far better luck with the formatting of XML documents when I work with them as XDocument types and simply use the Save method. For example xmlDoc.Save("C:\temp\xmlDoc.xml"); Simple as that. Also with this you can save over and over throughout the editing with little performance hit (at least none that I have noticed).
I would say this is caused by the indentation parameters. Did you try setting the Indented property to false?
I'm writing an xml file with settings. In this file can also be other xml documents. The code above ensures that it's not written in a single line with > etc but as xml in xml. So I have to work with the WriteNode-Method.
try removing
writer.Formatting = System.Xml.Formatting.Indented;
writer.Indentation = 2;
lines, and see what happens.
We did overcome this problem by using short tags of the form...
<value />
...instead of...
<value></value>
...then you can't have line breaks in the XML output. To do this, you have to query your tree before passing it to the writer.
/// <summary>
/// Prepares the XML Tree, to write short format tags, instead
/// of an opening and a closing tag. This leads to shorter and
/// particularly to valid XML files.
/// </summary>
protected static void Sto_XmlShortTags(XmlNode node)
{
// if there are children, make a recursive call
if (node.ChildNodes.Count > 0)
{
foreach (XmlNode childNode in node.ChildNodes)
Sto_XmlShortTags(childNode);
}
// if the node has no children, use the short format
else
{
if (node is XmlElement)
((XmlElement)node).IsEmpty = true;
}
}