I'm trying to write an XML file that will be picked up and parsed by another service. In order for this to happen the XML must be formatted in a very specific way, namely:
<?xml version="1.0"?>
<Feedbacks:Feedbacks xmlns:Feedbacks="Feedbacks">
<Feedbacks:Elements>
<Feedback:XMLFeedback xmlns:Feedback="Feedback">
<Feedback:MfgUnitID></Feedback:MfgUnitID>
<Feedback:MachineId></Feedback:MachineId>
<Feedback:OperationCode></Feedback:OperationCode>
<Feedback:ItemSeqNum></Feedback:ItemSeqNum>
<Feedback:OperDispositionCd></Feedback:OperDispositionCd>
<Feedback:ItemId></Feedback:ItemId>
<Feedback:ParentItemId></Feedback:ParentItemId>
<Feedback:ItemEndSize>1821</Feedback:ItemEndSize>
<Feedback:ItemDispositionCd></Feedback:ItemDispositionCd>
<Feedback:OperStartDate></Feedback:OperStartDate>
<Feedback:OperEndDate></Feedback:OperEndDate>
</Feedback:XMLFeedback>
</Feedbacks:Elements>
</Feedbacks:Feedbacks>
with data of course between the innermost elements. Here's the issue though, no matter what I do, I can't get any of the C# classes to keep the semicolons on the innermost nodes. As far as I know these need to stay, so is there a way in C# to force it to format the nodes this way? I've tried all of the create methods that I could find in the XMLDocument class. I can get the outer nodes formatted fine, but the inner ones just keep creating problems.
Edit, sorry here's the code that makes the inner nodes.
private void AppendFile(string filename, string[] headers, Dictionary<string, string> values)
{
XmlDocument doc = new XmlDocument();
doc.Load(filename);
XmlNode node = doc.GetElementsByTagName(headers[headers.Length - 2]).Item(0);
string[] hPieces = headers[headers.Length - 1].Split(':');
XmlElement appendee = doc.CreateElement(hPieces[0].Trim(), hPieces[1].Trim(), hPieces[0].Trim());
node.AppendChild(appendee);
foreach (KeyValuePair<string, string> pair in values)
{
string[] ePieces = pair.Key.Split(':');
//XmlElement element = doc.CreateElement(ePieces[0].Trim(), string.Empty, ePieces[1].Trim());
//XmlText text = doc.CreateTextNode(pair.Value);
XmlNode innerNode = doc.CreateNode(XmlNodeType.Element, ePieces[1].Trim(), ePieces[0].Trim());
node.InnerText = pair.Value;
// element.AppendChild(text);
appendee.AppendChild(innerNode);
}
doc.Save(filename);
}
The data for the inner nodes comes in as key value pairs in the dictionary. Where the keys contain the intended name.
Edit2: This is what the file output looks like
<?xml version="1.0" encoding="utf-8"?>
<Feedbacks:Feedbacks xmlns:Feedbacks="Feedbacks">
<Feedbacks:Elements>
<Feedback:XMLFeedback xmlns:Feedback="Feedback">
<MfgUnitID></MfgUnitID>
<MachineId></MachineId>
<OperationCode</OperationCode>
<ItemSeqNum></ItemSeqNum>
<OperDispositionCd></OperDispositionCd>
<ItemId></ItemId>
<ParentItemId></ParentItemId>
<ItemEndSize></ItemEndSize>
<ItemDispositionCd></ItemDispositionCd>
<OperStartDate></OperStartDate>
<OperEndDate></OperEndDate>
</Feedback:XMLFeedback>
</Feedbacks:Elements>
</Feedbacks:Feedbacks>
You can accompish this easily with XLinq:
using System.Xml.Linq;
XNamespace ns1 = "Feedbacks";
XNamespace ns2 = "Feedback";
var doc = new XElement("Feedbacks",
new XAttribute(XNamespace.Xmlns+"Feedbacks", ns1));
doc.Add(new XElement(ns1 + "Elements",
new XElement(ns2 + "Feedback",
new XAttribute(XNamespace.Xmlns+"Feedback", ns2),
new XElement(ns2 + "Unit"))));
Gives
<Feedbacks xmlns:Feedbacks="Feedbacks">
<Feedbacks:Elements>
<Feedback:Feedback xmlns:Feedback="Feedback">
<Feedback:Unit />
</Feedback:Feedback>
</Feedbacks:Elements>
</Feedbacks>
Although I believe that your own output should be valid XML, relying on the parent namespcae.
Related
I have to read some tags and attributes from an XML that has a defined structure but since those files can be generated from different sources, they can have different namespaces and prefixes.
This is the first XML sample
<Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:Order-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</cbc:CustomizationID>
<cbc:ID>ORD-001</cbc:ID>
<cbc:IssueDate>2016-10-01</cbc:IssueDate>
<cbc:OrderTypeCode listID="UNCL1001">221</cbc:OrderTypeCode>
<cac:ValidityPeriod>
<cbc:EndDate>2024-10-19</cbc:EndDate>
</cac:ValidityPeriod>
<cac:BuyerCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="IT:IPA">ITAK12MH</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID schemeID="IT:VAT">01567570254</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>A Custom Name</cbc:Name>
</cac:PartyName>
</cac:Party>
</cac:BuyerCustomerParty>
</Order>
This is the second XML sample with different namespaces and prefixes, but same structure (tags, attributes).
<ns10:Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ns2="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:ns3="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:ns4="http://www.w3.org/2000/09/xmldsig#" xmlns:ns5="http://uri.etsi.org/01903/v1.3.2#" xmlns:ns6="urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2" xmlns:ns7="urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2" xmlns:ns8="http://uri.etsi.org/01903/v1.4.1#" xmlns:ns9="urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2" xmlns:ns10="urn:oasis:names:specification:ubl:schema:xsd:Order-2">
<UBLVersionID>2.1</UBLVersionID>
<CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</CustomizationID>
<ID>ORD-001</ID>
<IssueDate>2016-10-01</IssueDate>
<OrderTypeCode listID="UNCL1001">221</OrderTypeCode>
<ns3:ValidityPeriod>
<EndDate>2024-10-19</EndDate>
</ns3:ValidityPeriod>
<ns3:BuyerCustomerParty>
<ns3:Party>
<EndpointID schemeID="IT:IPA">ITAK12MH</EndpointID>
<ns3:PartyIdentification>
<ID schemeID="IT:VAT">01567570254</ID>
</ns3:PartyIdentification>
<ns3:PartyName>
<Name>A Custom Name</Name>
</ns3:PartyName>
</ns3:Party>
</ns3:BuyerCustomerParty>
</ns10:Order>
Those files must be considered the same and so both valid.
A third example can be a file similar to the second where the namespaces are the same but their prefixes are different. Obviously the important thing is that the prefix used to match the namespace belongs to that particular tag.
I have no way of knowing in advance what will be the prefixes associated with namespaces.
<aaa:Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:aaa="urn:oasis:names:specification:ubl:schema:xsd:Order-2" xmlns:bbb="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
<UBLVersionID>2.1</UBLVersionID>
<CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</CustomizationID>
<ID>ORD-001</ID>
<IssueDate>2016-10-01</IssueDate>
<OrderTypeCode listID="UNCL1001">221</OrderTypeCode>
<bbb:ValidityPeriod>
<EndDate>2024-10-19</EndDate>
</bbb:ValidityPeriod>
<bbb:BuyerCustomerParty>
<bbb:Party>
<EndpointID schemeID="IT:IPA">ITAK12MH</EndpointID>
<bbb:PartyIdentification>
<ID schemeID="IT:VAT">01567570254</ID>
</bbb:PartyIdentification>
<bbb:PartyName>
<Name>A Custom Name</Name>
</bbb:PartyName>
</bbb:Party>
</bbb:BuyerCustomerParty>
</aaa:Order>
This last file must be considered valid as the others.
As you can see, the association between the tags and their namespaces are always the same. The only things that are changed are the prefixes.
My actual code uses XDocument and XElement classes to read the XML but it can be the way because I need to know the exact prefix for each tag and since they can vary, it works only with the first XML file sample.
XDocument doc;
XmlNamespaceManager manager;
using (XmlReader reader = XmlReader.Create(stream))
{
doc = XDocument.Load(reader);
// Retrieving namespaces of XML file
XPathNavigator navigator = doc.CreateNavigator();
navigator.MoveToFollowing(XPathNodeType.Element);
IDictionary<string, string> namespaces = navigator.GetNamespacesInScope(XmlNamespaceScope.All);
// Add namespaces to an XmlNamespaceManager to read nodes
manager = new XmlNamespaceManager(reader.NameTable);
foreach (KeyValuePair<string, string> ns in namespaces)
{
manager.AddNamespace(ns.Key, ns.Value);
}
}
XElement currentNode;
currentNode = doc.Root.XPathSelectElement("cbc:ID", manager);
if (currentNode != null)
item.DespatchAdviceId = currentNode.Value;
currentNode = doc.Root.XPathSelectElement("cbc:IssueDate", manager);
if (currentNode != null)
{
DateTime dataEmissione;
if (DateTime.TryParseExact(currentNode.Value, validDateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out dataEmissione))
item.OrderIssueDate = dataEmissione;
}
currentNode = doc.Root.XPathSelectElement("cac:BuyerCustomerParty/cac:Party/cac:PartyIdentification/cbc:ID", manager);
if (currentNode != null)
{
item.BuyerPartyId = currentNode.Value;
if (currentNode.Attribute("schemeID") != null)
item.BuyerPartySchemeId = currentNode.Attribute("schemeID").Value;
}
// ... and so on...
How can I read the XMLs without having to specify the namespace prefixes?
Should I use another .NET library or maybe a 3rd party one?
Using LocalName, you can linq it without adding the namespace.
//this is for <cbc:ID>ORD-001</cbc:ID>
var element = doc.Root.Elements().Where(x => x.Name.LocalName == "ID").FirstOrDefault();
If you want to go in the nested elements
var element = doc.Root.Elements().Where(x => x.Name.LocalName == "ValidityPeriod").
Elements().Where(x=> x.Name.LocalName == "EndDate").FirstOrDefault();
I need to know the exact prefix for each tag.
No, you don't. The prefixes are entirely irrelevant to qualified name of an element or attribute. If you want to go the XPath route, then don't read the namespaces and prefixes from the document to create your namespace manager, specify them yourself so you know what they are. Then use those in your query. For example, this will work with any of your XML documents:
var manager = new XmlNamespaceManager(new NameTable());
manager.AddNamespace("cbc",
"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2");
var id = doc.Root.XPathSelectElement("cbc:ID", manager);
What I would encourage, though, is that you ditch XPath. LINQ to XML is so much nicer. And another quick hint, there is an overload of XDocument.Load that accepts a stream. There's no need to create the XmlReader. So:
XNamespace order = "urn:oasis:names:specification:ubl:schema:xsd:Order-2";
XNamespace cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2";
XNamespace cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2";
var doc = XDocument.Load(stream);
var id = (string) doc.Elements(order + "Order")
.Elements(cbc + "ID")
.Single();
var issueDate = (DateTime) doc.Elements(order + "Order")
.Elements(cbc + "IssueDate")
.Single();
var buyerPartySchemeId = (string) doc.Descendants(cac + "BuyerCustomerParty")
.Descendants(cbc + "ID")
.Attributes("schemeID")
.Single();
Considering the following XML:
<Stations>
<Station>
<Code>HT</Code>
<Type>123</Type>
<Names>
<Short>H'bosch</Short>
<Middle>Den Bosch</Middle>
<Long>'s-Hertogenbosch</Long>
</Names>
<Country>NL</Country>
</Station>
</Stations>
There are multiple nodes. I need the value of each node.
I've got the XML from a webpage (http://webservices.ns.nl/ns-api-stations-v2)
Login (--) Pass (--)
Currently i take the XML as a string and parse it to a XDocument.
var xml = XDocument.Parse(xmlString);
foreach (var e in xml.Elements("Long"))
{
var stationName = e.ToString();
}
You can retrieve "Station" nodes using XPath, then get each subsequent child node using more XPath. This example isn't using Linq, which it looks like you possibly are trying to do from your question, but here it is:
XmlDocument xml = new XmlDocument();
xml.Load(xmlStream);
XmlNodeList stations = xml.SelectNodes("//Station");
foreach (XmlNode station in stations)
{
var code = station.SelectSingleNode("Code").InnerXml;
var type = station.SelectSingleNode("Type").InnerXml;
var longName = station.SelectSingleNode("Names/Long").InnerXml;
var blah = "you should get the point by now";
}
NOTE: If your xmlStream variable is a String, rather than a Stream, use xml.LoadXml(xmlStream); for line 2, instead of xml.Load(xmlStream). If this is the case, I would also encourage you to name your variable to be more accurately descriptive of the object you're working with (aka. xmlString).
This will give you all the values of "Long" for every Station element.
var xml = XDocument.Parse(xmlStream);
var longStationNames = xml.Elements("Long").Select(e => e.Value);
I need to take an XML file and create multiple output xml files from the repeating nodes of the input file. The source file "AnimalBatch.xml" looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<Animals>
<Animal id="1001">
<Quantity>One</Quantity>
<Adjective>Red</Adjective>
<Name>Rooster</Name>
</Animal>
<Animal id="1002">
<Quantity>Two</Quantity>
<Adjective>Stubborn</Adjective>
<Name>Donkeys</Name>
</Animal>
<Animal id="1003">
<Quantity>Three</Quantity>
<Color>Blind</Color>
<Name>Mice</Name>
</Animal>
</Animals>
The program needs to split the repeating "Animal" and produce 3 files named: Animal_1001.xml, Animal_1002.xml, and Animal_1003.xml
Each output file should contain just their respective element (which will be the root). The id attribute from AnimalsBatch.xml will supply the sequence number for the Animal_xxxx.xml filenames. The id attribute does not need to be in the output files.
Animal_1001.xml:
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>One</Quantity>
<Adjective>Red</Adjective>
<Name>Rooster</Name>
</Animal>
Animal_1002.xml
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>Two</Quantity>
<Adjective>Stubborn</Adjective>
<Name>Donkeys</Name>
</Animal>
Animal_1003.xml>
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>Three</Quantity>
<Adjective>Blind</Adjective>
<Name>Mice</Name>
</Animal>
I want to do this with XmlDocument, since it needs to be able to run on .Net 2.0.
My program looks like this:
static void Main(string[] args)
{
string strFileName;
string strSeq;
XmlDocument doc = new XmlDocument();
doc.Load("D:\\Rick\\Computer\\XML\\AnimalBatch.xml");
XmlNodeList nl = doc.DocumentElement.SelectNodes("Animal");
foreach (XmlNode n in nl)
{
strSeq = n.Attributes["id"].Value;
XmlDocument outdoc = new XmlDocument();
XmlNode rootnode = outdoc.CreateNode("element", "Animal", "");
outdoc.AppendChild(rootnode); // Put the wrapper element into outdoc
outdoc.ImportNode(n, true); // place the node n into outdoc
outdoc.AppendChild(n); // This statement errors:
// "The node to be inserted is from a different document context."
strFileName = "Animal_" + strSeq + ".xml";
outdoc.Save(Console.Out);
Console.WriteLine();
}
Console.WriteLine("END OF PROGRAM: Press <ENTER>");
Console.ReadLine();
}
I think I have 2 problems.
A) After doing the ImportNode on node n into outdoc, I call outdoc.AppendChild(n) which complains: "The node to be inserted is from a different document context." I do not know if this is a scope issue referencing node n within the ForEach loop - or if I am somehow not using ImportNode() or AppendChild properly. 2nd argument on ImportNode() is set to true, because I want the child elements of Animal (3 fields arbitrarily named Quantity, Adjective, and Name) to end up in the destination file.
B) Second problem is getting the Animal element into outdoc. I'm getting '' but I need ' ' so I can place node n inside it. I think my problem is how I am doing: outdoc.AppendChild(rootnode);
To show the xml, I'm doing: outdoc.Save(Console.Out); I do have the code to save() to an output file - which does work, as long as I can get outdoc assembled properly.
There is a similar question at: Split XML in Multiple XML files, but I don't understand the solution code yet. I think I'm pretty close on this approach, and will appreciate any help you can provide.
I'm going to be doing this same task using XmlReader, since I'm going to need to be able to handle large input files, and I understand that XmlDocument reads the whole thing in and can cause memory issues.
That's a simple method that seems what you are looking for
public void test_xml_split()
{
XmlDocument doc = new XmlDocument();
doc.Load("C:\\animals.xml");
XmlDocument newXmlDoc = null;
foreach (XmlNode animalNode in doc.SelectNodes("//Animals/Animal"))
{
newXmlDoc = new XmlDocument();
var targetNode = newXmlDoc.ImportNode(animalNode, true);
newXmlDoc.AppendChild(targetNode);
newXmlDoc.Save(Console.Out);
Console.WriteLine();
}
}
This approach seems to work without using the "var targetnode" statement. It creates an XmlNode object called targetNode from outdoc's "Animal" element in the ForEach loop. I think the main things that were problems in my original code were: A) I was getting nodelist nl incorrectly. And B) I couldn't "Import" node n, I think because it was associated specifically with doc. It had to be created as its own Node.
The problem with the prior proposed solution was the use of the "var" keyword. My program has to assume 2.0 and that came in with v3.0. I like Rogers solution, in that it is concise. For me - I wanted to do each thing as a separate statement.
static void SplitXMLDocument()
{
string strFileName;
string strSeq;
XmlDocument doc = new XmlDocument(); // The input file
doc.Load("D:\\Rick\\Computer\\XML\\AnimalBatch.xml");
XmlNodeList nl = doc.DocumentElement.SelectNodes("//Animals/Animal");
foreach (XmlNode n in nl)
{
strSeq = n.Attributes["id"].Value; // Animal nodes have an id attribute
XmlDocument outdoc = new XmlDocument(); // Create the outdoc xml document
XmlNode targetNode = outdoc.CreateElement("Animal"); // Create a separate node to hold the Animal element
targetNode = outdoc.ImportNode(n, true); // Bring over that Animal
targetNode.Attributes.RemoveAll(); // Remove the id attribute in <Animal id="1001">
outdoc.ImportNode(targetNode, true); // place the node n into outdoc
outdoc.AppendChild(targetNode); // AppendChild to make it stick
strFileName = "Animal_" + strSeq + ".xml";
outdoc.Save(Console.Out); Console.WriteLine();
outdoc.Save("D:\\Rick\\Computer\\XML\\" + strFileName);
Console.WriteLine();
}
}
Having problems getting NodeList.SelectSingleNode() to work properly.
My XML looks like this:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<inm:Results xmlns:inm="http://www.namespace.com/1.0">
<inm:Recordset setCount="18254">
<inm:Record setEntry="0">
<!-- snip -->
<inm:Image>fileName.jpg</inm:Image>
</inm:Record>
</inm:Recordset>
</inm:Results>
The data is a long series of <inm:Record> entries.
I open the doc and get create a NodeList object based on "inm:Record". This works great.
XmlDocument xdoc = new XmlDocument();
xdoc.Load(openFileDialog1.FileName);
XmlNodeList xRecord = xdoc.GetElementsByTagName("inm:Record");
I start looping through the NodeList using a for loop. Before I process a given entry, I want to check and see if the <inm:Image> is set. I thought it would be super easy just to do
string strImage = xRecord[i].SelectSingleNode("inm:Image").InnerText;
My thinking being, "For the XRecord that I'm on, go find the <inm:Image> value ...But this doesn't work as I get the exception saying that I need a XmlNameSpaceManager. So, I tried to set that up but could never get the syntax right.
Can someone show me how to use the correct XmlNameSpaceManager syntax in this case.
I've worked around the issue for now by looping through all of the childNodes for a given xRecord, and checking the tag once I loop around to it. I would like to check that value first to see if I need to loop over that <inm:Record> entry at all.
No need to loop through all the Record elements, just use XPath to specify the subset that you want:
XmlDocument xdoc = new XmlDocument();
xdoc.Load(openFileDialog1.FileName);
XmlNamespaceManager manager = new XmlNamespaceManager(xdoc.NameTable);
manager.AddNamespace("inm", "http://www.inmagic.com/webpublisher/query");
XmlNodeList nodes = xdoc.SelectNodes("/inm:Results/inm:Recordset/inm:Record[inm:Image != '']", manager);
Using the LINQ to XML libraries, here's an example for retrieving that said node's value:
XDocument doc = XDocument.Load(openFileDialog1.FileName);
List<XElement> docElements = doc.Elements().ToList();
XElement results = docElements.Elements().Where(
ele => ele.Name.LocalName == "Results").First();
XElement firstRecord = results.Elements().Where(
ele => ele.Name.LocalName == "Record").First();
XElement recordImage = firstRecord .Elements().Where(
ele => ele.Name.LocalName == "Image").First();
string imageName = recordImage.Value;
Also, by the way, using Hungarian notation for a type-checked language is overkill. You don't need to prepend string variables with str when it will always be a string.
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
string strImage = xRecord[i].SelectSingleNode("inm:Image",nsMgr).InnerText;
Should do it.
Using this Xml library, you can get all the records that have an Image child element with this:
XElement root = XElement.Load(openFileDialog1.FileName);
XElement[] records = root.XPath("//Record[Image]").ToArray();
If you want to be sure that the Image child contains a value, it can be expressed like this:
XElement[] records = root.XPath("//Record[Image != '']").ToArray();
In my previous question here, I didn’t understand how to solve my problem.
Linq to XML, how to acess an element in C#?
Here is my XML I need to parse:
<root>
<photo>/filesphoto.jpg</photo>
<photo:mtime>12</photo:mtime>
<text>some text</text>
</root>
To access the element I use this code:
var doc = XDocument.Parse(xml.Text);
doc.Descendants("text").FirstOrDefault().Value;
How can I access ?
I have try http://aspnetgotyou.blogspot.com/2010/06/xdocument-or-xelement-with-xmlnamespace.html,
But it is ignored <photo:mtime> and I need to access it.
Please write some code.
Contrary to #BrokenGlass' comments, your XML is not invalid. In fact the technique in the link you provided in your question (for loading namespaces) works fine. Maybe you just didn't change the example for your own needs. Here's a more compact generalization for parsing xml fragments with namespaces into an XElement:
public static XElement parseWithNamespaces(String xml, String[] namespaces) {
XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(new NameTable());
foreach (String ns in namespaces) { nameSpaceManager.AddNamespace(ns, ns); }
return XElement.Load(new XmlTextReader(xml, XmlNodeType.Element,
new XmlParserContext(null, nameSpaceManager, null, XmlSpace.None)));
}
Using your exact input:
string xml =
#"<root>
<photo>/filesphoto.jpg</photo>
<photo:mtime>12</photo:mtime>
<text>some text</text>
</root>";
XElement x = parseWithNamespaces(xml, new string[] { "photo" });
foreach (XElement e in x.Elements()) {
Console.WriteLine("{0} = {1}", e.Name, e.Value);
}
Console.WriteLine(x.Element("{photo}mtime").Value);
Prints:
photo = /filesphoto.jpg
{photo}mtime = 12
text = some text
12
Try this: (Your xml is changed a little, see )
string xml = "<root><photo>/filesphoto.jpg</photo><photoMtime>12</photoMtime><text>some text</text></root>";
var doc = XDocument.Parse(xml);
string value = doc.Descendants("text").FirstOrDefault().Value;
MessageBox.Show(value);