XDocument how to search by xpath - c#

I have a xml file like below, i want to find the node which property "name" value equals "ImageListView"
I have writen below code:
var nsmgr = new XmlNamespaceManager(new NameTable());
nsmgr.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1");
xpath = "//asmv1:assembly/dependency/dependentAssembly/assemblyIdentity[name='ImageListView']";
XElement ele = doc.XPathSelectElement(xpath, nsmgr);
ele.Remove();
but cannot find anything. is any wrong here? thanks.

Your XML has default namespace here :
<asmv1:assembly
......
xmlns="urn:schemas-microsoft-com:asm.v2"
......>
Therefore, all XML element without prefix considered in default namespace. You need to add prefix that point to default namespace URI, and use it in XPath :
var nsmgr = new XmlNamespaceManager(new NameTable());
nsmgr.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1");
nsmgr.AddNamespace("d", "urn:schemas-microsoft-com:asm.v2");
xpath = "//asmv1:assembly/d:dependency/d:dependentAssembly/d:assemblyIdentity[#name='ImageListView']";
XElement ele = doc.XPathSelectElement(xpath, nsmgr);
ele.Remove();
UPDATE :
fixed the XPath slightly. You need to use # to point to attribute : ... [#name='ImageListView']

Related

Specify namespace for new XElement

I'm trying to add new elements to an existing XDocument where the new XElement either specifies the namespace or is part of the default namespace.
I already have a XmlNamespaceManager and I can select elements using that.
XmlNamespaceManager nsMgr = new XmlNamespaceManager(new NameTable());
nsMgr.AddNamespace("default", "http://www.mismo.org/residential/2009/schemas");
nsMgr.AddNamespace("customNs", "http://custom.org");
Consider the following XML
<ROOT xmlns="http://www.mismo.org/residential/2009/schemas" xmlns:customNs="http://custom.org">
<ELM_1>
<ELM_1_SUB_1>Some value</ELM_1_SUB_1>
</ELM_1>
<customNs:ELM_2>
<customNs:ELM_2_SUB_1>Another value</customNs:ELM_2_SUB_1>
</customNs:ELM_2>
</ROOT>
I'd like to write some code that would result in this:
<ROOT xmlns="http://www.mismo.org/residential/2009/schemas" xmlns:customNs="http://custom.org">
<ELM_1>
<ELM_1_SUB_1>Some value</ELM_1_SUB_1>
<ELM_1_SUB_2>ADDED TO DEFAULT NAMESPACE</ELM_1_SUB_2>
</ELM_1>
<customNs:ELM_2>
<customNs:ELM_2_SUB_1>Another value</customNs:ELM_2_SUB_1>
<customNs:ELM_2_SUB_2>ADDED TO CUSTOM NAMESPACE</customNs:ELM_2_SUB_2>
</customNs:ELM_2>
</ROOT>
I have tried the following:
var elm1 = xDoc.XPathSelectElement("/default:ROOT/default:ELM_1", nsMgr);
elm1.Add(new XElement("default:ELM_1_SUB_2", "ADDED TO DEFAULT NAMESPACE"));
var elm2 = xDoc.XPathSelectElement("/default:ROOT/customNs:ELM_2", nsMgr);
elm2.Add(new XElement("customNs:ELM_2_SUB_2", "ADDED TO CUSTOM NAMESPACE"));
The above code does select the elements I want to add to with no issue but the Add throws an XmlException: The ':' character, hexadecimal value 0x3A, cannot be included in a name..
When I try without the namespace provided in the element name I don't get an error but it doesn't do what I want.
So this:
var elm1 = xDoc.XPathSelectElement("/default:ROOT/default:ELM_1", nsMgr);
elm1.Add(new XElement("ELM_1_SUB_2", "ADDED TO DEFAULT NAMESPACE"));
Results in this:
<ROOT xmlns="http://www.mismo.org/residential/2009/schemas" xmlns:customNs="http://custom.org">
<ELM_1>
<ELM_1_SUB_1>Some value</ELM_1_SUB_1>
<ELM_1_SUB_2 xmlns="">ADDED TO DEFAULT NAMESPACE</ELM_1_SUB_2>
</ELM_1>
<customNs:ELM_2>
<customNs:ELM_2_SUB_1>Another value</customNs:ELM_2_SUB_1>
</customNs:ELM_2>
</ROOT>
What am I missing to create the desired XML output?
Create XNamespace types with the desired values.
Use them when creating an XElement.
XNamespace defaultNs = "http://www.mismo.org/residential/2009/schemas";
XNamespace customNs = "http://custom.org";
elm1.Add(new XElement(defaultNs + "ELM_1_SUB_2", "ADDED TO DEFAULT NAMESPACE"));
elm2.Add(new XElement(customNs + "ELM_2_SUB_2", "ADDED TO CUSTOM NAMESPACE"));

