Click here to Skip to main content
14,869,990 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Wondering how to explain this one...
I have a C# command line project. This project runs another program called condor_status.exe as a process and reads the process output as a stream of XML. The second line of this XML output that my program sees is:

<!DOCTYPE classads SYSTEM "classads.dtd">

I have no control over the path to this classads.dtd or any of the XML I get, but my program will bomb if it doesn't find the DTD, and in fact I would like to use the DTD. If I go and get this classads.dtd file and put it in the same directory as I am running MY program, it reads it fine and I am parsing an XPathDocument with an XPathNavigator. But if I run my program from a shortcut or an absolute path, it bombs, saying it can't find the classads.dtd in the current working dir. Setting a PATH variable or workingdir on the process does no good because it's looking for classads.dtd in the directory MY program is run from, not the process my program runs. I would like to just have classads.dtd in a known dir and tell my XmlReader to look there, regardless of where my program is executed from.

A lot of examples at Microsoft show you how to use the XmlResolver to have your XmlReader reroute its search for a .dtd that is located at some web http:// address and look for it on a local drive by overriding the GetEntity function of an XmlUrlResolver and attaching that to your XmlReader. I tried modifying an example, but it doesn't seem to even execute the GetEntity function if it is looking for something called "classads.dtd" that is already local, i.e. not listed as being at an http:// address. I can't change the XML so I can't even see if the GetEntity function would execute as planned by putting a copy of classads.dtd on a local website.

Has anyone ever done this, told an XmlResolver to look for a .dtd that is listed without any kind of path, presumably in the current directory, and force it to look in an absolute directory, like "file:///C:\Condor\bin\classads.dtd" ?

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.XPath;

namespace condor_machines
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> Machines = new List<string>();
            // start up a condor_status process and read the -xml document
            // to an in-memory XML document (XPathDocument)
            Process condor_status = new Process();
            condor_status.StartInfo.UseShellExecute = false;
            condor_status.StartInfo.RedirectStandardOutput = true;
            condor_status.StartInfo.FileName = "C:\\Condor\\bin\\condor_status.exe";
            condor_status.StartInfo.Arguments = "-xml";
            condor_status.Start();
            //string output = condor_status.StandardOutput.ReadToEnd();
            Stream stream = condor_status.StandardOutput.BaseStream;

            // how can we validate this using classads.dtd if we aren't
            // in the directory with the .dtd when it's run?
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ValidationType = ValidationType.DTD;
            settings.ProhibitDtd = false;
            // the resolver here should point us the right way
            // what do I put here?

            XmlReader reader = XmlReader.Create(stream, settings);

            XPathDocument xPathDocument = new XPathDocument(reader);
            condor_status.WaitForExit();

            // we need an XPathNagivator to actually use anything in the
            // XPathDocument
            XPathNavigator xPathNavigator = xPathDocument.CreateNavigator();
            string Machine = "//a[@n = \"Machine\"]";
            XPathNodeIterator xPathNodeIterator = xPathNavigator.Select(Machine);
            while (xPathNodeIterator.MoveNext())
                Machines.Add(xPathNodeIterator.Current.Value);

            // we only want one entry per machine, not per slot
            Machines = removeDuplicates(Machines);
            foreach (string m in Machines)
                Console.WriteLine(m);
        }

        // &tc.
Posted

1 solution

Try adding this *AFTER* the StartInfo.FileName line:

condor_status.StartInfo.WorkingDirectory = System.IO.Path.GetDirectory(condor_status.StartInfo.FileName);


or set your own application's current directory to the same path as your CondorStatus app because it looks like it's writing a file to its own folder(?) or something along those lines. When you go to process the dtd file, your current directory must be where the target data file lives.
   
v4

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900