Reputation: 1
I need your help with JAXB marshalling. It's about namespaces. I have read different blogs and a lot of answers in this amazing site, but I haven't realize how to solve my problem.
I need to generate an XML with some tricky (at least for me) namespaces.
<?xml version="1.0" encoding="utf-8"?>
<cfdi:Comprobante xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd" version="3.2" fecha="2016-11-28T11:04:56" sello="MC7" formaDePago="una sola exhibición" noCertificado="00" certificado="MygA" subTotal="615.52" total="714.00" tipoDeComprobante="ingreso" LugarExpedicion="México DF" NumCtaPago="3138" TipoCambio="1.00" Moneda="MXN" metodoDePago="04" xmlns:cfdi="http://www.sat.gob.mx/cfd/3">
<cfdi:Emisor rfc="EMISOR" nombre="EMISOR">
<cfdi:DomicilioFiscal calle="SIN NUMERO" noExterior="na" municipio="México DF" estado="México" pais="MEX" codigoPostal="15620" />
<cfdi:ExpedidoEn calle="Calle" municipio="México" estado="México" pais="MEX" codigoPostal="63257" />
<cfdi:RegimenFiscal Regimen="GENERAL DE LEY PERSONAS MORALES" />
</cfdi:Emisor>
<cfdi:Receptor rfc="EMPRESA" nombre="EMPRESA">
<cfdi:Domicilio calle="Ave. Esclavitud No. 5300 " municipio="Mexico" pais="MEX" codigoPostal="52478" />
</cfdi:Receptor>
<cfdi:Conceptos>
<cfdi:Concepto cantidad="1.0000" unidad="no aplica" noIdentificacion="5213610219" descripcion="CONSUMO" valorUnitario="615.52" importe="615.52" />
</cfdi:Conceptos>
<cfdi:Impuestos totalImpuestosTrasladados="98.48">
<cfdi:Traslados>
<cfdi:Traslado impuesto="IVA" tasa="16.00" importe="98.48" />
</cfdi:Traslados>
</cfdi:Impuestos>
<cfdi:Complemento>
<tfd:TimbreFiscalDigital xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/TimbreFiscalDigital/TimbreFiscalDigital.xsd" version="1.0" UUID="070A8-5997-4F11-BCEE" FechaTimbrado="2016-11-28T11:05:05" selloCFD="MC7" noCertificadoSAT="20" selloSAT="In2" xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" />
</cfdi:Complemento>
<cfdi:Addenda xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.voxelgroup.net/xsd https://www.voxelgroup.net/xsd/addenda_v1.xsd" xmlns:voxel="https://www.voxelgroup.net/xsd">
<voxel:AdditionalInfo>
</voxel:AdditionalInfo>
</cfdi:Addenda>
</cfdi:Comprobante>
As you can see, this XML has
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
and
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd"
and
xmlns:cfdi="http://www.sat.gob.mx/cfd/3"
I have done different tests to solve this issue but I haven't had success.
The java class you will see now has been generated with xjc, (not getters and setters for sake of clarity):
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"informacionAduanera",
"cuentaPredial",
"complementoConcepto",
"parte"
})
@XmlRootElement( name = "Comprobante", namespace = "http://www.sat.gob.mx/cfd/3")
public static class Concepto {
@XmlElement(name = "InformacionAduanera")
protected List<TInformacionAduanera> informacionAduanera;
@XmlElement(name = "CuentaPredial")
protected Comprobante.Conceptos.Concepto.CuentaPredial cuentaPredial;
@XmlElement(name = "ComplementoConcepto")
protected Comprobante.Conceptos.Concepto.ComplementoConcepto complementoConcepto;
@XmlElement(name = "Parte")
protected List<Comprobante.Conceptos.Concepto.Parte> parte;
@XmlAttribute(name = "cantidad", required = true)
protected BigDecimal cantidad;
@XmlAttribute(name = "unidad", required = true)
protected String unidad;
@XmlAttribute(name = "noIdentificacion")
protected String noIdentificacion;
@XmlAttribute(name = "descripcion", required = true)
protected String descripcion;
@XmlAttribute(name = "valorUnitario", required = true)
protected BigDecimal valorUnitario;
@XmlAttribute(name = "importe", required = true)
protected BigDecimal importe;
}
And, this is the package-info.class
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.w3.org/2001/XMLSchema-instance",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package mx.gob.sat.cfd._3;
I have a namespaceMapper too:
public class MyNamespaceMapper extends com.sun.xml.bind.marshaller.NamespacePrefixMapper{
private static final String CFDI_URI = "http://www.sat.gob.mx/cfd/3";
private static final String CFDI_PREFIX = "cfdi";
private static final String XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";
private static final String XSI_PREFIX = "";//xsi";
private static final String SCHEMA_URI = "http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd";
private static final String SCHEMA_PREFIX = "";//schemaLocation";
@Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requiredPrefix) {
switch(namespaceUri){
case CFDI_URI:{ return CFDI_PREFIX; }
case XSI_URI:{ return XSI_PREFIX; }
case SCHEMA_URI:{ return SCHEMA_PREFIX; }
default: { return ""; }
}
}
}
Next, It's the output I get:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cfdi:Comprobante xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cfdi="http://www.sat.gob.mx/cfd/3" NumCtaPago="" LugarExpedicion="MEXICO" metodoDePago="02" tipoDeComprobante="ingreso" total="4000.00" Moneda="PESO" TipoCambio="1.0000" motivoDescuento="" descuento="0" subTotal="4000" condicionesDePago="EN UNA SOLA EXHIBICION" certificado="" noCertificado="00009200" formaDePago="CHEQUE" sello="" fecha="2016-12-02T12:40:42.302-06:00" folio="9" serie="A" version="3.2">
<xsi:Emisor nombre="PEPITO" rfc="PEPE">
<xsi:DomicilioFiscal codigoPostal="51890" pais="México" estado="México" municipio="México" colonia="México" noInterior="" noExterior="5300" calle="Esclavitud"/>
<xsi:RegimenFiscal Regimen="Regimen General de Ley Personas Morales"/>
</xsi:Emisor>
<xsi:Receptor nombre="EMPRESA" rfc="EMPRESA">
<xsi:Domicilio codigoPostal="51890" pais="México" estado="México" municipio="México" colonia="México" noInterior="" noExterior="5300" calle="Esclavitud"/>
</xsi:Receptor>
<xsi:Conceptos>
<xsi:Concepto importe="4000" valorUnitario="4000" descripcion="ARRENDAMIENTO DEL MES DE SEPTIEMBRE" unidad="N/A" cantidad="1"/>
</xsi:Conceptos>
<xsi:Impuestos>
<xsi:Traslados>
<xsi:Traslado importe="400" tasa="10" impuesto="ISR"/>
</xsi:Traslados>
</xsi:Impuestos>
</cfdi:Comprobante>
This is the closes I have been from the original xml format. I have tried differente approaches but I haven't got anything more.
As you can see, in the output still is missing a third namespace,
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd"
and every line must have the prefix cfdi not xsi.
I'll really appreciate any clue to get this done.
Thank you!
Upvotes: 0
Views: 1567
Reputation: 11
Maybe is too late, but I have something like this:
...
private Map<String, String> prefijos = new HashMap<String, String>();
prefijos.put("http://www.w3.org/2001/XMLSchema-instance","xsi");
prefijos.put("http://www.sat.gob.mx/cfd/3", "cfdi");
prefijos.put("http://www.sat.gob.mx/TimbreFiscalDigital", "tfd");
JAXBContext jaxbContext = JAXBContext.newInstance("mx.gob.sat.v33");
marshaller = jaxbContext.createMarshaller();
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new
NamespacePrefixMapperImpl(prefijos));
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,"http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv33.xsd");
DocumentBuilderFactory docBuilderFac = DocumentBuilderFactory.newInstance();
docBuilderFac.setNamespaceAware(true);
DocumentBuilder db = null;
db = docBuilderFac.newDocumentBuilder();
Document doc = db.newDocument();
marshaller.marshal(comprobante,doc);
...
My NamespacePrefixMapperImpl is like this:
public class NamespacePrefixMapperImpl extends NamespacePrefixMapper{
private final Map<String, String> map;
public NamespacePrefixMapperImpl(Map<String, String> map) {
this.map = map;
}
public String getPreferredPrefix(String namespaceUri, String suggestion,
boolean requirePrefix) {
String value = map.get(namespaceUri);
return (value != null) ? value : suggestion;
}
public String[] getPreDeclaredNamespaceUris() {
return new String[0];
}
}
Maybe you can take a look in this project
Upvotes: 0
Reputation: 5310
As this example shows, use the @XmlNs annotation to customize the NS prefix.
E.g.
@javax.xml.bind.annotation.XmlNs(prefix = "myns",
namespaceURI="http://myns/schema"
The examples will give you more context.
Even if you could get the RI classes to do what you want, it's better to use the APIs than hacking into implementation-only classes.
Upvotes: 1