XElement null when attributes exist - xelement

Given the following xml:
<root xmlns="http://tempuri.org/myxsd.xsd">
<node name="mynode" value="myvalue" />
</root>
And given the following code:
string file = "myfile.xml"; //Contains the xml from above
XDocument document = XDocument.Load(file);
XElement root = document.Element("root");
if (root == null)
{
throw new FormatException("Couldn't find root element 'parameters'.");
}
If the root element contains the xmlns attribute then the variable root is null. If I remove the xmlns attribute then root is NOT null.
Can anyone explain why this is?

When you declare your root element like <root xmlns="http://tempuri.org/myxsd.xsd"> this means that your root element all of its descendants are in http://tempuri.org/myxsd.xsd namespace. By default namespace of an element has an empty namespace and XDocument.Element looks for elements without namespace. If you want to access an element with a namespace you should explicitly specify the namespace.
var xdoc = XDocument.Parse(
"<root>" +
"<child0><child01>Value0</child01></child0>" +
"<child1 xmlns=\"http://www.namespace1.com\"><child11>Value1</child11></child1>" +
"<ns2:child2 xmlns:ns2=\"http://www.namespace2.com\"><child21>Value2</child21></ns2:child2>" +
"</root>");
var ns1 = XNamespace.Get("http://www.namespace1.com");
var ns2 = XNamespace.Get("http://www.namespace2.com");
Console.WriteLine(xdoc.Element("root")
.Element("child0")
.Element("child01").Value); // Value0
Console.WriteLine(xdoc.Element("root")
.Element(ns1 + "child1")
.Element(ns1 + "child11").Value); // Value1
Console.WriteLine(xdoc.Element("root")
.Element(ns2 + "child2")
.Element("child21").Value); // Value2
For your case
var ns = XNamespace.Get("http://tempuri.org/myxsd.xsd");
xdoc.Element(ns + "root").Element(ns + "node").Attribute("name")

Related

IGrouping does not contain a definition for Sum

Would anyone have an idea what's up here? I'm loading an XML file, parsing it and using LINQ to get some summary info. Here's the XML document:
<?xml version="1.0" encoding="utf-8"?>
<root>
<Ticker>
<Name>MSFT</Name>
<PurchaseDate>
2009-01-01
</PurchaseDate>
<Shares>44</Shares>
</Ticker>
<Ticker>
<Name>MSFT</Name>
<PurchaseDate>
2009-03-01
</PurchaseDate>
<Shares>33</Shares>
</Ticker>
<Ticker>
<Name>GOOG</Name>
<PurchaseDate>
2009-03-01
</PurchaseDate>
<Shares>122</Shares>
</Ticker>
<Ticker>
<Name>AAPL</Name>
<PurchaseDate>
2019-03-01
</PurchaseDate>
<Shares>89</Shares>
</Ticker>
</root>
My code:
var xmlStr = File.ReadAllText("ClientInfo.xml");
var Summary = XElement.Parse(xmlStr);
var data = from acct in Summary.Elements("Ticker")
select new
{
Ticker = (string)acct.Element("Name"),
Shares = (int)acct.Element("Shares")
};
var groupedDataByTicker = from acct in data
group acct by acct.Ticker into g
select new
{
Ticker = g.Key,
Shares = g.Sum(),
};
Works fine but when I add the g.Sum() bit I get this message:
'IGrouping>' does not contain a definition for 'Sum' and the best extension method overload 'Queryable.Sum(IQueryable)' requires a receiver of type 'IQueryable'
I can't make sense of it, what am I doing wrong?
In your code, you are trying to find the sum of the group itself.
Instead, you should be summing by the Shares property:
var groupedDataByTicker = from acct in data
group acct by acct.Ticker into g
select new
{
Ticker = g.Key,
Shares = g.Sum(row => row.Shares),
};

How to treat node that has no text?

There is an xml :
<mgns1:Champ_supplementaire>
<mgns1:CODE_CS>3</mgns1:CODE_CS>
<mgns1:VALEUR_CS />
</mgns1:Champ_supplementaire>
When trying to get :
NodeList nodeliste_cs3 = (NodeList) xpath.evaluate( "//mgns1:Champ_supplementaire[mgns1:CODE_CS=3]/mgns1:VALEUR_CS",doc, XPathConstants.NODESET);
...
Node node_cs3 = nodeliste_cs3.item(i);
list.add(node_cs3.getTextContent() + ";");
I get NullPointerException ! So how to deal with node with no text ?
You can explicitly add predicate to specify that you want to select node only if it contains text:
...mgns1:VALEUR_CS[normalize-space()]

