3

I am currently creating an XML document in Java. The document should have the following structure:

<?xml version="1.0" ?> 
<Cancelacion xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             RfcEmisor="VSI850514HX4" 
             Fecha="2011-11-23T17:25:06" 
             xmlns="http://cancelacfd.sat.gob.mx">
    <Folios>
        <UUID>BD6CA3B1-E565-4985-88A9-694A6DD48448</UUID> 
    </Folios>
</Cancelacion>

I want to know if there is a special way to create the attributes with form xmlns:xsd? I am currently declaring this attribute like this:

DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder;
docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
doc.setXmlVersion("1.0");
doc.setXmlStandalone(true);

Element cancelacion = doc.createElement("Cancelacion");
cancelacion.setAttribute("xmlns", "http://cancelacfd.sat.gob.mx");
cancelacion.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
cancelacion.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
cancelacion.setAttribute("RfcEmisor", rfc);
cancelacion.setAttribute("Fecha", fecha);

4 Answers 4

11

The solution my problem is to write the code as follows:

//Crear un document XML vacío
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
dbfac.setNamespaceAware(true);
DocumentBuilder docBuilder;
docBuilder = dbfac.newDocumentBuilder();
DOMImplementation domImpl = docBuilder.getDOMImplementation();
Document doc = domImpl.createDocument("http://cancelacfd.sat.gob.mx", "Cancelacion", null);
doc.setXmlVersion("1.0");
doc.setXmlStandalone(true);

Element cancelacion = doc.getDocumentElement();
cancelacion.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsd","http://www.w3.org/2001/XMLSchema");
cancelacion.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
cancelacion.setAttribute("RfcEmisor", rfc);
cancelacion.setAttribute("Fecha", fecha);

Element folios = doc.createElement("Folios");
cancelacion.appendChild(folios);
for (int i=0; i<uuid.length; i++) {
    Element u = doc.createElement("UUID");
    u.setTextContent(uuid[i]);
    folios.appendChild(u);
}
Sign up to request clarification or add additional context in comments.

Comments

2

Why should the document have your proposed structure? You're declaring namespaces with prefixes, but your example output doesn't include any elements in those namespaces. Those declarations are therefore unnecessary.

First, understand that xmlns (or xmlns:prefix) is the reserved XML pseudo-attribute for declaring namespaces. It's not a normal attribute. Second, the location of namespace declarations in the document shouldn't concern you, as long as you're creating elements in the desired namespaces in the first place.

Let the serializer decide where to place the namespace declarations.

Register an element in the correct namespace like this:

Element cancelacion = doc.createElementNS(
        "http://cancelacfd.sat.gob.mx", "Cancelacion");
doc.appendChild(cancelacion);

Element child = doc.createElementNS("http://cancelacfd.sat.gob.mx",
        "SomeChild");
cancelacion.appendChild(child);

When serialized:

DOMSource domSource = new DOMSource(doc);
StreamResult streamResult = new StreamResult(System.out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.transform(domSource, streamResult); 

Result:

<Cancelacion xmlns="http://cancelacfd.sat.gob.mx">
    <SomeChild/>
</Cancelacion>

Notice that Cancelacion and SomeChild were created in exactly the same way, but only Cancelacion contains the namespace declaration (because the declaration applies for all descendants). The serializer handled this for us.

Warning: What follows is a hack. I do not recommend using it. It will probably get you into trouble. You should probably stop reading. But...if you have no choice, it might work.

If you're desperate, you could manually splice in the unused namespaces. (Treating XML as a string is almost always a bad idea.)

First, save the result in an OutputStream that can be converted to a String:

ByteArrayOutputStream out = new ByteArrayOutputStream();
DOMSource domSource = new DOMSource(doc);
StreamResult streamResult = new StreamResult(out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.transform(domSource, streamResult);

Then jam the namespace declarations in there without any regard for what is good, right, and decent:

String[] parts = out.toString().split("\\\">", 2);
String result = parts[0] + 
    " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
    " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" + parts[1];

6 Comments

But hat if I need <Cancelacion instead of <xsd:Cancelacion ?? How can I declare the namespaces instead?
It should be declared this way because this XML should be signed and then sent via a web service to cancelacfd.sat.gob.mx... this is needed for cancelling an electronic invoice. I really don't understand why it should be this way, but it must be that ways. Otherwise, it would be rejected.
@user1084509 - Well, my edit shows how to get Cancelacion in the default namespace. Maybe this is enough? Those other declaration don't seem to be necessary.
The other declarations are obligatory... I don't know why. But I don't know how to obtain them. I edited my question with the code I have so far and the results Im getting.
@user1084509 - I added some bad advice on how to do this as a last resort.
|
1

xmlns:xsd is not an attribute, its a namespace declaration.

The DOM should create these declarations as and when they are needed.

Using the createElementNS and createAttributeNS methods will result in namespace declarations being created, but you need to understand XML namespaces.

In your example, the namespaces bound to xsd and xsi are not used so are superfluous. However, the Cancelacion element is in the default namespace which is defined by the xmlns="http://cancelacfd.sat.gob.mx" declaration in the XML you have provided.

So you should use:

doc.createElementNS("http://cancelacfd.sat.gob.mx", "Cancelacion");

to create that. Note that the namespace prefix (or lack thereof) is irrelevant as far as the meaning of the document is concerned.

2 Comments

And how should I create these DOM declarations for the node Cancelacion?
I cant get to have the xmlns:xsi and xmls:xsd declarations. I edited my code with what I have so far.
0

in my code, I wrote :

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document document = builder.newDocument();

    Element spectraexchage = document.createElementNS("http://www.lstelcom.com/Schema/SPECTRAexchange", "SPECTRAEXCHANGE");
    spectraexchage.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
    spectraexchage.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    spectraexchage.setAttribute("version", "2.4.28");
    document.appendChild(spectraexchage);

    DOMSource source = new DOMSource(document);
    StreamResult result = new StreamResult(System.out);
    transformer.transform(source, result);

output :

<SPECTRAEXCHANGE xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4.28" xmlns="http://www.lstelcom.com/Schema/SPECTRAexchange">

Comments

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.