I have an xml file
<BookLib>
<Book Id="1">
<Title>Title1</Title>
<Author>Author1</Author>
<Publisher>Publisher1</Publisher>
<Subject />
</Book>
<Book Id="2">
<Title>Title2</Title>
<Author>Author2</Author>
<Publisher>Publisher2</Publisher>
<Subject />
</Book>
<Book Id="3">
<Title>Title3</Title>
<Author>Author3</Author>
<Publisher>Author3</Publisher>
<Subject />
</Book>
</BookLib>
I want to select book id. I tried using this
#"/BookLib/Book/Title[contains(translate(text(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'),'" + searchText + "')]/#Id";
in XPathExpression
how can i retrieve 'id' using xpath in c#
Since #Id is below Book, not Id, you have to move back up to get it:
#"/BookLib/Book/Title[contains(translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'"
+ searchText.ToLower() + "')]/../#Id";
or do the comparison without moving down to Title in the first place:
#"/BookLib/Book[contains(translate(Title,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'"
+ searchText.ToLower() + "')]/#Id";
I personally prefer the latter because it seems a bit cleaner.
First you can use fn:lower-case() which is better than fn:translate as it use Unicode mapping to change the case. So it will work with accent like É->é, À->à, etc.
Then you can simplify by using XPath axes.
So, to get the #Id, you can use the following XPath (adapt to C#) :
#"//Book/Title[contains(lower-case(./text()),'" + searchText.ToLower() + "' )]/#Id";
Related
hi following XML is my input XML
<?xml version="1.0" encoding="utf-8"?>
<units xmlns="http://www.elsevier.com/xml/ani/ani" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ce="http://www.elsevier.com/xml/ani/common" xsi:schemaLocation="http://www.elsevier.com/xml/ani/ani http://www.elsevier.com/xml/ani/ani512-input-CAR.xsd">
<unit type="journal" xmlns="">
<unit-info>
<timestamp>2017-01-08T02:03:14Z</timestamp>
<order-id>12535892</order-id>
<parcel-id>none</parcel-id>
<unit-id>4756202</unit-id>
</unit-info>
<unit-content>
<bibrecord>
<item-info>
<status state="new" stage="S300" />
</item-info>
<head>
<citation-info>
<citation-type code="jo" />
<citation-language xmllang="ENG" />
<abstract-language xmllang="ENG" />
<author-keywords>
<author-keyword>Stroke</author-keyword>
<author-keyword> cerebral ischaemia</author-keyword>
<author-keyword> Neuro-protection</author-keyword>
<author-keyword> Neuro-protective agents</author-keyword>
</author-keywords>
</citation-info>
<citation-title xmllang="ENG" original="y">
<titletext>PATHOGENESIS AND NEURO-PROTECTIVE AGENTS OF STROKE</titletext>
</citation-title>
<abstracts>
<abstract>
<cepara>ABSTRACT: Stroke remains worlds second leading cause of mortality; and globally most frequent cause of long-lasting disabilities. The ischaemic pathophysiologic cascade leading to neuronal damage consists of peri-infarct depolarization, excitotoxicity, inflammation, oxidative stress, and apoptosis. Despite plethora of experimental evidences and advancement into the development of treatments, clinical treatment of acute stroke still remains challenging. Neuro-protective agents, as novel therapeutic strategy confer neuro-protection by targeting the pathophysiologic mechanism of stroke. The aim of this review is discussion of summary of the literature on stroke pathophysiology, current preclinical research findings of neuroprotective agents in stroke and possible factors that were responsible for the failure of these agents to translate in human stroke therapies.</cepara>
</abstract>
</abstracts>
<correspondence>
<person>
<ceinitials>M.</ceinitials>
<cesurname>Mubarak</cesurname>
</person>
<affiliation>
<organization> Bayero University Kano</organization>
<organization> Nigeria. Email: mubarakmahmad#yahoo.com</organization>
</affiliation>
</correspondence>
<root>
<author Seq="0">
<Inital>A.El</Inital>
<Surname>Khattabi</Surname>
<Givenname>Abdelkrim</Givenname>
</author>
</root>
</head>
</bibrecord>
</unit-content>
from this xml i need to delete root tag alone but i need all child element
<author Seq="0">
<Inital>A.El</Inital>
<Surname>Khattabi</Surname>
<Givenname>Abdelkrim</Givenname>
</author>
how to delete root tag alone. For this i followed following code
XDocument CarXML = new XDocument();
CarXML.Add(Root);
CarXML.Descendants("root").Remove();
CarXML.Save(#"CAR.XML");
But this code delete all xml tag. How to delete root element alone. i need child element
CarXML.ReplaceNodes(CarXML.Descendants("author").FirstOrDefault());
This replaces the whole content of the XML with the first descendant named author.
I'm looking for a fast and efficient way to retreive 2 strings from multiple xml files.
The files them selves aren't that big only 50kb to 100kb and the number of files can range from none to 100. I've included a sample of a very small xml file i'll be using. All xml files will be the same format and there's only 2 things i need to know from all files namely:
<Company>test bv.</Company>
<Ship>sss testing</Ship>
i want to store these strings in a struct/class since i cannot use Tuple in .net 3.5 (or am i mistaking?)
so the question: what is the most efficient way to do this? using Xdocument? using xmlReader? or something else?
<?xml version="1.0" encoding="utf-8"?>
<Collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Customer>
<ID>-1</ID>
<Updated>true</Updated>
<Company>test bv.</Company>
<Ship>sss testing</Ship>
<Adress>fggfgggff gvg</Adress>
<City>fgcgg</City>
<ZipCode>5454fc</ZipCode>
<Country>fcgggff</Country>
<BTW_Nmbr>55</BTW_Nmbr>
<IsTempCustomer>true</IsTempCustomer>
<PhoneNumbers>
<ContactData>
<ID>21</ID>
<Updated>true</Updated>
<Description>455656567</Description>
<Name>ghbbvh</Name>
<IsSendable>false</IsSendable>
</ContactData>
<ContactData>
<ID>22</ID>
<Updated>true</Updated>
<Description>2315098234146124302134</Description>
<Name>asdfawegaebf</Name>
<IsSendable>false</IsSendable>
</ContactData>
</PhoneNumbers>
<EmailAdresses />
</Customer>
<Order>
<ID>-1</ID>
<Updated>true</Updated>
<OrderNr>10330200</OrderNr>
<OrderDate>1-1-2005</OrderDate>
<StartDate>10-9-2013</StartDate>
<ExpirationDate>20-10-2013</ExpirationDate>
<Executor>Andre de Zwart</Executor>
<Executors />
<Reference />
<OrderDetail />
<IsDigital>true</IsDigital>
</Order>
<Materials>
<MaterialData>
<ID>108</ID>
<Updated>true</Updated>
<Description>ffdffggfg</Description>
<Amount>34</Amount>
</MaterialData>
<MaterialData>
<ID>109</ID>
<Updated>true</Updated>
<Description>ffccff</Description>
<Amount>45</Amount>
</MaterialData>
</Materials>
<HourExpenses>
<HourExpensesData>
<ID>43850</ID>
<Updated>true</Updated>
<Date>2013-10-06T00:00:00</Date>
<Notes>lala</Notes>
<Day>Sunday</Day>
<Hours>0.01</Hours>
<BusinessHours>0.01</BusinessHours>
<TravledHoursTo>0</TravledHoursTo>
<TravledHoursFrom>0</TravledHoursFrom>
<Start>2013-10-06T12:27:00</Start>
<Stop>2013-10-06T12:27:00</Stop>
</HourExpensesData>
<HourExpensesData>
<ID>43849</ID>
<Updated>true</Updated>
<Date>2013-09-17T00:00:00</Date>
<Notes>oke dus ik ben nu lekker aan het werk en ik typ wat spul er bij</Notes>
<Day>Tuesday</Day>
<Hours>0</Hours>
<BusinessHours>0.01</BusinessHours>
<TravledHoursTo>0</TravledHoursTo>
<TravledHoursFrom>0</TravledHoursFrom>
<Start>2013-09-17T12:31:31</Start>
<Stop>2013-09-17T12:31:32</Stop>
</HourExpensesData>
<HourExpensesData>
<ID>43855</ID>
<Updated>true</Updated>
<Date>2013-10-03T00:00:00</Date>
<Notes>test</Notes>
<Day>Thursday</Day>
<Hours>0</Hours>
<BusinessHours>0</BusinessHours>
<TravledHoursTo>12</TravledHoursTo>
<TravledHoursFrom>12</TravledHoursFrom>
<Start>0001-01-01T00:00:00</Start>
<Stop>0001-01-01T00:00:00</Stop>
</HourExpensesData>
</HourExpenses>
<TravelExpenses>
<TravelExpensesData>
<ID>672</ID>
<Updated>true</Updated>
<Date>2013-09-27T00:00:00</Date>
<Notes />
<KmTo>45</KmTo>
<KmFrom>45</KmFrom>
<Declaration>0</Declaration>
</TravelExpensesData>
</TravelExpenses>
<Signatures>
<ID>-1</ID>
<Updated>true</Updated>
<OrderID>10330200</OrderID>
<Completed>false</Completed>
<Notes>yay het werkt ;D</Notes>
</Signatures>
<RemovedDataList />
</Collection>
I would just use LINQ to XML in the simplest possible way:
var query = from file in files
let doc = XDocument.Load(file)
from customer in doc.Descendants("Customer")
select new {
Company = (string) customer.Element("Company"),
Ship = (string) customer.Element("Ship")
};
I'd expect that to be pretty quick already - but you should work out what your exact performance requirements are, then test them. (You almost certainly don't need "the most efficient" way - you need a sufficiently efficient way, whilst keeping the code readable.)
Note that if you want the values to be propagated out of the current method, you should create your own class to represent the company/ship pair.
Given an XML file like:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Policy id="832cbfc6-a451-4d77-a995-4ceb9d3bbe01" username ="DCassidy">
<Title>Test 1</Title>
</Policy>
<Policy id="832cbfc6-a451-4d77-a995-4ceb9d3bbe02" userName ="DCassidy">
<Title>Test 2</Title>
</Policy>........and so on
Is it possible to use LINQ to XML to return all the 'Policy' elements and their containing elements without having to specify each element thing like:
var subset = doc.Elements("Policy").SelectMany(x => new[] { x.Element("Title").Value });
I need to be able to dynamically add elements to the file, filter and return a subset.
preferabbly, returning a collection of XElemets so that later I can call:
subset.CreateReader() on.
EDIT
To be clearer. I will want to return ALL Policy objects and their descendants based on the username attribute. I the want to take that subset and use CreateReader() on it.
Can someone help please?
Thanks
You can use the Elements overload that does not specify a name to get all the child elements.
var xml = #"
<Root>
<Policy id='832cbfc6-a451-4d77-a995-4ceb9d3bbe01' username ='DCassidy'>
<Title>Test 1</Title>
</Policy>
<Policy id='832cbfc6-a451-4d77-a995-4ceb9d3bbe02' userName ='DCassidy'>
<Title>Test 2</Title>
</Policy>
</Root>
";
var xElement = XElement.Parse(xml);
var subset = xElement.Elements("Policy").SelectMany(e => e.Elements());
The subset is an IEnumerable<XElement> whose contents are:
<Title>Test 1</Title>
<Title>Test 2</Title>
It's not really clear what you mean, but perhaps:
var subset = doc.Elements("Policy").Descendants();
or
var subset = doc.Elements("Policy").DescendantsAndSelf();
This will get all descendants, not just direct ones. If you could be clearer about exactly what you're trying to achieve, that would help.
Use the Elements() method without specifying an element name to get all direct descendants:
XDocument.Root.Elements()
I'm trying to do very simple operations on a .cxml file. As you know it's basically an .xml file. This is a sample file I created to test the application:
<?xml version="1.0" encoding="utf-8"?>
<Collection xmlns:p="http://schemas.microsoft.com/livelabs/pivot/collection/2009" SchemaVersion="1.0" Name="Actresses" xmlns="http://schemas.microsoft.com/collection/metadata/2009">
<FacetCategories>
<FacetCategory Name="Nationality" Type="LongString" p:IsFilterVisible="true" p:IsWordWheelVisible="true" p:IsMetaDataVisible="true" />
</FacetCategories>
<!-- Other entries-->
<Items ImgBase="Actresses_files\go144bwo.0ao.xml" HrefBase="http://www.imdb.com/name/">
<Item Id="2" Img="#2" Name="Anna Karina" Href="nm0439344/">
<Description> She is a nice girl</Description>
<Facets>
<Facet Name="Nationality">
<LongString Value="Danish" />
</Facet>
</Facets>
</Item>
</Items>
<!-- Other entries-->
</Collection>
I can't get any functioning simple code like:
XDocument document = XDocument.Parse(e.Result);
foreach (XElement x in document.Descendants("Item"))
{
...
}
The test on a generic xml is working. The cxml file is correctly loaded in document.
While watching the expression:
document.Descendants("Item"), results
the answer is:
Empty "Enumeration yielded no results" string
Any hint on what can be the error? I've also add a quick look to get Descendants of Facet, Facets, etc., but there are no results in the enumeration. This obviously doesn't happen with a generic xml file I used for testing. It's a problem I have with .cxml.
Basically your XML defines a default namespace with the xmlns="http://schemas.microsoft.com/collection/metadata/2009" attribute:
That means you need to fully qualify your Descendants query e.g.:
XDocument document = XDocument.Parse(e.Result);
foreach (XElement x in document.Descendants("{http://schemas.microsoft.com/collection/metadata/2009}Item"))
{
...
}
If you remove the default namespace from the XML your code actually works as-is, but that is not the aim of the exercise.
See Metadata.CXML project under http://github.com/Zoomicon/Metadata.CXML sourcecode for LINQ-based parsing of CXML files.
Also see ClipFlair.Metadata project at http://github.com/Zoomicon/ClipFlair.Metadata for parsing one's CXML custom facets too
BTW, at http://ClipFlair.codeplex.com can checkout the ClipFlair.Gallery project for how to author ASP.net web-based forms to edit metadata fragments (parts of CXML files) and merge them together in a single one (that you then convert periodically to DeepZoom CXML with PAuthor tool from http://pauthor.codeplex.com).
If anyone is interested in doing nesting (hierarchy) of CXML collections see
http://github.com/Zoomicon/Trafilm.Metadata
and
http://github.com/Zoomicon/Trafilm.Gallery
I am trying to get the data from input xml message using functoids. But this doesn't seem to work. Below is my XML snippet
<?xml version="1.0" ?>
<ROOT>
<COMPANIES>
<COMPANY>
<NAME>FOO CORP</name>
</COMPANY>
<COMPANY>
<NAME>ACME CORP</name>
</COMPANY>
</COMPANIES>
<INFORMATIONS>
<INFORMATION>
<TESTING>
<TESTS>
<NAME>1221</NAME>
<TEST>
<TEXT>I AM SAM</TEXT>
</TEST>
</TESTS>
<TESTS>
<NAME>21</NAME>
<TEST>
<TEXT>FADFDF</TEXT>
</TEST>
</TESTS>
<TESTS>
<NAME>3001</NAME>
<TEST>
<TEXT>SGFGSDFG</TEXT>
</TEST>
</TESTS>
<TESTS>
<NAME>4569</NAME>
<TEST>
<TEXT>12312</TEXT>
</TEST>
</TESTS>
</TESTING>
<INFORMATION>
</INFORMATIONS>
</ROOT>
First I am trying to loop through COMPANY and get the NAME "ACME CORP". but which ever functoid i use (scripting, string extract etc) I always get the FOO CORP. I even tried inline XSLT but that also doesn't seem to work. Any idea how to get the 2nd COMPANY name?
Secondly, I have mapped <TEXT> directly to <node> in my destination schema. What i get is only 2 values from <TEXT>. Not all the <TEXT> are mapped to my <node>. Output i am getting is
I don't get is
I AM SAM
FADFDF
I don't get
<node>SGFGSDFG</node>
<node>12312</node>
Any one knows how i could get the values?
Thanks in advance
cheers,
Karthik
Q1: How to get the NAME of the second COMPANY?
1) Add Iteration functoid (Advanced Functoids) and connect to COMPANY node in your source schema
2) Add Equal functiod (Logical Functoids) and connect to Iteration functoid
3) Configure Equal functoid; add constant value 2
4) Add Value Mapping (Flattening) functoid (Advanced Functoids)
5) Connect output of Equal to input of Value Mapping
6) Connect NAME emlement of source schema to input of Value Mapping
7) Connect output of Value Mapping to destination schema element
Q2: Not all source TEXT elements are transformed to destination node
This seems to be a side effect of your mapping concering Q1 and I cannot reproduce your error.
Check minOccurs and maxOccurs of your source and destination schema for the elements/nodes in question.