I'm pretty new to this stuff and having a hard time figuring out how to properly access my data. What I have is an XML tree in this form:
<bpm:ResponseData
xmlns:bpm="http://rest.bpm.ibm.com/v1/data">
<status>200</status>
<data
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srch="http://rest.bpm.ibm.com/v1/data/search"
xsi:type="srch:SearchDetails">
<data>
<item key="assignedToUser"/>
<item key="bpdName">
<value xmlns:ns5="http://www.w3.org/2001/XMLSchema" xsi:type="ns5:string">
Some process name
</value>
</item>
<item key="instanceDueDate">
<value xmlns:ns5="http://www.w3.org/2001/XMLSchema" xsi:type="ns5:string">
2011-09-06T12:35:48Z
</value>
</item>
<item key="taskId">
<value xmlns:ns5="http://www.w3.org/2001/XMLSchema" xsi:type="ns5:decimal">
218
</value>
</item>
<item key="taskSubject">
<value xmlns:ns5="http://www.w3.org/2001/XMLSchema" xsi:type="ns5:string">
Task: Some process related task
</value>
</item>
</data>
<data>
<item key="bpdName">
<value xmlns:ns5="http://www.w3.org/2001/XMLSchema" xsi:type="ns5:string">
Another process name
</value>
</item>
<item key="instanceStatus">
<value xmlns:ns5="http://www.w3.org/2001/XMLSchema" xsi:type="ns5:string">
Active
</value>
</item>
<item key="taskId">
<value xmlns:ns5="http://www.w3.org/2001/XMLSchema" xsi:type="ns5:decimal">
253
</value>
</item>
<item key="taskSubject">
<value xmlns:ns5="http://www.w3.org/2001/XMLSchema" xsi:type="ns5:string">
Task: Another process related task
</value>
</item>
</data>
</data>
</bpm:ResponseData>
I need to extract exactly two things from this data: the taskSubject and the taskId. Preferably in a manner which would allow me to iterate over them. Something involving new{subject, id} would be nice.
I'm not quite sure how to handle thing task...
With
var items = from feed in XMLDocument.Descendants("data").Descendants("data") select feed;
I get the two data items. Is there any way to drill them down further, returning the value of the descendant with a specific "key" attribute?
Regards,
Michael
EDIT:
I figured this would work:
var items = from feed in XMLDocument.Descendants("data").Descendants("data") select
new{
subject = from subjects in feed.Elements() where (subjects.Attribute("key").Value=="taskSubject") select subjects.Value,
id = from subjects in feed.Elements() where (subjects.Attribute("key").Value == "taskId") select subjects.Value
};
But that seems pretty "dirty"...
This is a bit hackish, but it should work (tested on Mono 2.10.2):
var items = from data in document.Descendants("data")
let taskId =
data.Elements("item")
.Where(i => (string)i.Attribute("key") == "taskId")
.FirstOrDefault()
where taskId != null
let taskSubject =
data.Elements("item")
.Where(i => (string)i.Attribute("key") == "taskSubject")
.FirstOrDefault()
where taskSubject != null
select new {
TaskId = taskId.Element("value").Value.Trim(),
TaskSubject = taskSubject.Element("value").Value.Trim()
};
Related
Sorry for the trivial request, but it's a difficult time for me. I have this part of XML code:
<?xml version="1.0" encoding="UTF-8"?>
<ClinicalDocument xsi:schemaLocation="urn:hl7-org:v3 CDA.xsd" xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<structuredBody moodCode="EVN" classCode="DOCBODY">
<component>
<section ID="DESCRIPTION">
<code code="57832-8" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" codeSystemVersion="2.19" />
<title>DESCRIPTION</title>
<text>
<list ID="RQO">
<caption>REQUEST:</caption>
<item>
<content ID="Prest_1">90153 - CORTISOLO [S]</content>
</item>
<item>
<content ID="Prest_2">90171 - DEIDROEPIANDROSTERONE (DEA)</content>
</item>
<item>
<content ID="Prest_3">90172 - DEIDROEPIANDROSTERONE SOLFATO (DEA-S)</content>
</item>
<item>
<content ID="Prest_4">90413 - TESTOSTERONE [P]</content>
</item>
<item>
<content ID="Prest_5">90414 - TESTOSTERONE LIBERO</content>
</item>
</list>
<list ID="DIAG">
<caption>Problem:</caption>
<item>
<content ID="Prob_1">Control</content>
</item>
</list>
</text>
</section>
</component>
</structuredBody>
I would need to get the values contained in the text tag, and in particular:
1) Prest_1 2) 90153 - CORTISOLO [S]
and all the following lines. Thanks for your help.
LINQ to XML makes it easy.
c#
void Main()
{
const string FILENAME = #"e:\temp\ClinicalDocument.xml";
XDocument doc = XDocument.Load(FILENAME);
XNamespace ns = doc.Root.GetDefaultNamespace();
foreach (var el in doc.Descendants(ns + "content"))
{
Console.WriteLine("ID='{0}', Content='{1}'", el.Attribute("ID").Value, el.Value);
}
}
Output
ID='Prest_1', Content='90153 - CORTISOLO [S]'
ID='Prest_2', Content='90171 - DEIDROEPIANDROSTERONE (DEA)'
ID='Prest_3', Content='90172 - DEIDROEPIANDROSTERONE SOLFATO (DEA-S)'
ID='Prest_4', Content='90413 - TESTOSTERONE [P]'
ID='Prest_5', Content='90414 - TESTOSTERONE LIBERO'
ID='Prob_1', Content='Control'
I have some XML structured like this:
<form>
<section-1>
<item-1>
<value />
</item-1>
<item-2>
<value />
</item-2>
</section-1>
<section-2>
<item-3>
<value />
</item-3>
<item-4>
<value />
</item-4>
</section-2>
</form>
...and want to turn it into something sane like this:
<form>
<items>
<item id="1">
<value/>
</item>
<item id="2">
<value/>
</item>
<item id="3">
<value/>
</item>
<item id="4">
<value/>
</item>
</items>
</form>
I am struggling to turn the old XML into an array or object of values. Once in the new format I'd be able to do the following:
XDocument foo = XDocument.Load(form.xml);
var items = foo.Descendants("item")
.Select(i => new Item
{
value = i.Element("value").Value
});
...but in the current mess the xml is in can I wildcard the descendants selector?
var items = foo.Descendants("item"*)
...or something? I tried to follow this question's answer but failed to adapt it to my purpose.
Ah-ha! It did click in the end. If I leave the descendants selector blank and add in a where statement along the lines of what's in this question's answer
.Where(d => d.Name.ToString().StartsWith("item-"))
Then we get:
XDocument foo = XDocument.Load(form.xml);
var items = foo.Descendants()
.Where(d => d.Name.ToString().StartsWith("item-"))
.Select(i => new Item
{
value = i.Element("value").Value
});
...and I'm now able to iterate through those values while outputting the new XML format. Happiness.
I'm trying to insert a XML tag in an existing xml-file. To insert an XML-Tag in C# is not really a problem, but my Problem is, that i need the new beginning-tag and the ending-tag on a certain place in that file ... can anybody help me ...
here an Example:
this is the xml-file before:
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<Item>
<ItemID>2711</ItemID>
<ItemTypeID>P</ItemTypeID>
<ColorID>1</ColorID>
</Item>
<Item>
<ItemID>64566</ItemID>
<ItemTypeID>P</ItemTypeID>
<ColorID>3</ColorID>
</Item>
</DocumentElement>
... this should be the new XML-file -> with the new tag "Inventory":
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<Inventory>
<Item>
<ItemID>2711</ItemID>
<ItemTypeID>P</ItemTypeID>
<ColorID>1</ColorID>
</Item>
<Item>
<ItemID>64566</ItemID>
<ItemTypeID>P</ItemTypeID>
<ColorID>3</ColorID>
</Item>
</Inventory>
</DocumentElement>
can anybody help me?
You can wrap the existing Items in a new XElement then replace the nodes on the original document:
XDocument doc = XDocument.Parse("<DocumentElement><Item><ItemID>2711</ItemID><ItemTypeID>P</ItemTypeID><ColorID>1</ColorID></Item><Item><ItemID>64566</ItemID><ItemTypeID>P</ItemTypeID><ColorID>3</ColorID></Item></DocumentElement>");
var items = doc.Descendants("Item");
XElement inventory = new XElement("Inventory");
inventory.Add(items);
doc.Root.ReplaceNodes(inventory);
//now you can save the XDocument to a file or whatever
Creates this:
<DocumentElement>
<Inventory>
<Item>
<ItemID>2711</ItemID>
<ItemTypeID>P</ItemTypeID>
<ColorID>1</ColorID>
</Item>
<Item>
<ItemID>64566</ItemID>
<ItemTypeID>P</ItemTypeID>
<ColorID>3</ColorID>
</Item>
</Inventory>
</DocumentElement>
If you have LINQPad you can run this script: http://share.linqpad.net/7c636x.linq
You can try this
var doc = XDocument.Load(file);
var characters = doc.Descendants("DocumentElement").FirstOrDefault();
if (characters != null)
{
XElement xe = new XElement("Inventory");
characters.Add(xe);
var oColl = doc.Descendants("Item");
xe.Add(oColl);
}
doc.Save(file);
I am creating application to make Mod Menu's for Modern Warfare 3 (XRPC). I am making it customisable with XML, i have created an Example XML.
<MenuFile>
<Credits>
<Author>Callum Carmicheal</Author>
<Name>Sample</Name>
<Version>0.1</Version>
</Credits>
<InfoBar>
<Text>Created by ..., Enjoy</Text>
</InfoBar>
<Menu>
<Main>
<Header>
<Name>Main Menu</Name>
</Header>
<Item>
<Name>Enable Cheats</Name>
<Function>
<Menu>Mods</Menu>
</Function>
<Ignore>false</Ignore>
</Item>
<Item>
<Name> </Name>
<Function> </Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
</Main>
<Mods>
<Header>
<Name>Mods</Name>
</Header>
<Item>
<Name>Enable Cheats</Name>
<Function>
<Dvar>sv_cheats 1</Dvar>
</Function>
<Ignore>false</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
<Item>
<Name></Name>
<Function></Function>
<Ignore>True</Ignore>
</Item>
</Mods>
</Menu>
</MenuFile>
This is the markup for the Menu's, i have created some c# Code
private void button1_Click(object sender, EventArgs e) {
XmlDocument xml = new XmlDocument();
xml.LoadXml(System.IO.File.ReadAllText("menu.xml")); // suppose that myXmlString contains "<Names>...</Names>"
XmlNode credits_author = xml.SelectSingleNode("/MenuFile/Credits/Author");
XmlNode credits_name = xml.SelectSingleNode("/MenuFile/Credits/Name");
XmlNode credits_version = xml.SelectSingleNode("/MenuFile/Credits/Version");
Log("Credits(Author): " + credits_author.InnerText);
Log("Credits(Name): " + credits_name.InnerText);
Log("Credits(Version): " + credits_version.InnerText);
XmlNode InfoBar = xml.SelectSingleNode("/MenuFile/InfoBar/Text");
Log("");
Log("InfoBar Text: " + InfoBar.InnerText);
Log("");
Log("Menus");
XmlNodeList Menus = xml.SelectNodes("/MenuFile/Menu");
// This returns
// /MenuFile/Menu not /MenuFile/Menu/MainMenu....
// it should loop through MainMenu, Mods...
foreach (XmlNode MenuItem in Menus) {
Log("\t Menu: " + MenuItem.Name); // Main should me MainMenu or Mods
XmlNodeList Items = xml.SelectNodes("/MenuFile/Menu/" + MenuItem.Name);
foreach (XmlNode mi in Items) {
if (mi.Name == "Header") {
string xpath = FindXPath(mi);
string Header = xml.SelectSingleNode("/MenuFile/Menu/" + MenuItem.Name + "/Header/Name").InnerText;
Log("\t\t Header: " + Header);
}
else if (mi.Name == "Item") {
string Name = "";
string ignore = "";
}
}
}
}
But the problem is when trying to retrieve the MenuList/Menu's children nodes, it returns MenuList/Menu itself i have no clue.
I've tried debugging but the results are the same, can anyone see my error in this?
Your problem is that you are looping through the Menu nodes, not Main or Mods nodes:
XmlNodeList Menus = xml.SelectNodes("/MenuFile/Menu");
foreach (XmlNode MenuItem in Menus) {
will always return the outer Menu nodes.
To fetch the Main/Mods nodes use the following:
XmlNodeList menus = xml.SelectNodes("/MenuFile/Menu/*");
foreach (XmlNode menuItem in menus) {
Also, rather just fetch 'Header' and 'Items' nodes directly rather than performing an unnecessary "if":
XmlNode headerItem = menuItem.SelectSingleNode("Header");
...
XmlNodeList items = menuItem.SelectNodes("Item");
foreach (XmlNode item in items) {
...
I have an XML document which is confounding me. I'd like to (to start) pull all of the document nodes (/database/document), but it only works if I remove all of the attributes on the database element. Specifically the xmlns tag causes an xpath query for /database/document to return nothing - remove it, and it works.
xmlns="http://www.lotus.com/dxl"
I take it this has to do with XML namespaces. What is it doing, and more to the point, how do I make it stop? I just want to parse the document for data.
<?xml version="1.0" encoding="utf-8"?>
<database xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.lotus.com/dxl xmlschemas/domino_7_0_3.xsd"
xmlns="http://www.lotus.com/dxl"
version="7.0"
maintenanceversion="3.0"
path="C:\LotusXML\test1.nsf"
title="test1">
<databaseinfo numberofdocuments="3">
<datamodified>
<datetime dst="true">20090812T142141,48-04</datetime>
</datamodified>
<designmodified>
<datetime dst="true">20090812T154850,91-04</datetime>
</designmodified>
</databaseinfo>
<document form="NameAddress">
<noteinfo noteid="8fa" unid="x" sequence="2">
<created>
<datetime dst="true">20090812T130308,71-04</datetime>
</created>
<modified>
<datetime dst="true">20090812T142049,36-04</datetime>
</modified>
<revised>
<datetime dst="true">20090812T142049,35-04</datetime>
</revised>
<lastaccessed>
<datetime dst="true">20090812T142049,35-04</datetime>
</lastaccessed>
<addedtofile>
<datetime dst="true">20090812T130321,57-04</datetime>
</addedtofile>
</noteinfo>
<updatedby>
<name>MOOSE</name>
</updatedby>
<revisions>
<datetime dst="true">20090812T130321,57-04</datetime>
</revisions>
<item name="Name">
<text>joe</text>
</item>
<item name="OtherName">
<text>dave</text>
</item>
<item name="Address">
<text>here at home</text>
</item>
<item name="PictureHere">
<richtext>
<pardef id="1" />
<par def="1">
</par>
<par def="1" />
</richtext>
</item>
</document>
<document form="NameAddress">
<noteinfo noteid="8fe" unid="x" sequence="2">
<created>
<datetime dst="true">20090812T130324,59-04</datetime>
</created>
<modified>
<datetime dst="true">20090812T142116,95-04</datetime>
</modified>
<revised>
<datetime dst="true">20090812T142116,94-04</datetime>
</revised>
<lastaccessed>
<datetime dst="true">20090812T142116,94-04</datetime>
</lastaccessed>
<addedtofile>
<datetime dst="true">20090812T130333,90-04</datetime>
</addedtofile>
</noteinfo>
<updatedby>
<name>MOOSE</name>
</updatedby>
<revisions>
<datetime dst="true">20090812T130333,90-04</datetime>
</revisions>
<item name="Name">
<text>fred</text>
</item>
<item name="OtherName">
<text>wilma</text>
</item>
<item name="Address">
<text>bedrock</text>
</item>
<item name="PictureHere">
<richtext>
<pardef id="1" />
<par def="1">
</par>
<par def="1" />
</richtext>
</item>
</document>
<document form="NameAddress">
<noteinfo noteid="902" unid="x" sequence="2">
<created>
<datetime dst="true">20090812T130337,09-04</datetime>
</created>
<modified>
<datetime dst="true">20090812T142141,48-04</datetime>
</modified>
<revised>
<datetime dst="true">20090812T142141,47-04</datetime>
</revised>
<lastaccessed>
<datetime dst="true">20090812T142141,47-04</datetime>
</lastaccessed>
<addedtofile>
<datetime dst="true">20090812T130350,20-04</datetime>
</addedtofile>
</noteinfo>
<updatedby>
<name>MOOSE</name>
</updatedby>
<revisions>
<datetime dst="true">20090812T130350,20-04</datetime>
</revisions>
<item name="Name">
<text>julie</text>
</item>
<item name="OtherName">
<text>mccarthy</text>
</item>
<item name="Address">
<text>the pen</text>
</item>
<item name="PictureHere">
<richtext>
<pardef id="1" />
<par def="1">
</par>
<par def="1" />
</richtext>
</item>
</document>
</database>
The xmlns="http://www.lotus.com/dxl" sets a default namespace for contained nodes. It means that /database/document is really /{http://www.lotus.com/dxl}:database/{http://www.lotus.com/dxl}:document. Your XPath query will need to include the namespace:
XmlDocument doc = new XmlDocument();
doc.Load(fileName);
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("tns", "http://www.lotus.com/dxl");
var documents = doc.SelectNodes("/tns:database/tns:document", ns);
When there is an XML namespace defined, each element needs to preceded by it for it to be correctly recognized.
If you were to use LINQ to XML to read in this data it would look something like this:
XDocument xdoc = XDocument.Load("file.xml");
XNamespace ns = "http://www.lotus.com/dxl";
var documents = xdoc.Descendants(ns + "document");
XML namespaces are similar in concept to C# namespaces (or any other language that supports it). If you define a class inside a namespace, you wouldn't be able to access it without first specifying the namespace (this is what using statements do for you).
You need to specify the element by their full name, including the namespace. The easy way to do this is to define the appropriate XNamespace and prepend it to the element name.
XDocument myDoc;
XNamespace ns = "http://www.lotus.com/dxl";
XElement myElem = myDoc.Element(ns + "ElementName");
See MSDN for more information.