Getting nsi:type in xml - c#

So I have a XML File that looks like this
<MyObjectBuilder_Sector xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SectorObjects>
<MyObjectBuilder_EntityBase xsi:type="MyObjectBuilder_CubeGrid">
<EntityId>-8358349049537298307</EntityId>
<LinearVelocity x="0" y="0" z="0" />
</MyObjectBuilder>
</SectorObjects>
</MyObjectBuilder_Sector>
I was curious how in C# how I could retrieve that MyObjectBuilder_CubeGrid from the MyObjectBuilder_EntityBase node. The best i got is this
fileLoc = ofd.FileName;
XmlDocument xdoc = new XmlDocument();
xdoc.Load(fileLoc);
XmlNode typeOfNode = xdoc.SelectSingleNode("MyObjectBuilder_Sector/SectorObjects/MyObjectBuilder_EntityBase").ToString();
Which of course just gets me the node not the xsi:type of the node. I've looked all over for it and can not find an answer.
-Cheers
     Jacob Bender

You can access node's attribute this way :
XmlNode typeOfNode =
xdoc.SelectSingleNode("MyObjectBuilder_Sector/SectorObjects/MyObjectBuilder_EntityBase");
//here typeValue variable will contains "MyObjectBuilder_CubeGrid"
String typeValue = typeOfNode.Attributes["xsi:type"].Value;

Related

How to create xml element runtime?

I need to create xml element in runtime in the existing xml file. How do i do that in c#?
For example, there is a xml file as
<data value = "1">
<user>one</user>
</data>
I want to create a element in runtime and output should be like this,
<data value = "1">
<user>one</user>
<status>used</status>
</data>
Use AooendChild() to add new child node. Try Something like following
XmlDocument doc = new XmlDocument();
XmlNode root = doc.DocumentElement;
//Create a new node.
XmlElement elem = doc.CreateElement("Status");
elem.InnerText="used";
//Add the node to the document.
root.AppendChild(elem);

Reading XML file results in index out of range exception

Using C# I have an XML file like
<?xml version="1.0" encoding="utf-8"?>
<root>
<Account>
<name>Jani</name>
</Account>
</root>
and I also have a function to read the name node as:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("lib//user.xml");
XmlNode node;
node = xmlDoc.DocumentElement;
string name = node.Attributes[0].Value;
label1.Text = name.ToString();
but I am getting index out of range error as:
Why is this happening?
node = xmlDoc.DocumentElement;
string name = node.Attributes[0].Value;
node is your root node. Which looks like this:
<root>
How many attributes does it have? None, as it turns out. An attribute in XML is one of these bar="baz" things:
<foo bar="baz">
node.Attributes[0] refers to the first attribute. There is no first attribute, there's no second attribute -- you didn't use attributes in this XML at all. Hence, that's out of range. There's no first item in an empty collection.
What you want is an element named name, which is farther down inside your XML tree.
Probably this:
var node = xmlDoc.DocumentElement.SelectSingleNode("/root/Account/name");
And then you'll want to look at node.InnerText to get "Jani" out of it.
You are trying to read node.Attributes[0].Value but there is no attribtues in your sample XML file. Not sure of the exact syntax but it should probably be closer to node.Value
As mentioned by other answers, your current XML does not have attributes.
private void DoIt()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"M:\StackOverflowQuestionsAndAnswers\38924171\38924171\data.xml");
XmlNode node;
node = xmlDoc.DocumentElement;
//string name = node.Attributes[0].Value;
string name = node["Account"].InnerText;
}
If your XML did have attributes
<?xml version="1.0" encoding="utf-8"?>
<root>
<Account name="Jani" />
</root>
Then you could do this:
private void DoItAgain()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"M:\StackOverflowQuestionsAndAnswers\38924171\38924171\data2.xml");
XmlNode node;
node = xmlDoc.DocumentElement;
string name = node["Account"].Attributes[0].Value;
}

C# how to create a custom xml document

I'm really just trying to create a custom xml document for simple configuration processing.
XmlDocument xDoc = new XmlDocument();
string[] NodeArray = { "Fruits|Fruit", "Vegetables|Veggie"};
foreach (string node in NodeArray)
{
XmlNode xmlNode = xDoc.CreateNode(XmlNodeType.Element,node.Split('|')[0],null);
//xmlNode.Value = node.Split('|')[0];
xmlNode.InnerText = node.Split('|')[1];
xDoc.DocumentElement.AppendChild(xmlNode);
}
What i'm trying to get is this.
<?xml version="1.0" encoding="ISO-8859-1"?>
<Fruits>Fruit</Fruits>
<Vegetables>Veggie</Vegetables>
i get not set to value of an object at xDoc.DocumentElement.AppendChild(xmlNode);
Unfortunately, You can't make that XML structure.
All XML documents must have a single root node. You can't have more.
Try something like this
XmlDocument xDoc = new XmlDocument();
xDoc.AppendChild( xDoc.CreateElement("root"));
string[] NodeArray = { "Fruits|Fruit", "Vegetables|Veggie" };
foreach (string node in NodeArray)
{
XmlNode xmlNode = xDoc.CreateNode(XmlNodeType.Element, node.Split('|')[0], null);
//xmlNode.Value = node.Split('|')[0];
xmlNode.InnerText = node.Split('|')[1];
xDoc.DocumentElement.AppendChild(xmlNode);
}
It is not possible to have that XML structure as XML MUST have a single root element. You may want to try:
<?xml version="1.0" encoding="ISO-8859-1"?>
<items>
<Fruits>Fruit</Fruits>
<Vegetables>Veggie</Vegetables>
</items>