Getting XML node using XPath returns null

I am trying to get a node in a simple XML, but no matter what I try I always get null.
I am guessing that the issue is the namespace.
I am simply trying to get the value of the ID element, 331377697.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("E:\\0323.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace("cac", "http://xxxxxx Some URL XXXX");
manager.AddNamespace("cbc", "http://xxxxxx Some URL XXXX");
string query = "/StandardBusinessDocument/Invoice/cbc:ID";
XmlNode xmlNode = xmlDoc.SelectSingleNode(query, manager);
The XML:
<StandardBusinessDocument xmlns="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader">
<StandardBusinessDocumentHeader>
...
</StandardBusinessDocumentHeader>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ccts="urn:un:unece:uncefact:documentation:2"
...
</Invoice>
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>1234</cbc:CustomizationID>
<cbc:ProfileID>1234564</cbc:ProfileID>
<cbc:ID>331377697</cbc:ID>
<cbc:IssueDate>2017-03-23</cbc:IssueDate>
<cbc:InvoiceTypeCode listID="UNCL1001">380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode listID="ISO4217">NOK</cbc:DocumentCurrencyCode>
<cac:OrderReference>
<cbc:ID>146136</cbc:ID>
</cac:OrderReference>
...
You must specify the exact namespaces.
Also you have to specify namespace prefixes for all elements in the XPath.
manager.AddNamespace("nsDoc", "http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader");
manager.AddNamespace("nsInvoice", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
manager.AddNamespace("cbc", "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2");
string query = "/nsDoc:StandardBusinessDocument/nsInvoice:Invoice/cbc:ID";
It's supposed to work.

Can't find a certain node in XML

My problem is that I can't seem to get a list of nodes I need. I have tried multiple solutions and it doesn't seem to work. This is a part of my xml file:
<findItemsByCategoryResponse xmlns="http://www.ebay.com/marketplace/search/v1/services">
<ack>Success</ack>
<version>1.13.0</version>
<timestamp>2016-08-23T07:33:22.497Z</timestamp>
<searchResult count="100">
<item>
<itemId>152210133431</itemId>
<title>...</title>
<globalId>EBAY-GB</globalId>
<primaryCategory>
<categoryId>218</categoryId>
<categoryName>Magic the Gathering</categoryName>
</primaryCategory>
<galleryURL>
http://thumbs4.ebaystatic.com/m/meIDrVqhmbpQMYCxzeUvR9Q/140.jpg
</galleryURL>
<viewItemURL>
http://www.ebay.co.uk/itm/MTG-See-Unwritten-Khans-Tarkir-MYTHIC-MINT-/152210133431
</viewItemURL>
<paymentMethod>PayPal</paymentMethod>
<autoPay>false</autoPay>
<location>London,United Kingdom</location>
<country>GB</country>
<shippingInfo>
<shippingServiceCost currencyId="GBP">1.1</shippingServiceCost>
<shippingType>Flat</shippingType>
<shipToLocations>GB</shipToLocations>
</shippingInfo>
<sellingStatus>
<currentPrice currencyId="GBP">0.5</currentPrice>
<convertedCurrentPrice currencyId="GBP">0.5</convertedCurrentPrice>
<bidCount>0</bidCount>
<sellingState>Active</sellingState>
<timeLeft>P0DT0H19M12S</timeLeft>
</sellingStatus>
<listingInfo>
<bestOfferEnabled>false</bestOfferEnabled>
<buyItNowAvailable>false</buyItNowAvailable>
<startTime>2016-08-18T07:52:34.000Z</startTime>
<endTime>2016-08-23T07:52:34.000Z</endTime>
<listingType>Auction</listingType>
<gift>false</gift>
</listingInfo>
<condition>
<conditionId>1000</conditionId>
<conditionDisplayName>New</conditionDisplayName>
</condition>
<isMultiVariationListing>false</isMultiVariationListing>
<topRatedListing>false</topRatedListing>
</item>
</searchResult>
<paginationOutput>...</paginationOutput>
<itemSearchURL>...</itemSearchURL>
</findItemsByCategoryResponse>
Normally there are 100 item nodes in this xml file, I just shorted the file. I tried to get the ''item'' nodes and everything inside in a XmlNodeList, but when I debug it says it contains 0 items. After this I want to retrieve some data, as you can see in the code. Note: I tried a lot of xpath values!
Here is the code I used:
XmlDocument xmlText = new XmlDocument();
xmlText.Load(basicUrl);
XmlElement root = xmlText.DocumentElement;
XmlNodeList xnList = root.SelectNodes("//item");
foreach(XmlNode item in xnList)
{
string title = item["title"].InnerText;
Console.WriteLine(title);
}
XPath Expressions are always namespace aware (if the Element has a Namespace then the XPath must reference it by namespace). Also, in XPath expressions, the 'default' namespace is always in the URI "". In your case you should do something like this :
XmlDocument xmlText = new XmlDocument();
xmlText.Load(yourXml);
XmlElement root = xmlText.DocumentElement;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlText.NameTable);
nsmgr.AddNamespace("t", "http://www.ebay.com/marketplace/search/v1/services");
XmlNodeList xnList = xmlText.SelectNodes("//t:item", nsmgr);
foreach (XmlNode item in xnList)
{
string title = item["title"].InnerText;
Console.WriteLine(title);
}
SelectNodes with namespace :
https://msdn.microsoft.com/en-US/library/4bektfx9(v=vs.110).aspx

C#: Read XML Attribute

Using C#2.0 and VIsualStudio2005
I'm trying to access the "DisplayName" inside "MonitorResponseRecord"
from an XML file like the one Below:
<Magellan xsi:schemaLocation="http://tempuri.org/XMLSchema.xsd ..\Schema\Configuration.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
<SchemaVersion>1.0</SchemaVersion>
<MonitorScope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="CleanStationChemicalManifoldFeed5" xmlns="http://tempuri.org/XMLSchema.xsd">
<PersonalSafety>
<MonitorResponseRecord Enabled="true" DisplayName="ChemicalManifoldFeed5ControllerFault">
<ExpressionMonitor>
<Expression>(ChemicalManifold.Feed5.DispenseValve = Open) and ((ChemicalManifold.Feed5.ViolatedRegion = HighProcess) or (ChemicalManifold.Feed5.ViolatedRegion = LowProcess) or (ChemicalManifold.Feed5.ViolatedRegion = Minimum))</Expression>
<TestInterval>0.1</TestInterval>
<MinimumTimeBetweenResponses>5</MinimumTimeBetweenResponses>
</ExpressionMonitor>
<Response>
<PostAlarm>
<AlarmName>ChemicalManifold_Feed5_ControllerFault</AlarmName>
<Parameter1 />
<Parameter2>Alarm Region = {ChemicalManifold.Feed5.ViolatedRegion}</Parameter2>
<Parameter3>{RecipeName}-{StepName}</Parameter3>
<Parameter4>FlowSetpoint = {ChemicalManifold.Feed5.Setpoint}-LPM, ActualFlow = {ChemicalManifold.Feed5.FlowMeter}-LPM</Parameter4>
</PostAlarm>
<ResponseEvent>
<TargetResource />
<Event>PA</Event>
<Reason>ChemicalSupply</Reason>
</ResponseEvent>
</Response>
</MonitorResponseRecord>
</PersonalSafety>
<PersonalSafety>
<MonitorResponseRecord Enabled="true" DisplayName = "PressureValveFailure">
...
...
...and soon
My current C# attempt is as follows, BUT it always hangs up when I try to XmlDocument.Load("");
XmlDocument doc = new XmlDocument();
doc.Load("../UMC0009.Configuration.Root.xml");
string attrVal = doc.SelectSingleNode("MonitorResponseRecord/#DisplayName").Value;
BUUUUT won't work :/ any help out there?
UPDATE:
the exception I recieve is as follows, and occures at the doc.Load("...") line:
{"Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function."} System.Exception {System.Xml.XPath.XPathException}
Your XPath query will be relative to the document root:
doc.SelectSingleNode("MonitorResponseRecord/#DisplayName")
To make it search anywhere in the doc prefix it with double slash:
doc.SelectSingleNode("//MonitorResponseRecord/#DisplayName")
If that still doesn't work I would try the above example after stripping out all those namespace declarations on the two root nodes.
Otherwise, with the namespace declarations you may find you need to define XML namespace mappings and use prefixes in your XPath like:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("x", "http://tempuri.org/XMLSchema.xsd");
doc.SelectSingleNode("//x:MonitorResponseRecord/#DisplayName")
What about:
XmlDocument doc = new XmlDocument();
doc.Load("UMC0009.Configuration.Root.xml");
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("ns", "http://tempuri.org/XMLSchema.xsd");
string attrVal = doc.SelectSingleNode("//ns:MonitorResponseRecord/#DisplayName", nsmgr).Value;
Using a namespace manager, specify your namespace URI and use it in your XPath.
It works for me.

XPath doesn't work as desired in C#

My code doesn't return the node
XmlDocument xml = new XmlDocument();
xml.InnerXml = text;
XmlNode node_ = xml.SelectSingleNode(node);
return node_.InnerText; // node_ = null !
I'm pretty sure my XML and Xpath are correct.
My Xpath : /ItemLookupResponse/OperationRequest/RequestId
My XML :
<?xml version="1.0"?>
<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
<OperationRequest>
<RequestId>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx</RequestId>
<!-- the rest of the xml is irrelevant -->
</OperationRequest>
</ItemLookupResponse>
The node my XPath returns is always null for some reason. Can someone help?
Your XPath is almost correct - it just doesn't take into account the default XML namespace on the root node!
<ItemLookupResponse
xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
*** you need to respect this namespace ***
You need to take that into account and change your code like this:
XmlDocument xml = new XmlDocument();
xml.InnerXml = text;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
nsmgr.AddNamespace("x", "http://webservices.amazon.com/AWSECommerceService/2005-10-05");
XmlNode node_ = xml.SelectSingleNode(node, nsmgr);
And then your XPath ought to be:
/x:ItemLookupResponse/x:OperationRequest/x:RequestId
Now, your node_.InnerText should definitely not be NULL anymore!
Sorry for the late reply but I had a similar problem just a moment ago.
if you REALLY want to ignore that namespace then just delete it from the string you use to initialise the XmlDocument
text=text.Replace(
"<ItemLookupResponse xmlns=\"http://webservices.amazon.com/AWSECommerceService/2005-10-05\">",
"<ItemLookupResponse>");
XmlDocument xml = new XmlDocument();
xml.InnerXml = text;
XmlNode node_ = xml.SelectSingleNode(node);
return node_.InnerText;

Categories

Resources