Java getNodeName and namespaces - java

Given 2 XML files that conform to the same schema (both valid), one has namespaces, the other one has not (sample):
XML File 1
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<message xmlns="http://www.somewhere.com/X">
<messageheader>
...
</message>
XML File 2
<?xml version="1.0" encoding="UTF-8"?>
<ns1:message xmlns:ns1="http://www.somewhere.com/X">
<ns1:messageheader>
...
</ns1:message>
The issue is that the code that parses the file uses the Element.getNodeName() getter to determine node names before extracting and storing the text content. This method was used as opposed to XPath when parsing the XML due to performance.
Therefore the following sample code was implemented to do the parsing:
for(int i = 0; i < someElement.getChildNodes().getLength(); i++) {
if(someElement.getChildNodes().item(i).getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
Element element = (Element) someElement.getChildNodes().item(i);
if(element.getNodeName().equals("ns1:messageheader")) {
...
}
...
}
}
The above code only works with XML File 2.
Is it possible to determine whether a file uses the namespace prefix on elements so both files can be parsed using getNodeName() - so I can use the same code to parse both files?
I agree this is an awful way to parse the XML. Unfortunately, my code was implemented before switching to JAXB which I love (for the moment).
Thanks
Andez

Use getLocalName() instead of getNodeName(). This will return the unqualified name of the element.

Try this:
if (element.getLocalName().equals("messageheader") &&
"http://www.somewhere.com/X".equals(element.getNamespaceURI())) { ...
You have to check that the local name and the namespace match, regardless of the prefix.

Related

Partial XML parsing giving an element not bound exception

I'm trying to parse an XML document with DSpace XOAI library. This is the input XML:
<?xml version="1.0" encoding="UTF-8"?>
<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
...
<ListRecords>
<record>
<header>
...
</header>
<metadata>
<crossref xmlns="http://www.crossref.org/xschema/1.1" xsi:schemaLocation="http://www.crossref.org/xschema/1.1 http://www.crossref.org/schema/unixref1.1.xsd">
...
</crossref>
</metadata>
</record>
</ListRecords>
</OAI-PMH>
From what I could deduce from debugging, each metadata node is parsed individually by XOAI library. And, in that context, I get this error (which makes sense, because the xsi namespace is defined in parent OAI-PMH node):
ERROR: 'The prefix "xsi" for attribute "xsi:schemaLocation" associated with an element type "crossref" is not bound.'
For what I could understand from the library source code, it uses the Oracle java javax.xml.transform.Transformer to make the transformations. We can set any Transformer to be executed.
I'm already using an XSLT file for transforming the input XML in the format expected by the library. However, I couldn't find a way to create a rule in XSLT to ignore the xsi:schemaLocation that is causing the error.
The other option is create a new Transformer in Java. I was looking at Transformer.setOutputProperty, but I couldn't make a working configuration that ignores this error in crossref node.
Do you guys know how can I correctly parse the contents of crossref node in that local context?
Thanks in advance!

Write stylesheet tag with XML API (STaX/DOM/..)

i'm having some trouble to write a particular xml tag (using an XmlStreamWriter).
Basically, we have an XMLWriter that is based on "javax.xml.stream.XMLStreamWriter" (STaX) which is working fine.
All the xml files that are written begin automatically with the tag :
< ?xml version="1.0" encoding="ISO-8859-1"?> (first space is added to display the xml line)
What we need now is to add a new line (stylesheet) to write every single xml file with the beginning lines :
< ?xml version="1.0" encoding="ISO-8859-1"?> (same as above)
< ?xml-stylesheet type="text/xsl" href="myXsl.xsl"?> (same as above)
I tried to do it the hard-coded way, using the XmlStreamWriter.writeCharacters(String) but the problem is that "<" and ">" are special characters so the output in the xml file is "<"/">".
Also, this is not very clean coding..
In the same way that STaX writes the first line using "XMLStreamWriter.writeStartDocument(String encoding, String version)", does anyone know an XML (XSL/XSLT?) API which WRITER does write the tag :
< ?xml-stylesheet type="text/xsl" href="myXsl.xsl"?> (same as above)
Any help would be much appreciated :)
It is called a processing instruction.
See XMLStreamWriter.writeProcessingInstruction, for instance.
In your case:
writer.writeProcessingInstruction("xml-stylesheet",
"type=\"text/xsl\" href=\"myXsl.xsl\"");
(Not tested.)

