I have a oracle query to generate below xml result and I like to check only if there is any attribute value inside SUBQUERY and COL_LIST_ITEM nodes not others. If nodes has attribute value than write "it has attribute value" else "no attribute value". I am not sure if my code is correct! Is there any way to do that?
<VIEW xmlns="http://xmlns.oracle.com/ku" version="1.0">
<SCHEMA value1="USER1">USER2</SCHEMA>
<NAME value1="VIEW_TBL_A">VIEW_TBL_B</NAME>
<COL_LIST>
<COL_LIST_ITEM>
</COL_LIST_ITEM>
<COL_LIST_ITEM src="2">
<NAME>FIELD_A2</NAME>
</COL_LIST_ITEM>
</COL_LIST>
<SUBQUERY value1="SELECT FIELD_A1
FROM TBL_A
WHERE FIELD_A1 = 111">SELECT FIELD_A1, FIELD_A2
FROM TBL_A
WHERE FIELD_A1 = 111</SUBQUERY>
</VIEW>
Here is my Code
using (OracleConnection conn1 = new OracleConnection(oradb1))
{
conn1.Open();
using (OracleCommand crtCommand = new OracleCommand("SELECT dbms_metadata.get_sxml('VIEW','VIEW_TBL_A') FROM dual;", conn1))
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(crtCommand.ExecuteScalar().ToString());
}
}
how about an XDocument
XDocument doc = XDocument.Parse(crtCommand.ExecuteScalar().ToString());
XNamespace ns = "http://xmlns.oracle.com/ku";
if (doc.Descendants(ns + "COL_LIST_ITEM").Any(c => c.Attributes().Any()))
Console.WriteLine("COL_LIST has value");
and of course add your other nodes in to check
You should use LINQ to XML to query your XML document:
XDocument document = XDocument.Load(xmlFile);
IEnumerable<XElement> elements =
from element in document.Root.Elements("SUBQUERY")
where element.HasAttributes
select element;
Refer to the article here for more details.
I also ran into a similar problem, while working on a Universal Windows App, and was also very frustrated when VS didn't specify clearly what the problem was. Although after hours of surfing the web, I found the solution. It was simple, but i don't know why VS didn't specify it. Anyways, here it is :-
Add another reference to your project :-
using System.Linq; apart from using System.Xml.Linq;
using System.Linq;
using System.Xml.Linq;
The errors will go & the project will build.
For more help reference this article :-
problem with using refrence to System.Xml.Linq
Related
I'm new with C#. please help me.
data.xml
<?xml version="1.0" standalone="yes"?>
<DataSet1 xmlns="http://tempuri.org/DataSet1.xsd">
<Language>
<Id>001</Id>
<English>"Welcome to India"</English>
<German>"Willkommen in Indien"</German>
</Language>
</DataSet1>
How to read value of Id using C# Xml? I'm new with C#. please help me.
My effort:
XmlDocument doc = new XmlDocument();
XmlReader reader = XmlReader.Create(#"D:\data.xml");
while(reader.Read())
{
reader.MoveToContent();
if (reader.IsStartElement("DataSet1"))
{
reader.ReadToDescendant("Language");
string str2 = reader.Name.ToString();
MessageBox.Show(str2);
}
}
I'd strongly advise you to use LINQ to XML, which is a much simpler API than XmlDocument, and has excellent namespace support. Here's an example to get the Id value with LINQ to XML:
using System;
using System.Xml.Linq;
public class Program
{
public static void Main()
{
XDocument doc = XDocument.Load("test.xml");
XNamespace ns = "http://tempuri.org/DataSet1.xsd";
string id = doc.Root // From the root...
.Element(ns + "Language") // select the Language direct child...
.Element(ns + "Id") // and the Id child of that...
.Value; // and then take the text value
Console.WriteLine(id);
}
}
Obviously if your XML doesn't just have a single Language element you'll need to pick the right one, etc. You should read the LINQ to XML documentation for more information.
Use XmlDocument, if you Need further help leave a comment :)
XmlDocument xdoc = new XmlDocument("YourXmlString");
XmlNodeList xNodes = xdoc.GetElementsByTagName("Id");
string Wished = xNodes[0].InnerText;
Little bit of explanation:
I recommend XmlDocument a lot because I really like to work with it myself, and besides that it has some pretty neat features to explore. Besides that, it is easy to get or to iterate through nodes
I'm trying to pull some values from some customer-supplied XML documents, using XmlDocument.SelectSingleNode().
SelectSingleNode() takes an XPATH string, and very simple searches are failing. E.g. with this:
<?xml version="1.0"?>
<xmlTicket>
<TicketDataSet xmlns="http://tempuri.org/Ticket.xsd">
<Ticket>
<TicketNumber>0123-456-789</TicketNumber>
...
</Ticket>
</TicketDataSet>
</xmlTicket>
XmlDocument.SelectSingleNode("//TicketNumber") returns null.
The problem is clearly the namespace. If I remove the xmlns= from the doc, the XPATHs work fine. If I use namespace neutral XPATH queries, they also work fine:
doc.SelectSingleNode("//*[local-name()='TicketNumber']");
But I can't do the former and I'd rather not do the latter.
I've found examples of how to configure a namespace manager, and tried to work out how to make this work for a default namespace.
This didn't work:
var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace("", "http://tempuri.org/Ticket.xsd");
var ticketNumberNode = doc.SelectSingleNode("//TicketNumber", nsm);
And this didn't work:
var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace("default", "http://tempuri.org/Ticket.xsd");
var ticketNumberNode = doc.SelectSingleNode("//default:TicketNumber", nsm);
Any ideas?
===
Note: I updated the XML to show more of the structure. The problem seems to be related to having default namespaces applied to parts of the document, rather than to its entirety.
Try xml linq :
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);
string ticketNumber = (string)doc.Descendants().Where(x => x.Name.LocalName == "TicketNumber").FirstOrDefault();
}
}
}
The solution is strange but you should specify namespace with prefix in SelectionNamespaces property and specify this prefix in XPath queries. It doesn't matter if this namespace is default namespace with no prefix: you should use one. On the other side, you should add nodes to XML without prefix.
In your example the code should looks like this:
doc.setProperty("SelectionNamespaces", "xmlns:abc='http://tempuri.org/Ticket.xsd'");
doc.selectSingleNode("//abc:TicketNumber");
Why is this Xpath not working using XDocument.XPathSelectElement?
Xpath:
//Plugin/UI[1]/PluginPageCategory[1]/Page[1]/Group[1]/CommandRef[2]
XML
<Plugin xmlns="http://www.MyNamespace.ca/MyPath">
<UI>
<PluginPageCategory>
<Page>
<Group>
<CommandRef>
<Images>
</Images>
</CommandRef>
<CommandRef>
<Images>
</Images>
</CommandRef>
</Group>
</Page>
</PluginPageCategory>
</UI>
</Plugin>
C# Code:
myXDocument.XPathSelectElement("//Plugin/UI[1]/PluginPageCategory[1]/Page[1]/Group[1]/CommandRef[2]", myXDocument.Root.CreateNavigator());
When namespaces are used, these must be used in the XPath query also. Your XPath query would only work against elements with no namespace (as can be verified by removing the namespace from your XML).
Here's an example showing how you create and pass a namespace manager:
var xml = ... XML from your post ...;
var xmlReader = XmlReader.Create( new StringReader(xml) ); // Or whatever your source is, of course.
var myXDocument = XDocument.Load( xmlReader );
var namespaceManager = new XmlNamespaceManager( xmlReader.NameTable ); // We now have a namespace manager that knows of the namespaces used in your document.
namespaceManager.AddNamespace( "prefix", "http://www.MyNamespace.ca/MyPath" ); // We add an explicit prefix mapping for our query.
var result = myXDocument.XPathSelectElement(
"//prefix:Plugin/prefix:UI[1]/prefix:PluginPageCategory[1]/prefix:Page[1]/prefix:Group[1]/prefix:CommandRef[2]",
namespaceManager
); // We use that prefix against the elements in the query.
Console.WriteLine(result); // <CommandRef ...> element is printed.
Hope this helps.
This should probably be a comment on #Cumbayah's post, but I can't seem to leave comments on anything.
You are probably better off using something like this instead of using XmlReader to get the nametable.
var xml = ... XML from your post ...;
var myXDocument = XDocument.Parse(xml);
var namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("prefix", "http://www.MyNamespace.ca/MyPath");
var result = ...;
The easiest way in your case is to use XPath axes and node test for node name and position to select the element.
Your XPath selection:
myXDocument.XPathSelectElement("//Plugin/UI[1]/PluginPageCategory[1]/Page[1]/Group[1]/CommandRef[2]", myXDocument.Root.CreateNavigator());
Can be easily translate to:
myXDocument.XPathSelectElement("/child::node()[local-name()='Plugin']/child::node()[local-name()='UI'][position()=1]/child::node()[local-name()='PluginPageCategory'][position()=1]/child::node()[local-name()='Page'][position()=1]/child::node()[local-name()='Group'][position()=1]/child::node()[local-name()='CommandRef'][position()=2]");
There is no need to create and pass XmlNamespaceManager as parameter.
There is a way to do it without any change to the xpath. The solution I've found is to remove the namespace when parsing the XML into the XDocument.
Here is an exemple:
var regex = #"(xmlns:?[^=]*=[""][^""]*[""])";
var myXDocument = XDocument.Parse(Regex.Replace("MyXmlContent", regex, "", RegexOptions.IgnoreCase | RegexOptions.Multiline))
Now that the namespace is gone, it is easyer to manipulate.
I know this question has been asked in a similar fashion before, but I can't seem to get this working.
I have some xml:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<Research xmlns="http://www.rixml.org/2005/3/RIXML" xmlns:xalan="http://xml.apache.org/xalan" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" createDateTime="2011-03-29T15:41:48Z" language="eng" researchID="MusiJvs3008">
<Product productID="MusiJvs3008">
<StatusInfo currentStatusIndicator="Yes" statusDateTime="2011-03-29T15:41:48Z" statusType="Published" />
<Source>
<Organization type="SellSideFirm" primaryIndicator="Yes">
<OrganizationID idType="Reuters">9999</OrganizationID>
And I'm trying to read values using xpath:
XPathDocument xmldoc = new XPathDocument(xmlFile);
XPathNavigator nav = xmldoc.CreateNavigator();
XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable);
nsMgr.AddNamespace(string.Empty, "http://www.rixml.org/2005/3/RIXML");
XPathNavigator result = nav.SelectSingleNode("/Research", nsMgr); // <-- Returns null!
But even a simple select of the root node returns null! I am sure I have something wrong with my namespace. Can someone please help?
Ideally I want simple lines that will let me select values from the xml file, i.e.
String a = xmlDoc.SelectSingleNode(#"/Research/Product/Content/Title").Value;
BTW, I have no (direct) control over the XML file content.
I don't believe you can use an empty namespace alias and have it used automatically by the XPath expression. As soon as you use an actual alias, it should work though. This test is fine, for example:
using System;
using System.Xml;
using System.Xml.XPath;
class Test
{
static void Main()
{
string xmlFile = "test.xml";
XPathDocument xmldoc = new XPathDocument(xmlFile);
XPathNavigator nav = xmldoc.CreateNavigator();
XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable);
nsMgr.AddNamespace("x", "http://www.rixml.org/2005/3/RIXML");
XPathNavigator result = nav.SelectSingleNode("/x:Research", nsMgr);
Console.WriteLine(result);
}
}
Do you have to use XPath and XPathDocument, by the way? I tend to find that LINQ to XML is a much more pleasant API, particularly when it comes to namespaces. If you're using .NET 3.5 and you have no particular requirement to use XPath, I'd suggest you check it out.
Make the following changes
nsMgr.AddNamespace("x", "http://www.rixml.org/2005/3/RIXML");
XPathNavigator result = nav.SelectSingleNode("/x:Research", nsMgr);
i could post, and answer my own question, for the native equivalent of this code. Instead i'll just add it as an answer to the end.
When using the native IXMLDOMDocument (version 6) object:
//Give the default namespace as alias of "x"
document.setProperty("SelectionNamespaces","xmlns:x='http://www.rixml.org/2005/3/RIXML'");
//Query for the nodes we want
document.selectSingleNode("/x:Research");
Bonus Question: Why, oh why, does no Xml Document object model query the default namespace when no namespace is specified... sigh
I have some c# code running on sharepoint that i use to check inside the xml of an infopath document to see if i should checking the document or discard the document.
The code is working fine for a couple of different form templates i have created but is failing on my latested one.
I have discovered that the XmlNamespaceManager i am creating contains the wrong diffinition for the "MY" namepsace.
I'll try to explain
I have this code to decalre my XmlNamespaceManager
NameTable nt = new NameTable();
NamespaceManager = new XmlNamespaceManager(nt);
// Add prefix/namespace pairs to the XmlNamespaceManager.
NamespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
NamespaceManager.AddNamespace("xhtml", "http://www.w3.org/1999/xhtml");
NamespaceManager.AddNamespace("dfs", "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution");
NamespaceManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-07-14T13:45:59");
NamespaceManager.AddNamespace("xd", "http://schemas.microsoft.com/office/infopath/2003");`
I can then use the following line of code to search for the xml i am after
XPathNavigator nav = xml.CreateNavigator().SelectSingleNode("//my:HasSaved", NamespaceManager);
nav.Value then gets be the data i want.
This all works fine on a couple of my form templates. I ahve a new form template and have discovered that i need to use thi line instead
NamespaceManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-11-30T17:39:37");
The date is different.
My problem is that i cannot add this twice as only 1 set of forms will work.
So my question is. Is there a way i can generate the NamespaceManager object from the XML file as this is all contained in the header?
I have not been able to find a simple way round this.
I found a way of doing this. Instead of adding the "my" namespace it can be pulled from the XmlDocument object. This might just be a bit of luck that it works this way but i'm happy with it.
NamespaceManager.AddNamespace("my", formXml.DocumentElement.NamespaceURI
formXML is an XmlDocument created from the infopath XML
One option would be to try to load the xml node using the first namespace, if that doesn't give any results, call PushScope(), override the first namespace definition, select, etc...
var doc = new XmlDocument();
doc.LoadXml(#"<?xml version=""1.0""?>
<root xmlns:my=""http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-11-30T17:39:37"" value=""1"">
<my:item>test</my:item>
</root>");
var nameTable = new NameTable();
var namespaceManager = new XmlNamespaceManager(nameTable);
namespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
namespaceManager.AddNamespace("xhtml", "http://www.w3.org/1999/xhtml");
namespaceManager.AddNamespace("dfs", "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution");
namespaceManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-07-14T13:45:59");
namespaceManager.AddNamespace("xd", "http://schemas.microsoft.com/office/infopath/2003");
// n will be null since the namespace url doesn't match
var n = doc.SelectSingleNode("descendant::my:item", namespaceManager);
namespaceManager.PushScope();
namespaceManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-11-30T17:39:37");
// will work
n = doc.SelectSingleNode("descendant::my:item", namespaceManager);
namespaceManager.PopScope();
Another option is to parse the attributes in the header and look for any contained namespaces
foreach(XmlAttribute attribute in doc.DocumentElement.Attributes)
{
var url = namespaceManager.LookupNamespace(attribute.LocalName);
if(url != null && url != attribute.Value)
{
namespaceManager.RemoveNamespace(attribute.LocalName, url);
namespaceManager.AddNamespace(attribute.LocalName, attribute.Value);
}
}
You don't need to do anything like this. Just use "my2" or something for the second namespace. You then need the new namespace prefix for any nodes that use the new namespace, and use the old "my" namespace prefix for all the nodes that still use the old namespace.