Link to home
Start Free TrialLog in
Avatar of lina000
lina000

asked on

DTD Tree in Java

Hi!!
I'm wondering if anyone can help in this!!
How can I create a tree structure from a DTD file??

any help or recommendations will be highly appreciated!
Thanks in advance.
Avatar of Mayank S
Mayank S
Flag of India image

Avatar of lina000
lina000

ASKER

mayankeagle,
Thanks for replying!
what you have suggested is helpful but I'm looking for more control on the DTD and if possible a way to store the different elements (with their sub elements) in an array or other structure.

what I need is to get all the elements with their sub-sub elements (till leaf) stored in a way so that I can easy refer to!!

Thanks again.
Here's what you want:

http://www.wutka.com/dtdparser.html

You construct a DTDParser object, passing in the file that has the DTD.

Then call the parse method:

http://www.wutka.com/dtdparserapi/com/wutka/dtd/DTDParser.html#parse()

That returns a DTD object -- And once you have that, you get HashTables with all the goodies:

http://www.wutka.com/dtdparserapi/com/wutka/dtd/DTD.html

Oh, P.S.: Here's the home page with the download link:

http://www.wutka.com/dtdparser.html

>> what I need is to get all the elements with their sub-sub elements (till leaf) stored in a way so that I can easy refer to

Have a look at the "Related Examples" in the links that I posted. They might contain something useful. You can also search for as many examples as you want, on that site.
ASKER CERTIFIED SOLUTION
Avatar of john-at-7fff
john-at-7fff

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of lina000

ASKER

Thanks all for replying!!
john-at-7fff, the DTD parser is definitely what I need! I've download the package but I don't know how to add it to my code I don't know where I should add the classes or even put the files in the right place!!any guide from your side will be really helpful.

Thanks
If the classes are in a JAR file, then you should put the JAR in your jdk/jre/lib/ext folder.

You can also put the classes anywhere, actually, and just make sure that the directory containing them (or the JAR containing them) is in the class-path.

http://www.mindprod.com/jgloss/classpath.html
Put the .jar (found in the .zip you download) in the directory where you put the source for DTDParseDemo

Then, on Windows, for instance:

    javac -classpath dtdparser121.jar DTDParseDemo.java
    java -cp dtdparser121.jar;. DTDParseDemo

Personally, I would avoid putting a lot of supporting jars in my jre/lib/ext folder. The reason is that people tend to forget the jars are there, and then you might run into a conflict later on (the classic conflict is when you download software, and it puts its version of the XML parser in there; then later on, other software starts to break). Also, since the jar is sitting there, if you want to give the code to someone else to run, you inevitably forget to tell them about this special jar they are going to need.

Avatar of lina000

ASKER

Now what I did is as follow I created a folder "run" under C:\skd\bin and I moved the file dtdparser121.jar to the "run" folder and I also moved the folder "com" (under classes in the dtdparser zip file) I tried what you’ve suggested and this is what I got!

C:\sdk\bin>javac -C:\sdk\bin\run dtdparser121.jar DTDParser.java
javac: invalid flag: -C:\sdk\bin\run
Usage: javac <options> <source files>
where possible options include:
  -g                        Generate all debugging info
  -g:none                   Generate no debugging info
  -g:{lines,vars,source}    Generate only some debugging info
  -nowarn                   Generate no warnings
  -verbose                  Output messages about what the compiler is doing
  -deprecation              Output source locations where deprecated APIs are us
ed
  -classpath <path>         Specify where to find user class files
  -sourcepath <path>        Specify where to find input source files
  -bootclasspath <path>     Override location of bootstrap class files
  -extdirs <dirs>           Override location of installed extensions
  -d <directory>            Specify where to place generated class files
  -encoding <encoding>      Specify character encoding used by source files
  -source <release>         Provide source compatibility with specified release
  -target <release>         Generate class files for specific VM version
  -help                     Print a synopsis of standard options


C:\sdk\bin>java -cp dtdparser121.jar;. DTDPasrseDemo
Exception in thread "main" java.lang.NoClassDefFoundError: DTDPasrseDemo
What you have will probably work if you fix the javac command. You have:

    javac -C:\sdk\bin\run dtdparser121.jar DTDParser.java

You want:

    javac -classpath dtdparser121.jar DTDParseDemo.java

"DTDParseDemo.java" is the program I pasted in above. Note that the name HAS TO BE DTDParseDemo.java, because that (DTDParseDemo) is the name of the class.

