Retrieving attributes from XML - c#

Why does running this code...
XmlDocument doc = new XmlDocument();
string xml = #"<?xml version=""1.0"" encoding=""utf-8"" ?>
<BaaBaa>
<BlackSheep HaveYouAny=""Wool"" />
</BaaBaa>";
doc.LoadXml(xml);
XmlNodeList nodes = doc.SelectNodes("//BaaBaa");
foreach (XmlElement element in nodes)
{
Console.WriteLine(element.InnerXml);
XmlAttributeCollection attributes = element.Attributes;
Console.WriteLine(attributes.Count);
}
Produce the following output in the command prompt?
<BlackSheep HaveYouAny="Wool" />
0
That is, shouldn't attributes.Count return 1?

When you call SelectNodes with "//BaaBaa" it returns all elements of "BaaBaa".
As you can see from your own document, BaaBaa has no attributes, it's the "BlackSheep" element that has the single attribute "HaveYouAny".
If you want to get the attribute count of child elements, you have to navigate to that from the node you are on when iterating through the nodes.

element.Attributes contains the attributes of the element itself, not its children.
Since the BaaBaa element doesn't have any attributes, it is empty.
The InnerXml property returns the XML of the element's contents, not of the element itself. Therefore, it does have an attribute.

<BlackSheep HaveYouAny=""Wool"" /> // innerXml that includes children
<BaaBaa> // is the only node Loaded, which has '0' attributes
solution
XmlAttributeCollection attributes = element.FirstChild.Attributes;
Will produce the following, required output
<BlackSheep HaveYouAny="Wool" />
1

Related

Extracting objects from xml that uses node prefixes using xpath

I have the following XML in a file called C:\temp\config.xml:
<?xml version="1.0" encoding="utf-8"?>
<dvp:systemConfig xmlns:devop="urn:foo.com:sys:rules">
<dvp:map id="rootFolderMap">
<dvp:entry key="anything" value="folder1"/>
<dvp:entry key="config" value="folder2"/>
<dvp:defaultValue value="folder1" />
</dvp:map>
<dvp:map id="folderMappings">
<dvp:entry key="SYS" value="System" />
<dvp:entry key="OPS" value="Operations" />
<dvp:entry key="DEV" value="Development" />
<dvp:defaultValue value="Miscellaneous" />
</dvp:map>
</dvp:systemConfig>
I am now trying to write C# code that will extract values from this XML. In particular, the list of value properties in the nodes.
List<string> folderNames = new List<string>
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\temp\config.xml");
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
XmlNodeList xmlNodeList =
doc.SelectNodes("/systemConfig/map[#id='folderMappings']/entry",nsMgr);
foreach (XmlNode xmlNode in xmlNodeList)
{
// I'm hoping xmlNodeList now contains a list of <dvp:entry> nodes.
string folderName = xmlNode.Attributes["value"].ToString().Trim();
folderNames.Add(folderName);
}
However, this code returns an empty xmlNodeList, so the final loop has no items.
I'm not sure how to use the XmlNamespaceManager to pick up the "dvp" prefix, or whether it figures this out when it loads the XmlDocument from the XML on disk.
Can anyone give me some guidance how one goes about using xpath to retrieve values for xml with prefixed nodes? Unfortunately I do not have the power to change the format of the XML so I have to work with the xml I'm provided with.
thanks heaps,
David.
you can ignore the namespace using local-name()
XmlNodeList xmlNodeList =
doc.SelectNodes("/*[local-name()='systemConfig']/*[local-name()='map'][#id='folderMappings']");

How to to get value of a xml node without the child nodes values appended?

How to get value of a xml node without the child nodes values appended?
Innertext gives the values of children appended. Is there any way I can remove that string from value of the parent node? /text() doesn't work because I am deserializing the xml file.
Use LINQ to XML:
string xml = "<rootNode><node1><node11>v1</node11></node1></rootNode>";
XDocument xDocument = XDocument.Parse(xml);
XElement xmlElement = xDocument.Element("node11");
string value = xmlElement.Value; // v1

Read first root node from XML

