Returning List<string> from XDocument - linq

<dataList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<headers>
<header>Template name</header>
</headers>
<rows>
<row>
<data>Template1</data>
</row>
<row>
<data>Template2</data>
</row>
</rows>
</dataList>
XDocument xml = new XDocument();
xml = XDocument.Parse(xmlstringFromAbove);
List<string> list = (from c in xml.Elements("data")
select c.Value).ToList();
This code returns an empty list.
How can I get a list of strings containing Template1 and Template2 ?

The Elements method only returns immediate children, use Descendants instead:
var xml = XDocument.Parse(xmlstringFromAbove);
var list = (from c in xml.Descendants("data") select c.Value).ToList();

Related

xpath to pull nodes based on element partial match

On the below xml snip i'd like to pull row nodes for different batches which is essentially a time stamp, i.e., JP1800 stands for Japan 18 o'clock time.
//*[Batch='LN12000'] pulls all London noon nodes while
data/row pulls all of them including empty Batch values.
How would I pull all London times as //*[Batch='LN'*] does not work?
<?xml version="1.0"?>
-<data>
+<header>
+<row>
+<row>
+<row>
-<row>
<Date>2019-10-21</Date>
<Series>23</Series>
<OnTheRun>N</OnTheRun>
<Depth>0</Depth>
<Batch>JP1700</Batch>
</row>
-<row>
<Date>2019-10-21</Date>
<Series>23</Series>
<OnTheRun>N</OnTheRun>
<Depth>4</Depth>
<Batch>JP1800</Batch>
</row>
It sounds like you're looking for something like starts-with function. :
//header/row/Batch[starts-with(.,"LN")]
And here we have some PHP code exemple, look:
<?php
$xml = <<<XML
<?xml version="1.0"?>
<data>
<header>
<row>
<Date>2019-10-21</Date>
<Series>23</Series>
<OnTheRun>N</OnTheRun>
<Depth>0</Depth>
<Batch>JP1700</Batch>
</row>
<row>
<Date>2019-02-05</Date>
<Series>27</Series>
<OnTheRun>X</OnTheRun>
<Depth>89</Depth>
<Batch>LN9877</Batch>
</row>
</header>
</data>
XML;
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$query = $xpath->query('//header/row/Batch[starts-with(.,"LN")]');
/** #var DOMElement $node */
foreach ($query as $node) {
print($node->nodeValue); //outputs LN9877
}
https://www.w3.org/TR/1999/REC-xpath-19991116/#function-starts-with

XPath: return first met child which has specific attribute

Have following hierarchy:
Parent1
--> child1(#name = 'abc')
--> child2(#name = 'xyz')
--> child3(#name = 'qqq')
Parent2
--> child1
--> child2(#name = 'yui')
XPath which returns following nodes needed:
child1 from Parent1
and
child2 from Parent2
the rule is following:
return first occurred child only which has specific attribute, in this case #name
note:
first() and [1] doesn't work
The following xpath:
/root/node()/node()[#name][position()=1]
With this XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<parent1>
<child1 name="abc"></child1>
<child2 name="xyz"></child2>
<child3 name="qqq"></child3>
</parent1>
<parent2>
<child1></child1>
<child2 name="yui"></child2>
</parent2>
</root>
Returns:
Element='<child1 name="abc" />'
Element='<child2 name="yui" />'

JAXB Moxy getValueByXpath gives null

I want to see if a theme element exists with specified name in the following xml file.
input.xml
<data>
<artifacts>
<document id="efqw4eads">
<name>composite</name>
</document>
<theme id="1">
<name>Terrace</name>
</theme>
<theme id="2">
<name>Garage</name>
</theme>
<theme id="3">
<name>Reception</name>
</theme>
<theme id="4">
<name>Grade II</name>
</theme>
</artifacts>
</data>
I have the following code. return true statement of the method is never executed. answer always contains a null value.
public boolean themeExists(String name, Data data){
String expression = "artifacts/theme[name='"+name+"']/name/text()";
String answer = jaxbContext.getValueByXPath(data, expression, null, String.class);
if(answer == null || answer.equals("")){
return false;
}
return true;
}
This use case isn't currently supported by EclipseLink JAXB (MOXy). I have opened the following enhancement you can use to track our progress:
http://bugs.eclipse.org/413823
There is no <artifacts/> element you're look for in the first axis step. Your XPath expression should be something like
String expression = "data/theme[name='"+name+"']/name/text()";

Can't get XPathSelectElements to work with XElement

I am creating an in-memory Xml tree using XElement. Here is a sample of my xml:
<Curve>
<Function>createCurve</Function>
<Parameters>
<Input>
<BaseCurve>
<CurveType Type="String">16fSmoothCurve</CurveType>
<Ccy Type="String">USD</Ccy>
<Tenors>
<Item Type="String">1M</Item>
<Item Type="String">3M</Item>
<Item Type="String">1U</Item>
<Item Type="String">Z1</Item>
</Tenors>
<Rates>
<Item Type="String">.02123</Item>
<Item Type="String">.02214</Item>
<Item Type="String">.021234</Item>
<Item Type="String">.02674</Item>
</Rates>
</BaseCurve>
</Input>
</Parameters>
</Curve>
I am creating the xml by chaining together XElements. For example,
var root = new XElement("Curve",
new XElement("Function", "createCurve"),
new XElement("Parameters"), etc);
I would then like to query the XElement via XPath. For example,
var tenors = root.XPathSelectElements("//Tenors/Item");
var rates = root.XPathSelectElements("//Rates/Item");
I can successfully select a single element, for example,
var firstTenor = root.XPathSelectElement("//Tenors/Item");
var firstRate = root.XPathSelectElement("//Rates/Item");
However, trying to select multiple elements give me 0 results.
I've tried creating an XDocument and querying off of that however I get the same results. I've also tried adding an XDeclaration to the beginning of the tree but no luck.
Why can I not query multiple elements from my XElement tree?
Thanks!
Drew
Use XmlNodeList:
XmlNodeList nodesXml = root.SelectNodes("//Tenors/Item");
foreach (XmlNode item in nodList)
{
var tenors = item.InnerText;
}
That what I do, and it works perfect.

how to select all desendent from xmlfile

I have the following XML snippet:
<dependency>
<dependentAssembly dependencyType="install" allowDelayedBinding="true" size="92160">
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>CPxsdsbvZSAAkmARkxa8ychL2aLZRc=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
How to select this node using LINQ, or all decendent nodes for it:
<dsig:Transforms>
Thanks.
XDocument.Load("file.xml").Root.Descendants(XName.Get("dsig", "Transforms"));
Something like this should work:
XElement docElem = XElement.Load(pathToXml);
XNamespace ns = "http://www.w3.org/2000/09/xmldsig#";
// This assumes you know there will be exactly one "Transforms" element
XElement transforms = docElem.Descendants(ns + "Transforms").Single();
foreach (XElement transform in transforms.Elements()) {
// Do something with each Transform element
}
For this to work the complete XML (with namespace prefix declarations) must be loaded.

Resources