How to read a node in a serialized XML file? - c#

I'm trying to read a node in a serialized XML file. Here is the the first part of the XML file (I'm using a screen cap because pasting ended up with weird formatting):
And this is the code I'm using to read the XML and the error it's throwing:
I'm trying to read the <ScenarioDescription> node.
As per request, here's the entire XML file. Unfortunately it's just a complete mess. Here is a link to the XML file.

You should You would need to specify the namespace. In this particular case, the default namespace is used to declare the http://schemas.datacontract.org/2004/07/ModelLib namespace.
var xml = new XmlDocument();
xml.LoadXml(str);
XmlNamespaceManager ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("x", xml.DocumentElement.NamespaceURI);
var root = xml.DocumentElement;
var test = root.SelectSingleNode("//x:ScenarioDescription",ns);
var scenarioText = test.InnerText;

You can use the following code to access the ScenarioDescription node and its InnerText
var document = new XmlDocument();
document.Load(s);
var root = document.DocumentElement;
var node = root["ScenarioDescription"];
var text = node?.InnerText;
SelectSingleNode accepts the xpath expression, you simply can use XmlElement indexer instead. Otherwise you'll need to create a XmlNamespaceManager instance and add your root namespace to it
You can supply the XmlNamespaceManager object as a parameter to the
SelectNodes or SelectSingleNode method of the XmlDocument class to
execute XPath query expressions that reference namespace-qualified
element and attribute name

Related

Creating XmlNode with specified spread sheet type

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);

Set XML string using node.innerXML - use of prefix causes error

I am creating a huge xml from DB and most of it's part is hard-coded(pre-defined values),so I decided to create string using StringBuilder and assigning it to node's InnerXML but prefix used for one of the attribute is not allowing me to set the string stating "Prefix not declared".
XMLNode addr = DocumentElement.createElement("element","address",null);
addr.InnerXML = "<test><s1>ttt</s1><s2 xsi:type="test">yyy</s2></test>";
prefix xsi is causing the error here. Is there any workaround for this.
xsi seems to be a namespace. You will need to either declare that namespace or not use it. Using it without declaring it is invalid.
Had some similar problem, the only way I found to fix this problem, is to add the needed namespace to your InnserXml:
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml("<Document xmlns=\"www.abc.com\" xmlns:xsi=\"w3.org/2001/XMLSchema-instance\"></Document>");
XmlNode t = xdoc.CreateElement("element", "t", null);
t.InnerXml = "<originalText xmlns:xsi=\"w3.org/2001/XMLSchema-instance\"><reference xsi:value=\"testVal\"/></originalText>";
xdoc.FirstChild.AppendChild(t);
The workaround is:
Firstly simply create XMLDocument and assign plain innerXML without namespace and prefixes as
XmlDocument ccda_xDoc = new XmlDocument();
ccda_xDoc.LoadXml("<ClinicalDocument></ClinicalDocument>");
XmlElement root = ccda_xDoc.DocumentElement;
root.InnerXml = #" My XML String without Prefix for any namespace";
Then Search for the node where you want to apply prefix to and add attribute with prefix:
XmlNode xsiValue = root.SelectSingleNode("encounter/code[#code='99201']");
XmlAttribute xsitype = structuredBody.CreateAttribute("sdtc", "valueSet", "urn:hl7-org:sdtc");
xsitype.Value = "2.16.840.1.113883.3.464.1003.101.12.1047";
xsiValue.Attributes.Prepend(xsitype);
Finally Apply namespaces to root node as :
ccda_xDoc.DocumentElement.SetAttribute("xmlns", "urn:hl7-org:v3");
ccda_xDoc.DocumentElement.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
ccda_xDoc.DocumentElement.SetAttribute("xmlns:voc", "urn:hl7-org:v3/voc");
ccda_xDoc.DocumentElement.SetAttribute("xmlns:sdtc", "urn:hl7-org:sdtc");

C# parsing Xml SelectingNode

I'm having troubles using Xml on my C# program.
the xml http://pastebin.com/Ufxaght6 (from sandbox)
I'm trying to get any info on the XML, I succeed using recursive loop on nodes, but I want to use something more efficient.
I'm trying this :
XmlDocument document = new XmlDocument();
document.LoadXml(response);
XmlNode node = document.SelectSingleNode("/getnewsalesresult/request/user");
if (node != null)
Logger.WriteLine(node.InnerText);
else
Logger.WriteLine("fail");
This gives always a null.
I think the problem comes from the 'getnewsalesresult' (Wildcard maybe ?).
From the XML :
<getnewsalesresult xmlns="http://www.sandbox.priceminister.com/res/schema/getnewsales" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sandbox.priceminister.com/res/schema/getnewsales http://www.sandbox.priceminister.com/res/schema/getnewsales/getnewsales.2014-02-11.xsd">
Any idea ?
Thanks in advance.
Your XML has default namespace (xmlns="..."). Default namespace has a different nature. The element where the default namespace declared and all of it's descendant without prefix and without different namespace declaration considered in the same default namespace.
The easiest way to get element in namespace is just to ignore the namespace (as also suggested in comment to this question) :
string xpath = "/*[local-name()='getnewsalesresult']/*[local-name()='request']/*[local-name()='user']";
XmlNode node = document.SelectSingleNode(xpath);
A more proper way is to register a prefix that mapped to the default namespace URI, then use that prefix in your XPath :
XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
ns.AddNamespace("d", "http://www.sandbox.priceminister.com/res/schema/getnewsales");
XmlNode node =
document.SelectSingleNode("/d:getnewsalesresult/d:request/d:user", ns);
don't miss to pass XmlNamespaceManager object as 2nd parameter of SelectSingleNode().

