I am struggling with this situations for a while!! and i really hope i can get some help from you.
in a method i am receiving this XML as a string :
<?xml version="1.0" encoding="utf-16" standalone="no"?>
<VC_001_CreateDocument>
<VCRequest>
<Header>
<OrganisationData>
<ClientId />
<UserId />
<Pass />
</OrganisationData>
<Article>
<OutcomeSource>ERP</OutcomeSource>
<ArticleNumber>6034967-Sample</ArticleNumber>
<ProductNumbers>
<ProductNumber Type="GTIN" Level="PRI" />
</ProductNumbers>
<Forecast />
<ERPStatus>APP</ERPStatus>
<SerialisationFlag />
<CSDBArticleNumber>6034967-Sample</CSDBArticleNumber>
<ArticleDescription>Rose</ArticleDescription>
<WorkflowId />
<CommonName />
<PharmaceuticalForm />
<Strength />
<PackageWeight />
<PackageSize />
<PackageType />
<GS1GLN />
<GS1CompanyPrefix />
<Customer>
<CustomerId />
<CustomerErpNumber />
</Customer>
<ShelfLife />
<Region />
<ProductionSites>
<ProductionSite>
<ProductionSiteId />
<ProductionSiteErpNumber />
</ProductionSite>
</ProductionSites>
<GenericArticleField01 />
<GenericArticleField02 />
<GenericArticleField03 />
<GenericArticleField04 />
<GenericArticleField05 />
<RequiredFields>
<RequiredField Name="" />
</RequiredFields>
<Comment />
<Checked />
<TargetMarkets>
<TargetMarket>
<GS1NHRN />
<GenericFields Type="" Language="" />
<Mah />
<Wholesaler />
</TargetMarket>
</TargetMarkets>
<VerificationSystem />
<Email />
<FixData />
<StartValueInitial />
<SubPools>
<SubPool>
<AggregationLevel />
<PoolIdentProductNumber />
<QuantityPerLevel />
<IncompletePackagingRule />
<QuantityOfLayer />
<GenerationPattern />
<PostProductionSerialNumberAssignment />
<PrePrinting />
<Factor />
<Threshold />
<SerialNumberType />
<ExtensionDigit />
<SerialNumberSource />
<DeliveranceInformation>
<MinimumValue />
<PercentualAmount />
</DeliveranceInformation>
</SubPool>
</SubPools>
<Report>
<ReportExternal />
<ReportVerificationSystem />
</Report>
</Article>
</Header>
</VCRequest>
</VC_001_CreateDocument>
to transform in an Envelope to use in my SOAP Request exactly like this: reading the node values of course if they have!
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:csdb="http://site.de/csdb">
<soapenv:Header/>
<soapenv:Body>
<csdb:VC_001_CreateDocument>
<csdb:VARequest>
<csdb:Header>
<csdb:OrganisationData>
<csdb:ClientId>EDP</csdb:ClientId>
<csdb:UserId>webservice</csdb:UserId>
<csdb:Pass>!password*</csdb:Pass>
</csdb:OrganisationData>
</csdb:Header>
<csdb:Article>
<csdb:OutcomeSource>ERP</csdb:OutcomeSource>
<csdb:ArticleNumber>6034967-Sample</csdb:ArticleNumber>
<csdb:ProductNumbers>
<csdb:ProductNumber type="GTIN" level="PRI"></csdb:ProductNumber>
</csdb:ProductNumbers>
<csdb:Forecast></csdb:Forecast>
<csdb:ERPStatus></csdb:ERPStatus>
<csdb:SerialisationFlag></csdb:SerialisationFlag>
<csdb:CSDBArticleNumber>6034967-AMOSTRA</csdb:CSDBArticleNumber>
<csdb:ArticleDescription>PINOX ROSA</csdb:ArticleDescription>
<csdb:WorkflowId></csdb:WorkflowId>
<csdb:CommonName></csdb:CommonName>
<csdb:PharmaceuticalForm></csdb:PharmaceuticalForm>
<csdb:Strength></csdb:Strength>
<csdb:PackageWeight></csdb:PackageWeight>
<csdb:PackageSize></csdb:PackageSize>
<csdb:PackageType></csdb:PackageType>
<csdb:GS1GLN></csdb:GS1GLN>
<csdb:GS1CompanyPrefix></csdb:GS1CompanyPrefix>
<csdb:Customer>
<csdb:Customer></csdb:Customer>
<csdb:CustomerId></csdb:CustomerId>
<csdb:CustomerErpNumber></csdb:CustomerErpNumber>
</csdb:Customer>>
<csdb:ShelfLife></csdb:ShelfLife>
<csdb:Region></csdb:Region>
<csdb:ProductionSites>
<csdb:ProductionSite>
<csdb:ProductionSiteId></csdb:ProductionSiteId>
<csdb:ProductionSiteErpNumber></csdb:ProductionSiteErpNumber>
</csdb:ProductionSite>
</csdb:ProductionSites>
<csdb:GenericArticleField01></csdb:GenericArticleField01>
<csdb:GenericArticleField02></csdb:GenericArticleField02>
<csdb:GenericArticleField03></csdb:GenericArticleField03>
<csdb:GenericArticleField04></csdb:GenericArticleField04>
<csdb:GenericArticleField05></csdb:GenericArticleField05>
<csdb:RequiredFields>
<csdb:RequiredField name="?"></csdb:RequiredField>
</csdb:RequiredFields>
<csdb:Comment></csdb:Comment>
<csdb:Checked></csdb:Checked>
<csdb:GS1NHRN GS1NHRNNational="?"></csdb:GS1NHRN>
<csdb:TargetMarkets>
<csdb:TargetMarket targetMarket="?">
<csdb:GS1NHRN GS1NHRNNational="?"></csdb:GS1NHRN>
<csdb:GenericFields type="?" language="?"></csdb:GenericFields>
<csdb:Mah></csdb:Mah>
<csdb:Wholesaler></csdb:Wholesaler>
</csdb:TargetMarket>
</csdb:TargetMarkets>
<csdb:Verificationsystem></csdb:Verificationsystem>
<csdb:Email></csdb:Email>
<csdb:FixData></csdb:FixData>
<csdb:StartValueInitial></csdb:StartValueInitial>
<csdb:Subpools>
<csdb:Subpool>
<csdb:AggregationLevel></csdb:AggregationLevel>
<csdb:PoolIdentProductNumber type="?"></csdb:PoolIdentProductNumber>
<csdb:QuantityPerLevel></csdb:QuantityPerLevel>
<csdb:IncompletePackagingRule></csdb:IncompletePackagingRule>
<csdb:QuantityOfLayer></csdb:QuantityOfLayer>
<csdb:GenerationPattern></csdb:GenerationPattern>
<csdb:PostProductionSerialNumberAssignment></csdb:PostProductionSerialNumberAssignment>
<csdb:PrePrinting></csdb:PrePrinting>
<csdb:Factor></csdb:Factor>
<csdb:Threshold></csdb:Threshold>
<csdb:SerialNumberType></csdb:SerialNumberType>
<csdb:ExtensionDigit></csdb:ExtensionDigit>
<csdb:SerialNumberSource></csdb:SerialNumberSource>
<csdb:DeliveranceInformation>
<csdb:MinimumValue></csdb:MinimumValue>
<csdb:PercentualAmount></csdb:PercentualAmount>
</csdb:DeliveranceInformation>
</csdb:Subpool>
</csdb:Subpools>
<csdb:Report>
<csdb:ReportExternal></csdb:ReportExternal>
<csdb:ReportVerificationSystem></csdb:ReportVerificationSystem>
</csdb:Report>
</csdb:Article>
</csdb:VCRequest>
</csdb:VC_001_CreateDocument>
</soapenv:Body>
</soapenv:Envelope>
THis is exactly the XML that i receive and that's the envelope that i will have to create (Request generated by SOAPUI),the nodes will have dynamic Values of course, those parameteres were just an example.
i assume this is the easiest way since i can't "add service reference" because i am trying to develop a DLL where the webservices will be nested. There's no web.config where this DLL is going to be installed.
Thank you soo much for helping me with the logic for this problem that is driving me crazy
Using xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
StreamReader reader = new StreamReader(FILENAME);
reader.ReadLine(); // skip the utf-16 in header that Net Library doesn't accept
XDocument doc = XDocument.Load(reader);
string soapHeader = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:csdb=\"http://site.de/csdb\">" +
"<soapenv:Header/>" +
"<soapenv:Body>" +
"</soapenv:Body>" +
"</soapenv:Envelope>";
XElement soap = XElement.Parse(soapHeader);
XNamespace nsCsdb = soap.GetNamespaceOfPrefix("csdb");
XNamespace nsSoapenv = soap.GetNamespaceOfPrefix("soapenv");
XElement body = soap.Descendants(nsSoapenv + "Body").FirstOrDefault();
body.Add(doc.Root);
foreach (XElement child in body.Descendants())
{
child.Name = nsCsdb.GetName(child.Name.LocalName);
List<XAttribute> atList = child.Attributes().ToList();
child.Attributes().Remove();
foreach (XAttribute at in atList)
child.Add(new XAttribute(nsCsdb.GetName(at.Name.LocalName), at.Value));
}
}
}
}
Related
I got fragmented xml file (document without root element/node):
<?xml version="1.0" standalone="no" ?>
<WndPos name="Login" l="703" r="1264" t="323" b="909" />
<WndPos name="Main" l="703" r="768" t="323" b="609" />
<LayerManager />
<ViewLayers name="Roof" roof="1">
<Layer level="1" visible="1" />
</ViewLayers>
<DirProfiles>
<ProfileInfo ProfileName="Control" DatabasePath="D:\Database\Control" />
</DirProfiles>
<DirHistory>
<ProfileInfo Use="Database" Path="D:\Database\Control" />
</DirHistory>
I am reading this file using the following:
string xmlPath = Environment.GetEnvironmentVariable("USERPROFILE") + "\\my.xml";
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
XDocument doc = new XDocument(new XElement("root"));
XElement root = doc.Descendants().First();
using (StreamReader fs = new StreamReader(xmlPath))
using (XmlReader xr = XmlReader.Create(fs, settings))
{
while(xr.Read())
{
if (xr.NodeType == XmlNodeType.Element)
{
root.Add(XElement.Load(xr.ReadSubtree()));
}
}
}
Later on I change <DirProfiles>...</DirProfiles> section and getting the following data:
<?xml version="1.0" standalone="no" ?>
<WndPos name="Login" l="703" r="1264" t="323" b="909" />
<WndPos name="Main" l="703" r="768" t="323" b="609" />
<LayerManager />
<ViewLayers name="Roof" roof="1">
<Layer level="1" visible="1" />
</ViewLayers>
<DirProfiles>
<ProfileInfo ProfileName="Control1" DatabasePath="D:\Database\Control1" />
<ProfileInfo ProfileName="Control2" DatabasePath="D:\Database\Control2" />
<ProfileInfo ProfileName="Control3" DatabasePath="D:\Database\Control3" />
<ProfileInfo ProfileName="Control4" DatabasePath="D:\Database\Control4" />
<ProfileInfo ProfileName="Control5" DatabasePath="D:\Database\Control5" />
</DirProfiles>
<DirHistory>
<ProfileInfo Use="Database" Path="D:\Database\Control" />
</DirHistory>
This result xml fragment I have to write to the file which should be fragmented xml file (without root element).
I tried to do the following:
doc.Save();
But it saves with root element and application can't work with this xml.
Below is the XML I am trying to parse. I need to extract the DLRNUMBER tag from the first FL nodelist (first one). I am trying to use Xdocument. I don't know the syntax to get the tag.
XDocument xdoc = XDocument.Load(#"C:\Temp\FR_in.xml");
var query = from e in xdoc.Descendants("FLSS")
select e;
Below is the XML:
<PACK Id="NI">
<PROP Id="KEY1" Val="NI_NY" />
<PROP Id="SOURCE" Val="NI" />
<PROP Id="TARGET" Val="NY" />
<REQUEST Id="CREATE_FR">
<PROP Id="PROID" Val="LIBRARY.OBJECT" />
<DOBJ Id="FH"> <ATTR Id="PAYTYPE" Val="WR" />
<ATTR Id="DTREATED" Val="3/20/2018" />
<ATTR Id="DUEDATE" Val="3/20/2018" />
<ATTR Id="AMOUNT" Val="1499.5" />
<ATTR Id="SOURCE" Val="DS" />
<ATTR Id="CREATOR" Val="DSI" />
<ATTR Id="APPROVER" Val="UF03567" />
<COLL Id="FLSS">
<FL>
<DOBJ Id="FL_1">
<ATTR Id="ACCTNUMBER" Val="162101" />
<ATTR Id="CENTER" Val="506" />
<ATTR Id="DLRNUMBER" Val="48" />
<ATTR Id="DLR" Val="58D" />
<ATTR Id="PAYEE" Val="58D" />
<ATTR Id="PAYMENTTYPE" Val="WR" />
<ATTR Id="AMOUNT" Val="1499.5" />
</DOBJ>
<DOBJ Id="FL_2">
<ATTR Id="ACCTNUMBER" Val="194061" />
<ATTR Id="CENTER" Val="506" />
<ATTR Id="DLRNUMBER" Val="48" />
<ATTR Id="DLR" Val="58D" />
<ATTR Id="PAYEE" Val="58D" />
<ATTR Id="PAYMENTTYPE" Val="WR" />
<ATTR Id="AMOUNT" Val="1499.5" />
</DOBJ>
</FL>
</COLL>
</DOBJ>
</REQUEST>
</PACK>
In Descendants you have to provide the XName of the nodes to search for. In your code example you try to search for a value of an attribute of a node.
You can do this:
var result = xdoc.Descendants("ATTR")
.FirstOrDefault(element =>
element.Attribute("Id")?.Value == "DLRNUMBER")?.Attribute("Val")?.Value;
This finds the first ATTR tag that has an Id attribute with the value DLRNUMBER and returns the value of its Val attribute.
If there may be other DLRNUMBER values at different levels that you don't want to find, you can consider to find the COLL node first:
var collNode = xdoc.Descendants("COLL").FirstOrDefault();
var result = collNode.Descendants("ATTR")
.FirstOrDefault(element =>
element.Attribute("Id")?.Value == "DLRNUMBER")?.Attribute("Val")?.Value;
or refine the search according to your requirements and the kind of xml you expect as input.
Try following. I prefer to get all items in an array so I can select one or more items as needed. :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication31
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement fl = doc.Descendants("FL").FirstOrDefault();
int[] dlrNumbers = fl.Elements("DOBJ").Select(x => x.Elements("ATTR").Where(y => (string)y.Attribute("Id") == "DLRNUMBER").Select(y => (int)y.Attribute("Val"))).SelectMany(y => y).ToArray();
}
}
}
Based on the XML below:
<?xml version="1.0" encoding="Windows-1252"?>
<ConfData>
<CfgAgentGroup>
<CfgGroup>
<DBID value="109" />
<tenantDBID value="1" />
<name value="group1" />
<contractDBID value="0" />
</CfgGroup>
<agentDBIDs>
<DBID value="103" />
<DBID value="994" />
</agentDBIDs>
</CfgAgentGroup>
<CfgAgentGroup>
<CfgGroup>
<DBID value="110" />
<tenantDBID value="1" />
<name value="group2" />
<contractDBID value="0" />
</CfgGroup>
<agentDBIDs>
<DBID value="102" />
<DBID value="103" />
<DBID value="1019" />
<DBID value="1020" />
</agentDBIDs>
</CfgAgentGroup>
</ConfData>
How can I get the <CfgGroup> element if the attribute value is 103 (referring to agentDBIDs/DBID value, NOT CfgGroup/DBID value)?
Any suggestions?
You can use SelectNodes() passing the following XPath as parameter to pull out CfgGroup elements where the corresponding agentDBIDs/DBID/#value equals 103, from an XmlDocument :
/ConfData/CfgAgentGroup[agentDBIDs/DBID/#value=103]/CfgGroup
working demo example :
var xml = #"<ConfData>
<CfgAgentGroup>
<CfgGroup>
<DBID value='109' />
<tenantDBID value='1' />
<name value='group1' />
<contractDBID value='0' />
</CfgGroup>
<agentDBIDs>
<DBID value='103' />
<DBID value='994' />
</agentDBIDs>
</CfgAgentGroup>
<CfgAgentGroup>
<CfgGroup>
<DBID value='110' />
<tenantDBID value='1' />
<name value='group2' />
<contractDBID value='0' />
</CfgGroup>
<agentDBIDs>
<DBID value='102' />
<DBID value='103' />
<DBID value='1019' />
<DBID value='1020' />
</agentDBIDs>
</CfgAgentGroup>
</ConfData>";
var doc = new XmlDocument();
doc.LoadXml(xml);
var result = doc.DocumentElement.SelectNodes("/ConfData/CfgAgentGroup[agentDBIDs/DBID/#value=103]/CfgGroup");
foreach(XmlNode r in result)
{
Console.WriteLine(r.OuterXml);
}
Dotnetfiddle Demo
output :
<CfgGroup><DBID value="109" /><tenantDBID value="1" /><name value="group1" /><contractDBID value="0" /></CfgGroup>
<CfgGroup><DBID value="110" /><tenantDBID value="1" /><name value="group2" /><contractDBID value="0" /></CfgGroup>
If I understood your question correctly, this should do
var xDoc = XDocument.Parse(File.ReadAllText(#"C:\YourDirectory\sample.xml"));
var cfgAgentGroups = xDoc.Descendants("CfgAgentGroup");
var cfgGroups = cfgAgentGroups
.Where(n => n.Element("agentDBIDs")
.Elements("DBID")
.Any(dbid => dbid.Attribute("value").Value == "103"))
.Select(cag => cag.Element("CfgGroup"));
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement CfgAgentGroup = doc.Descendants("CfgAgentGroup").Where(x => (int)x.Element("agentDBIDs").Element("DBID").Attribute("value") == 103).FirstOrDefault();
XElement cfgGroup = CfgAgentGroup.Element("CfgGroup");
}
}
}
Using C# I have extracted data from Google Analytics Data API and have got it in an xmldocument. From that point I want to export it to flat file format (txt file). I am trying to use the xmlnode class to write out element attribute values within the 'entry' elements but cant do it. XML code below:
<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dxp="http://schemas.google.com/analytics/2009" xmlns:openSearch="http://a9.com/- /spec/opensearch/1.1/">
<id>https://www.googleapis.com/analytics/v2.4/data?ids=ga:xxxxxxxxx&dimensions=ga:date,ga:hostname&metrics=ga:visits,ga:newVisits,ga:visitBounceRate,ga:transactions,ga:transactionRevenue,ga:itemQuantity&start-date=2012-09-20&end-date=2012-09-26&start-index=1&max-results=1000</id>
<updated>2012-09-27T08:08:53.621Z</updated>
<title type="text">Google Analytics Data for Profile xxxxxxxxx</title>
<link rel="self" type="application/atom+xml" href="https://www.googleapis.com/analytics/v2.4/data?ids=ga:xxxxxxxxx&dimensions=ga:date,ga:hostname&metrics=ga:visits,ga:newVisits,ga:visitBounceRate,ga:transactions,ga:transactionRevenue,ga:itemQuantity&start-date=2012-09-20&end-date=2012-09-26&start-index=1&max-results=1000" />
<author>
<name>Google Analytics</name>
</author>
<generator>Google Analytics</generator>
<openSearch:totalResults>49</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>1000</openSearch:itemsPerPage>
<dxp:aggregates>
<dxp:metric name="ga:visits" type="integer" value="942258" />
<dxp:metric name="ga:newVisits" type="integer" value="393698" />
<dxp:metric name="ga:visitBounceRate" type="percent" value="26.960025810340692" />
<dxp:metric name="ga:transactions" type="integer" value="328" />
<dxp:metric name="ga:transactionRevenue" type="currency" value="427646.331187" />
<dxp:metric name="ga:itemQuantity" type="integer" value="322" />
</dxp:aggregates>
<dxp:containsSampledData>true</dxp:containsSampledData>
<dxp:dataSource>
<dxp:property name="ga:profileId" value="xxxxxxxxx" />
<dxp:property name="ga:webPropertyId" value="UA-33036832-1" />
<dxp:property name="ga:accountName" value="TCO-UK-TC.com-[thomascook.com]" />
<dxp:tableId>ga:xxxxxxxxx</dxp:tableId>
<dxp:tableName>ThomasCook UK - Analytics Extract (VP /search)</dxp:tableName>
</dxp:dataSource>
<dxp:endDate>2012-09-26</dxp:endDate>
<dxp:startDate>2012-09-20</dxp:startDate>
<entry>
<id>https://www.googleapis.com/analytics/v2.4/data?ids=ga:xxxxxxxxx&ga:date=20120920&ga:hostname=87.248.112.8&start-date=2012-09-20&end-date=2012-09-26</id>
<updated>2012-09-27T08:08:53.621Z</updated>
<title type="text">ga:date=20120920 | ga:hostname=87.248.112.8</title>
<link rel="alternate" type="text/html" href="http://www.google.com/analytics" />
<dxp:dimension name="ga:date" value="20120920" />
<dxp:dimension name="ga:hostname" value="87.248.112.8" />
<dxp:metric name="ga:visits" type="integer" value="3" />
<dxp:metric name="ga:newVisits" type="integer" value="3" />
<dxp:metric name="ga:visitBounceRate" type="percent" value="100.0" />
<dxp:metric name="ga:transactions" type="integer" value="0" />
<dxp:metric name="ga:transactionRevenue" type="currency" value="0.0" />
<dxp:metric name="ga:itemQuantity" type="integer" value="0" />
</entry>
<entry>
<id>https://www.googleapis.com/analytics/v2.4/data?ids=ga:xxxxxxxxx&ga:date=20120920&ga:hostname=alpha.thomascook.com&start-date=2012-09-20&end-date=2012-09-26</id>
<updated>2012-09-27T08:08:53.621Z</updated>
<title type="text">ga:date=20120920 | ga:hostname=alpha.thomascook.com</title>
<link rel="alternate" type="text/html" href="http://www.google.com/analytics" />
<dxp:dimension name="ga:date" value="20120920" />
<dxp:dimension name="ga:hostname" value="alpha.thomascook.com" />
<dxp:metric name="ga:visits" type="integer" value="160" />
<dxp:metric name="ga:newVisits" type="integer" value="109" />
<dxp:metric name="ga:visitBounceRate" type="percent" value="21.25" />
<dxp:metric name="ga:transactions" type="integer" value="0" />
<dxp:metric name="ga:transactionRevenue" type="currency" value="0.0" />
<dxp:metric name="ga:itemQuantity" type="integer" value="0" />
</entry>
....so on.....
In the code below I need to change it to locate the entry elements, but can't find it. Using "/entry" yields nothing.
XmlNamespaceManager xmlnsm = new XmlNamespaceManager(xmld.NameTable);
xmlnsm.AddNamespace("dxp", "http://schemas.google.com/analytics/2009");
xmlnsm.AddNamespace("openSearch", "http://a9.com/-/spec/opensearch/1.1/");
xmlnsm.AddNamespace("gd", "http://schemas.google.com/g/2005");
foreach (XmlNode xmlnd in xmld.SelectNodes("//dxp:dimension", xmlnsm))
{
DimVal = xmlnd.Attributes["value"].Value.ToString();
DimName = xmlnd.Attributes["name"].Value.Replace("ga:", "");
// ...
}
I could be missing a namespace. Can anyone please help me out?
XDocument xDoc = XDocument.Load(fileToLoad); //or XDocument.Parse(xmlString)
XNamespace dxp = "http://schemas.google.com/analytics/2009";
XNamespace ns = "http://www.w3.org/2005/Atom";
var result =
xDoc.Descendants(ns + "entry")
.Select(e => new
{
Dimension = e.Descendants(dxp + "dimension")
.ToDictionary(d => d.Attribute("name").Value, d => d.Attribute("value").Value),
Metric = e.Descendants(dxp + "metric")
.ToDictionary(d => d.Attribute("name").Value, d => d.Attribute("value").Value)
})
.ToList();
Print the result:
foreach(var entry in result)
{
foreach (var dim in entry.Dimension)
Console.WriteLine(dim.Key + " = " + dim.Value);
Console.WriteLine();
foreach (var met in entry.Metric)
Console.WriteLine(met.Key + " = " + met.Value);
Console.WriteLine("---------------");
}
If you're just interested in getting all of the dxp:dimension elements you could use
GetElementsByTagName("dimension", "http://schemas.google.com/analytics/2009")
instead of
SelectNodes("//dxp:dimension", xmlnsm)
If you're intent on using SelectNodes, I think you need another / ("///dxp:dimension").
Specifically for your case you can do:
foreach(XmlElement ele in xmld.GetElementsByTagName("element"))
{
foreach(XmlElement dim in ele.GetElementsByTagName("dimension", "http://schemas.google.com/analytics/2009")
{
// Do w/e w/ the element
}
foreach(XmlElement met in ele.GetElementsByTagName("metric", "http://schemas.google.com/analytics/2009")
{
// Do w/e w/ the element
}
}
I have the following XML:
<funds>
<fund name="A" ITEM0="7%" ITEM1="8%" ITEM2="9%" ITEM3="10%" ITEM4="11%" ITEM5="" />
<fund name="B" ITEM0="11%" ITEM1="11%" ITEM2="13%" ITEM3="14%" ITEM4="16%" ITEM5="" />
<fund name="C" ITEM0="" ITEM1="" ITEM2="" ITEM3="" ITEM4="" ITEM5="" />
<fund name="D" ITEM0="7%" ITEM1="8%" ITEM2="9%" ITEM3="10%" ITEM4="11%" ITEM5="" />
<fund name="E" ITEM0="2%" ITEM1="3%" ITEM2="3%" ITEM3="5%" ITEM4="5%" ITEM5="" />
<fund name="F" ITEM0="" ITEM1="" ITEM2="" ITEM3="" ITEM4="" ITEM5="" />
<fund name="G" ITEM0="3%" ITEM1="3%" ITEM2="3%" ITEM3="5%" ITEM4="5%" ITEM5="" />
</funds>
<ToAppend>
<append name="A" ITEM="10" />
<append name="B" ITEM="15" />
<append name="C" ITEM="20" />
<append name="D" ITEM="20" />
<append name="E" ITEM="15" />
<append name="F" ITEM="10" />
<append name="G" ITEM="10" />
</ToAppend>
How can I loop through all of the attributes in //ToAppend/append and if 'name' is a match in //funds/fund add the attribute ITEM from //ToAppend/append to //funds/fund ?
I'm trying to append the matching items to the first list but I'm not having too much luck. Trying to get this working via C# under the 2.0 framework.
Thanks in advance!
edit:
XmlNode xmlNodeInner = root.SelectSingleNode("//ToAppend/append");
XmlNode ToBeUpdated = root.SelectSingleNode("//funds/fund");
foreach (XmlElement element in ToBeUpdated)
{
Console.WriteLine(element.InnerXml);
//Match the 'name' from xmlNodeInner to the 'name' of ToBeUpdated
//if{magic occurs here and they match}
{
element.SetAttribute("ITEM6", "value from xmlNodeInner");
}
}
I just dont know how to do the comparison inquiry to determine if A=A, or even exists, since there is no guarentee on that.
Hopefully it would come out something like:
<fund name="G" ITEM0="3%" ITEM1="3%" ITEM2="3%" ITEM3="5%" ITEM4="5%" ITEM5="" ITEM6="10"/>
This seems to work:
namespace ConsoleApplication1
{
using System;
using System.Xml;
class Program
{
static void Main( string[] args )
{
const string xml = #"
<root>
<funds>
<fund name='A' ITEM0='7%' ITEM1='8%' ITEM2='9%' ITEM3='10%' ITEM4='11%' ITEM5='' />
<fund name='B' ITEM0='11%' ITEM1='11%' ITEM2='13%' ITEM3='14%' ITEM4='16%' ITEM5='' />
<fund name='C' ITEM0='' ITEM1='' ITEM2='' ITEM3='' ITEM4='' ITEM5='' />
<fund name='D' ITEM0='7%' ITEM1='8%' ITEM2='9%' ITEM3='10%' ITEM4='11%' ITEM5='' />
<fund name='E' ITEM0='2%' ITEM1='3%' ITEM2='3%' ITEM3='5%' ITEM4='5%' ITEM5='' />
<fund name='F' ITEM0='' ITEM1='' ITEM2='' ITEM3='' ITEM4='' ITEM5='' />
<fund name='G' ITEM0='3%' ITEM1='3%' ITEM2='3%' ITEM3='5%' ITEM4='5%' ITEM5='' />
</funds>
<ToAppend>
<append name='A' ITEM='10' />
<append name='B' ITEM='15' />
<append name='C' ITEM='20' />
<append name='D' ITEM='20' />
<append name='E' ITEM='15' />
<append name='F' ITEM='10' />
<append name='G' ITEM='10' />
</ToAppend>
</root>
";
// XPath that finds all "funds/fund" nodes that have a "name" attribute with the value "{0}".
const string xpathTarget = #"//funds/fund[#name='{0}']";
// XPath that finds all "ToAppend/append" nodes that have a "name" and "ITEM" attribute.
const string xpathSourceNodes = #"//ToAppend/append[#name and #ITEM]";
var doc = new XmlDocument();
doc.LoadXml( xml );
foreach ( XmlNode sourceNode in doc.SelectNodes( xpathSourceNodes ) )
{
string name = sourceNode.Attributes[ "name" ].Value;
string item = sourceNode.Attributes[ "ITEM" ].Value;
XmlNode targetNode = doc.SelectSingleNode( String.Format( xpathTarget, name ) );
if ( null != targetNode )
{
XmlAttribute newAttribute = doc.CreateAttribute( "ITEM6" );
newAttribute.Value = item;
targetNode.Attributes.Append( newAttribute );
}
}
}
}
}