Get data by XPath in C# - c#

So I have this XML:
<?xml version="1.0" encoding="utf-8"?>
<M_ChucVu>
<ChucVu>
<MaChucVu>1
</MaChucVu>
<TenChucVu>
</TenChucVu>
</ChucVu>
<ChucVu>
<MaChucVu>2
</MaChucVu>
<TenChucVu>
</TenChucVu>
</ChucVu>
<ChucVu>
<MaChucVu>23</MaChucVu>
<TenChucVu>12</TenChucVu>
</ChucVu>
<ChucVu>
<MaChucVu>44</MaChucVu>
<TenChucVu>44</TenChucVu>
</ChucVu>
</M_ChucVu>
and I want to retrieve the ChucVu tags that contain an empty TenChucVu tag so the result is this:
<ChucVu>
<MaChucVu>1
</MaChucVu>
<TenChucVu>
</TenChucVu>
</ChucVu>
<ChucVu>
<MaChucVu>2
</MaChucVu>
<TenChucVu>
</TenChucVu>
</ChucVu>

XDocument doc = ...;
var query = doc.XPathSelectElements("//ChucVu[TenChucVu='']");

Another XPath that should work
/M_ChucVu[./ChucVu/TenChucVu='']
for example
var doc = new XmlDocument();
doc.LoadXml(yourXmlString);
var elem = doc.DocumentElement;
var sel = elem.SelectNodes("/M_ChucVu[./ChucVu/TenChucVu!='']");
// print or use sel.InnerXml

The XPath you need is:
/*/ChucVu[not(string(TenChucVu))]
or
/*/ChucVu[string-length(TenChucVu)=0]

You can as:
string xparth = String.Format("//ChucVu[TenChucVu='{0}']", '');
XmlDocument doc = new XmlDocument();
doc.Load("Xml");
XmlElement root = doc.DocumentElement;
XmlNode node = root.SelectSingleNode(xparth);
XmlNodeList list = root.SelectNodes(xparth);

Related

Formatting XML with XmlDocument

