I am trying to parse a string representation of a xml document with jdom2. I expect the xml string
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
to be a valid xml document. But when I run this simple code snippet:
import java.io.IOException;
import java.io.StringReader;
import org.jdom2.*;
public class Main {
public static void main(String []args){
SAXBuilder parser = new SAXBuilder();
String data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
try {
Document doc = parser.build(new StringReader(data));
} catch (JDOMException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I receive the error:
org.jdom2.input.JDOMParseException: Error on line 1: Premature end of file.
at org.jdom2.input.sax.SAXBuilderEngine.build(SAXBuilderEngine.java:232)
at org.jdom2.input.sax.SAXBuilderEngine.build(SAXBuilderEngine.java:303)
at org.jdom2.input.SAXBuilder.build(SAXBuilder.java:1196)
at testpack.Main.main(Main.java:32)
Does the xml specification not allow an xml payload without an root element?
If not, how should I check if the xml document is empty?
Edit: I also noticed that the documentation in Jdom2 for the Document() class states that
A document must have a root element, so this document will not be well-formed and accessor methods will throw an IllegalStateException if this document is accessed before a root element is added.
It might just be that Jdom2 doesn't support empty xml documents?
After further investigation I have noted that the specification for and xml document as defined by w3 specifies that a 'Well formed xml document' should adhere to
It contains one or more elements.
Meaning zero elements is not an option. The input xml String is a malformed xml string.
Related
I would like to know if it is possible to disable the [Fatal Error]:1:50: White spaces are required between publicId and systemId. error in my java program.
Im using java built-in DOM parser api to parse an XML document. The xml document is deliberately incorrect because I want to learn how to handle exceptions related to xml parsing. I also want to say that when the xml document is correct, no exception occurs.
I have already tried with the following :
try {
Document doc = documentBuilder.parse(xmlDocument)
} catch (Throwable t){
System.out.println("An error occur when parsing");
}
The code inside the catch block is displayed correctly but the fatal error message is still showing.
If anyone has a solution, I would be delighted, thanks.
The problem is that by default the error handler for the XML parser prints the errors to the output. You can install your own handler to capture or ignore the errors:
class NullErrorHandler implements ErrorHandler {
#Override
public void fatalError(SAXParseException e) {
// do nothing
}
#Override
public void error(SAXParseException e) {
// do nothing
}
#Override
public void warning(SAXParseException e) {
// do nothing
}
}
Use it as follows:
documentBuilder.setErrorHandler(new NullErrorHandler());
You could also have an error handler that, for example, stored the exceptions in lists in member variables, so you could access them and examine them after parsing the document.
Here's a fully worked-out example:
import javax.xml.parsers.*;
import org.xml.sax.*;
String xml = """
<?xml version="1.0"?>
<!DOCTYPE whatsupdoc PUBLIC
"http://example.com/bugs""http://example.com/bunny">
""";
InputSource getXmlInput(String xml) {
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xml));
return is;
}
var documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
documentBuilder.parse(getXmlInput(xml)); // prints the error and throws
documentBuilder.setErrorHandler(new NullErrorHandler());
documentBuilder.parse(getXmlInput(xml)); // only throws, does not print
After doing a GIT rebase, out of nowhere, I started receiving this exception:
by: org.xml.sax.SAXParseException: "The content of elements must consist of well-formed character data or markup"
The Java code simply tries to unmarshall an xml file to a jaxb object. Something like this:
...
FGIXmlValidationEventCollector collector = new FGIXmlValidationEventCollector();
Unmarshaller unmarshaller = null;
try {
unmarshaller = context.createUnmarshaller();
unmarshaller.setSchema(getSchema());
unmarshaller.setEventHandler(collector);
} catch (JAXBException e) {
throw new FGIXmlException(e);
} catch (SAXException e) {
throw new FGIXmlException(e);
}
public Schema getSchema() throws SAXException {
SchemaFactory schemaFactory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI);
URL schemaLocation = getClass().getResource("/config/xsd/fgi.xsd");
**return schemaFactory.newSchema(schemaLocation); // exception is thrown here!!!**
}
I'm clueless. There was no code change that justifies this. This code has worked for many years. I don't know why after some trivial git pull/rebase I ended up with this behavior. By the way, there's no apparent problem whatsoever with the XML file that I want to unmarshall. It's an UFT-8 xml file. I've even tried changing the encoding but to no avail.
Any ideas?
Thank you
I have a large XML file that I want to parse
XML - The XML file has over 300 cases and other tags
i'm only interested in the Cases. What I want todo is take all the cases and everything in the case tag and save it in a new DOM doc that only holds the cases, Once I have this New DOM I want to send it to another class that will take the information and format it into a word document( but i'll takle that once I get there)
an example of my XML is
<suite>
<cases>
<case>
<id/>
<title/>
<type/>
<priority/>
<estimate/>
<references/>
<custom>
<functional_area/>
<technology_dependence/>
<reviewed/>
<steps_completed>
</steps_completed>
<preconds> </preconds>
<steps_seperated>
<step>
<index/>
<content>
</content>
<expected>
</expected>
</step>
<step>
<index/>
<content>
</content>
<expected>
</expected>
</step>
<step>
</steps_seperated>
</custom>
</case>
</suite>
</cases>
There are about 400 of these case nodes
My java
setting up the initial
private void setXMLdoc(String path){
xmlDoc = getDocument(path) ;
}
getting the xml file
private Document getDocument(String path) {
try{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(path);
} catch (ParserConfigurationException ex) {
Logger.getLogger(ImportXML.class.getName()).log(Level.SEVERE, null, ex);
} catch (SAXException ex) {
Logger.getLogger(ImportXML.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ImportXML.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
would this create a new doc that only contains the cases?
NodeList fList = xmlDoc.getElementsByTagName("case");
also how would I print out all elements todo with the case? / print out all the elements todo with all the cases
Thanks in advance - im still pretty new so sorry if this question doesn't make sense or seems a bit basic
The approximate code will be
DOMParser parser=new DOMParser();
InputSource source=new InputSource(<the XML file/network stream>);
parser.parse(source);
Element docElement=parser.getDocument().getDocumentElement();
XPath xPath=xPathFactory.newXPath();
XPathExpression expression_=xPath.compile("//case");
NodeList list_=(NodeList)expression_.evaluate(docElement,XPathConstants.NODESET);DocumentBuilder documentBuilder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document newDocument=documentBuilder.newDocument();
Element newElement=newDocument.createElement("SOME_NAME");
newDocument.appendChild(newElement);
for(int i=0;i<list_.getLength();i++){Node n=newDocument.importNode(list_.item(i),true);newElement.appendChild(n);}
then send the 'newDocument' to the other class
I'm a total Java virgin, and I've been stumbling slowly but surely in developing an IRC bot for my friends. So far, I've gotten nearly all of the features in working order. But, I'm really wracking my brain over this problem here, my bot so far can reply with a link, but every week, I have to change the link in the java file manually and recompile the whole thing. So, I want it to be able to parse the pertinent values from an XML file in the same directory the bot's java files are in, and be able to update those same values through an IRC client.
import org.jibble.pircbot.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.xml.sax.*;
import org.w3c.dom.*;
public class ModBot extends PircBot {
static String inputFile = "./botdata.xml";
static String outputFile = "./botdata.xml";
public ModBot() {
setLogin("ModBot");
this.setName("ModBot");
setVersion(" ");
}
public void onMessage(String channel, String sender, String login, String hostname, String message) {
if (message.equalsIgnoreCase("!lolcat")) {
sendMessage(channel, sender + "http://i.imgur.com/4IX4cUL.jpg");
}
if (message.startsWith("!updatelolcat ")) {
if(login.equals("Mainmod"));
String changelolcat = message.substring(14);
}
}
}
And the XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE botdata [
<!ELEMENT botdata (lolcat,partytime,start,end)>
<!ELEMENT lolcat (#PCDATA)>
<!ELEMENT partytime (start,end)>
<!ELEMENT start (#PCDATA)>
<!ELEMENT end (#PCDATA)>
]>
<botdata>
<lolcat>http://i.imgur.com/4IX4cUL.jpg</lolcat>
<partytime>
<start>8:45:30</start>
<end>11:00:00</end>
</partytime>
</botdata>
What I want to do is take whatever "changelolcat" is, and overwrite the current link in the XML, and then a way to read from the same XML to send what's in "lolcat" to anyone replying "!lolcat". I've been going through xpath and jdom and stuff, and I just can't make sense of it. What I've read with methods using xpath looks promising, and I'd prefer to use it because it's prettier to read.
EDIT:
It worked, I put in
try {DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse("botdata.xml");
Node botdata = document.getElementsByTagName("botdata").item(0);
NodeList nodes = botdata.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node element = nodes.item(i);
if ("lolcat".equals(element.getNodeName())) {
element.setTextContent(changelolcat);
}
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource domSource = new DOMSource(document);
StreamResult streamResult = new StreamResult(new File("botdata.xml"));
transformer.transform(domSource, streamResult);
}catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
}
after String changelolcat = message.substring(14);
EDIT: I figured out how to parse from my XML to send what's in a node as a message, does this look right? I feel like I'm not supposed to keep copying the doc builder over and over in different methods
if (message.equalsIgnoreCase("!lolcat")) {
try {
DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder =
documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(botxml);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
String lolcat = xpath.evaluate("//lolcat", document);
sendMessage(channel, sender + lolcat);
} catch (Exception e) {
e.printStackTrace();
}
}
One way to do this would be to use the javax.xml.parsers.DocumentBuilder to parse your xml file into javax.swing.text.Document, which provides a great interface for getting and modifying individual elements and their values. You can then write the modified document back to the original file, overwriting it with the new version.
Here are some links to the relevant javadocs:
Document
DocumentBuilder
You might also want to look at the javadocs for the DocumentBuilderFactory object, which is definitely the best way to generate DocumentBuilders.
I am newbie in XML parsing world. I found solution for reading xml file with 'namespaces' as given below. I refered this stackoverflow link Default XML namespace, JDOM, and XPath and reading Element works. But I am not able to modify the element. Here goes my problem statements.
My xml file looks like this.
<?xml version="1.0" encoding="UTF-8"?>
<ProofSpecification xmlns="http://www.zurich.ibm.com/security/idemix"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.zurich.ibm.com/security/idemix ProofSpecification.xsd">
<Declaration>
<AttributeId name="id1" proofMode="unrevealed" type="string" />
<AttributeId name="id2" proofMode="unrevealed" type="string" />
</Declaration>
<Specification>
<Credentials>
<Credential issuerPublicKey="file:/Users/ipk.xml"
credStruct="file:/Users/CredStruct_ResUAC.xml" name="SpecResUAC">
<Attribute name="FirstName">id1</Attribute>
<Attribute name="LastName">id2</Attribute>
</Credential>
</Credentials>
<Pseudonyms>
<Pseudonym name="pseudonym"></Pseudonym>
<DomainPseudonym>1331859289489</DomainPseudonym>
</Pseudonyms>
<Messages />
</Specification>
</ProofSpecification>
And my java code snippet looks like this.
public class ModifyXMLFileJDom {
public static void main(String[] args) throws JDOMException, IOException {
try {
SAXBuilder builder = new SAXBuilder();
File xmlFile = new File("/blabla/ProofSpecResUAC_old.xml");
Document doc = (Document) builder.build(xmlFile);
XPath xpath = XPath.newInstance("x:ProofSpecification/x:Specification/x:Pseudonyms/x:DomainPseudonym");
xpath.addNamespace("x", doc.getRootElement().getNamespaceURI());
System.out.println("domainPseudonym: "+xpath.valueOf(doc));
xpath.setVariable("555555", doc);
XMLOutputter xmlOutput = new XMLOutputter();
xmlOutput.setFormat(Format.getPrettyFormat());
xmlOutput.output(doc, new FileWriter("/blabla/proofSpecOut.xml"));
System.out.println("File updated!");
} catch (IOException io) {
io.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
}
}
This piece of code works fine and Reading Element "domainPseudonym" works.
But I want to modify this element from
<DomainPseudonym>1331859289489</DomainPseudonym> to
<DomainPseudonym>555555</DomainPseudonym>
I tried modifying using function xpath.setVariable("555555", doc) but not working and not giving out any error. The end result is that it copies the same content to the new xml file "proofSpecOut.xml".
XPath is not used for modifying the xml, only for finding parts of it. XPath.setVariable() is only for setting variables in your xpath expression. You want to use XPath.selectSingleNode() to retrieve one of the Elements of your document and then you want to modify that directly using Element.setText().