views:

249

answers:

3

This may seem like an odd question, but I have my own reasons for this! I am trying to parse a Delphi 2009 project file (.dproj), which is an XML representation of the project. I Can load the document into an XmlDocument, but when I try and get to the units that are used in the project, SelectNodes gives me an empty list.

An example of the project is below :

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&gt;
...
...
<ItemGroup>
  <DelphiCompile Include="Package.dpk">
    <MainSource>MainSource</MainSource>
  </DelphiCompile>
  <DCCReference Include="vcl.dcp"/>
  <DCCReference Include="Unit1.pas"/>
  <DCCReference Include="Unit2.pas"/>
  <DCCReference Include="Unit3.pas"/>
  <DCCReference Include="Unit4.pas"/>
  <DCCReference Include="Unit5.pas"/>
  ...
</ItemGroup>
</Project>

An example of the code is below:

  ProjectDocument.Load(FileName);
  XmlNodeList nodeList;
  XmlElement RootNode = ProjectDocument.DocumentElement;

  string xmlns = RootNode.Attributes["xmlns"].Value;

  // This gives an empty list
  nodeList = RootNode.SelectNodes("/Project/ItemGroup/DCCReference");
  foreach (XmlNode title in nodeList)
  {
    Console.WriteLine(title.InnerXml);
  }

  // This also gives an empty list
  nodeList = RootNode.SelectNodes("/ItemGroup/DCCReference");
  foreach (XmlNode title in nodeList)
  {
    Console.WriteLine(title.InnerXml);
  }

The question is really, what am I doing wrong, as I must be missing something. The only odd thing is that the document is not a .xml, it is a .dproj.

So, thanks in advance if you can solve this.

Mark

+3  A: 

Quoting the documentation:

Remarks

If the XPath expression requires namespace resolution, you must use the SelectNodes overload which takes an XmlNamespaceManager as its argument. The XmlNamespaceManager is used to resolve namespaces.

Note If the XPath expression does not include a prefix, it is assumed that the namespace URI is the empty namespace. If your XML includes a default namespace, you must still use the XmlNamespaceManager and add a prefix and namespace URI to it; otherwise, you will not get any nodes selected.

You need the two-argument version of SelectNodes. Also, note that the nodes you're selecting have no contents, so the InnerXML property will be empty. Once you get a non-empty list, your code will still print a list of empty lines.

Rob Kennedy
Great, a combination of both these answers did the trick. Thanks
Mmarquee
+2  A: 

You need to use a XmlNamespaceManager:

var nsmgr = new XmlNamespaceManager(ProjectDocument.NameTable);
nsmgr.AddNamespace("x", ProjectDocument.DocumentElement.NamespaceURI);
var nodes = doc.SelectNodes("descendant::x:DCCReference", nsmgr);
Darin Dimitrov
Great, a combination of both these answers did the trick. Thanks
Mmarquee
A: 

Also, why aren't you parsing the DPR file with your own simple parser? Find the uses line, then grab every line after that, strip the comments, and the final comma, until you hit a line with a semicolon.

Benefit #2 besides simpler parsing is this works with EVERY delphi version, whereas DPROJ and equivalent files are famously different from delphi version to version.

Warren P