how to read values in this xml file?

R

Rich P

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
</PropertyGroup>
</Project>


I am using the following code to read the value in the <ProductVersion>
tag in the above xml file:

----------------------------------
XPathDocument doc = new XPathDocument(myxml.xml);
XPathNavigator nav = doc.CreateNavigator();

XPathExpression expr;
expr = nav.Compile("/Project/PropertyGroup/ProductVerion");
XPathNodeIterator iterator = nav.Select(expr);

iterator.MoveNext(); //actually in a loop
XPathNavigator nav2 = iterator.Current.Clone();
Console.WriteLine("version " + nav2.Value.ToString());
----------------------------------

this works if I leave out

xmlns="http://schemas.microsoft.com/developer/msbuild/2003"

from the <Project> tag. But the actual file that I am trying to read
contains the "xmlns ..." text and my routine won't read the
ProductVersion tag. I am hoping that the methods I am using here are
outdated and there are newer methods/classes I could use to perform this
read. Any help appreciated.

Thanks

Rich
 
R

Rich P

OK. I found this routine which sort of does the trick

XmlTextReader reader = new XmlTextReader ("data5.xml");
while (reader.Read())
{switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
Console.Write("<" + reader.Name);
Console.WriteLine(">");
break;
case XmlNodeType.Text: //Display the text in each element.
Console.WriteLine (reader.Value);
break;
case XmlNodeType.EndElement: //Display the end of the element.
Console.Write("</" + reader.Name);
Console.WriteLine(">");
break;
}
}
Console.ReadLine();
}

Except that I want to isolate the <ProductVersion> value. Well, at
least I'm making some progress.

Rich
 
P

Peter Duniho

Rich said:
[...]
----------------------------------
XPathDocument doc = new XPathDocument(myxml.xml);
XPathNavigator nav = doc.CreateNavigator();

XPathExpression expr;
expr = nav.Compile("/Project/PropertyGroup/ProductVerion");
XPathNodeIterator iterator = nav.Select(expr);

iterator.MoveNext(); //actually in a loop
XPathNavigator nav2 = iterator.Current.Clone();
Console.WriteLine("version " + nav2.Value.ToString());
----------------------------------

this works if I leave out

xmlns="http://schemas.microsoft.com/developer/msbuild/2003"

from the <Project> tag. But the actual file that I am trying to read
contains the "xmlns ..." text and my routine won't read the
ProductVersion tag. [...]

I think the problem you're running into is that with the xmlns
declaration, the element names actually implicitly include that XML
namespace, and so the namespace has to be included in the fully
qualified element name for your XPath expressions.

Unfortunately, as far as I know, there's no way to get XPathNavigator to
handle this automatically, because while the namespace itself is the URI
declared in the "xmlns" attribute, XPath requires a prefix, not the full
URI. You can't just stick the URI in front of the element name and have
it work.

But, you can get it to work in a "semi-automatic" way by creating an
XmlNamespaceManager that maps a prefix of your choosing to the URI for
the namespace, and then use that prefix in your XPath expression.

See below for a concise-but-complete code example that demonstrates the
technique (my apologies in advance for broken string literals...they
tend not to survive newsgroup copy-and-paste very well, but I assume you
can make the necessary edits after the fact if there's a problem).

You can also read about it here:
http://msdn.microsoft.com/en-us/library/e5t11tzt.aspx

If that doesn't answer your question, you really need to post a
concise-but-complete code example yourself, so that we can see what your
code is really doing and why it doesn't work.

Pete


using System;
using System.Xml.XPath;
using System.Xml;
using System.IO;

namespace TestXmlWithNamespace
{
class Program
{
static void Main(string[] args)
{
string strXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<Project ToolsVersion=\"3.5\" DefaultTargets=\"Build\"" +
"
xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" +
"<PropertyGroup>" +
"<ProductVersion>9.0.30729</ProductVersion>" +
"<SchemaVersion>2.0</SchemaVersion>" +
"<OutputType>WinExe</OutputType>" +

"<AppDesignerFolder>Properties</AppDesignerFolder>" +
"</PropertyGroup>" +
"</Project>";

XPathDocument doc = new XPathDocument(new
StringReader(strXml));
XPathNavigator nav = doc.CreateNavigator();
XmlNamespaceManager manager = new
XmlNamespaceManager(nav.NameTable);

manager.AddNamespace("default",
"http://schemas.microsoft.com/developer/msbuild/2003");

foreach (XPathNavigator xpath in
nav.Select("/default:project/default:propertyGroup/default:productVersion",
manager))
{
Console.WriteLine(xpath.Name);
}

Console.WriteLine("done");
Console.ReadLine();
}
}
}
 
T

Tom Shelton

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
</PropertyGroup>
</Project>

Well, if you using 2008, then I would do it something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;

namespace ConsoleApplication52
{
class Program
{
private const string Xml = @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project ToolsVersion=""3.5"" DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
<PropertyGroup>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
</PropertyGroup>
</Project>";

static void Main ( string[] args )
{
XNamespace dName = "http://schemas.microsoft.com/developer/msbuild/2003";
XElement doc = XElement.Load ( new StringReader ( Xml ) );
var s = ( from version in doc.Descendants ( dName + "ProductVersion" ) select version.Value ).FirstOrDefault ();
Console.WriteLine ( s );
}
}
}
 
R

Rich P

Thanks all for your replies. The manager suggestion worked as
advertised and the xml.linq method also worked well and less code.

Now I have a wealth of methods for reading xml. Question: is it
accurate that the XmlTextReader method will outperform xml.linq? I do
have hundreds (if not more) xml files that I will have to read.

Thanks again all for the help.

Rich
 
P

Peter Duniho

Rich said:
Thanks all for your replies. The manager suggestion worked as
advertised and the xml.linq method also worked well and less code.

Now I have a wealth of methods for reading xml. Question: is it
accurate that the XmlTextReader method will outperform xml.linq? I do
have hundreds (if not more) xml files that I will have to read.

It just depends. In theory, the linear behavior of the XmlTextReader is
more efficient and thus faster. But it's also less convenient to use,
and for small files, so much of the time cost of dealing with the file
is in just the basic processing of opening the file, reading something
from it, and closing it, costs that are incurred no matter what
technique you use to access the data in the file.

And of course, if you need random access to the data in the file,
XmlTextReader becomes unwieldy and potentially much less efficient.

If you have long files, and you know in advance that the data you need
to access is always close to the beginning of the file, I would say that
XmlTextReader is going to be a slam dunk for better performance. But
otherwise, there are too many variables to predict whether there will be
a significant, or any, improvement in performance. You're better off
using the API that is most convenient, and then watching for performance
issues in case they do occur.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top