简体   繁体   中英

Having trouble formatting multiple nodes from a text to XML conversion in Java

I have a Java program which converts text files to XML. I need the following format:

    <app:defaults>
    <app:schedules>
    <app:run>
    <app:schedule>schedule frequency value</app:schedule>
    </app:run>
    </app:schedules>
    <app:rununit>
    <app:agent>agent hostname value</app:agent>
    </app:rununit> 
    </app:defaults>

The ending "/app:schedules" tag is not appending in the correct place after the "/app:run" tag. The program is instead generating the following (which is not correct):

   <app:defaults>
   <app:schedules>
   <app:run>
   <app:schedule>schedule frequency value</app:schedule>
   </app:run>
   <app:rununit>
   <app:agent>agent hostname value</app:agent>
  </app:rununit> 
  </app:schedules>
 </app:defaults>

The method in the java program is as follows: for this example i expilicitly added the text to each node to show what the data should be. - this method takes String args otherwise from the input text file.

 public static void main(String[] args) {
  String infile = args[0];
  String outxml = args[1];

 BufferedReader in;
 StreamResult out;

 DocumentBuilderFactory icFactory = DocumentBuilderFactory.newInstance();
  DocumentBuilder icBuilder;
  try {
    in = new BufferedReader(new FileReader(infile));
    out = new StreamResult(outxml);

    icBuilder = icFactory.newDocumentBuilder();
    Document doc = icBuilder.newDocument();
    Element mainRootElement = doc.createElementNS ("http://dto.cybermation.com/application", "app:appl");
    mainRootElement.setAttribute("name", "TESTSHEDULE");
    doc.appendChild(mainRootElement);

                 ...

       private static Node processTagElements3(Document doc, String "app:defaults") {

        Element node1 = doc.createElement("app:schedules");
        Element node2 = doc.createElement("app:run");
        Element node3 = doc.createElement("app:schedule");
        Element node4 = doc.createElement("app:rununit");
        Element node5 = doc.createElement("app:agent");

        node1.appendChild(node2);
        node2.appendChild(node3);
        node3.appendChild(doc.createTextNode("schedule frequency value"));
        node1.appendChild(node4);
        node4.appendChild(node5);
        node5.appendChild(doc.createTextNode("agent hostname value"));

    return node1;
}

I've tested this using different appenchild parameters between these nodes but ran up against a brick wall with formatiing this output. Any suggestions, advice on the best way to organize the node tag insertions is really appreciated. There could be somthing simple I am missing.

Note: I'm not an expert in for XML parsing in Java.

Just trying to stitch some example codes I got in my machine and see if that solves your problem. So here it is.

Example code:

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringReader;
import java.io.StringWriter;\

public class test {

    public static void main(String[] args) throws Exception {

        String xml = "<app:defaults>\n" +
                "    <app:schedules>\n" +
                "    <app:run>\n" +
                "    <app:schedule>schedule frequency value</app:schedule>\n" +
                "    </app:run>\n" +
                "    </app:schedules>\n" +
                "    <app:rununit>\n" +
                "    <app:agent>agent hostname value</app:agent>\n" +
                "    </app:rununit> \n" +
                "    </app:defaults>";
        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
                .parse(new InputSource(new StringReader(xml)));

        NodeList errNodes = doc.getElementsByTagName("error");
        if (errNodes.getLength() > 0) {
            Element err = (Element)errNodes.item(0);
            System.out.println(err.getElementsByTagName("errorMessage")
                    .item(0).getTextContent());
        } else {
            // success
            DOMSource domSource = new DOMSource(doc);
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(domSource, result);

            System.out.println(writer.toString());
        }
}

Output:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  <app:defaults>
    <app:schedules>
      <app:run>
        <app:schedule>schedule frequency value</app:schedule>
      </app:run>
    </app:schedules>
    <app:rununit>
      <app:agent>agent hostname value</app:agent>
    </app:rununit> 
  </app:defaults>

This code seems to be working as what you will expecting it to be. Give it a try and let me know whether the solution is okay.

I think the idea here is to use pre-baked Java APIs than writing our own parser. Because these APIs are generally more reliable since many others would be using it daily.

Things would be way easier if you had named your nodes with meaningful names (let's say runNode , etc), don't you think?

That being said, this is probably what you want:

    Element defaultNode = doc.createElement("app:default");
    Element schedulesNode = doc.createElement("app:schedules");
    Element runNode = doc.createElement("app:run");
    Element scheduleNode = doc.createElement("app:schedule");
    Element rununitNode = doc.createElement("app:rununit");
    Element agentNode = doc.createElement("app:agent");

    defaultNode.appendChild(schedulesNode);
    schedulesNode.appendChild(runNode);
    runNode.appendChild(scheduleNode);
    scheduleNode.appendChild(doc.createTextNode("schedule frequency value"));
    defaultNode.appendChild(rununitNode);
    rununitNode.appendChild(agentNode);
    agentNode.appendChild(doc.createTextNode("agent hostname value"));

Note the defaultNode used.

Thanks all! I decided to modify the script to accept file input as my arg - this works fine now and is a simpler solution:

public class test2 {

public static void main(String[] args) throws Exception {
      File file = new File(args[0]);

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try{
 DocumentBuilder builder = factory.newDocumentBuilder();

  FileInputStream fis = new FileInputStream(file);
     InputSource is = new InputSource(fis);
     Document doc = builder.parse(is);

    NodeList errNodes = doc.getElementsByTagName("error");
    if (errNodes.getLength() > 0) {
        Element err = (Element)errNodes.item(0);
        System.out.println(err.getElementsByTagName("errorMessage").item(0).getTextContent());
    } else {
  // success
        DOMSource domSource = new DOMSource(doc);
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.transform(domSource, result);

        System.out.println(writer.toString());
          }
        } catch (Exception e) {
        e.printStackTrace();
        }
      }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM