XML C# Parse - Complex - c#

I have been on google for a while but am just stumped. I need to parse xml of this nature. I can't seem to skip to elements in the middle, e.g. Folder. I have limited the xml as there were many 'Folder' elements. Any guidance would be appreciated. I was after the FolderID element's attribute ID.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo MajorVersion="14"
MinorVersion="1"
MajorBuildNumber="225"
MinorBuildNumber="46"
Version="Exchange2010_SP1"
xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<m:GetFolderResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:GetFolderResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Folders>
<t:Folder>
<t:FolderId Id="AAMkADk5MmY1ZThmLTM2MzAtNGVh" ChangeKey="AQAAABYAAACSe/NBrSZiQKqHx8yL+lIRAAAA1EWM" />
<t:ParentFolderId Id="AAMkADk5MmY1ZThmLTM2MzAtNGVh" ChangeKey="AQAAAA==" />
<t:DisplayName>Top of Information Store</t:DisplayName>
<t:TotalCount>0</t:TotalCount>
<t:ChildFolderCount>15</t:ChildFolderCount>
<t:EffectiveRights>
<t:CreateAssociated>true</t:CreateAssociated>
<t:CreateContents>true</t:CreateContents>
<t:CreateHierarchy>true</t:CreateHierarchy>
<t:Delete>true</t:Delete>
<t:Modify>true</t:Modify>
<t:Read>true</t:Read>
<t:ViewPrivateItems>true</t:ViewPrivateItems>
</t:EffectiveRights>
<t:PermissionSet>
<t:Permissions>
<t:Permission>
<t:UserId>
<t:DistinguishedUser>Default</t:DistinguishedUser>
</t:UserId>
<t:CanCreateItems>false</t:CanCreateItems>
<t:CanCreateSubFolders>false</t:CanCreateSubFolders>
<t:IsFolderOwner>false</t:IsFolderOwner>
<t:IsFolderVisible>false</t:IsFolderVisible>
<t:IsFolderContact>false</t:IsFolderContact>
<t:EditItems>None</t:EditItems>
<t:DeleteItems>None</t:DeleteItems>
<t:ReadItems>None</t:ReadItems>
<t:PermissionLevel>None</t:PermissionLevel>
</t:Permission>
<t:Permission>
<t:UserId>
<t:DistinguishedUser>Anonymous</t:DistinguishedUser>
</t:UserId>
<t:CanCreateItems>false</t:CanCreateItems>
<t:CanCreateSubFolders>false</t:CanCreateSubFolders>
<t:IsFolderOwner>false</t:IsFolderOwner>
<t:IsFolderVisible>false</t:IsFolderVisible>
<t:IsFolderContact>false</t:IsFolderContact>
<t:EditItems>None</t:EditItems>
<t:DeleteItems>None</t:DeleteItems>
<t:ReadItems>None</t:ReadItems>
<t:PermissionLevel>None</t:PermissionLevel>
</t:Permission>
</t:Permissions>
</t:PermissionSet>
<t:UnreadCount>0</t:UnreadCount>
</t:Folder>
</m:Folders>
</m:GetFolderResponseMessage>
</m:ResponseMessages>
</m:GetFolderResponse>
</s:Body>
</s:Envelope>

LINQ to XML is the best .NET XML Parsing API.
See
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/xdocument-class-overview
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace ConsoleApp12
{
class Program
{
static void Main(string[] args)
{
var doc = XDocument.Load(#"c:\temp\foo.xml");
var ns = (XNamespace)"http://schemas.microsoft.com/exchange/services/2006/types";
var folders = doc.Descendants(ns + "Folder");
foreach (var e in folders)
{
var folderId = e.Element(ns + "FolderId").Attribute("Id").Value;
Console.WriteLine(folderId);
}
Console.WriteLine("Hit any key to exit.");
Console.ReadKey();
}
}
}

You should learn about serlialization. It's very easy to convert an XML to and from a object in C#. https://www.codeproject.com/Articles/483055/XML-Serialization-and-Deserialization-Part
That said, this will get you the data you're after. It's not very reusable and won't help you with any xml files other than ones with one instance of that attribute, but it's what you're after so here you go.
string FolderId;
string ChangeKey;
using (StreamReader sr = new StreamReader("c:\\myfile.xml"))
{
string line;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("<t:FolderId Id="))
{
try
{
var lineArray = line.Split('\"');
FolderId = lineArray[1];
ChangeKey = lineArray[3];
}
catch
{
// handle exception
}
}
}
}

You can use the XSD.exe to create a schema class. and then using XML deserializer, you can deserialize/parse xml to object

Using xml linq
XDocument doc = XDocument.Load(FILENAME);
List<XElement> folders = doc.Descendants().Where(x => x.Name.LocalName == "Folder").ToList();
XNamespace tNs = folders.FirstOrDefault().GetNamespaceOfPrefix("t");
XElement id_AAMkADk5MmY1ZThmLTM2MzAtNGVh = folders.Where(x => (string)x.Element(tNs + "FolderId").Attribute("Id") == "AAMkADk5MmY1ZThmLTM2MzAtNGVh").FirstOrDefault();

Related

take data from xml c#

its my xml file:
<?xml version="1.0" encoding="UTF-8"?>
<metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:title>Tytu�1</dc:title>
<dc:creator>autor1</dc:creator>
<dc:subject>Tem1</dc:subject>
<dc:description>O1</dc:description>
<dc:publisher>wydawca1</dc:publisher>
<dc:contributor>wsp�tw�rca1</dc:contributor>
<dc:date>data wydania1</dc:date>
<dc:type>typ zasobu1</dc:type>
<dc:format>format1</dc:format>
<dc:identifier>identyfikator1</dc:identifier>
<dc:source>�r�d�o1</dc:source>
<dc:language>j�zyk1</dc:language>
<dc:relation>powi�zania1</dc:relation>
<dc:coverage>zakres1</dc:coverage>
<dc:rights>prawa1</dc:rights>
</metadata>
Here is my code:
using System;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var dc = "dc";
XDocument doc = XDocument.Load("C:\\Users\\Mateusz\\Desktop\\DublinCore.xml");
var authors = doc.Descendants( dc + "subject");
foreach (var author in authors)
{
Console.WriteLine(author.Value);
}
Console.ReadLine();
}
}
}
I want view in console information about subject.
I think problem is in using namespace.
For example:
<Author>Author</Author> code will work
<dc:Author>Author</Author> code doesn't work
Can someone help me with it?
You need to use XNamespace. So your code becomes:
static void Main(string[] args)
{
XNamespace dc = "http://purl.org/dc/elements/1.1/";
XDocument doc = XDocument.Load("C:\\Users\\Mateusz\\Desktop\\DublinCore.xml");
var authors = doc.Descendants(dc + "subject");
foreach (var author in authors)
{
Console.WriteLine(author.Value);
}
Console.ReadLine();
}
Incidentally it is rather confusing when you use a variable name authors to extract the subject nodes!

Parse the Nodes of XML files

