LINQ to XML Example that Excludes Elements where Descendants Contains Value - c#

I'm new to LINQ to XML and was wondering if anyone could help me construct the following query.
I want to return all the <response> elements that do not contain a descendant <status> element that contains "404".
My XML is shown below. In this case, only the first <response> element (and descendants) should be returned.
<multistatus xmlns="DAV:">
<response>
<href>/principals/users/test/</href>
<propstat>
<prop>
<calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">
<href xmlns="DAV:">/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9</href>
</calendar-home-set>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>/principals/users/test/calendar-proxy-write/</href>
<propstat>
<prop>
<calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav" />
</prop>
<status>HTTP/1.1 404 Not Found</status>
</propstat>
</response>
<response>
<href>/principals/users/test/calendar-proxy-read/</href>
<propstat>
<prop>
<calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav" />
</prop>
<status>HTTP/1.1 404 Not Found</status>
</propstat>
</response>
</multistatus>

Assuming that your XML is stored in the string variable xml:
XDocument document = XDocument.Parse(xml);
XNamespace ns = document.Root.GetDefaultNamespace();
var responsesExcept404s = document
.Descendants(ns + "response")
.Where(x => !x.Descendants(ns + "status")
.Single()
.Value.Contains("404"));
Notice the usage of ns variable - since your XML has default namespace set via xmlns attribute, it is necessary to specify that namespace when using LINQ to XML (such as in Descendants() method).
Then you can simply iterate over results and, to make this super-useful, output them to the console:
responsesExcept404s.ToList().ForEach(Console.WriteLine);

XDocument xDoc = XDocument.Parse(xml);
XNamespace ns = XNamespace.Get("DAV:");
var responses = xDoc.Descendants(ns + "status")
.Where(s => !s.Value.Contains(" 404 "))
.Select(s => s.Parent.Parent);

Here ya go: (cheating with XPath)
XDocument xdoc = XDocument.Load(new FileStream("XMLFile2.xml", FileMode.Open, FileAccess.Read));
XPathNavigator nav = xdoc.CreateNavigator();
var nsm = new XmlNamespaceManager(nav.NameTable);
nsm.AddNamespace("s", "DAV:");
var nodes = xdoc.XPathSelectElements("s:multistatus/s:response[.//*[name(.)='status' and .='HTTP/1.1 404 Not Found']]", nsm);

You can get use the linq statement as shown below
XDocument doc = XDocument.Parse(xml);
List<XElement> responseWithOut404 =
(from element in doc.Descendants("response")
let xElement = element.Descendants("status").First()
where !xElement.Value.Contains("404")
select element)
.ToList();

Try this:
Document doc = XDocument.Load(path);
XNamespace nsd = doc.Root.GetDefaultNamespace();
var res = doc.Descendants(nsd +"response");
var filteredEle = new List<XElement>();
foreach (var ele in res)
{
if (CheckEle(ele,nsd))
{
filteredEle.Add(ele);
}
}
private bool CheckEle(XElement ele, XNamespace nsd)
{
return ele.Element(nsd + "propstat").Element(nsd + "status").Value != "HTTP/1.1 404 Not Found";
}

Related

Simplest way to get XML nodes with namespace?