Modifying an XML node with user-provided namespace and node value

It has taken a while, but I have finally been able to modify an XML document based on user input for the namespace and node name:
string nodeName = "DefinitionName"; // this is really provided by the user
string namespace = "http://schemas.datacontract.org/2004/07/Xxx.Session"; // also user-provided
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(taskResolved.XmlPathAndFileName);
XmlElement rootElement = xmlDocument.DocumentElement;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xmlDocument.NameTable);
namespaceManager.AddNamespace("snuh", namespace); // hard-coded prefix, grrr...
XmlNodeList xmlNodes;
xmlNodes = rootElement.SelectNodes("//snuh:" + nodeName, namespaceManager);
I feel like I'm doing something wrong because I have to hard-code a prefix (snuh). I could try and choose a prefix, like snuh, that I can hope will never appear in a document, but that isn't foolproof. Another option is to use a GUID for a prefix, but this just seems like a hack work-around. Am I missing something? Is there a better way?
The top of the XML doc looks like this:
<?xml version="1.0" encoding="utf-8"?>
<SessionStateInfo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="1"
z:Type="Xxx.SessionStateInfo"
z:Assembly="Xxx.Common, Version=6.2.0.0, Culture=neutral, PublicKeyToken=null"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
xmlns="http://schemas.datacontract.org/2004/07/Xxx.Session">
<CoaterNumber>25</CoaterNumber>
<DefinitionName z:Id="2">TwoLineMarkerDefinition</DefinitionName>
<EnableManualMode>true</EnableManualMode>
If you want to simply select the first DefinitionName node.
You may write
XmlNode node = rootElement[nodeName, namespace];
and if you want the whole list:
XmlNodeList nodeList = rootElement.GetElementsByTagName(nodeName, namespace);
What about using the XPath local-name() and namespace-uri() functions?
string xpath = string.Format("//*[local-name()='{0}' and namespace-uri()='{1}']", nodeName, namespace);
xmlNodes = rootElement.SelectNodes(xpath);
Don't know if those functions are supported in XmlDocument though, haven't tested it.

Reading Elements within a Namespace

I have an XML file that looks like:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://www.someurl.com/somefile.xslt"?>
<AutoInsuranceClaim xmlns="http://www.someurl.com/schemas/AutoInsuranceClaim">
<Identification>
<BaseOwner>3</BaseOwner>
<BaseType>ABC123</BaseType>
<BaseTypeRef>471038341757</BaseTypeRef>
</Identification>
</AutoInsuranceClaim>
and I'm trying to read the Identification node. Here's my code:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"..\..\Data.xml");
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("ns", "http://www.someurl.com/schemas/AutoInsuranceClaim");
XmlNodeList nodeList = xmlDoc.SelectNodes(#"/ns:AutoInsuranceClaim/Identification", nsmgr);
Console.WriteLine("There are {0} nodes...", nodeList.Count);
I know I should get a least 1 value. My understanding of .NET XML parsing is that if you have a default namespace with no prefix, you have to create your own namespace. But this should have returned 1.
If not, what am I missing?
I might be grasping at straws here, but shouldn't you be namespacing both entities in your xpath expression?
XmlNodeList nodeList = xmlDoc.SelectNodes(#"/ns:AutoInsuranceClaim/ns:Identification", nsmgr);
XElement root = XElement.Load("Data.xml");
var identifications = root.Descendants()
.Where(x => x.Name.LocalName == "Identification")
.ToList()
The problem is that you're trying to find an Identification node without a namespace, but it will have defaulted to the same namespace as the parent due to the xmlns=... part. Try this:
var nodeList = xmlDoc.SelectNodes("/ns:AutoInsuranceClaim/ns:Identification",
nsmgr);
Having tried it myself, it printed a count of 1.
Personally I'd use LINQ to XML instead though, which makes namespace easier handling:
XDocument doc = XDocument.Load(#"..\..\Data.xml");
XNamespace ns = "http://www.someurl.com/schemas/AutoInsuranceClaim";
var nodes = doc.Root.Elements(ns + "Identification");

Categories