0

EDIT Now i know why people use string builder, using JAXB is a pain and very time consuming, at least for me it was because i have a very complex XML to generate. Appreciate the help :)

I have a java application which collects user data.

I also created a template XSL. Now i am stuck. What is my next step? Should i use the java to code to create an XML? If so, what kind of XML am i creating, i need my HTML to be strict at the end. Sorry if this is a duplicate, i couldn't find anything and i'm completely new to XML. So one more question is, would this be valid syntax for an xml:

StringBuilder sb = new StringBuilder(500);
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
sb.append("<report version=\"").append(reportVersion).append("\" generated=\"").append(scanVersion).append("\">\r\n");
sb.append("</report >");

The output would be

<?xml version="1.0" encoding="UTF-8"?>
<report version="alpha" generated="1">
</report >

How do i use java now to get the version and generated?

Also i understand there is xslt 1.0 and 2.0, which one should i pick?

EDIT:

I was playing around with JAXB and got the following two classes made.

import java.util.ArrayList;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Report
{
    String              title;
    String              reportBy;
    String              reportFor;
    String              scanDate;
    String              scanVersion;
    String              reportDate;
    String              reportVersion;
    String              desc;
    ArrayList<String>   alertSeverity;
    ArrayList<String>   alertDetails;

    public String getTitle()
    {
        return title;
    }

    @XmlElement
    public void setTitle(String title)
    {
        this.title = title;
    }

    public String getBy()
    {
        return reportBy;
    }

    @XmlElement
    public void setBy(String reportBy)
    {
        this.reportBy = reportBy;
    }

    public String getFor()
    {
        return reportFor;
    }

    @XmlElement
    public void setFor(String reportFor)
    {
        this.reportFor = reportFor;
    }

    public String getScanDate()
    {
        return scanDate;
    }

    @XmlElement
    public void setScanDate(String scanDate)
    {
        this.scanDate = scanDate;
    }

    public String getScanVersion()
    {
        return scanVersion;
    }

    @XmlElement
    public void setScanVersion(String scanVersion)
    {
        this.scanVersion = scanVersion;
    }

    public String getReportDate()
    {
        return reportDate;
    }

    @XmlElement
    public void setReportDate(String reportDate)
    {
        this.reportDate = reportDate;
    }

    public String getReportVersion()
    {
        return reportVersion;
    }

    @XmlElement
    public void setReportVersion(String reportVersion)
    {
        this.reportVersion = reportVersion;
    }


    public String getDesc()
    {
        return reportVersion;
    }

    @XmlElement
    public void setDesc(String desc)
    {
        this.desc = desc;
    }
}

and the main:

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class JAXBExample {
    public static void main(String[] args) {
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date date = new Date();

        Report report = new Report();
        report.setTitle("my custom title");
        report.setBy("hans");
        report.setFor("pepe");
        report.setScanDate(dateFormat.format(date));
        report.setScanVersion("orignal version");
        report.setReportDate(dateFormat.format(date));
        report.setReportVersion("version is alpha");
        report.setDesc("some random desc");

      try {

        File file = new File("C:\\Users\\testuser\\Desktop\\file.xml");


        JAXBContext jaxbContext = JAXBContext.newInstance(Report.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

        // output pretty printed
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        jaxbMarshaller.marshal(report, file);
        jaxbMarshaller.marshal(report, System.out);

          } catch (JAXBException e) {
        e.printStackTrace();
          }

    }
}

I just have no idea what to do with my ArrayList which i need to loop to add elements in, etc.

The current output is:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<report>
    <by>hans</by>
    <desc>version is alpha</desc>
    <for>pepe</for>
    <reportDate>2016/02/28 18:36:33</reportDate>
    <reportVersion>version is alpha</reportVersion>
    <scanDate>2016/02/28 18:36:33</scanDate>
    <scanVersion>orignal version</scanVersion>
    <title>my custom title</title>
</report>

Now i have two arrays that are supposed to go into this report, not sure what to do about them. Not only that but if the user did not pick the item to go in, then it's not supposed to. SO the xml won't always be the same, one attribute might not be there and sometimes it might be. Does that make sense?

EDIT 2: What i need is something like this

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<report>
    <by>hans</by>
    <desc>version is alpha</desc>
    <for>pepe</for>
    <reportDate>2016/02/28 18:36:33</reportDate>
    <reportVersion>version is alpha</reportVersion>
    <scanDate>2016/02/28 18:36:33</scanDate>
    <scanVersion>orignal version</scanVersion>
    <title>my custom title</title>
    <site host="1" name="1" port="80" ssl="true">
        <items>
            <item>
                <name>item 1</name>
                <id>1</id>
            </item>
            <item>
                <name>item 2</name>
                <id>1</id>
            </item>
        </items>
    </site>
    <site host="2" name="2" port="80" ssl="true">
        <items>
            <item>
                <name>item 1</name>
                <id>1</id>
            </item>
            <item>
                <name>item 2</name>
                <id>1</id>
            </item>
        </items>
    </site>
</report>

All of this is contained in an ArrayList How do i go about using JAXB to create this xml? Any input would be appreciated :)