I have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<createTransactionResponse xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<messages>
<resultCode>Ok</resultCode>
<message>
<code>I00001</code>
<text>Successful.</text>
</message>
</messages>
<transactionResponse>
<responseCode>1</responseCode>
<authCode>25C10X</authCode>
<messages>
<message>
<code>1</code>
<description>This transaction has been approved.</description>
</message>
</messages>
</transactionResponse>
</createTransactionResponse>
What is the easiest way to get the value "Successful." from createTransactionResponse->messages->message->text?
Here is my code:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("anet", "AnetApi/xml/v1/schema/AnetApiSchema.xsd");
var myNodes = doc.SelectNodes("//anet:messages", nsmgr);
myNodes returns 2 nodes. The innerxml of node[0] is:
<resultCode xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">Ok</resultCode><message xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
<code>I00001</code>
<text>Successful.</text>
</message>
The innerxml of node[1] is:
<message xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
<code>1</code>
<description>This transaction has been approved.</description>
</message>
My problem is I can't go any deeper than that.
//anet:messages/message yields nothing.
//anet:createTransactionResponse/messages yields nothing.
I'm just trying to get specific element values such as "I00001" and "25C10X".
What am I doing wrong?
Namespace bindings are inherited, so the child elements are in the same namespace as their parents here.
You need to add the missing namespace prefixes to your query:
//anet:messages/anet:message/anet:text
That said, I'd usually prefer LINQ to XML over XPath:
XNamespace ns = "AnetApi/xml/v1/schema/AnetApiSchema.xsd";
var root = XElement.Parse(xml);
var text = (string) root.Elements(ns + "messages")
.Descendants(ns + "text")
.Single();
See this fiddle for a working demo.
You can also use the LocalName property to avoid using the namespace:
XDocument root = XDocument.Parse(xml);
string text = root.Descendants()
.First(node => node.Name.LocalName == "messages").Elements()
.First(node => node.Name.LocalName == "message").Elements()
.First(node => node.Name.LocalName == "text").Value;

Load data from XML nodes

i have this structure of data:
<?xml version="1.0" encoding="windows-1250"?>
<?xml-stylesheet type="text/xsl" href="usb71105.xsl"?>
<manas:usb xmlns:manas="http://www.manas.info/">
<manas:qr00>
<manas:verzemanas>26052708</manas:verzemanas>
<manas:verzexml>2016.03.29a</manas:verzexml>
<manas:druhtisku>U_Tisk2P/2159405/TRUE</manas:druhtisku>
</manas:qr00>
<manas:qr00>
<manas:verzemanas>26052710</manas:verzemanas>
<manas:verzexml>2016.03.30a</manas:verzexml>
<manas:druhtisku>U_Tisk2P/FALSE</manas:druhtisku>
</manas:qr00>
</manas:usb>
I need to save values of: manas:verzemanas ; manas:verzexml ;
I have this code:
XmlDocument doc = new XmlDocument();
doc.Load("d:\\83116623.XML");
foreach (XmlNode node in doc.DocumentElement)
{
string name = node.Attributes[0].ToString();
}
Have you any ideas please?
You're probably better off with XDocument. Also you need to use the namespace prefix. E.g.:
XNamespace ns = "http://www.manas.info/";
var xdoc = XDocument.Load(#"c:\temp\a\a.xml");
var verze = xdoc.Root.Elements(ns + "qr00")
.Elements(ns + "verzemanas")
.Select(e => e.Value);
verze.ToList().ForEach(v => Console.WriteLine(v));
prints
26052708
26052710

Get Element from XDocument & Edit Attribute

<GetPromotionByIdResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MajorVersion="2" xmlns="http://fake.com/services">
<Header>
<Response ResponseCode="OK">
<RequestID>1</RequestID>
</Response>
</Header>
<Promotion PromotionId="5200" EffectiveDate="2014-10-10T00:00:00" ExpirationDate="2014-11-16T23:59:00" PromotionStatus="Active" PromotionTypeName="DefaultPromotion">
<Description TypeCode="Long" Culture="en-AU">Promotion Description</Description>
</Promotion>
</GetPromotionByIdResponse>
Im trying to extract this
<Promotion PromotionId="5200" EffectiveDate="2014-10-10T00:00:00" ExpirationDate="2014-11-16T23:59:00" PromotionStatus="Active" PromotionTypeName="DefaultPromotion">
<Description TypeCode="Long" Culture="en-AU">Promotion Description</Description>
</Promotion>
and convert the PromotionId="5200" to PromotionId="XXX"
I can extract the < Promotion > element with the below code but cant work out how to change the attribute
XNamespace xmlResponseNamespace = xmlPromotionResponse.Root.GetDefaultNamespace();
XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());
nsm.AddNamespace("def", xmlResponseNamespace.ToString());
XElement xmlPromotionElement =
xmlPromotionResponse
.Descendants().SingleOrDefault(p => p.Name.LocalName == "Promotion");
You can try this way :
XNamespace ns = "http://fake.com/services";
XElement xmlPromotionElement = xmlPromotionResponse.Descendants(ns+"Promotion")
.SingleOrDefault();
xmlPromotionElement.Attribute("PromotionId").Value = "XXX";
Use simple XNamespace + local-name to reference an element in namespace. Then you can use .Attribute() method to get XAttribute from an XElement and change the attribute's value.
Try this : It returns the value of all attributes in Promotion Tag.
XNamespace ns1 = XNamespace.Get("http://fake.com/services");
var readPromotion = from a in xx.Descendants(ns1 + "Promotion")
select new
{
PromotionID = (string)a.Attribute("PromotionId"),
EffectiveDate = (string)a.Attribute("EffectiveDate"),
ExpirationDate = (string)a.Attribute("ExpirationDate"),
PromotionStatus = (string)a.Attribute("PromotionStatus"),
PromotionTypeName = (string)a.Attribute("PromotionTypeName"),
Description = (string)a.Value
};
foreach (var read in readPromotion)
{
// Read values
}