python+selenium xpath Unable to locate element

company_name = 'google'
browser.get('https://m.tianyancha.com/search?key=&checkFrom=searchBox')
ele = browser.find_element_by_xpath("//input[#id='live-search']")
ele.clear()
ele.send_keys(company_name, Keys.ENTER)
name = browser.find_element_by_xpath(
"//div[#class='new-border-bottom pt5 pb5 ml15 mr15'][1]//a[#class='query_name in-block']/span/em")
if name.text:
if name.text == company_name:
check = '1'
else:
check = '0'
else:
check = '0'
the error is :
NoSuchElementException: Message: no such element: Unable to locate
element: {"method":"xpath","selector":"//div[#class='new-border-bottom
pt5 pb5 ml15 mr15'][1]//a[#class='query_name in-block']/span/em"}
Your relative Xpath is wrong.
name = browser.find_element_by_xpath(
"//div[#class='new-border-bottom pt5 pb5 ml15 mr15'][1]//a[#class='query_name in-block']/span/em"
you cannot have // two times in your xpath. // means relative from the element you start with.
Check your Xpath for name.

Changing node values in XML using VBS with similar names

I am facing this challenge with changing values of nodes in an xml file which has same names, using VBScript. Following is the sample XML:
- <MappingData>
<Name>Name 1</Name>
- <ValueField FieldName="Name 2">
<CharValue>Value 1</CharValue>
</ValueField>
- <ValueField FieldName="Name 3">
<CharValue>Value 1</CharValue>
</ValueField>
My requirement is to change the values of both occurrences of tag
<CharValue>
.
I could have done this if there was any attribute in these tags, but in this case I am stuck.
I tried the following code, but could'nt get what I need.
Set NodeList = objXMLDoc.documentElement.selectNodes("//MappingData/ValueField/CharValue")
For i = 0 To NodeList.length - 1
node.Text = "Value 1"
Next
Any help is appreciated. Thanks.
Try the following code
Set xDoc = CreateObject( "Msxml2.DOMDocument.6.0" )
xDoc.setProperty "SelectionLanguage", "XPath"
xDoc.async = False
xDoc.load "test.xml"
Set nNodes = xDoc.selectNodes("//MappingData/ValueField/CharValue")
For i = 0 To nNodes.Length - 1
nNodes(i).text = "Changed value " & i
Next
xDoc.Save "test.xml"

Retrieve the value of a XML attribute in VBS

<Requirement Description="description" Operation="Configure">
<Action ID="1000" Name="Split">
<Contract>
<Parameter Name="Version">4</Parameter>
<Parameter Name="DefaultServer">192.168.00.</Parameter>
<Parameter Name="DefaultUser">administrator</Parameter>
<Parameter Name="DefaultPassword">password</Parameter>
<Parameter Name="DefaultDomain">192.168.00.00</Parameter>
<Parameter Name="Split">1</Parameter>
</Contract>
</Action>
</Requirement>
From the above XML document my aim is to replace the IP address for both the attributes default server and default domain from a VBScript.
Set objXMLDoc = CreateObject("Microsoft.XMLDOM")
objXMLDoc.async = False
objXMLDoc.load(XMLFullPath)
Set NodeList = objXMLDoc.documentElement.SelectNodes("//Parameter")
NodeList(i).nodeName
Give name as Parameter and NodeList(i).Text gives me values like 4, IP address, administrator and others. But I am not able to get the attribute name so that I can directly change the value of the attribute.
To answer your question, you can use the getAttribute function to access an attribute's value:
NodeList(i).getAttribute("Name")
You can also add a predicate to the XPath expression in your SelectNodes call to retrieve only the desired elements:
Set NodeList = objXMLDoc.documentElement.SelectNodes("//Parameter[#Name = 'DefaultServer' or #Name = 'DefaultDomain']")
This way, you don't have to retrieve and loop through the Parameter nodes that you're not interested in.
A bit rusty, but I think you can use this to retrieve the nodevalue by nodename:
Function getTag(nList, nName)
Dim i
i = 0
Do while i < nList.childNodes.length
if (nList.childNodes(i).nodeName = nName) then
getTag = nList.childNodes(i).childNodes(0).text
Exit Function
end if
i = i + 1
Loop
End Function
And to set it, probably
Sub setTag(nList, nName, val)
Dim i
i = 0
Do while i < nList.childNodes.length
if (nList.childNodes(i).nodeName = nName) then
nList.childNodes(i).childNodes(0).text = val
Exit Sub
end if
i = i + 1
Loop
End Sub

Resources