0

This is my current XML file it gives me the dialogue for different characters, or at least it should. I want it to work so that I can specify the entity id and the option/quest id and get the output. So what should I do? Any help is appreciated, thank you very much.

<?xml version="1.0"?>
<dialoge>
<entity id="1"> <!-- questgiver -->
    <quest id="1">
        <option id="1">
            <precondition>player has not started quest</precondition>
            <output>hello there, can you kill 2 enemies for me?</output>
        </option>
        <option id="2">
            <precondition>player has completed quest and player has not...</precondition>
            <output>thankyou, have a sword for your troubles.</output>
        </option>
        <option id="3">
            <precondition>player has not finished quest</precondition>
            <output>you haven't finished yet.</output>
        </option>
        <option id="4">
            <outpur>thank you.</outpur>
        </option>
    </quest>
</entity>
<entity id="2"> <!-- villager -->
    <option id="1">
        <precondition>village is being destroyed</precondition>
        <output>our village is being destroyed, please help us!</output>
    </option>
    <option id="2">
        <precondition>village has been saved or destroyed</precondition>
        <output>we will never forget this.</output>
    </option>
    <option id="3">
        <output>hello.</output>
    </option>
</entity>
</dialoge>

This is what I currently have, but it does not work. I know this is probably a stupid question, but I couldn't find an answer anywhere on the web. Thanks.

public static void read() {
    try {
        File file = new File("text.xml");
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(file);
        doc.getDocumentElement().normalize();

        System.out.println("root of xml file " + doc.getDocumentElement().getNodeName());
        NodeList nodes = doc.getElementsByTagName("entity");
        System.out.println("==========================");

        for(int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if(node.getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) node;
                        if(element.getElementsByTagName("entity").item(0).getTextContent().equals("output")) {

                }
                System.out.println("" + getValue("output", element));
            }
        }
    }catch(Exception e) {
        e.printStackTrace();
    }
}

private static String getValue(String tag, Element element) {
    NodeList nodes = element.getElementsByTagName(tag).item(0).getChildNodes();
    Node node = (Node) nodes.item(0);
    return node.getNodeValue();
}
Alexander O'Mara
  • 58,688
  • 18
  • 163
  • 171
Dylan Deshler
  • 59
  • 1
  • 8

2 Answers2

2

Simplest method might be to use XPath...

try {
    File file = new File("text.xml");
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(file);
    doc.getDocumentElement().normalize();

    XPath xpath = XPathFactory.newInstance().newXPath();
    XPathExpression xExpress = xpath.compile("//*[@id='1']");
    NodeList nl = (NodeList) xExpress.evaluate(doc, XPathConstants.NODESET);
    System.out.println("Found " + nl.getLength() + " matches");
} catch (Exception e) {
    e.printStackTrace();
}

The xpath query //*[@id='1'] will find all nodes in the document which have the attribute id with a value of 1

Have a look at WC3 XPath Tutorial and How XPath works for more details about XPath

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • if I want to find only for `entity` tag? :) – Braj Jul 23 '14 at 02:01
  • `//entity[@id='1']` or `//entity` if you want all the entities regardless of id value – MadProgrammer Jul 23 '14 at 02:02
  • Seeing that my xml file has two different elements with id's, and they both have child elements that also have id's, how should I go about finding them? Would I do entity[@id='1'] and then option[@id='1']? Thank you, and this seems like a good solution. – Dylan Deshler Jul 23 '14 at 15:35
  • It depends, are you only interested in the child elements or do you need the parent element as well? You could use //entity[@id='1']/quest/option[@id='1'], which will return all the option elemens with the id of 1 that are children of the entity/quest nodes, where entity has an id of 1. You could also do two separate queries, getting the entity nodes first, the using the entity nodes as the anchor point (instead of doc) and search for the option nodes. Think of xPath as a query language for XML, it's very powerful – MadProgrammer Jul 23 '14 at 21:32
1

In general, DOM is easier to use but has an overhead of parsing the entire XML before you can start using it where as SAX parser is parsing the XML, and encounters a tag starting (e.g. <something>), then it triggers the startElement event (actual name of event might differ). read more..

See Java Tutorial on Parsing an XML File Using SAX

Here is the sample code:

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class GetElementAttributesInSAXXMLParsing extends DefaultHandler {

    public static void main(String[] args) throws Exception {
        DefaultHandler handler = new GetElementAttributesInSAXXMLParsing();
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setValidating(false);
        SAXParser parser = factory.newSAXParser();
        parser.parse(new File("text.xml"), handler);    
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes)
            throws SAXException {

        System.out.println("Tag Name:"+qName);
        // get the number of attributes in the list
        int length = attributes.getLength();

        // process each attribute
        for (int i = 0; i < length; i++) {

            // get qualified (prefixed) name by index
            String name = attributes.getQName(i);
            System.out.println("Attribute Name:" + name);

            // get attribute's value by index.
            String value = attributes.getValue(i);
            System.out.println("Attribute Value:" + value);
        }
    }
}
Community
  • 1
  • 1
Braj
  • 46,415
  • 5
  • 60
  • 76
  • Thank you for posting this it is very helpful, but I am confused on startElement(), in what I read it seems like it will be called automatically, how does this happen? Also what are the variables referring to String uri, String localName... etc. Thank you for the help. – Dylan Deshler Jul 23 '14 at 15:39
  • @user3053027 It's known as a visitor pattern. The sax parser will automatically call the methods of the handler in response to changes as the XML document is read. This approach is really good if you only want to parse the document once, from start to finish. If you want to respectively query the document, you will need to use a DOM approach, which will allow you to jump into the document where ever you want, move in any direction and perform repeated queries... – MadProgrammer Jul 23 '14 at 21:33