Access all nodes in xml using linq

I have xml:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<UpdateMemberHireStatus xmlns="http://tempuri.org/">
<member>
<HireAvailability>
<code>1</code>
<name>פנוי</name>
</HireAvailability>
<HireRejectReason>
<code>2</code>
<name>wow</name>
</HireRejectReason>
<IdNumber>43504349</IdNumber>
<note> </note>
</member>
</UpdateMemberHireStatus>
and I want to use LINQ to access all the nodes in the xml.
Here's what I have tried:
XNamespace ns = "tempuri.org/";
IEnumerable<HireStatus> status = from r in doc.Descendants(ns + "UpdateMemberHireStatus")
.Descendants(ns + "member")
select new HireStatus() { };
return status.ToList();
Use Descendants
var xml = XDocument.Load(XMLStream);
var allEle = xml.Descendants("UpdateMemberHireStatus"); //you can do linq now.
You can use XDocument also in the following way:
string xmlPath = "D://member.xml";
XmlDocument doc = new XmlDocument();
xdoc = XDocument.Load(xmlPath);
doc.LoadXml(xdoc.ToString());
var memberStatus= (from mem in xdoc.Descendants("member")
select mem);
foreach (XElement element in memberStatuses.ToList())
IEnumerable<XNode> nodes = element.Nodes();
var x = XElement.Load(XMLStream);
var all = x.DescendantNodes();

How to get a node from xml with c#- what am I doing wrong?

Namespaces and XML are still confusing the hell out of me.
Here is my XML (that comes from a SOAP request)
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<MyResponse xmlns="http://tempuri.org/">
<OutputXML xmlns="http://tempuri.org/XMLSchema.xsd">
<Result>
<OutputXML>
<Result>
<Foo>
<Bar />
</Foo>
</Result>
</OutputXML>
</Result>
</OutputXML>
</MyResponse>
</soap:Body>
</soap:Envelope>
I am trying to extract the actual XML part from the SOAP response (starting with the Foo element):
var nsmgr = new XmlNamespaceManager(document.NameTable);
nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("", "http://tempuri.org/");
nsmgr.AddNamespace("", "http://tempuri.org/XMLSchema.xsd");
var xml = document.DocumentElement
.SelectSingleNode("Foo", nsmgr)
.InnerXml;
But SelectSingleNode returns null. I've tried some different variations on this but can't get anything working. What am I not understanding?
Try this one:
var nsmgr = new XmlNamespaceManager(document.NameTable);
nsmgr.AddNamespace("aaa", "http://tempuri.org/XMLSchema.xsd");
var xml = document.DocumentElement
.SelectSingleNode("aaa:Foo", nsmgr)
.InnerXml;
this is because of Default namespaces has no perfix.
You can use GetElementsByTagName to use namespace uri directly:
var xml = document.GetElementsByTagName("Foo",
"http://tempuri.org/XMLSchema.xsd")[0].InnerXml;
You can use LINQ to XML to get your result, also specify the namespace
XDocument document = XDocument.Load("test.xml");
XNamespace ns = "http://tempuri.org/XMLSchema.xsd";
var test = document.Descendants(ns + "Foo").FirstOrDefault();
Or if you don't want to specify NameSpace then:
var test2 = document.Descendants()
.Where(a => a.Name.LocalName == "Foo")
.FirstOrDefault();

Categories

Resources