How to parse all the XML files under a given directory as an input to the application and write its output to a text file.
Note: The XML is not always the same the nodes in the XML can vary and have any number of Child-nodes.
Any help or guidance would be really helpful on this regard :)
XML File Sample
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>
<CNT>USA</CNT>
<CODE>3456</CODE>
</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
</CATALOG>
C# Code
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace XMLTagParser
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please Enter the Location of the file");
// get the location we want to get the sitemaps from
string dirLoc = Console.ReadLine();
// get all the sitemaps
string[] sitemaps = Directory.GetFiles(dirLoc);
StreamWriter sw = new StreamWriter(Application.StartupPath + #"\locs.txt", true);
// loop through each file
foreach (string sitemap in sitemaps)
{
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// cycle through each child noed
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
// first node is the url ... have to go to nexted loc node
foreach (XmlNode locNode in node)
{
string loc = locNode.Name;
// write it to the console so you can see its working
Console.WriteLine(loc + Environment.NewLine);
// write it to the file
sw.Write(loc + Environment.NewLine);
}
}
}
catch {
Console.WriteLine("Error :-(");
}
}
Console.WriteLine("All Done :-)");
Console.ReadLine();
}
}
}
Preferred Output:
CATALOG/CD/TITLE
CATALOG/CD/ARTIST
CATALOG/CD/COUNTRY/CNT
CATALOG/CD/COUNTRY/CODE
CATALOG/CD/COMPANY
CATALOG/CD/PRICE
CATALOG/CD/YEAR
CATALOG/CD/TITLE
CATALOG/CD/ARTIST
CATALOG/CD/COUNTRY
CATALOG/CD/COMPANY
CATALOG/CD/PRICE
CATALOG/CD/YEAR
This is a recursive problem, and what you are looking for is called 'tree traversal'. What this means is that for each child node, you want to look into it's children, then into that node's children (if it has any) and so on, recording the 'path' as you go along, but only printing out the names of the 'leaf' nodes.
You will need a function like this to 'traverse' the tree:
static void traverse(XmlNodeList nodes, string parentPath)
{
foreach (XmlNode node in nodes)
{
string thisPath = parentPath;
if (node.NodeType != XmlNodeType.Text)
{
//Prevent adding "#text" at the end of every chain
thisPath += "/" + node.Name;
}
if (!node.HasChildNodes)
{
//Only print out this path if it is at the end of a chain
Console.WriteLine(thisPath);
}
//Look into the child nodes using this function recursively
traverse(node.ChildNodes, thisPath);
}
}
And then here is how I would add it into your program (within your foreach sitemap loop):
try
{
// new xdoc instance
XmlDocument xDoc = new XmlDocument();
//load up the xml from the location
xDoc.Load(sitemap);
// start traversing from the children of the root node
var rootNode = xDoc.FirstChild;
traverse(rootNode.ChildNodes, rootNode.Name);
}
catch
{
Console.WriteLine("Error :-(");
}
I made use of this other helpful answer: Traverse a XML using Recursive function
Hope this helps! :)

cannot get node by using selectSingleNode method

my xml file is like below:
<?xml version="1.0"?>
<UpdateInboundim613Response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" status="SUCCESS" message="Success" schemaRevisionDate="2016-07-19" schemaRevisionLevel="0" returnCode="0" xmlns="http://schemas.hp.com/SM/7">
<model>
<keys>
<TransactionID type="String">E-InHPSXIM1089779</TransactionID>
</keys>
<instance uniquequery="TransactionID="E-InHPSXIM1089779"" recordid="E-InHPSXIM1089779">
<TransactionDetailedTrace xsi:nil="true" />
<TransactionMessage type="Array">
<TransactionMessage type="String" />
</TransactionMessage>
<OVSCSolutionDescription type="Array">
<OVSCSolutionDescription type="String">Issue: EL-BANK OUTSIDE WAREHOUSE EGYPT IMEA[2702]Interface[[E1 0/0/0]]|Router|ELBKCE1GW /pg-h-pg1252-256675160|143.34.213.18|Down Solution: As per update from Mai Shrief that the site has been suspended on 30th June. So no need of any investigation. Resolved By: BT NOC</OVSCSolutionDescription>
</OVSCSolutionDescription>
<OVSCTicketID type="String">E-IM004004076</OVSCTicketID>
<RIMSImpact xsi:nil="true" />
<attachments />
</instance>
</model>
<messages>
<message type="String" xmlns="http://schemas.hp.com/SM/7/Common">TransactionStatusDetail in $L.file is:IM Ticket: E-IM004004076 is valid for Update Subtype: Resolve</message>
</messages>
</UpdateInboundim613Response>
but my code cannot get value of element "OVSCTicketID":
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"C:\zzx\Project\SM\R5.1\Harness\InBound.xml");
XmlNode sigNode = xmlDoc.SelectSingleNode("/UpdateInboundim613Response/model/instance/OVSCTicketID");
if (sigNode != null)
{
Console.WriteLine(sigNode.InnerText);
}
can you please tell me what's the problem and how to fix it?
Your Xml document uses the default namespace "http://schemas.hp.com/SM/7". You need to use the XmlNamespaceManager to select that node under this namespace.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"C:\zzx\Project\SM\R5.1\Harness\InBound.xml");
var namespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
namespaceManager.AddNamespace("ns", "http://schemas.hp.com/SM/7");
XmlNode sigNode = xmlDoc.SelectSingleNode("//ns:UpdateInboundim613Response//ns:model//ns:instance//ns:OVSCTicketID",namespaceManager);
if (sigNode != null)
{
Console.WriteLine(sigNode.InnerText);
}
Above code should work fine.
Using xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace defaultNs = ((XElement)doc.FirstNode).GetDefaultNamespace();
string ovsCTicketID = (string)doc.Descendants(defaultNs + "OVSCTicketID").FirstOrDefault();
}
}
}