How can i modify xml-stylesheet attribute value in java

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet href="Sample.xsl" type="text/xsl"?>
<MyDoc>.....</MyDoc>
I want to modify the attribute href's value to 'MyDoc.xsl'. I have tried using XPath but it returns nothing:
//xml-stylesheet[contains(text(), 'Sample.xsl')]/#href";
Also using Document only gives elements starting at MyDoc
NodeList list = taggedC32Doc.getElementsByTagName("*");
Is there any way i can do this?
The line you want to change is a Processing Instruction, not an Element, so neither of your attempts to find it as an element will work. Try
/processing-instruction(xml-stylesheet)
You can then get that node's data, which will be href="Sample.xsl" type="text/xsl". Perform the appropriate string manipulation to find and change the href pseudo-attribute in that string -- sorry, most XML APIs don't provide any assistance in doing so, because as far as XML is concerned the PI's data is an unformatted string even though it's usually structured to resemble attributes -- and set the new data back into the ProcessingInstruction node.

soap java: read and change nodes in xml files

I have a number of pre-generated, static xml files containing soap requests. I can read them, send the request, and get back and answer from the server. I would like to get some advice on how to create a dynamic process:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getProject xmlns="http://myserver/">
<atr1>string</atr1>
<atr2>string</atr2>
</getProject>
</soap:Body>
</soap:Envelope>
So, I want to be able to read these xml files, change the values of the nodes , etc. to real values gathered from user input at run-time. What would be the best way to go: read the xml file line by line and use a regex to replace value, or maybe make a temp copy of the xml file, use sax to replace the node value, then send the new xml, or completely discard the pre-generated xml files and instead create them on-the-fly, or how? Any suggestions would be appreciated.
Using regexes would be fragile, because the formatting of the XML could change in ways you're not expecting, and still be well-formed and valid XML, but not fit your regexes. In general it's not recommended to use regexes to parse XML.
Using SAX to read in the XML file (why make a temp copy?), copy all nodes to the output, modifying certain ones to put in the user-supplied values. That sounds like a good, workable solution.
Create the XML from scratch: that does sound simpler, if you know their structure in advance, and it's not too big. One way to do this would be to use an XSLT stylesheet, and pass in the user-supplied values as parameters.
You could use castor and create objects from the xml, and xml from the objects.
private void changeTagData(List<String> tagNameList, SOAPBody body) {
for(String tagName : tagNameList){
NodeList nodeList = body.getElementsByTagName(tagName);
int length = nodeList.getLength();
Node node;
for (int i = 0; i < length; i++) {
node = (Node) nodeList.item(i);
node.setTextContent("change tag data");
}
}
}
XStream can also be used in this process i am also doing some what same thing. If you like you can try XStream also.

how to reference XSD Schema location while parsing XML Doc via SAX Xerces?

how to reference XSD Schema location while parsing XML via SAX Xerces?
< ?xml version="1.0" encoding="ISO-8859-1"?> < com.firma
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
< !-- xsi:noNamespaceSchemaLocation="F:\...\myschema_v2.5.xsd"
Must I reference this element really within the XML Doc??? I hope, not...
-- >
I also set it as follows in Java code, which is not elegant, while schema location is fixed(not appropriate for production)
SaxParser.setProperty(
"http://java.sun.com/xml/jaxp/properties/schemaSource",
"F:...\myschema_v2.5.xsd"
);
include the schema in your jar and load it using getResourceAsStream in the following way
reader.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource",
new InputSource(getClass().getResourceAsStream(xsdLocation)));
I got it.
one must use as follows, giving "/com/firma/project/.../myschema_v2.5.xsd" as parameter.
not forgetting the "/" in the path at the very beginning.

Categories