SharePoint XML Parse c# - c#

I have such XML structure which was returned by SharePoint web services.
<rs:data ItemCount="4" xmlns:rs="urn:company:rowset">
<z:row ows_AssetId="HP010336520" />
<z:row ows_AssetId="HP010336519" />
<z:row ows_AssetId="HP010354403" />
<z:row ows_AssetId="HP010357062" />
</rs:data>
private static void Parser(List<XmlNode> data)
{
List<XmlNodeList> rows = (from row in data.AsEnumerable()
select row.SelectNodes("data/row")).ToList();
}
I was trying to query for a row, but no luck. Could you guys please help me?

You need to use an XmlNamespaceManager when querying the node list. Not seen in your code is the declaration of the 'z' namespace in the document's root: xmlns:z="#RowsetSchema".
Try the following in your Parser method:
NameTable nameTable = new NameTable();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(nameTable);
nsmgr.AddNamespace("z", "#RowsetSchema");
List<XmlNodeList> rows = (from row in data.AsEnumerable()
select row.SelectNodes("//z:row", nsmgr)).ToList();

I'm not at a place where I can test right now, but I believe at least part of the issue is your omission of namespaces in your query -- rather than "data/row", try "rs:data/z:row".

Related

Tricky to read XML from web service C#

I have looked everywhere, and cannot find anything to help me.
I am writing a program that connects to a webservice and then the webservice sends an XML response. After the response is received I have to retrieve certain values from it, but this is where it gets tricky
Here is a snippet of the returned XML:
<?xml version="1.0"?>
<MobilePortalSellingCategoriesHierarchy xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Response xmlns="http://blabla.com/service/">Successful</Response>
<ResponseNumber xmlns="http://blabla.com/service/">0</ResponseNumber>
<SellingCategoriesHierarchy xmlns="http://tym2sell.com/PortalService/">
<Response>Successful</Response>
<ResponseNumber>0</ResponseNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId xsi:nil="true" />
<SellingCategoryName>category1</SellingCategoryName>
<DeliveryMethod />
<DeliveryMethodNumber>0</DeliveryMethodNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId xsi:nil="true" />
<SellingCategoryName>category1_Item</SellingCategoryName>
<DeliveryMethod />
<DeliveryMethodNumber>0</DeliveryMethodNumber>
<SellingCategories>
<PortalSellingCategory>
<SellingCategoryId>2</SellingCategoryId>
<SellingCategoryName>Item2</SellingCategoryName>
<DeliveryMethod>Display</DeliveryMethod>
<DeliveryMethodNumber>1</DeliveryMethodNumber>
<VoucherValue>0.00</VoucherValue>
<IsVariablePrice>true</IsVariablePrice>
<MinimumVoucherValue>1.00</MinimumVoucherValue>
<MaximumVoucherValue>1000.00</MaximumVoucherValue>
<VoucherValueIncrement>1.00</VoucherValueIncrement>
<AdditionalInputItems>
<PortalAdditionalInputItem>
<InputItemId>-1</InputItemId>
<Label>Value:</Label>
<IsNumericOnly>true</IsNumericOnly>
<MaximumLength>7</MaximumLength>
<Hidden>false</Hidden>
</PortalAdditionalInputItem>
<PortalAdditionalInputItem>
<InputItemId>4</InputItemId>
<Label>Mobile Number</Label>
<IsNumericOnly>true</IsNumericOnly>
<MaximumLength>15</MaximumLength>
<Hidden>false</Hidden>
</PortalAdditionalInputItem>
</AdditionalInputItems>
<TwoStep>false</TwoStep>
<SelectedIcon>SamplePicture</SelectedIcon>
<UnSelectedIcon>SamplePicture</UnSelectedIcon>
This repeats from the SellingCategories node just under Response for a couple of times.
Here is a Snippet of my code where I get the XML as string.
XmlDocument xml = new XmlDocument();
xml.LoadXml(receivedData);
XmlNodeList xnList = xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
foreach (XmlNode xn in xnList)
{
string sellingCategoryName = xn["SellingCategoryName"].InnerText;
string SelectedIcon = xn["SelectedIcon"].InnerText;
string UnSelectedIcon = xn["UnSelectedIcon"].InnerText;
richTextBox1.AppendText(string.Format("Name: {0} {1} {2}", sellingCategoryName, SelectedIcon, UnSelectedIcon));
}
I have tried changing xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
to
xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy/SellingCategoriesHierarchy/SellingCategories/PortalSellingCategory");
I need to select each SellingCategoryName and list the SellingCategoryName(s) and all the other items underneath it.
I was hoping to get something in the lines of:
Category1
Category1_Item
Item2
SamplePicture
Sample Picture
Mine only reads the First Node and then returns "Successful" to me.
I havve also tried:
XElement root = XElement.Load("FilePath");
var sellingCategoryNames = from PortalSellingCategory in root.Elements("MobilePortalSellingCategoriesHierarchy")
where (string)PortalSellingCategory.Element("SellingCategoriesHierarchy").Element("SellingCategories").Element("PortalSellingCategory") != ""
select PortalSellingCategory;
foreach (var xEle in sellingCategoryNames)
{
richTextBox1.Text = (string)xEle;
}
Any help would be greatly appreciated.
What you are doing with
xml.SelectNodes("/MobilePortalSellingCategoriesHierarchy");
is selecting your root node, which is just one. Thats why you only get one item in your list back. Is the hierarchy important? I can see that PortalSellingCategory can also be inside another PortalSellingCategory. If not maybe you could try the following select:
xml.SelectNodes("//PortalSellingCategory");
This will search for every node named "PortalSellingCategory" in your response, no mather where in the hierarchy it is.
EDIT:
And yes, you should look out for the namespaces, sry for didnt seeing that.
If you like geeting all the nodes with XPath you must create a new NamespaceManager and at it to your selectNodes call:
XmlDocument xml = new XmlDocument();
xml.LoadXml(data);
XmlNamespaceManager ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("ns", "http://tym2sell.com/PortalService/");
XmlNodeList xnList = xml.SelectNodes("//ns:PortalSellingCategory", ns);
I would use XElement instead of XMLDocument, and then use Linq to query or pick the elmements like: XElement xContact = ....
int contactno = (int?)xContact.Element("command").Element("contactperson").Attribute("contactpersonid") ?? -1;
if (xContact.Element("command").Element("contactperson").Element("name").Element("firstname") != null)
console.writeline(xContact.Element("command").Element("contactperson").Element("name").Element("firstname").Value);
var doc= new XmlDocument();
doc.Load("FilePath");
var nodeList = xml.GetElementsByTagName("PortalSellingCategory");
Hi,
It returns the collection of nodes, and you just have to query it to get needed informations.
Feel free to ask help if needed.
Dimitri.

