英文:
XmlDocument Parse scientific notation in xpath attribute value to a number
问题
我有一个XML文件,其中的值以科学计数法保存,我需要对这个值进行一些比较。但是科学计数法的数字不按预期工作。
下面是我的代码:
XmlDocument doc = new XmlDocument();
doc.LoadXml("<MainLevel><SubLevel Name=\"test\" Amount=\"0.0E0\"></SubLevel></MainLevel>");
XmlNodeList? xmlLevelsList1 = doc.SelectNodes("MainLevel/SubLevel[@Amount<=275.00]"); // 这不返回任何内容,因为0.0E0是科学计数法
doc.LoadXml("<MainLevel><SubLevel Name=\"test\" Amount=\"0.00\"></SubLevel></MainLevel>");
XmlNodeList? xmlLevelsList2 = doc.SelectNodes("MainLevel/SubLevel[@Amount<=275.00]"); // 这不返回任何内容,因为0.00是正确的格式
我希望xmlLevelsList1
返回1个节点,而不是0。它返回0是因为
"0.0E0" 不是有效的数字。
英文:
I have XML where the values are saved in scientific notation and I need to preform some comparisons on that value . But the scientific notation numbers are not working as expected.
Below is the code I have:
XmlDocument doc = new XmlDocument();
doc.LoadXml("<MainLevel><SubLevel Name=\"test\" Amount=\"0.0E0\"></SubLevel></MainLevel>");
XmlNodeList? xmlLevelsList1 = doc.SelectNodes("MainLevel/SubLevel[@Amount<=275.00]");// this does not return anything because 0.0E0 is in scientific notation
doc.LoadXml("<MainLevel><SubLevel Name=\"test\" Amount=\"0.00\"></SubLevel></MainLevel>");
XmlNodeList? xmlLevelsList2 = doc.SelectNodes("MainLevel/SubLevel[@Amount<=275.00]"); this does not return anything because 0.00 is a good format
I want xmlLevelsList1
to return 1 node instead of 0. It is returning 0 because
> "0.0E0" is not a valid number.
答案1
得分: 1
以下是翻译好的内容:
最好使用 *LINQ to XML* API。它自2007年以来就可在.Net Framework中使用。
正如 @zx485 已经指出的:*"XSLT 1.0不支持科学计数法。"*
因此,我们无法使用XPath表达式。
在.Net方面将其转换为 **double** 数据类型即可完成任务。
**c#**
void Main()
{
XDocument doc = XDocument.Parse(@"<MainLevel>
<SubLevel Name='test' Amount='0.0E0'></SubLevel>
<SubLevel Name='test1' Amount='10.0E1'></SubLevel>
<SubLevel Name='test1' Amount='4.0E5'></SubLevel>
<SubLevel Name='test1' Amount='2.75E2'></SubLevel>
<SubLevel Name='test1' Amount='2.76E2'></SubLevel>
</MainLevel>");
var xmlLevelsList1 = doc.Descendants("SubLevel")
.Where(d => double.Parse(d.Attribute("Amount").Value) <= 275.00);
Console.WriteLine(xmlLevelsList1);
}
**Output**
<SubLevel Name="test" Amount="0.0E0"></SubLevel>
<SubLevel Name="test1" Amount="10.0E1"></SubLevel>
<SubLevel Name="test1" Amount="2.75E2"></SubLevel>
英文:
It is better to use LINQ to XML API. It is available in the .Net Framework since 2007.
As @zx485 already pointed out: "XSLT 1.0 does not have support for scientific notation."
So, we cannot use an XPath expression.
Converting to a double data type on the .Net side does the job.
c#
void Main()
{
XDocument doc = XDocument.Parse(@"<MainLevel>
<SubLevel Name='test' Amount='0.0E0'></SubLevel>
<SubLevel Name='test1' Amount='10.0E1'></SubLevel>
<SubLevel Name='test1' Amount='4.0E5'></SubLevel>
<SubLevel Name='test1' Amount='2.75E2'></SubLevel>
<SubLevel Name='test1' Amount='2.76E2'></SubLevel>
</MainLevel>");
var xmlLevelsList1 = doc.Descendants("SubLevel")
.Where(d => double.Parse(d.Attribute("Amount").Value) <= 275.00);
Console.WriteLine(xmlLevelsList1);
}
Output
<SubLevel Name="test" Amount="0.0E0"></SubLevel>
<SubLevel Name="test1" Amount="10.0E1"></SubLevel>
<SubLevel Name="test1" Amount="2.75E2"></SubLevel>
答案2
得分: 0
The number()
function can be used in XPath 1.0
/MainLevel/SubLevel[number(@Amount) <= 275.00]
Given
<?xml version="1.0" encoding="utf-8" ?>
<MainLevel>
<SubLevel Name="test" Amount="0.0E0"></SubLevel>
<SubLevel Name="test1" Amount="10.0E1"></SubLevel>
<SubLevel Name="test1" Amount="4.0E5"></SubLevel>
<SubLevel Name="test1" Amount="2.75E2"></SubLevel>
<SubLevel Name="test1" Amount="2.76E2"></SubLevel>
</MainLevel>
Will return
<SubLevel Name="test" Amount="0.0E0"/>
<SubLevel Name="test1" Amount="10.0E1"/>
<SubLevel Name="test1" Amount="2.75E2"/>
Tested with xmllint
that uses libxml2
xmllint --xpath '/MainLevel/SubLevel[number(@Amount) <= 275.00]' tmp.xml
<SubLevel Name="test" Amount="0.0E0"/>
<SubLevel Name="test1" Amount="10.0E1"/>
<SubLevel Name="test1" Amount="2.75E2"/>
Testing with python lxml
from lxml import etree
tree = etree.parse("tmp.xml")
[e.get('Amount') for e in tree.xpath('/MainLevel/SubLevel[number(@Amount) <= 275.00]')]
['0.0E0', '10.0E1', '2.75E2']
英文:
The number()
function can be used in XPath 1.0
/MainLevel/SubLevel[number(@Amount) <= 275.00]
Given
<?xml version="1.0" encoding="utf-8" ?>
<MainLevel>
<SubLevel Name="test" Amount="0.0E0"></SubLevel>
<SubLevel Name="test1" Amount="10.0E1"></SubLevel>
<SubLevel Name="test1" Amount="4.0E5"></SubLevel>
<SubLevel Name="test1" Amount="2.75E2"></SubLevel>
<SubLevel Name="test1" Amount="2.76E2"></SubLevel>
</MainLevel>
Will return
<SubLevel Name="test" Amount="0.0E0"/>
<SubLevel Name="test1" Amount="10.0E1"/>
<SubLevel Name="test1" Amount="2.75E2"/>
Tested with xmllint
that uses libxml2
xmllint --xpath '/MainLevel/SubLevel[number(@Amount) <= 275.00]' tmp.xml
<SubLevel Name="test" Amount="0.0E0"/>
<SubLevel Name="test1" Amount="10.0E1"/>
<SubLevel Name="test1" Amount="2.75E2"/>
Testing with python lxml
from lxml import etree
tree = etree.parse("tmp.xml")
[e.get('Amount') for e in tree.xpath('/MainLevel/SubLevel[number(@Amount) <= 275.00]')]
['0.0E0', '10.0E1', '2.75E2']
答案3
得分: 0
使用Saxon.NET:
using System.Xml;
using Saxon.Api;
XmlDocument doc = new XmlDocument();
doc.LoadXml("<MainLevel><SubLevel Name=\"test\" Amount=\"0.0E0\"></SubLevel></MainLevel>");
XmlNodeList? xmlLevelsList1 = doc.SelectNodes("MainLevel/SubLevel[@Amount<=275.00]");// 因为0.0E0采用科学计数法,所以这里没有返回任何内容
Console.WriteLine(xmlLevelsList1.Count);
Processor processor = new Processor();
var docBuilder = processor.NewDocumentBuilder();
var xdmDoc = docBuilder.Wrap(doc);
var xpathCompiler = processor.NewXPathCompiler();
var xdmResult = xpathCompiler.Evaluate("MainLevel/SubLevel[@Amount<=275.00]", xdmDoc);
Console.WriteLine(xdmResult.Count);
Output:
0
1
请注意,虽然您可以对Microsoft DOM(即XmlDocument/XmlNode)运行XPath 3.1,但Saxon有自己的树模型,建议只在无法切换到Saxon的本机树模型的遗留代码中使用Microsoft DOM。
英文:
Using Saxon.NET:
using System.Xml;
using Saxon.Api;
XmlDocument doc = new XmlDocument();
doc.LoadXml("<MainLevel><SubLevel Name=\"test\" Amount=\"0.0E0\"></SubLevel></MainLevel>");
XmlNodeList? xmlLevelsList1 = doc.SelectNodes("MainLevel/SubLevel[@Amount<=275.00]");// this does not return anything because 0.0E0 is in scientific notation
Console.WriteLine(xmlLevelsList1.Count);
Processor processor = new Processor();
var docBuilder = processor.NewDocumentBuilder();
var xdmDoc = docBuilder.Wrap(doc);
var xpathCompiler = processor.NewXPathCompiler();
var xdmResult = xpathCompiler.Evaluate("MainLevel/SubLevel[@Amount<=275.00]", xdmDoc);
Console.WriteLine(xdmResult.Count);
Output:
0
1
Do note that, while you can run XPath 3.1 against the Microsoft DOM (i.e. XmlDocument/XmlNode) that Saxon has its own tree model and it is recommended to only use the Microsoft DOM if you have legacy code where you can't switch to Saxon's native tree model.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论