Solved

DTD Tree in Java

Posted on 2004-04-15
34
1,354 Views
Last Modified: 2013-11-23
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.
0
Comment
Question by:lina000
  • 17
  • 9
  • 6
  • +1
34 Comments
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10833361
0
 

Author Comment

by:lina000
ID: 10838376
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.
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10838408
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

0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10838416
Oh, P.S.: Here's the home page with the download link:

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

0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10839330
>> 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.
0
 
LVL 4

Accepted Solution

by:
john-at-7fff earned 500 total points
ID: 10839508
The Wutka code is really what you want.

It doesn't require a Level 2 XML parser, and it is used by other projects (for example, DTDDoc at SourceForge -- http://dtddoc.sourceforge.net/credits.html).

Here's a sample DTD (located at http://7fff.com/schedule.dtd):

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT schedule      (tasks)>
<!ELEMENT tasks         (task*)>
<!ELEMENT task          (name,description,id,earliestStart,latestFinish,minSeconds,maxSeconds)>
<!ELEMENT name          (#PCDATA)>
<!ELEMENT description   (#PCDATA)>
<!ELEMENT id            (#PCDATA)>
<!ELEMENT earliestStart (#PCDATA)>
<!ELEMENT latestFinish  (#PCDATA)>
<!ELEMENT minSeconds    (#PCDATA)>
<!ELEMENT maxSeconds    (#PCDATA)>

And here's the output from a little program I wrote in 15 minutes using Wutka's jar:

name
  #PCDATA
id
  #PCDATA
task
  name
  description
  id
  earliestStart
  latestFinish
  minSeconds
  maxSeconds
earliestStart
  #PCDATA
tasks
  task
schedule
  tasks
latestFinish
  #PCDATA
maxSeconds
  #PCDATA
description
  #PCDATA
minSeconds
  #PCDATA

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.DTDPCData;
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();
                  System.out.println(el.getName());
                  dumpItem(el.getContent());
            }
      }

      public void dumpItem(DTDItem item) {
            if (item instanceof DTDPCData) {
                  DTDPCData pcData = (DTDPCData) item;
                  System.out.println("  #PCDATA");
            }
            else if (item instanceof DTDSequence) {
                  DTDSequence seq = (DTDSequence) item;
                  dumpItems(seq.getItems());
                  
            }
            else if (item instanceof DTDName) {
                  DTDName name = (DTDName) item;
                  System.out.println("  " + name.getValue());
            }
            else if (item instanceof DTDMixed) {
                  DTDMixed mixed = (DTDMixed) item;
                  dumpItems(mixed.getItems());
            }
            else
                  System.out.println("Unknown: " + item);
      }

      public void dumpItems(DTDItem[] items) {
            for (int i = 0; i < items.length; i++) {
                  dumpItem(items[i]);
            }
      }

      public static void main(String[] args)
            throws MalformedURLException, IOException {
            DTDParseDemo demo =
                  new DTDParseDemo(new URL("http://7fff.com/schedule.dtd"));
      }
}
0
 

Author Comment

by:lina000
ID: 10840769
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
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10840796
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
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10841294
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.

0
 

Author Comment

by:lina000
ID: 10841391
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
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10841419
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

0
 
LVL 30

Expert Comment

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

Then try running the program.
0
 

Author Comment

by:lina000
ID: 10841586
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.
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10841732
What error do you get while running?
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10841779
Absolutely -- you can use a file. Just a sec.

0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10841942
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
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10842007
Just out of curiosity, why do you need to parse the DTD?
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:lina000
ID: 10842186
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.
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10842291
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.

0
 

Author Comment

by:lina000
ID: 10842434
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!
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10842444
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

0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10842450
OK -- Well, the code I've given you should give you a start.
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10842479
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 . . .
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10842703
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.
0
 

Author Comment

by:lina000
ID: 10842781
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)>
]>
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10842998
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"));
      }
}

0
 

Author Comment

by:lina000
ID: 10843244
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!
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10843309
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!
0
 

Author Comment

by:lina000
ID: 10843430
Thank you so much for your help!!
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 10843452
Glad to be of service!

Let me know when you get your dtd2sql program working!!
0
 

Expert Comment

by:tonqo
ID: 11075830
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)
0
 
LVL 4

Expert Comment

by:john-at-7fff
ID: 11076488
Tongo -- You should probably post a new question for something like that.
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 11115586
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.
0
 

Expert Comment

by:tonqo
ID: 11116149
I am sorry I didn't know. I have posted a new question
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
Browsers only know CSS so your awesome SASS code needs to be translated into normal CSS. Here I'll try to explain what you should aim for in order to take full advantage of SASS.
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.
The viewer will learn how to count occurrences of each item in an array.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now