Adding ANY user input as a node in an XML document - c#

I want to add an XML string as new node to an existing XML document.
For example, suppose the input from the user is:
<bk:book>
<title>Pride And Prejudice</title>
<authorlastname>Jane</authorlastname>
<authorfirstname>Austen</authorfirstname>
<price>24.95</price>
</bk:book>
I am trying to insert that user input as follows:
xml_SourceDoc.Root.LastNode.AddAfterSelf(XElement.Parse(xmlString));
However, that statement is raising this exception:
bk is an undeclared prefix. Line 1, position 2.
How can I change my approach so that I can successfully insert any text that is input by the user?

If you really don't know what the user will enter, you can simply handle it as CDATA via the LINQ to XML XCData Class.
Here is what your sample data would look like when inserted as a node in a container XML document:
<doc>
<content><![CDATA[<bk:book>
<title>Pride And Prejudice</title>
<authorlastname>Jane</authorlastname>
<authorfirstname>Austen</authorfirstname>
<price>24.95</price>
</bk:book>]]></content>
</doc>
And here is an example program that creates the above example document:
using System;
using System.Xml;
using System.Xml.Linq;
public class CDataExample
{
public static void Main()
{
string documentXml = "<doc><content></content></doc>";
XElement doc = XElement.Parse(documentXml, LoadOptions.None);
string userInput =
#"<bk:book>
<title>Pride And Prejudice</title>
<authorlastname>Jane</authorlastname>
<authorfirstname>Austen</authorfirstname>
<price>24.95</price>
</bk:book>";
XCData cdata = new XCData(userInput);
doc.Element("content").Add(cdata);
Console.WriteLine(doc.ToString());
}
}

Check the xml is parsable first:
Check well-formed XML without a try/catch?
if(IsValidXML(xmlString))
{
xml_SourceDoc.Root.LastNode.AddAfterSelf(XElement.Parse(xmlString));
}

first, create XElement you want to add:
xmlString = new XElement(new XElement("book", new XAttribute("bk) ,(new XElement("title",
titleValue), new EXelement("authorlastname", authorlastNameValue ...
and so on.
then add it:
xml_SourceDoc.Root.Add(xmlString);
exception you mention is caused that you do not add attribute creating XElement

Related

How to parse GENERIC XML envelope and get all nodes values(inner text) separated (not concatenated)

I want to parse ANY SOAP response XML, not knowing ahead the structure, usually if I have a string xml with response, strXML, and I would do this:
XmlDocument doc = new XmlDocument();
doc.LoadXml(strXML);
String str = doc.InnerText;
return str;
I would get the values of all nodes, the text, but concatenated.
I want to parse SOAP responses in a generic way.
For example if I have this response envelope coming:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:hy="http://www.herongyang.com/Service/">
<soapenv:Header/>
<soapenv:Body>
<hy:GetExchangeRateResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<ratePart xsi:type="xsd:decimal">123.14</ratePart>
</hy:GetExchangeRateResponse>
</soapenv:Body>
</soapenv:Envelope>
The c# code above would return me for this envelope the good value, 123.14, but if there would be an extra child node to hy:GetExchangeRateResponse let say :
123.14
and
234.14
then I would get: 123.14234.14 concatenated, I want to have something like 123.14, 234.14 ...
PS: usually the services I worked with were returning one value so yeah although is a simple way was working, but not when there are multiple nodes/text.
You can fetch all text nodes from the document and then process each node separately.
For example:
var texts = doc.SelectNodes("//text()").Cast<XmlNode>().Select(x => x.Value).ToArray();
will fetch all text node values into texts (array of string).
using System;
using System.Linq;
using System.Xml.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
string xxx = "the xml response with multiple final nodes";
XDocument doc = XDocument.Parse(xxx);
List<string> texts = (from node in doc.DescendantNodes().OfType<XText>() select node.Value).ToList();
string asLongString = string.Join(",", texts);
Console.WriteLine("Values {0}", asLongString);
}
}
this guy gave me the answer first sorry :) https://csharpforums.net/members/johnh.4/

Read an XML document and removing nodes