How to get a specific XML value from an XML using C#?

I have the below XML as:
<Requests xmlResponse="true">
<Request response="yes" responsewait="120000" sequence="1" type="Fulfillment">
<RequestData>
<PrintControl>FTP</PrintControl>
<User>81DF</User>
<Documents>
<AddressChangeLetter>
<DocumentInfo>
<AddressChange AddressChangeId="109346" Branch="418" LastChangeDate="">
<Name>AAA NOVAK</Name>
<TaxID>123123121</TaxID>
<OldAddress1>BOX 216</OldAddress1>
<OldAddress2>NYANE 68017</OldAddress2>
<OldAddress3 />
<OldAddress4 />
<NewAddress1>P O BOX 216</NewAddress1>
<NewAddress2>CERESCO NE 68017</NewAddress2>
<NewAddress3 />
<NewAddress4 />
<DateChanged>05/08/2013</DateChanged>
<AccountInfo AcctNum="231232311" AcctStatusCodes="IX" />
</AddressChange>
</DocumentInfo>
</AddressChangeLetter>
</Documents>
</RequestData>
I wanted to get the name or the value which is under the tag "Documents". Since in the above XML, the tag under the "Document" tag is "AddressChangeLetter", therefore, I want to get this name. How will I do it.
Something along the lines of... (it's not perfect, but it'll get you started - Google the functions I've used to get it working properly):
XmlDocument xml = new XmlDocument();
xml.Load(yourPathGoesHere)
XmlNodeList addressNodes = xml.GetElementsByTagName("AddressChange");
foreach (XmlNode oneNode in addressNodes) {
myVariableToGrabNames = oneNode["Name"].InnerText;
}
This can be done pretty easily using Linq to XML e.g.
var xml = ...;
var xdoc = XDocument.Parse(xml);
foreach (var e in xdoc.Descendants("Documents").Elements())
{
var name = e.Name; // AddressChangeLetter
}

XML Manipulation and Injection

I've the following XML structure which is a part of a xml document:
<p:sp xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
....
....
....
<p:txBody>
<a:bodyPr wrap="square" rtlCol="0" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:noAutofit />
</a:bodyPr>
<a:lstStyle xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />
<a:p xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:endParaRPr lang="en-US" sz="1200" dirty="0">
<a:solidFill><a:schemeClr val="tx1" />
</a:solidFill>
<a:latin typeface="Verdana" pitchFamily="34" charset="0" />
<a:ea typeface="Verdana" pitchFamily="34" charset="0" />
<a:cs typeface="Verdana" pitchFamily="34" charset="0" /></a:endParaRPr>
</a:p>
</p:txBody>
</p:sp>
I want to select p:txBody and want to inject a:p at the end, I'm using the following code but the txBody i am receiving is not the correct one, because i guess it's extracting that from the doc object not from the shape object:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("p", "http://schemas.openxmlformats.org/presentationml/2006/main");
XmlNode txBody = shape.SelectSingleNode("//p:txBody", nsmgr);
where shape is an XMLNode object having the OuterXml as mentioned above, and using the following code for xml injection:
XmlDocumentFragment fragment = doc.CreateDocumentFragment();
string xml = "valid xml";
fragment.InnerXml = xml;
txBody.Append(fragment);
but the injection is being done in wrong shape.
Your xpath isn't specific enough if it is getting you the wrong node. You need to give it more information to get the node you want. IE what sets the node you want to be different than the other(s)?
As you have it now, you are saying give me the first node you find that has the p namespace and the node name txBody anywhere in the file.
You have shape. but the // in "//p:txBody" says start from the root of the file. If you mean to start from the shape, use .// so like ".//p:txBody"
Use LINQ2XML. It's a complete replacement to other XML APIs.
XElement doc=XElement.Load("yourXML.xml");
XNamespace p = "http://schemas.openxmlformats.org/presentationml/2006/main";
XNamespace s= "http://schemas.openxmlformats.org/drawingml/2006/main";
doc.Elements(p+"txBody").First().Add(new XElement(s+"tagName","value"));

Linq to XML select distinct value from

I am working with sharePoint Lists webservice, in order to load a dropdown in search page I need to extract all the "ows_Country" name from XML, returend in XMLNode in the Format of :
<rs:data ItemCount="1" xmlns:rs="urn:schemas-microsoft-com:rowset">
<z:row ows_Title="Nike" ows_ID="1" ows_Country="Spain" xmlns:z="#RowsetSchema" />
<z:row ows_Title="Addidas" ows_ID="4" ows_Country="Brazil" xmlns:z="#RowsetSchema" />
<z:row ows_Title="Puma" ows_ID="5" ows_Country="Spain" xmlns:z="#RowsetSchema" />
</rs:data>
I need to use LINQ to get the distinct "ows_Country" from the XMLNode, Kindly help is probably my first experience with LINQ as well as XML.
XNamespace rs = "urn:schemas-microsoft-com:rowset";
XNamespace z = "#RowsetSchema";
XDocument doc = XDocument.Load(...);
var result = doc.Element(rs + "data")
.Elements(z + "row")
.Select(e => (string)e.Attribute("ows_Country"))
.Distinct()
.ToList();

Inserting XML Fragment after last specific node/element

I want to add an XML fragment to the last element to an XML document and I having problems i.e. the error I get is:
"The reference node is not a child of
this node".
So my existing XML document looks like this:
<MAP>
<LAYER name ="My first Layer">
<DATASET name="foo dataset" />
<SYMBOLOGY>
<SYMBOL colour="red" />
</SYMBOLOGY>
</LAYER>
<LAYER name="My second Layer">
<DATASET name="bar dataset" />
<SYMBOLOGY>
<SYMBOL colour="blue" />
</SYMBOLOGY>
</LAYER>
</MAP>
The XML fragment I want to insert after the last LAYER element is:
<LAYER name="My third Layer">
<DATASET name="whatever dataset" />
<SYMBOLOGY>
<SYMBOL colour="yellow" />
</SYMBOLOGY>
</LAYER>
The code I am using is:
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = inputXML; //which is basically the third layer example - see above.
XmlElement rootElement = xmlDocument.DocumentElement;
XmlNode lastLayerNode = rootElement.SelectSingleNode(#"//LAYER[last()]");
rootElement.InsertAfter(xmlDocFrag, lastLayerNode); //error raised here.
Any ideas on what I'm doing wrong here would be much appreciated. My XPath query seems find and it seems to select the correct last layer it just won't insert after it for some bizarre reason.
UPDATE/SOLUTION - How to do this with XPATH
Finally figured it out in XPath - see the code below, I think it was down to basically not selecting the correct parent node in the first place, it's incorrect to select the last LAYER then try and InsertAfter() on this node. Better to select the level above i.e. MAP then AppendChild(). See below:
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = inputXML;
XmlElement mapElement = (XmlElement)xmlDocument.SelectSingleNode(#"//MAP[last()]");
mapElement.AppendChild(xmlDocFrag);
Thanks to all the replies and help too :)
Taking into consideration that you need this to work with Framework 2.0, here's another solution:
string xml = "<map><layer>1</layer><layer>2</layer></map>";
string addMe = "<layer>3</layer>";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = addMe;
XmlElement rootElement = xmlDocument.DocumentElement;
rootElement.AppendChild(xmlDocFrag);
This results in:
<map><layer>1</layer><layer>2</layer><layer>3</layer></map>
Things look pretty good, but I would first try to avoid the xpath selection for the last node, and instead just use this:
rootElement.InsertAfter(xmlDocFrag, rootElement.LastChild);
I had similar issue, I used the ImportNode method to solve it
Here is a small example how you can use it to add node from different xml (stored in string) to your example at desired node in xml tree
string xmlstring =#"<tag>.....</tag>"; // holds xml tree to be appended
XmlDocument xml2 = new XmlDocument();
xml2.Load(#"path_of_main_xml");
XmlDocument xml1 = new XmlDocument();
xml1.Load(new StringReader(xmlString));
// get the node you want to import which in this icase is string
XmlNode elem = xml1.DocumentElement;
// use importNode to import it
XmlNode impnode = xml2.ImportNode(elem,true);
// get the node list of all node of particular tag name
XmlNodeList eNode = xml2.GetElementsByTagName("tag_name_of_parent");
eNode[0].AppendChild(impnode); // append new node
// write back the updates to same file
XmlWriter writer = XmlWriter.Create(#"path_of_main_xml");
xml2.Save(writer);

Categories

Resources