Read XElement Fragment from xml file to XElement Element

I have xml fragment in an xml-File. The fragment has tags with namespace.
How can I read that xml fragment, which represent exactly an XElement element ?
<node id="n0::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="91.44" width="59.49119999999999" x="364.256180835285" y="-698.4404365079365"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="48.677734375" x="5.406732812499968" y="4.0">MELEIN</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="27.35546875" x="16.067865624999968" y="20.843814062500087">8,00<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="-0.2720492775317138" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
I tried a lot of different ways the last one nearly comes to the target
var mngr = new System.Xml.XmlNamespaceManager(new System.Xml.NameTable());
mngr.AddNamespace(string.Empty, "urn: ignore"); // or proper URL
mngr.AddNamespace("y", "urn:ignore"); // or proper URL
var parserContext = new System.Xml.XmlParserContext(null, mngr, null, System.Xml.XmlSpace.None, null);
var txtReader = new System.Xml.XmlTextReader("block.graphml", System.Xml.XmlNodeType.Element, parserContext);
var ele = XElement.Load(txtReader);
but it crashes in the last line with System.InvalidOperationException
Is there any easy way to import xml fragment to an existing xelement?
I would prefer the way XElement.load("block.graphml"); This didn't work at all.
Thanks for your tips
You can do it like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
string input = File.ReadAllText(FILENAME);
XElement element = XElement.Parse("<Root xmlns:y=\"www.mynamespace.com\"></Root>");
element.Add(input);
}
}
}
​

Unable to Parse XMl after unwrapping soap body

I have been trying hard to parse an xml string, but all to no avail
<EnquirySingleItemResponse xmlns="http://tempuri.org/"> <EnquirySingleItemResult>
<Response>
<MSG>SUCCESS</MSG>
<INFO>TESTING</INFO>
</Response> </EnquirySingleItemResult> </EnquirySingleItemResponse>
My Code returns null or the texts in the xml tags no matter how i parse it. I have checked some post, but they seem not to be working.
See my code snipped below
XElement anotherUnwrappedResponse = ( from _xml in axdoc.Descendants(tempuri + "EnquirySingleItemResponse")
select _xml).FirstOrDefault();
string response = anotherUnwrappedResponse.Value;
axdoc.Descendants is used because i unwrapped the soap body, to have the xml above
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input =
"<EnquirySingleItemResponse xmlns=\"http://tempuri.org/\">" +
"<EnquirySingleItemResult>" +
"<Response>" +
"<MSG>SUCCESS</MSG>" +
"<INFO>TESTING</INFO>" +
"</Response> </EnquirySingleItemResult> </EnquirySingleItemResponse>";
XDocument doc = XDocument.Parse(input);
string msg = doc.Descendants().Where(x => x.Name.LocalName == "MSG").FirstOrDefault().Value;
string info = doc.Descendants().Where(x => x.Name.LocalName == "INFO").FirstOrDefault().Value;
}
}
}
​

Categories