Failed to remove tags that have "xsi: nil" in them via xslt
I have the following xml which contains multiple xml tags with xsi: nil = "true". These are tags that are mostly null. I cannot use / find any sxlt transformer to remove these tags from the xml and get the rest of the xml.
<?xml version="1.0" encoding="utf-8"?>
<p849:retrieveAllValues xmlns:p849="http://package.de.bc.a">
<retrieveAllValues>
<messages xsi:nil="true" />
<existingValues>
<Values>
<value1> 10.00</value1>
<value2>123456</value2>
<value3>1234</value3>
<value4 xsi:nil="true" />
<value5 />
</Values>
</existingValues>
<otherValues xsi:nil="true" />
<recValues xsi:nil="true" />
</retrieveAllValues>
</p849:retrieveAllValues>
source to share
The reason for the error you are getting
[Fatal Error] file2.xml: 5:30: The "xsi" prefix for the "xsi: nil" attribute associated with item type "messages" is not associated.
is the absence of a prefix with the name "xsi", declared, you must specify it in the root element, for example:
<p849:retrieveAllValues xmlns:p849="http://package.de.bc.a"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<retrieveAllValues>
<messages xsi:nil="true" />
// other code...
Update
If you are unable to modify the XML document you receive from the webservice, you can try the following approach (if that approach works for you):
- Modify your
xslt
document to handle XML documents without specifying element prefixes - Set property
namespaceAware
DocumentBuilderFactory
to false
After that the transformer yout shouldn't complain
source to share
It doesn't look like this will be possible in XSLT - due to the missing namespace declarations, you need to parse the XML file with a parser other than the namespace, but all XSLT processors I've tried "Get along well with such documents, they should rely on some information that is only present when parsed with namespace recognition, even if the document does not actually contain named nodes.
So you have to approach it differently, for example by traversing the DOM tree. Since you say you are working in Java, here is an example using the Java DOM APIs (example is run as is in the Groovy console , or wrap it in a correct class definition and add any exception handling to run it as Java)
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.w3c.dom.ls.*;
public void stripNils(Node n) {
if(n instanceof Element &&
"true".equals(((Element)n).getAttribute("xsi:nil"))) {
// element is xsi:nil - strip it out
n.getParentNode().removeChild(n);
} else {
// we're keeping this node, process its children (if any) recursively
NodeList children = n.getChildNodes();
for(int i = 0; i < children.getLength(); i++) {
stripNils(children.item(i));
}
}
}
// load the document (NB DBF is non-namespace-aware by default)
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document xmlDoc = db.parse(new File("input.xml"));
stripNils(xmlDoc);
// write out the modified document, in this example to stdout
LSSerializer ser =
((DOMImplementationLS)xmlDoc.getImplementation()).createLSSerializer();
LSOutput out =
((DOMImplementationLS)xmlDoc.getImplementation()).createLSOutput();
out.setByteStream(System.out);
ser.write(xmlDoc, out);
In the original XML example, this produces the correct result:
<?xml version="1.0" encoding="UTF-8"?>
<p849:retrieveAllValues xmlns:p849="http://package.de.bc.a">
<retrieveAllValues>
<existingValues>
<Values>
<value1> 10.00</value1>
<value2>123456</value2>
<value3>1234</value3>
<value5/>
</Values>
</existingValues>
</retrieveAllValues>
</p849:retrieveAllValues>
Blank lines are not actually blank lines, they contain whitespace text nodes on either side of the deleted elements, since only the elements themselves are deleted here.
source to share