NOTE: You only need the .jar. You don't need the classes/ directory or anything in it (com/ etc.).

Put the .java file and the .jar in a folder outside of \sdk\bin -- i.e., anywhere on the disk. Whatever is convenient for you. For example, make a directory called C:\dtdparsing

Then use the commands as I suggested:

    javac -classpath dtdparser121.jar DTDParseDemo.java
   java -cp dtdparser121.jar;. DTDParseDemo

Try adding dtdparser121.jar to the classpath like: set classpath=%classpath%; C:\skd\bin\run\dtdparser121.jar;.

Then try running the program.
Avatar of lina000

ASKER

I got the .class file and the compilation is done but the only problem is in running the sample code that  john-at-7fff had post! I also tried to retrieve the dtd file from the URL but I go an error saying that the XML couldn't be displayed! I was thinking if there is a way where I can send a file instead of the URL!! do you think that will work??

Thanks all.
What error do you get while running?
Absolutely -- you can use a file. Just a sec.

By "I tried to retrieve the DTD file from the URL" --

Do you mean in a browser? Internet Explorer cannot display a DTD.

To read a file, here's what you do:

1. Decide on the location of the DTD file. For instance, it might be in C:\dtdparsing. For the quick fix I'm about to describe, it will be a lot easier if everything is in a directory under C:\, and the directory names don't have spaces in them and so forth.

2. Create the file schedule.dtd in that directory.

You will want to paste in the contents of the DTD I show above. You can also try it on your own DTD.

3. Change the line that in DTDParseDemo.java that loads to this:

DParseDemo demo = new DTDParseDemo(new URL("file:///dtdparsing/schedule.dtd"));

That file URL will open the file on disk, assuing the file is in C:\dtdparsing

4. Learn more about Java. You need to learn how to set up your classpath. Also, to get a lot out of this DTD parsing stuff, you're going to have to read the JavaDoc for the code. The documentation is in your downloaded ZIP, but it's also here: http://www.wutka.com/dtdparserapi/index.html
Just out of curiosity, why do you need to parse the DTD?
Avatar of lina000

ASKER

john-at-7fff,
I'm working on the DTD to relational schema mapping! and I hope that this thing can be easily handeled in java (btw I don't know alot about java)!
The mapping technique that I'm using is some how simple all what I need is to know the elements, their sub-elements and thier * elements!!
BTW if I need to get all the sub elements (i.e. under schedule I will have all the elements under tasks->task->name ....etc) how can I implement this thing??

Thanks.
For the code I wrote, it should traverse the DTD down to the bottom.

However, to generate a schema, you have to have a lot more information, some of which is not in the DTD.

For example, you might have an element in the DTD that is supposed to be a number.

In the XML, it might like like this:

<orderQuantity>500</orderQuantity>

There is nothing in the DTD that tells you that orderQuantity should be a number, rather than a String, which would be a big problem for getting your schema right.

Are you just trying to generate a schema from a DTD?

Unless the DTD is really complicated, you should probably just do it by hand.

Object/relational mapping is a big topic. If you're going to use this for a real project, you should use a package that provides object/relational mapping -- for instance, Hibernate: http://www.hibernate.org/

In any case, what I've given you should get you started on parsing a DTD.

For the larger problem of getting a schema from a DTD, you should do some googling.

This is a big project.

Avatar of lina000

ASKER

I won't go that deep!I will only gonna map simple DTDs!
at the mean time I only need to store the elements(with all thier sub elements) in a hashtable so I can easly process them!
Here's an article that should give you a sense of how tricky it can be to generate SQL from a DTD.

He has written code in Python, which you might be able to adapt to Java. But then you'd have to know Python, too!   :-)

http://gnosis.cx/publish/programming/xml_matters_12.html

OK -- Well, the code I've given you should give you a start.
Give me a few minutes, and I might be able to update that program so that it gives you an idea of what SQL generation might look like . . .
Could you post the DTD you want to convert to SQL?

Also: For the basic question you initially posed, I think I've answered it. You might want to post a separate question for the DTD -> SQL topic.
Avatar of lina000

ASKER

Here is a DTD example

