I have a file with the following content (myfile.xml). I have to get all content coming under (including product node) a product with id=1.
<products>
<product id="1">
<category>q</category>
</product>
<product id="2">
<category>w</category>
</product>
<product id="3">
<category>e</category>
</product>
</products>`
i.e. the result should be :
<product id="1">
<category>q</category>
</product>
How can I do this?
using XPath in Linq
var root = XElement.Load("myfile.xml");
root.XPathSelectElements( "/products/product[#id=1]");
var root = XElement.Load("path to the file");
var node = root.Descendants("product").FirstOrDefault(e=>e.Attribute("id").Value == "1");
Related
<document>
<element>
<attribut a:name="my-name">My Name</attribut>
<attribut a:parent="parent1">Parent 1</attribut>
</element>
</document>
In this XML document, how to select the node which has the attribut a:name ?
$xmlTest = <<<XML
<?xml version="1.0" encoding="UTF-8" ?>
<document xmlns:a="http://example.org/a">
<element>
<attribut a:name="my-name">My Name</attribut>
<attribut a:parent="parent1">Parent 1</attribut>
</element>
</document>
XML;
$xml = new SimpleXMLElement($xmlTest);
echo current($xml->xpath('//element/attribut[#a:name]'));
I have the following code for generating a xml from a rabl template:
obj = OpenStruct.new
obj.categories = [{node: ["Foo","Bar"]},{node: ["Test1","Test2"]}]
Rabl::Renderer.xml(obj, 'adapter_xml')
and this is the rabl template adapter_xml.rabl
object #obj => :root
attributes :categories
which generates this XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<categories>
<category>
<node>
<node>Foo</node>
<node>Bar</node>
</node>
</category>
<category>
<node>
<node>Test1</node>
<node>Test2</node>
</node>
</category>
</categories>
</root>
But what I want to achieve is the following format, without the extra <node> tags:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<categories>
<category>
<node>Foo</node>
<node>Bar</node>
</category>
<category>
<node>Test1</node>
<node>Test2</node>
</category>
</categories>
</root>
Is there any way to do this with rabl? Or do I have to modify the ruby code mentioned first?
If ancestor nodes defines namespaces, I can use them:
> Nokogiri::XML(<<-XML
<?xml version='1.0' encoding='UTF-8'?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="bookid">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:creator opf:role="aut">John Doe</dc:creator>
</metadata>
</package>
XML
> xml.at_xpath("//dc:creator[#opf:role='aut']", xml.at_xpath("//xmlns:metadata").namespaces).text
=> "John Doe"
However, what shall I do with following XML?
> Nokogiri::XML(<<-XML
<?xml version='1.0' encoding='UTF-8'?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="bookid">
<metadata>
<dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf" opf:role="aut">John Doe</dc:creator>
</metadata>
</package>
XML
> xml.at_xpath("//dc:creator[#opf:role='aut']", xml.at_xpath("//xmlns:metadata").namespaces).text
Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //dc:creator[#opf:role='aut']
I think xml.remove_namespaces! or literal namespace arguments for at_xpath is last resort.
To programmatically collect all the namespaces, use Document#collect_namespaces.
xml = Nokogiri::XML(xmldata)
ns = xml.collect_namespaces
puts xml.at('//dc:creator[#opf:role="aut"]', ns).text
Output:
John Doe
I have a file with the following content (myfile.xml). I have to get all content coming under (including product node) a product with id=1.
<products>
<product id="1">
<category>q</category>
</product>
<product id="2">
<category>w</category>
</product>
<product id="3">
<category>e</category>
</product>
</products>`
i.e. the result should be :
<product id="1">
<category>q</category>
</product>
How can I do this?
I have the restriction that I should use XmlTextReader or XPathNavigator only for this, otherwise I could have used this : Getting data from xml by attribute vlaue
Wouldn't XmlReader.GetAttribute() work?
http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.getattribute(v=vs.100)
Add in some Skip() to move the iterator:
http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.skip(v=vs.100)
I have complex soap XML like below.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<MessageHeader>
<From>
<Type>string</Type>
</d3p1:From>
<d3p1:To>
<Role>string</Role>
</d3p1:To>
</MessageHeader>
<Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/sxvt">
<StrongToken>string</StrongToken>
</Security>
</soap:Header>
<soap:Body>
<FunctionResponse xmlns="http://www.yyy.com/webservices">
<FunctionRS TimeStamp="dateTime">
<Message>string<Message>
<Success>
<SuccessMessage>string</SuccessMessage>
</Success>
<Warnings>
<Warning Type="string" Text="string" />
<Warning Type="string" Text="string" />
</Warnings>
<Errors>
<Error Type="string" Text="string" />
<Error Type="string" Text="string" />
</Errors>
<Items>
<Item SequenceNo="Int" ">
<SamplePrice>
<Prices>
<Price>
<ToatlPrice>
<ItemNo>Int </ItemNo>
<ItemPrice>Int </ItemPrice>
</ToatlPrice>
</Price>
</Prices>
</SamplePrice >
</Item>
<Item SequenceNo="Int" ">
<SamplePrice>
<Prices>
<Price>
<ToatlPrice>
<ItemNo>Int </ItemNo>
<ItemPrice>Int </ItemPrice>
</ToatlPrice>
</Price>
</Prices>
</SamplePrice >
</Item>
</Items>
<Info>
<CurrencyCode>
<string>string</string>
<string>string</string>
</CurrencyCode>
</Infor>
</FunctionRS>
</FunctionResponse>
</soap:Body>
</soap:Envelope>
here i want the results of FunctionRS tag. I have created the class for the FunctionRS tag.
I have created FunctionRS class.
var result = resultNewDataSet.Descendants("FunctionRS").Select(t => new FunctionRS
{
Message = t.Descendants("Message").First().Value,
//Success = t.Descendants("Success").First().Value
});
using the above code i am able to get Message tag, but i am not able get the array lists (like Success, warnings,Items,etc) and class (like Info).
How can i Serialize the above xml using LINQ to XML.
Thanks in advance.
Elements you are looking for are in http://www.yyy.com/webservices namespace however in your query you are not using namespaces. I am not sure how FunctionRS or Message could be found as you are looking for them in the empty namespace. Try the following:
var resultNewDataSet = XDocument.Parse(
#"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:d3p1=""unknownnamespace"">
<soap:Header>
<MessageHeader>
<d3p1:From>
<Type>string</Type>
</d3p1:From>
<d3p1:To>
<Role>string</Role>
</d3p1:To>
</MessageHeader>
<Security xmlns=""http://schemas.xmlsoap.org/ws/2002/12/sxvt"">
<StrongToken>string</StrongToken>
</Security>
</soap:Header>
<soap:Body>
<FunctionResponse xmlns=""http://www.yyy.com/webservices"">
<FunctionRS TimeStamp=""dateTime"">
<Message>string</Message>
<Success>
<SuccessMessage>string</SuccessMessage>
</Success>
<Warnings>
<Warning Type=""string"" Text=""string"" />
<Warning Type=""string"" Text=""string"" />
</Warnings>
<Errors>
<Error Type=""string"" Text=""string"" />
<Error Type=""string"" Text=""string"" />
</Errors>
<Items>
<Item SequenceNo=""Int"">
<SamplePrice>
<Prices>
<Price>
<ToatlPrice>
<ItemNo>Int </ItemNo>
<ItemPrice>Int </ItemPrice>
</ToatlPrice>
</Price>
</Prices>
</SamplePrice >
</Item>
<Item SequenceNo=""Int"">
<SamplePrice>
<Prices>
<Price>
<ToatlPrice>
<ItemNo>Int </ItemNo>
<ItemPrice>Int </ItemPrice>
</ToatlPrice>
</Price>
</Prices>
</SamplePrice >
</Item>
</Items>
<Info>
<CurrencyCode>
<string>string</string>
<string>string</string>
</CurrencyCode>
</Info>
</FunctionRS>
</FunctionResponse>
</soap:Body>
</soap:Envelope>");
XNamespace webServicesNs = "http://www.yyy.com/webservices";
var result = resultNewDataSet
.Descendants(webServicesNs + "FunctionRS")
.Select(t => new
{
Message = (string)t.Descendants(webServicesNs + "Message").First(),
Success = (string)t.Descendants(webServicesNs + "Success").First(),
Warnings = t
.Element(webServicesNs + "Warnings")
.Elements(webServicesNs + "Warning")
.Select(w => new
{
#Type = (string)w.Attribute("Type"),
#Text = (string)w.Attribute("Text")
})
});
foreach (var r in result)
{
Console.WriteLine(r);
foreach (var w in r.Warnings)
{
Console.WriteLine(w);
}
}
(I included the Xml since the one you provided was broken and I had to fix it to make it possible to load to XDocument).
Here is the result I got:
{ Message = string, Success = string, Warnings = System.Linq.Enumerable+WhereSel
ectEnumerableIterator`2[System.Xml.Linq.XElement,<>f__AnonymousType0`2[System.St
ring,System.String]] }
{ Type = string, Text = string }
{ Type = string, Text = string }