I am trying to create an XML file using XmlDocument that will then be passed to an API. Most of the data outputs correctly however there is one element that does not, no matter what I try.
Here is my current output
<agentInventoryReference xmlns="demo.org.uk/demo/AgentInventoryReference"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<agentInventoryIdentity xmlns="">
<shed xmlns="demo.org.uk/demom/AgentInventoryIdentifier">TAX</shed>
<arrivalPort xmlns="demo.org.uk/demo/AgentInventoryIdentifier">LHR</arrivalPort>
<masterAirwayBillPrefix xmlns="demo.org.uk/demo/AgentInventoryIdentifier">125</masterAirwayBillPrefix>
<masterAirwayBillNumber xmlns="demo.org.uk/demo/AgentInventoryIdentifier">12345678</masterAirwayBillNumber>
<nominatedAgent xmlns="demo.org.uk/demo/AgentInventoryIdentifier">DRB</nominatedAgent>
</agentInventoryIdentity>
I need to drop the xmlns="" at the end of the opening agentInventoryIdentity element.
My code looks like this:
XmlDocument generateInventoryXml = new XmlDocument();
XmlElement root = generateInventoryXml.CreateElement ("agentInventoryReference", "demo.org.uk/demo/AgentInventoryReference");
root.SetAttribute("xmlns", "demo.org.uk/demo/AgentInventoryReference");
root.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
generateInventoryXml.AppendChild(root);
XmlElement agentInventoryIdentity = generateInventoryXml.CreateElement("agentInventoryIdentity");
XmlElement shed = generateInventoryXml.CreateElement("shed", "demo.org.uk/Sequoia/AgentInventoryIdentifier");
XmlElement arrivalport = generateInventoryXml.CreateElement("arrivalPort", "demo.org.uk/demo/AgentInventoryIdentifier");
XmlElement masterAirwayBillPrefix = generateInventoryXml.CreateElement("masterAirwayBillPrefix","demo.org.uk/demo/AgentInventoryIdentifier");
XmlElement masterAirwayBillNumber = generateInventoryXml.CreateElement("masterAirwayBillNumber", "demo.org.uk/demo/AgentInventoryIdentifier");
XmlElement nominatedAgent = generateInventoryXml.CreateElement("nominatedAgent", "demo.org.uk/demo/AgentInventoryIdentifier");
shed.InnerText = shedCode;
arrivalport.InnerText = arrivalPort;
masterAirwayBillPrefix.InnerText = awbPrefix;
masterAirwayBillNumber.InnerText = awbNumber;
nominatedAgent.InnerText = agent;
agentInventoryIdentity.AppendChild(shed);
agentInventoryIdentity.AppendChild(arrivalport);
agentInventoryIdentity.AppendChild(masterAirwayBillPrefix);
agentInventoryIdentity.AppendChild(masterAirwayBillNumber);
agentInventoryIdentity.AppendChild(nominatedAgent);
generateInventoryXml.DocumentElement.AppendChild(agentInventoryIdentity);
GenerateInventoryXml = generateInventoryXml.InnerXml;
Try this:
XmlElement agentInventoryIdentity = generateInventoryXml.CreateElement("agentInventoryIdentity",generateInventoryXml.DocumentElement.NamespaceURI);`
Or
XmlElement agentInventoryIdentity = generateInventoryXml.CreateElement("agentInventoryIdentity","demo.org.uk/demo/AgentInventoryReference");

parsing attribute from xml file

I'm trying to parse the following:
<?xml version="1.0" encoding="utf-8"?>
<GC>
<CREATED>01/23/2014 16:10:18</CREATED>
<DATA>
<CONTAINER name="home" type="xml" version="1.1.0.0">
<HEADER>
<ATTRIBUTE name="lang" value="EN" />
<ATTRIBUTE name="destination" value="UK" />
</HEADER>
</CONTAINER>
</DATA>
</GC>
How do I go about finding the value when name="lang"?
So far I have this:
XmlDocument Doc = new XmlDocument();
Doc.Load(#path);
XmlNode node = Doc.DocumentElement.SelectSingleNode("/GC/DATA/CONTAINER/HEADER/ATTRIBUTE/NAME");
string SI = node.Attributes["lang"].InnerText;
Doesn't seem to work unfortunately, could use some help. Many thanks.
This will do it:
XmlNode node =
Doc.SelectSingleNode("/GC/DATA/CONTAINER/HEADER/ATTRIBUTE[#name = 'lang']/#value");
string SI = node.InnerText;
And I would advise using a null check:
XmlNode node =
Doc.SelectSingleNode("/GC/DATA/CONTAINER/HEADER/ATTRIBUTE[#name = 'lang']/#value");
string SI = null;
if(node != null)
{
SI = node.InnerText;
}
With using LINQ to XML you can get it like this:
XDocument xDoc = XDocument.Load("path");
var element = xDoc.Descendans("ATTRIBUTE").First();
var nameAttribute = (string)element.Attribute("name");
This will get you the value of the attribute in the ATTRIBUTE tag which has name == lang:
XmlDocument Doc = new XmlDocument();
Doc.Load(#path);
XmlNode node = Doc.DocumentElement.SelectSingleNode("/GC/DATA/CONTAINER/HEADER/ATTRIBUTE[#name='lang']");
string SI = node.Attributes["value"].InnerText;
XmlNode node = Doc.DocumentElement.SelectSingleNode("/GC/DATA/CONTAINER/HEADER/ATTRIBUTE[#name='lang']");
string SI = node.Attributes["value"].Value;

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();

Read a XML (from a string) and get some fields - Problems reading XML

I have this XML (stored in a C# string called myXML)
<?xml version="1.0" encoding="utf-16"?>
<myDataz xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<listS>
<sog>
<field1>123</field1>
<field2>a</field2>
<field3>b</field3>
</sog>
<sog>
<field1>456</field1>
<field2>c</field2>
<field3>d</field3>
</sog>
</listS>
</myDataz>
and I'd like to browse all <sog> elements. For each of them, I'd like to print the child <field1>.
So this is my code :
XmlDocument xmlDoc = new XmlDocument();
string myXML = "<?xml version=\"1.0\" encoding=\"utf-16\"?><myDataz xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><listS><sog><field1>123</field1><field2>a</field2><field3>b</field3></sog><sog><field1>456</field1><field2>c</field2><field3>d</field3></sog></listS></myDataz>"
xmlDoc.Load(myXML);
XmlNodeList parentNode = xmlDoc.GetElementsByTagName("listS");
foreach (XmlNode childrenNode in parentNode)
{
HttpContext.Current.Response.Write(childrenNode.SelectSingleNode("//field1").Value);
}
but seems I can't read a string as XML? I get System.ArgumentException
You should use LoadXml method, not Load:
xmlDoc.LoadXml(myXML);
Load method is trying to load xml from a file and LoadXml from a string. You could also use XPath:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
string xpath = "myDataz/listS/sog";
var nodes = xmlDoc.SelectNodes(xpath);
foreach (XmlNode childrenNode in nodes)
{
HttpContext.Current.Response.Write(childrenNode.SelectSingleNode("//field1").Value);
}
Use Linq-XML,
XDocument doc = XDocument.Load(file);
var result = from ele in doc.Descendants("sog")
select new
{
field1 = (string)ele.Element("field1")
};
foreach (var t in result)
{
HttpContext.Current.Response.Write(t.field1);
}
OR : Get the node list of <sog> tag.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(myXML);
XmlNodeList parentNode = xmlDoc.GetElementsByTagName("sog");
foreach (XmlNode childrenNode in parentNode)
{
HttpContext.Current.Response.Write(childrenNode.SelectSingleNode("field1").InnerText);
}
The other answers are several years old (and do not work for Windows Phone 8.1) so I figured I'd drop in another option. I used this to parse an RSS response for a Windows Phone app:
XDocument xdoc = new XDocument();
xdoc = XDocument.Parse(xml_string);
Or use the XmlSerializer class.
XmlSerializer xs = new XmlSerializer(objectType);
obj = xs.Deserialize(new StringReader(yourXmlString));
I used the System.Xml.Linq.XElement for the purpose. Just check code below for reading the value of first child node of the xml(not the root node).
string textXml = "<xmlroot><firstchild>value of first child</firstchild>........</xmlroot>";
XElement xmlroot = XElement.Parse(textXml);
string firstNodeContent = ((System.Xml.Linq.XElement)(xmlroot.FirstNode)).Value;

manipulation of xml using c#

If I want to add, update or delete node in the xml using c#, how can it be done? My xml is shown below. I dont want transactionID node. I want to add a node called <Transformation>XML</Transformation> after corelationID node.
<?xml version="1.0" ?>
<GovTalkMessage xmlns="http://www.govtalk.gov.uk/CM/envelope">
<EnvelopeVersion>2.0</EnvelopeVersion>
<Header>
<MessageDetails>
<Class>HMRC-VAT-DEC</Class>
<Qualifier>poll</Qualifier>
<Function>submit</Function>
<TransactionID />
<CorrelationID>1B93D48C02D740C6B79DE68A27F3ADE5</CorrelationID>
<ResponseEndPoint PollInterval="10">https://secure.dev.gateway.gov.uk/poll</ResponseEndPoint>
<GatewayTimestamp>2011-04-05T07:41:43.018</GatewayTimestamp>
</MessageDetails>
<SenderDetails />
</Header>
<GovTalkDetails>
<Keys />
</GovTalkDetails>
<Body />
</GovTalkMessage>
The easiest thing to use would be LINQ to XML. For example:
XDocument doc = XDocument.Load("file.xml");
XNamespace ns = "http://www.govtalk.gov.uk/CM/envelope";
// Remove TransationID
XElement transactionElement = doc.Descendants(ns + "TransactionID").Single();
transactionElement.Remove();
// Add XML:
XElement correlationElement = doc.Descendants(ns + "CorrelectionID").Single();
XElement newElement = new XElement(ns + "XML");
correlationElement.AddAfterSelf(newElement);
// Save back
doc.Save("new-file.xml");
//Load the XML
XmlDocument documentXML = new XmlDocument();
documentXML.Load(Server.MapPath("AddDeleteUpdate.xml"));
XmlNamespaceManager xmlns = new XmlNamespaceManager(documentXML.NameTable);
xmlns.AddNamespace("bk", "http://www.govtalk.gov.uk/CM/envelope");
//Identify the parent node i.e <MessageDetails>
XmlNode nodeMessage = documentXML.SelectSingleNode("//bk:GovTalkMessage/bk:Header/bk:MessageDetails", xmlns);
//Delete the node.
XmlNode nodeTransactionID = documentXML.SelectSingleNode("//bk:GovTalkMessage/bk:Header/bk:MessageDetails/bk:TransactionID", xmlns);
nodeMessage.RemoveChild(nodeTransactionID);
//Create the new XML noded to be added.
XmlNode controlAttrNode = null;
controlAttrNode = documentXML.CreateElement("Transformation");
controlAttrNode.InnerText = "XML";
controlAttrNode.Attributes.RemoveAll();
//Get the node object to where it need to be added.
XmlNode nodeCorrelation = documentXML.SelectSingleNode("//bk:GovTalkMessage/bk:Header/bk:MessageDetails/bk:CorrelationID", xmlns);
//Insert the node after.
nodeMessage.InsertAfter(controlAttrNode, nodeCorrelation);
documentXML.Save(Server.MapPath("AddDeleteUpdate.xml"));
You'll need
XMLNode.InsertAfter(newChildNode,referenceChildNode)
This should kickstart you:
http://msdn.microsoft.com/en-US/library/system.xml.xmlnode.insertafter%28v=VS.80%29.aspx

Categories

Resources