XmlDocument Remove XMLNS from Root Element

New here, looking to get a little help with my XmlDocument. Is it possible to have string data in my root element AND remove the xmlns= attribute from being shown? I'm looking for something like this:
<Rulebase author=yadda datetime=bingbang version=1.x </Rulebase>
When I try to use my string data by doing:
xmlDom.AppendChild(xmlDom.CreateElement("", "Rulebase", data));
XmlElement xmlRoot = xmlDom.DocumentElement;
It ends up looking like this:
<Rulebase xmlns="version=0 author=username date=7/13/2011 </Rulebase>
and it also appends xmlns="" to all my other nodes.
The CreateElement overload you're using takes a prefix as it's first argument, local name as second, and namespace as third. If you don't want a namespace, don't use this overload. Just use the one that takes a local name as the one and only argument. Then add your data separately as child elements and attributes.
var xmlDom = new XmlDocument();
XmlElement root = xmlDom.CreateElement("Rulebase");
xmlDom.AppendChild(root);
XmlElement data = xmlDom.CreateElement("Data");
root.AppendChild(data);
XmlAttribute attribute = xmlDom.CreateAttribute("author");
attribute.Value = "username";
data.Attributes.Append(attribute);
attribute = xmlDom.CreateAttribute("date");
attribute.Value = XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.RoundtripKind);
data.Attributes.Append(attribute);
Console.WriteLine(xmlDom.OuterXml);
Creates (formatting added)
<Rulebase>
<Data author="username" date="2011-07-13T22:44:27.5488853-04:00" />
</Rulebase>
Using XmlDocument to generate XML is pretty tedious though. There are many better ways in .NET, like XmlSerializer and DataContractSerializer. You can also use Linq-to-Xml and XElement. Or you can use an XmlWriter.Create(). Lots of options.

Can i create a XmlNamespaceManager object from the xml file i am about to read?

I have some c# code running on sharepoint that i use to check inside the xml of an infopath document to see if i should checking the document or discard the document.
The code is working fine for a couple of different form templates i have created but is failing on my latested one.
I have discovered that the XmlNamespaceManager i am creating contains the wrong diffinition for the "MY" namepsace.
I'll try to explain
I have this code to decalre my XmlNamespaceManager
NameTable nt = new NameTable();
NamespaceManager = new XmlNamespaceManager(nt);
// Add prefix/namespace pairs to the XmlNamespaceManager.
NamespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
NamespaceManager.AddNamespace("xhtml", "http://www.w3.org/1999/xhtml");
NamespaceManager.AddNamespace("dfs", "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution");
NamespaceManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-07-14T13:45:59");
NamespaceManager.AddNamespace("xd", "http://schemas.microsoft.com/office/infopath/2003");`
I can then use the following line of code to search for the xml i am after
XPathNavigator nav = xml.CreateNavigator().SelectSingleNode("//my:HasSaved", NamespaceManager);
nav.Value then gets be the data i want.
This all works fine on a couple of my form templates. I ahve a new form template and have discovered that i need to use thi line instead
NamespaceManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-11-30T17:39:37");
The date is different.
My problem is that i cannot add this twice as only 1 set of forms will work.
So my question is. Is there a way i can generate the NamespaceManager object from the XML file as this is all contained in the header?
I have not been able to find a simple way round this.
I found a way of doing this. Instead of adding the "my" namespace it can be pulled from the XmlDocument object. This might just be a bit of luck that it works this way but i'm happy with it.
NamespaceManager.AddNamespace("my", formXml.DocumentElement.NamespaceURI
formXML is an XmlDocument created from the infopath XML
One option would be to try to load the xml node using the first namespace, if that doesn't give any results, call PushScope(), override the first namespace definition, select, etc...
var doc = new XmlDocument();
doc.LoadXml(#"<?xml version=""1.0""?>
<root xmlns:my=""http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-11-30T17:39:37"" value=""1"">
<my:item>test</my:item>
</root>");
var nameTable = new NameTable();
var namespaceManager = new XmlNamespaceManager(nameTable);
namespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
namespaceManager.AddNamespace("xhtml", "http://www.w3.org/1999/xhtml");
namespaceManager.AddNamespace("dfs", "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution");
namespaceManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-07-14T13:45:59");
namespaceManager.AddNamespace("xd", "http://schemas.microsoft.com/office/infopath/2003");
// n will be null since the namespace url doesn't match
var n = doc.SelectSingleNode("descendant::my:item", namespaceManager);
namespaceManager.PushScope();
namespaceManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-11-30T17:39:37");
// will work
n = doc.SelectSingleNode("descendant::my:item", namespaceManager);
namespaceManager.PopScope();
Another option is to parse the attributes in the header and look for any contained namespaces
foreach(XmlAttribute attribute in doc.DocumentElement.Attributes)
{
var url = namespaceManager.LookupNamespace(attribute.LocalName);
if(url != null && url != attribute.Value)
{
namespaceManager.RemoveNamespace(attribute.LocalName, url);
namespaceManager.AddNamespace(attribute.LocalName, attribute.Value);
}
}
You don't need to do anything like this. Just use "my2" or something for the second namespace. You then need the new namespace prefix for any nodes that use the new namespace, and use the old "my" namespace prefix for all the nodes that still use the old namespace.

Categories

Resources