I am currently using DOM to navigate xml in my C# project. However, some XML that i've come across lately is a bit different.
whereas usually I have:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<entry>
<author>
<name>Me =)</name>
</author>
<content>
<somefield1>
<Subfield>subfield data</subfield>
</somefield>
</content>
</entry>
</feed>
and can navigate using foreach entry as entry, selectsinglenode(/content/somefield1/subfield), innertext to get the data from the subfield for each entry, the new XML looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
<atom:entry>
<atom:author>
<name>Me =)</name>
</atom:author>
<atom:content>
<somefield1>
<Subfield>subfield data</subfield>
</somefield>
</atom:content>
</atom:entry>
</atom:feed>
selectsinglenode(/atom:content/somefield1/subfield) is definitely not going to work...any suggestions?
atom: is just the namespace, and possibly you might just ignore it. If it still not works, you may have to use:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom");
selectsinglenode("atom:content/somefield1/subfield", nsmgr);
Which is documented here
Related
I have below xml structure:
<?xml version="1.0" encoding="UTF-8" ?>
<rss>
<channel>
<item>
<title>Some Title</title>
</wp:comment>
<wp:comment_approved><![CDATA[1]]></wp:comment_approved>
</wp:comment>
</wp:comment>
<wp:comment_approved><![CDATA[1]]></wp:comment_approved>
</wp:comment>
</item>
</channel>
</rss>
I can easily get all wp:comments by:
xmlNode.SelectNodes("*[name()='wp:comment']")
But how can I get all wp:comments where wp:comment_approved has value 1?
it's updated #Stefan Hegny answer, as you need not comment_approvedelement, but wp:comment
xmlNode.SelectNodes("//*[name()='wp:comment'][./*[local-name() = 'comment_approved' and . = '1']")
i'm not sure if default css locators working here, but in common css xPath i'll use this locator (logic is simple - you seach some element, that contains element with special parameter, so you can adjust this locator to your needs):
//someTag[./innerTag[text() = '1']]
I have xml files which look like this:
<?xml version="1.0" encoding="utf-8"?>
<record id="177" restricted="false">
<type>record type</type>
<startdate>2000-10-10</startdate>
<enddate>2014-02-01</enddate>
<titles>
<title xml:lang="en" type="main">Main title</title>
<!-- only one title element with type main -->
<title xml:lang="de" type="official">German title</title>
<!-- can have more titles of type official -->
</titles>
<description>description of the record</description>
<categories>
<category id="122">
<name>category name</name>
<description>category description</description>
</category>
<!-- can have more categories -->
</categories>
<tags>
<tag id="5434">
<name>tag name</name>
<description>tag description</description>
</tag>
<!-- can have more tags -->
</tags>
</record>
How do I select the data from these xml files using LINQ, or should I use something else?
You can load xml into XDocument objects using either the Load() method
for files, or the Parse() method for strings:
var doc = XDocument.Load("your-file.xml");
// OR
var doc = XDocument.Parse(yourXmlString);
Then you can access the data using LINQ:
var titles =
from title in doc.XPathSelectElements("//title")
where title.Attribute("type").Value == "official"
select title.Value;
Was searching for examples of Xmlserializer and found this: How to Deserialize XML document
So why not to try. I did Ctrl+C and Edit -> Paste Special -> Paste XML As Classes in Visual Studio 2013 and... Whoa I got all the classes generated. One condition target framework must be 4.5 and this function is available from Visual Studio 2012+ (as stated in that post)
I am trying to split a XML file to multiple small xml files in C#.net and am
trying to get the best possible approach to this. Any help on this will be
great... Sample example on what I am trying to do...
Source XML document
<?xml version="1.0" standalone="yes"?>
<DATABASE>
<DOC>
<DOCID>8510188</DOCID>
<ISSUE>2010</ISSUE>
<CAT>Literature and Art</CAT>
<TITLE>Test</TITLE>
<TEXT>Test</TEXT>
</DOC>
<DOC>
<DOCID>1510179</DOCID>
<ISSUE>2012</ISSUE>
<CAT>Miscellaneous</CAT>
<TITLE>Test</TITLE>
<TEXT>Test</TEXT>
</DOC>
</DATABASE>
Should split to two xml documents as below
1)
<?xml version="1.0" standalone="yes"?>
<DATABASE>
<DOC>
<DOCID>8510188</DOCID>
<ISSUE>2010</ISSUE>
<CAT>Literature and Art</CAT>
<TITLE>Test</TITLE>
<TEXT>Test</TEXT>
</DOC>
</DATABASE>
2)
<?xml version="1.0" standalone="yes"?>
<DATABASE>
<DOC>
<DOCID>1510179</DOCID>
<ISSUE>2012</ISSUE>
<CAT>Miscellaneous</CAT>
<TITLE>Test</TITLE>
<TEXT>Test</TEXT>
</DOC>
</DATABASE>
Well, I'd use LINQ to XML:
XDocument doc = XDocument.Load("test.xml");
var newDocs = doc.Descendants("DOC")
.Select(d => new XDocument(new XElement("DATABASE", d)));
foreach (var newDoc in newDocs)
{
newDoc.Save(/* work out filename here */);
}
(I'm assuming you want to save them. Maybe you don't need to. I've tested this just by printing them out to the console instead.)
In C#, Asp.Net, I am trying to return the Error node inside of BISearchResponse:
I am able to get the GetWireResult node returned in an XMLNode.
How do I get to the Error node?
<?xml version="1.0" encoding="utf-8" ?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <soap:Body>
- <GetWireResponse xmlns="http://OpenSolutions.com/">
<GetWireResult><?xml version="1.0"?>
<BISearchResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Error xmlns="https://bixg.choicepoint.com/webservices/3.0">
<Message>BI System: Failed to Login</Message>
<Code>536870917</Code>
</Error>
</BISearchResponse>
</GetWireResult>
</GetWireResponse>
</soap:Body>
</soap:Envelope>
My code:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(result);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("ab", "http://OpenSolutions.com/");
nsmgr.AddNamespace("bg", " https://bixg.choicepoint.com/webservices/3.0");
nsmgr.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
XmlNode xmlnode = xmlDoc.DocumentElement.SelectSingleNode("/soap:Envelope/soap:Body/ab:GetWireResponse", nsmgr);
This works to here.
.
I am adding the xml here, but it is only visible in edit mode.
<?xml version="1.0" encoding="utf-8" ?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <soap:Body>
- <GetWireResponse xmlns="http://OpenSolutions.com/">
<GetWireResult><?xml version="1.0"?> <BISearchResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Error xmlns="https://bixg.choicepoint.com/webservices/3.0"> <Message>BI System: Failed to Login</Message> <Code>536870917</Code> </Error> </BISearchResponse></GetWireResult>
</GetWireResponse>
</soap:Body>
</soap:Envelope>
In debug mode, when you copy this XML, try choose another debug visualizer, e.g. "Text visualizer". You can select it clicking the magnifying glass icon in datatip.
I think your XML looks like:
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetWireResponse xmlns="http://OpenSolutions.com/">
<GetWireResult>
<?xml version="1.0"?>
<BISearchResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Error xmlns="https://bixg.choicepoint.com/webservices/3.0">
<Message>BI System: Failed to Login</Message>
<Code>536870917</Code>
</Error>
</BISearchResponse>
</GetWireResult>
</GetWireResponse>
</soap:Body>
</soap:Envelope>
or
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetWireResponse xmlns="http://OpenSolutions.com/">
<GetWireResult>
<![CDATA[
<?xml version="1.0"?>
<BISearchResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Error xmlns="https://bixg.choicepoint.com/webservices/3.0">
<Message>BI System: Failed to Login</Message>
<Code>536870917</Code>
</Error>
</BISearchResponse>
]]>
</GetWireResult>
</GetWireResponse>
</soap:Body>
</soap:Envelope>
No matter. So you can select GetWireResult using following XPath:
/soap:Envelope/soap:Body/ab:GetWireResponse/ab:GetWireResult
and then load it content in new XML document and get desired response.
You're almost there. Extend your XPath
"/soap:Envelope/soap:Body/ab:GetWireResponse"
to
"/soap:Envelope/soap:Body/ab:GetWireResponse/ab:GetWireResult/ab:BISearchResponse/bg:Error"
However that extra XML prologue stuck in there in the middle, <?xml version="1.0"?>, makes the XML not well-formed. I'm surprised it can be processed at all. I would think the C# API should throw an exception on xmlDoc.LoadXml(result).
Another approach, seeing as the above does not return anything for you, would be to use your C# code to explore the structure of the XML document and print out the children of each node. E.g. if you are getting a node for "/soap:Envelope/soap:Body/ab:GetWireResponse" but not for "/soap:Envelope/soap:Body/ab:GetWireResponse/ab:GetWireResult", does ab:GetWireResponse have what text node children, and if so, what are their values (contents)? That should give insight into why the XPath is not working.
If there's a block of unparsed (i.e. escaped) XML in there, you could either copy it out and parse it as XML like you said, or just search for the pattern you need using a regexp... depending on the complexity.
How can i remove preprocessing instructions from an XML in a greener way? suppose that I have this xml in a string variable (which is a property of a class),I wanted to write it as value of another xml node,How can i achieve it in a cleaner way?
<?xml version="1.0" encoding="utf-8" ?>
<bookstore>
<book genre="autobiography">
<title>The Autobiography of Benjamin Franklin</title>
<author>
<first-name>Benjamin</first-name>
<last-name>Franklin</last-name>
</author>
<price>8.99</price>
</book>
<book genre="novel">
<title>The Confidence Man</title>
<author>
<first-name>Herman</first-name>
<last-name>Melville</last-name>
</author>
<price>11.99</price>
</book>
</bookstore>
You help would be much appreciated !!
If you can load it in an XmlDocument: FirstChild returns the <?xml version="1.0" encoding="utf-8" ?> node, and NextSibling returns the rest.
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNode node = doc.FirstChild.NextSibling;
Edit: Your xml looks a lot like the example on msdn for XPathNavigator.Select. Have you tried using that?
Edit2: You can get the name of the top level element using:
string topLevelNode = doc.DocumentElement.Name;
Try the code below. It will load the text to XmlDocument object first
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlAsText);
Then you can get the OutherXml using below:
xmlDoc.DocumentElement.OuterXml;