I have an XML file, similar to the one below. I will read the XML and find the EmpId node. Based on other data will determine if I need to keep this node or delete the node. Currently have a process which reads it and creates a list of Record Ids which I will need to remove. In the below XML I will want to keep the EmpId = Emp1 and remove EmpId = Emp2. The removal is the node.
I believe the best approach is to read the XML first to determine which nodes to keep and then go thru the XML again and remove the necessary nodes.
What's the best approach to remove these nodes?
I'm open to creating a new XML document and creating the node which need to be kept. Based on the data I'm reading it's 50/50 if I'll be removing more nodes or keeping more nodes.
...
<HeaderNode>
<Details>
<SubmissionId>1</SubmissionId>
<EmpDetail>
<RecordId>1</RecordId>
<EmpDempgraphic>
<EmpId>Emp1</EmpId>
</EmpDempgraphic>
</EmpDetail>
<EmpDetail>
<RecordId>2</RecordId>
<EmpDempgraphic>
<EmpId>Emp2</EmpId>
</EmpDempgraphic>
</EmpDetail>
</Details>
</HeaderNode>
...
Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace XML
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement EmpDetail = doc.Descendants("EmpDetail").Where(x => (int)x.Element("RecordId") == 2).FirstOrDefault();
EmpDetail.Remove();
}
}
}
Unless the document is huge, just load it into an XDocument, Remove the elements you don't want, and Save the document back out.

Reading a XML File using XPath Expression in C#

I am currently having a problem with reading a XML file using XPath expression. I have used the XmlDocument class. When I try reading a particular node from the XML, I get an empty list. The node which I am trying to read is the ID below ProductionRequest.
Here is the XML file which I tried to read:
<?xml version="1.0" encoding="iso-8859-1"?>
<ProductionSchedule xmlns="http://www.wbf.org/xml/b2mml-v02">
<ID>00000020000000</ID>
<Location>
<EquipmentID>8283</EquipmentID>
<EquipmentElementLevel>Site</EquipmentElementLevel>
<Location>
<EquipmentID>0</EquipmentID>
<EquipmentElementLevel>Area</EquipmentElementLevel>
</Location>
</Location>
<ProductionRequest>
<ID>0009300000000</ID>
<ProductProductionRuleID>W001</ProductProductionRuleID>
<StartTime>2017-04-20T23:57:20</StartTime>
<EndTime>2017-04-20T24:00:00</EndTime>
</ProductionRequest>
</ProductionSchedule>
This is the code which I used to read the above XML
using System;
using System.Xml.Linq;
using System.Xml;
using System.Xml.XPath;
namespace XML
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
string fullName = "F:\\Programming\\XML\\Example XML.xml";
XmlDocument xreader = new XmlDocument();
xreader.Load(fullName);
XmlNode root = xreader.DocumentElement;
XmlNodeList xnList1 =
xreader.SelectNodes("/ProductionSchedule/ProductionRequest/ID");
}
}
}
I could not find the cause for this problem. Could anyone help me in this regard. Looking forward for valuable inputs.
Your xml contains namespace http://www.wbf.org/xml/b2mml-v02 at root level node <ProductionSchedule>
And you are using the XPath expression /ProductionSchedule/ProductionRequest/ID but this XPath expression is not suitable for this xml document and that's why you can't get any desired value.
You need to use the below XPath expression to get the id's of all <ProductionRequest> node.
XmlNodeList xnList1 = xreader.SelectNodes("//*[name()='ProductionSchedule']/*[name()='ProductionRequest']/*[name()='ID']");
OR you can add namespace manually like
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xreader.NameTable);
nsmgr.AddNamespace("x", "http://www.wbf.org/xml/b2mml-v02");
XmlNodeList xnList1 = xreader.SelectNodes("//x:ProductionSchedule/x:ProductionRequest/x:ID", nsmgr);
And finally, you can read id from any of the parent nodes in variable xnList1 like
foreach (XmlNode id in xnList1)
{
Console.WriteLine(id.InnerText);
}
Output:

Modify a xml node with spacing and quotes as attricutes

I am trying to access to the child node of an XML but the my first XML node has spacing and quotes as attributes.
var xml = #"<Envelope xsd "http">
<Catalog>
<Price>
<Value Default ="yes">P1</Value>
</Price>
</Catalog>
</Envelope>";
Im trying to change the attribute value of Default from "yes" to "1" but node always returns null.
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var node = doc.SelectSingleNode("/*/Catalog/Price/Value");
Any ideas?
I do not think that is valid xml, did you perhaps mean the following
using System;
using System.Globalization;
using System.Xml;
namespace ConsoleApplication9
{
class Program
{
private static void Main(string[] args)
{
//Valid XML
string xml = #"<Envelope xsd='http'>
<Catalog>
<Price>
<Value Default='yes'>P1</Value>
</Price>
</Catalog>
</Envelope>";
var doc = new XmlDocument();
doc.LoadXml(xml);
//Select the Value Node
XmlNode node = doc.SelectSingleNode("/*/Catalog/Price/Value");
//Set the Default attribute to 1
node.Attributes["Default"].Value = 1.ToString(CultureInfo.InvariantCulture);
//Check the output
Console.WriteLine(doc.InnerXml.ToString(CultureInfo.InvariantCulture));
//Press enter to exit
Console.ReadLine();
}
}
}
Just saying.
See http://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx.
Use // instead of /* since // gets the root of the document
This might appear a little hardcoded but it should work:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
Namespace ns= "http"; //set the namespace of the root node here
//the following is where you change the value to 1
doc.Document.Descendants(ns+"Envelope").FirstorDefault().Descendants(ns+"Catalog").Descendants(ns+"Price").FirstorDefault().Elements("Value").Attribute("Default").SetValue("1");
Also, the xml looks a little wrong to me, as someone mentioned, the root node needs to be corrected.

Extract contents from XML file

I have a C# application that uses a button to generate a file. Currently, I want to use C# to extract out contents from the XML file and pass it as a string. For example in my XML file, I have a tag name. I want to use c# to extract the name from the XML file. How should I go about achieving it? Below is the sample code I have currently. The entire process must be carried out using a button click.
private void button1_Click(object sender, EventArgs e)
{
XElement xml = XElement.Load("C:\\Windows 7.xml");
IEnumerable<XElement> propertyIDs = xml.Descendants("PropertyId");
foreach (XElement child in xml.Elements())
{
XElement row = child.Element("my:VM_Name");
string test = xml.ToString();
Console.WriteLine(test);
}
}
Please access this link to view my xml file: http://pastebin.com/NKhBb4Zh
I rewrote your example and changed it to make use of the XmlDocument class. As there is the my Namespace I had to add a NameSpaceManager. using this you may even select a spefic node.
string url = #"e:\temp\data.xml";
XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(url);
XmlElement docElement = doc.DocumentElement;
/// loop through all childNodes
foreach (XmlNode childNode in docElement.ChildNodes)
{
Console.WriteLine(childNode.Name + ": " + childNode.InnerText);
}
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2011-05-27T03:57:48");
/// use the given XmlNamespaceManager to select a specific element
XmlNode node = docElement.SelectSingleNode("my:VM_DiskSize", mgr);
/// use innerText for node text and value for attributes only
Console.WriteLine("\n" + node.Name + ": " + node.InnerText);
hth
The comments you added to your question were very helpful. In particular:
I added this code:
XElement name = xml.Element("my:VM_Name");
string test = xml.ToString();
Console.WriteLine(test);
But I am still unable to extract out Windows 7 from the XML tag
And:
i get this error The ':' character, hexadecimal value 0x3A, cannot be included in a name.
Let's start with the error first. You cannot pass to the Element method an ns:name pair as you've done. With this API, the namespace (ns) must be supplied programatically via the XName type. So instead, that line should read:
XElement name = xml.Element(XName.Get("VM_Name", "my"));
Here we pass the qualified name as an actual XName and not as a colon-delimited string as it originates. Pay attention to the order; the namespace comes second using this syntax.
Now, once you have done all this, the other line in which you have a problem is:
string test = xml.ToString();
Here, xml refers to your root XML node whereas what you actually want is, presumably, the element for which you just queried: xml.Element(XName.Get("VM_Name", "my")). Furthermore, to get the text contents of that node, you should use the Value property. I suspect what you really want is:
string test = name.Value;

Categories