I work with three kinds of XML files :
Type A:
<?xml version="1.0" encoding="UTF-8"?>
<nfeProc versao="2.00" xmlns="http://www.portalfiscal.inf.br/nfe">
</nfeProc>
Tyepe B:
<?xml version="1.0" encoding="UTF-8"?>
<cancCTe xmlns="http://www.portalfiscal.inf.br/cte" versao="1.04">
</cancCTe>
Type C:]
<?xml version="1.0" encoding="UTF-8"?>
<cteProc xmlns="http://www.portalfiscal.inf.br/cte" versao="1.04">
</cteProc>
I have try with this code to read the first node :
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
XmlNodeList ml = xmlDoc.GetElementsByTagName("*");
XmlElement root = xmlDoc.DocumentElement;
exti = root.ToString();
but dont return anything i want to read the first node , need to know if the file is nfeProc ,canCTE or cteProc
The second question is how i get the value from "value" in the same tag???
Thanks
From this post:
//Root node is the DocumentElement property of XmlDocument
XmlElement root = xmlDoc.DocumentElement
//If you only have the node, you can get the root node by
XmlElement root = xmlNode.OwnerDocument.DocumentElement
I would suggest using XPath. Here's an example where I read in the XML content from a locally stored string and select whatever the first node under the root is:
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(xml));
XmlNode node = doc.SelectSingleNode("(/*)");
If you aren't required to use the XmlDocument stuff, then Linq is your friend.
XDocument doc = XDocument.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
XElement first = doc.GetDescendants().FirstOrDefault();
if(first != null)
{
//first.Name will be either nfeProc, canCTE or cteProc.
}
Working with Linq to XML is the newest and most powerful way of working with XML in .NET and offers you a lot more power and flexibility than things like XmlDocument and XmlNode.
Getting the root node is very simple:
XDocument doc = XDocument.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
Console.WriteLine(doc.Root.Name.ToString());
Once you have constructed an XDocument you don't need to use any LINQ querying or special checking. You simply pull the Root property from the XDocument.
Thanks i have solved this way the first part
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(nomear);
XmlNodeList ml = xmlDoc.GetElementsByTagName("*");
XmlNode primer = xmlDoc.DocumentElement;
exti = primer.Name;
First, to be clear, you're asking about the root element, not the root node.
You can use an XmlReader to avoid having to load large documents completely into memory. See my answer to a how to find the root element at https://stackoverflow.com/a/60642354/1307074.
Second, once the reader is referencing the element, you can use the reader's Name property to get the qualified tag name of the element. You can get the value as a string using the Value property.

Adding XML attribute to an element

Looking to add an attribute to an existing xml element <D_COMMS>, not replace the existing attribute just add it to the beginning.
This is the XML
<OUTPUT version="2.0">
<RESPONSE>
<DATA id="17fb13cca6c5463597fdf340c044069f">
<![CDATA[<ID> jdfkldklfjdkl</ID><D_COMMS>ON this date...</D_COMMS>]]>
</DATA>
</RESPONSE>
This XML is the result of a HTTPWebResponse so this is what the XMl looks like when it comes back to me and I need to add a value to the D_COMMS element and send it back.Tried something like this to look for the descendant DATA and add it that way.
var addelement = doc.Descendants("DATA").First();
addelement.Add(XElement("D_COMMS","On this date we said"));
A better one to set attribute is in here Adding attributes to an XML node
XmlElement id = doc.CreateElement("id");
id.SetAttribute("userName", "Tushar");
You can find the DATA node and add an attribute as follows:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNodeList dataNodes = doc.GetElementsByTagName("DATA");
if (dataNodes != null && dataNodes.Count > 1)
{
dataNodes[0].Attributes.Append(doc.CreateAttribute("D_COMMS", "On this date we said"));
}

XmlDocument.SelectNodes question

What's the difference using root node to select and using document object to select nodes?
Which way is preferred.
For example,
1.
XmlDocument Doc = new XmlDocument();
Doc.Load(mem);
XmlNodeList nodeList = Doc.SelectNodes(#"//#id");
2.
XmlDocument Doc = new XmlDocument();
Doc.Load(mem);
XmlElement root = Doc.DocumentElement;
XmlNodeList nodeList = root.SelectNodes(#"//#id");
In fact, I never got any differences. And use just
Doc.SelectNodes(#"//#id");
because if document's root exists
bool b = Doc.OuterXml == Doc.DocumentElement.OuterXml; // true
Since XPath's // expression always matches from the document root, the result will be the same whether you start from the document root or from its documentElement.
So I guess you're better off using the shorter Doc.SelectNodes("//#id"); syntax.
The root of an XML document contains its document element at least, but it may also contain processing instructions and comments. For instance, in this XML document:
<!-- This is a child of the root -->
<document_element>
<!-- This is a child of the document element -->
<document_element>
<!-- This is also a child of the root -->
the root has three child nodes, one of which is its top-level element. In this case, this:
XmlNodeList comments = doc.SelectNodes("comment()");
and this:
XmlNodeList comments = doc.DocumentElement.SelectNodes("comment()");
return totally different results.

Categories

Resources