<!DOCTYPE note [
      <!ELEMENT note (to, from, heading, paragraph*,date)>
      <!ELEMENT date (day, month, year)>
      <!ELEMENT to (#PCDATA)>
                <!ELEMENT from (#PCDATA)>
      <!ELEMENT heading (#PCDATA)>
      <!ELEMENT paragraph (#PCDATA)>
]>
OK -- What follows will give you a sense of what is involved. Code at the bottom.

This takes the DTD:

 <!ELEMENT note (to, from, heading, paragraph*,date)>
 <!ELEMENT date (day, month, year)>
 <!ELEMENT to (#PCDATA)>
 <!ELEMENT from (#PCDATA)>
 <!ELEMENT heading (#PCDATA)>
 <!ELEMENT paragraph (#PCDATA)>

And produces this:

create table date (
  day varchar(128),
  month varchar(128),
  year varchar(128)
);

create table note (
  to varchar(128),
  from varchar(128),
  heading varchar(128),
  paragraph varchar(128),
  date varchar(128)
);

This isn't done. As I said, this is a hard problem. If you could solve it in a useful way, you could make some $.

Here's what else you would have to consider:

-- the code would have to somehow infer that date shouldn't be a table, but rather, say, some underlying data type in the database. This judgement requires knowledge of what you're trying to do.

-- It would also have to look at the cardinality of paragraph, and know that it should generate a table for that, with a 1:many relationship between note and paragraph.

-- Also, the converter would have to know about SQL reserved names. For example, you can't have a column or table called date.

That's just the start.

As I've said, I've answered your fundamental question about parsing a DTD.

Good luck.

Here's the code.

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;

import com.wutka.dtd.DTD;
import com.wutka.dtd.DTDElement;
import com.wutka.dtd.DTDItem;
import com.wutka.dtd.DTDMixed;
import com.wutka.dtd.DTDName;
import com.wutka.dtd.DTDParser;
import com.wutka.dtd.DTDSequence;

public class DTDParseDemo {

      public DTDParseDemo(URL u) throws IOException {
            DTDParser parser = new DTDParser(u);
            DTD dtd = parser.parse();
            Hashtable elements = dtd.elements;

            for (Enumeration e = elements.elements(); e.hasMoreElements();) {
                  DTDElement el = (DTDElement) e.nextElement();
                  if (!(el.getContent() instanceof DTDMixed)) {
                        System.out.println("create table " + el.getName() + " (");
                        dumpItem(el.getContent());
                  }
            }
      }

      public void dumpItem(DTDItem item) {
            if (item instanceof DTDSequence) {
                  DTDSequence seq = (DTDSequence) item;
                  dumpItems(seq.getItems());

            } else if (item instanceof DTDName) {
                  DTDName name = (DTDName) item;
                  System.out.print("  " + name.getValue() + " varchar(128)");
            }
      }

      public void dumpItems(DTDItem[] items) {
            for (int i = 0; i < items.length; i++) {
                  if (i != 0)
                        System.out.println(",");
                  dumpItem(items[i]);
            }
            System.out.println("\n);\n");
      }

      public static void main(String[] args)
            throws MalformedURLException, IOException {
            DTDParseDemo demo = new DTDParseDemo(new URL("file:///eclipse/workspace/DTDParse/example.dtd"));
      }
}

Avatar of lina000

ASKER

This is really helpful!! (Thanks a lot)
Hope this will be the last comment in this question :-)
I was checking the DTDParser documentation and I found the DTDGardinal class!! I'm wondering if I can check the gardinality (zero-to-many) for an element
for example if a given element has a parent-element with gardinality zero to many show its parent-elment and if an element has a sub-element with gardinality zero to many don't show this sub-element !!

Again thanks for your help!
You can use the DTDCardinal class -- You'll have to experiment to figure out the exact cardinality. The JavaDoc says that there are special constants called NONE MANY (I don't have the name exactly right). But at some point, you should be able to say something like:

if (cardinal.equals(DTDCardinal.NONE)) {
   Do something
}

Sorry I can't help you further on this one.

Good luck!!

To bring this further, you're going to have to learn a lot more Java!
Avatar of lina000

ASKER

Thank you so much for your help!!
Glad to be of service!

Let me know when you get your dtd2sql program working!!
Could you show me how to convert the relational database schema like the one above to a DTD, like example.dtd ( i.e. to do the opposite of what the above java code does)
Tongo -- You should probably post a new question for something like that.
You MUST. Don't disturb closed threads this way. You get your question-points only for asking your own questions so use them for that. Don't try to save them by asking in someone else's page.
I am sorry I didn't know. I have posted a new question