8
  • How do i use java now to get the version and generated? Use a xml parser. Also do not generate the xml from strings. There are much better ways to generate xml than doing this. Commented Feb 28, 2016 at 23:09
  • @fabian how? I am very new to this and i'm not sure how to proceed, what's a better way to generate xml's? Commented Feb 28, 2016 at 23:17
  • Just do a web seach for java + one of these keywords: DOM StaX JAXB Commented Feb 28, 2016 at 23:23
  • @fabian i was using JAXB earlier, i got as far as adding a single node but when it came to more complex logic, like if i had items in a ArrayList I wasn't sure what to do. I'll update with where i had left off. Commented Feb 28, 2016 at 23:38
  • Of course you cannot add more than one top-level element. This would result in a non-wellformed xml (single root element). Use another class as root containing the list of Reports or marshal every Report seperately (or marshal fragments). Commented Feb 29, 2016 at 0:08

1 Answer 1

1

Step 1

Create an XSD that represents the structure you want in the XML. If you're not familiar with XSD, I encourage you to read this tutorial.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified">

    <xs:element name="report">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="1" name="by" type="xs:string" />
                <xs:element minOccurs="0" maxOccurs="1" name="desc" type="xs:string" />
                <xs:element minOccurs="0" maxOccurs="1" name="for" type="xs:string" />
                <xs:element minOccurs="0" maxOccurs="1" name="reportDate"
                    type="xs:dateTime" />
                <xs:element minOccurs="0" maxOccurs="1" name="reportVersion"
                    type="xs:string" />
                <xs:element minOccurs="0" maxOccurs="1" name="scanDate"
                    type="xs:dateTime" />
                <xs:element minOccurs="0" maxOccurs="1" name="scanVersion"
                    type="xs:string" />
                <xs:element minOccurs="0" maxOccurs="1" name="title"
                    type="xs:string" />
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="site" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="site">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="1" maxOccurs="1" ref="items" />
            </xs:sequence>
            <xs:attribute use="required" name="host" type="xs:string" />
            <xs:attribute use="required" name="name" type="xs:string" />
            <xs:attribute use="required" name="port" type="xs:string" />
            <xs:attribute use="required" name="ssl" type="xs:string" />
        </xs:complexType>
    </xs:element>

    <xs:element name="items">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="item" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="item">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="1" maxOccurs="1" name="name" type="xs:string" />
                <xs:element minOccurs="1" maxOccurs="1" name="id" type="xs:string" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

Note 1: the type xs:dateTime allows only datetimes formatted in ISO 8601. Source W3C. If you really want a custom datetimes format, you will have to write your own pattern based on strings (and therefore loosing the full power of dates validation).

Note 2: as you noticed, xs:element have a minOccurs and maxOccurs that can be tweaked if you know an element is mandatory or not.

Step 2

You can use the tool XJC (bundled with Java) to generate automatically the corresponding Java classes. These classes will be directly usable by JAXB to serialize data into the desired XML format.

The following command should do the trick:

/path/to/jdk/bin/xjc -d /path/to/output/folder -p your.package.name /path/to/report.xsd

The following classes should be generated (sample)

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "name",
    "id"
})
@XmlRootElement(name = "item")
public class Item {

    @XmlElement(required = true)
    protected String name;
    @XmlElement(required = true)
    protected String id;

    public String getName() {
        return name;
    }

    public void setName(String value) {
        this.name = value;
    }

    public String getId() {
        return id;
    }

    public void setId(String value) {
        this.id = value;
    }
}

Note: the generated classes are simple POJO that I don't encourage to directly work with (only JAXB should work with). If you already have a Report class that is structured according to your business, you could create a few XmlAdapter to map between business objects and JAXB-POJO.

Step 3

Fill these objects with report's data:

Item i1 = new Item();
i1.setName("item 1");
i1.setId("1");

Item i2 = new Item();
i2.setName("item 2");
i2.setId("2");

Items items = new Items();
items.getItem().addAll(Arrays.asList(i1, i2));

Site s1 = new Site();
s1.setHost("1");
s1.setName("1");
s1.setPort("80");
s1.setSsl("true");
s1.setItems(items);

Site s2 = new Site();
s2.setHost("2");
s2.setName("2");
s2.setPort("80");
s2.setSsl("true");
s2.setItems(items);

Report r = new Report();
r.setBy("hans");
r.setDesc("version is alpha");
r.setFor("pepe");
r.setReportDate(DatatypeFactory.newInstance().newXMLGregorianCalendar("2016-02-28T18:36:33"));
r.setReportVersion("version is alpha");
r.setScanDate(DatatypeFactory.newInstance().newXMLGregorianCalendar("2016-02-28T18:36:33"));
r.setScanVersion("original version");
r.setTitle("my custom title");
r.getSite().addAll(Arrays.asList(s1, s2));

Note: if you have xmlAdapters, this step becomes less tedious.

Step 4

Save them in XML

JAXBContext jaxbContext = JAXBContext.newInstance(Report.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(r, new File("report.xml"));

Note: report.xml will be exactly in the format you need.

Step 5

Transform the XML in HTML

StreamResult result = new StreamResult(new File("output.html"));
StreamSource source = new StreamSource(new File("report.xml"));
StreamSource xslt = new StreamSource(new File("transform.xslt"));

Transformer transformer = TransformerFactory.newInstance().newTransformer(xslt);

transformer.transform(source, result);
Sign up to request clarification or add additional context in comments.

3 Comments

I already did all this but thanks for the reply! I was going to upload my solution but now i don't have to :D The only issue i have is with JAXB creatin lt and gt in the xml because when the xml is transformed using the xsl, the br and other inserted tags do not do their job.
@codeCompiler77 Why do you need to store html tags in XML ? These tags should only be added by the XSL.
it's a data dump, along with the carriage return, which i removed and replace with <br/> tags. I needed a way to preserve the new line which was not happening in JAXB, I'm going to sleep. I can update the topic tomorrow when i have my code in front of me :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.