I have a template XML that looks something similar to this
<a:Demographics>
<b:Id>
<c:IdValue></c:IdValue>
<c:IdScheme></c:IdScheme>
<c:IdType></c:IdType>
</b:Id>
</a:Demographics>
Using Visual Studio and c#, How can I parse the xml, then based on my current record, add my own data into c:IdValue, c:IdScheme and c:IdType as these are required xml fields. They have been left blank in the template so that my the program will fill them I then need to save that as a new xml file but that should be straightforward once the values have been added.
I am open to using any library that can get the job done!
A valid XML must have namespace prefix declaration somewhere, I assume your XML has it. Then you can do something like this using XDocument :
XDocument doc = XDocument.Load("path_to_xml_file.xml");
XNamespace a = "http://uri.for.a.prefix.com";
XNamespace b = "http://uri.for.b.prefix.com";
XNamespace c = "http://uri.for.c.prefix.com";
XElement id = doc.Descendants(a+"Demographics")
.First()
.Element(b+"Id");
id.Element(c+"IdValue").Value = "new value here";
id.Element(c+"IdScheme").Value = "new scheme here";
id.Element(c+"IdType").Value = "new type here";
doc.Save("path_to_new_xml_file.xml");
you can use System.Xml.Linq
Load the Template
XDocument Template = XDocument.Load("Template.xml");
Modify it
void AddData(string elemName, string value)
{
XElement element = Template.Root.Descendants("elemName").First();
element.Value = value;
}
and Save it
Template.Save("newXml.xml");
Related
I'm little bit new in xml manipulation. I want to create a XmlNode.
I've already tried to OwnerDocument.CreateElement method and also tried OwnerDocument.CreateNode method, but I can't create the following XmlNode:
<Data ss:Type="String"/>
Can you help me with this problem? I already tried everything which I found, but nothing.
XmlDocument has been superseded in the .NET framework by the newer XDocument API, which plays nicer with Linq and in general is a modern library to use for XML manipulation.
Here is an example how you can use that API to insert an element into an existing XML document, with an attribute that has a namespace prefix which is previously declared.
XDocument ownerDocument = XDocument.Parse("<OwnerDocument></OwnerDocument>");
XNamespace ssNameSpace = "http://whatever/somenamespace";
// add namespace declaration to the root, set ss as the namespace prefix
// you only need to do this if the document doesn't already have the namespace declaration
ownerDocument.Root.Add(new XAttribute(XNamespace.Xmlns + "ss", ssNameSpace.NamespaceName));
// add our new data element to the root, and add the type attribute prefixed with the ss namespace
ownerDocument.Root.Add(new XElement("Data", new XAttribute(ssNameSpace + "Type", "String")));
That will produce the following XML:
<OwnerDocument xmlns:ss="http://whatever/somenamespace">
<Data ss:Type="String" />
</OwnerDocument>
If you are really tied to using XmlDocument, you can acheive the same there as follows:
XmlDocument ownerDocument = new XmlDocument();
ownerDocument.LoadXml("<OwnerDocument></OwnerDocument>");
// add namespace declaration to the root, set ss as the namespace prefix
var nsDeclarationAttribute = ownerDocument.CreateAttribute("xmlns:ss");
nsDeclarationAttribute.Value = "http://whatever/somenamespace";
ownerDocument.DocumentElement.Attributes.Append(nsDeclarationAttribute);
// add data element, and add a type attribute to that
var dataElement = ownerDocument.CreateElement("Data");
var typeAttribute = ownerDocument.CreateAttribute("Type", "http://whatever/somenamespace");
typeAttribute.Value = "String";
dataElement.Attributes.Append(typeAttribute);
// append to main document
ownerDocument.DocumentElement.AppendChild(dataElement);
I'm delving into the world of XmlDocument building and thought I'd try to re-build (at least, in part) the Desktop tree given by Microsoft's program UISpy.
So far I am able to grab a child of the desktop and write that to a XML document, and then grab each child of that and write those to an XML document.
So far the code looks like this...
using System.Windows.Automation;
using System.Xml;
namespace MyTestApplication
{
internal class TestXmlStuff
{
public static void Main(string[] args)
{
XmlDocument xDocument = new XmlDocument();
AutomationElement rootElement = AutomationElement.RootElement;
TreeWalker treeWalker = TreeWalker.ContentViewWalker;
XmlNode rootXmlElement = xDocument.AppendChild(xDocument.CreateElement("Desktop"));
AutomationElement autoElement = rootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "GitHub"));
string name = autoElement.Current.Name;
while (autoElement != null)
{
string lct = autoElement.Current.LocalizedControlType.Replace(" ", "");
lct = (lct.Equals("") ? "Cusotm" : lct);
XmlElement temp = (XmlElement)rootXmlElement.AppendChild(xDocument.CreateElement(lct));
//temp.InnerText = lct;
string outerXML = temp.OuterXml;
rootXmlElement = temp;
autoElement = treeWalker.GetNextSibling(autoElement);
}
}
}
}
...and the resulting XML file...
Now, when I add a line to change the InnerText Property of each XML element, like temp.InnerText = lct I get an oddly formated XML file.
What I expected from this was that each InnerText would be on the same line as the start and end tags of the XML element, but instead all but the last element's InnerText is located on a new line.
So my question is, why is that? Is there something else I could be doing with my XML elements to have their InnerText appear on the same line?
As I said in a comment, XML isn't a display format, so it gets formatted however IE chooses to do so.
To get closer to what you were expecting, you might want to consider using an attribute rather than innertext:
XmlElement temp = (XmlElement)rootXmlElement.AppendChild(xDocument.CreateElement(lct));
var attr = xDocument.CreateAttribute("type");
attr.Value = lct;
temp.Attributes.Append(attr);
IE displays the attributes within the opening element, which may be good enough for your purposes.
From the XML perspective, what you're currently creating is called Mixed Content - you have an element that contains both text and other elements. From a hierarchical perspective, those text nodes and other elements occupy the same position within the hierarchy - so I'd assume that this is why IE is displaying them as "equals" - both nested under their parent element and at the same indentation level.
I am trying to create an xml in c# and specifying the namespace and then the prefix on each element.
<bk:library xmlns:bk="www.namespace.com/ww">
<bk:books>
<bk:book>
<bk:title>Title </bk:book>
</bk:book>
<bk:books>
</bk:library>
I have done the following code:
XmlDocument doc = new XmlDocument();
root = doc.AppendChild(doc.CreateElement("library"));
var booksNode = root.appendChild(doc.CreateElement("bk","books","www.namespace.com/ww"));
Console.WriteLine(doc.OuterXml);
I get something like this:
<bk:books xmlns:bk="www.namespace.com/ww">
So it outputs both the prefix and the namespace
It doesn't output the xml as I would like it (shown above).
Any idea how I can get the xml to be output like I have shown?
thanks
Try this
XmlDocument doc = new XmlDocument();
XmlElement root = (XmlElement)doc.AppendChild(doc.CreateElement("bk","library","www.namespace.com/ww"));
var booksNode = root.AppendChild(doc.CreateElement("bk", "books", "www.namespace.com/ww"));
Console.WriteLine(doc.OuterXml);
I have the below xml string in one string variable.
string xmlString = "<a:ORegions>
<a:ID>1</a:ID>
<a:regionCode>US</a:regionCode>
</a:ORegions>
<a:ORegions>
<a:ID>2</a:ID>
<a:regionCode>CANADA</a:regionCode>
</a:ORegions>
<a:ORegions>
<a:ID>3</a:ID>
<a:regionCode>ASIA</a:regionCode>
</a:ORegions>
Now i want to access regionCode values, that is US, CANADA, ASIA
How i can do that using c#. I am new to xml parsing.
You can deserialize that string (assuming you fix the various syntax errors) via the System.Xml namespace classes, particularly XmlDocument, such as with its Load method. To access the namespaces (a in a:Oregions and such is a namespace), you'll want an XmlNamespaceManager. You'd then register the namespaces (they must be defined somewhere) with the manager and use that when querying the XmlDocument.
Use LinqToXml
var doc = XDocument.Parse(xmlString);
You can then access elements, values and attributes within:
XNamespace xmlNamespace = "a";
//e.g. Retrieve's a list of regioncodes...
var ids = doc.Elements(xmlNamespace + "ORegions")
.Select(r => r.Element("regionCode").Value);
XmlDocument document = new XmlDocument();
document.Load(filePath);
foreach (XmlNode node in document.GetElementsByTagName("a:regionCode"))
Console.WriteLine(node.InnerText);
Load function is already defined in xmlData class
public class XmlData
{
public void Load(XElement xDoc)
{
var id = xDoc.XPathSelectElements("//ID");
var listIds = xDoc.XPathSelectElements("/Lists//List/ListIDS/ListIDS");
}
}
I'm just calling the Load function from my end.
XmlData aXmlData = new XmlData();
string input, stringXML = "";
TextReader aTextReader = new StreamReader("D:\\test.xml");
while ((input = aTextReader.ReadLine()) != null)
{
stringXML += input;
}
XElement Content = XElement.Parse(stringXML);
aXmlData.Load(Content);
in load function,im getting both id and and listIds as null.
My test.xml contains
<SEARCH>
<ID>11242</ID>
<Lists>
<List CURRENT="true" AGGREGATEDCHANGED="false">
<ListIDS>
<ListID>100567</ListID>
<ListID>100564</ListID>
<ListID>100025</ListID>
<ListID>2</ListID>
<ListID>1</ListID>
</ListIDS>
</List>
</Lists>
</SEARCH>
EDIT: Your sample XML doesn't have an id element in the namespace with the nss alias. It would be <nss:id> in that case, or there'd be a default namespace set up. I've assumed for this answer that in reality the element you're looking for is in the namespace.
Your query is trying to find an element called id at the root level. To find all id elements, you need:
var tempId = xDoc.XPathSelectElements("//nss:id", ns);
... although personally I'd use:
XDocument doc = XDocument.Parse(...);
XNamespace nss = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner";
// Or use FirstOrDefault(), or whatever...
XElement idElement = doc.Descendants(nss + "id").Single();
(I prefer using the query methods on LINQ to XML types instead of XPath... I find it easier to avoid silly syntax errors etc.)
Your sample code is also unclear as you're using xDoc which hasn't been declared... it helps to write complete examples, ideally including everything required to compile and run as a console app.
I am looking at the question 3 hours after it was submitted and 41 minutes after it was (last) edited.
There are no namespaces defined in the provided XML document.
var listIds = xDoc.XPathSelectElements("/Lists//List/ListIDS/ListIDS");
This XPath expression obviously doesn't select any node from the provided XML document, because the XML document doesn't have a top element named Lists (the name of the actual top element is SEARCH)
var id = xDoc.XPathSelectElements("//ID");
in load function,im getting both id and and listIds as null.
This statement is false, because //ID selects the only element named ID in the provided XML document, thus the value of the C# variable id is non-null. Probably you didn't test thoroughly after editing the XML document.
Most probably the original ID element belonged to some namespace. But now it is in "no namespace" and the XPath expression above does select it.
string xmldocument = "<response xmlns:nss=\"http://schemas.microsoft.com/SQLServer/reporting/reportdesigner\"><action>test</action><id>1</id></response>";
XElement Content = XElement.Parse(xmldocument);
XPathNavigator navigator = Content.CreateNavigator();
XmlNamespaceManager ns = new XmlNamespaceManager(navigator.NameTable);
ns.AddNamespace("nss", "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner");
var tempId = navigator.SelectSingleNode("/id");
The reason for the null value or system returned value is due to the following
var id = xDoc.XPathSelectElements("//ID");
XpathSElectElements is System.xml.linq.XElment which is linq queried date. It cannot be directly outputed as such.
To Get individual first match element
use XPathSelectElement("//ID");
You can check the number of occurrences using XPathSelectElements as
var count=xDoc.XPathSelectElements("//ID").count();
you can also query the linq statement as order by using specific conditions
Inorder to get node value from a list u can use this
foreach (XmlNode xNode in xDoc.SelectNodes("//ListIDS/ListID"))
{
Console.WriteLine(xNode.InnerText);
}
For Second list you havnt got the value since, the XPath for list items is not correct