java - convert - xmlgregoriancalendar c#
JAXB Bindings File Establece el tipo @XmlElement en String en lugar de XMLGregorianCalendar (2)
ACTUALIZAR
resumiendo:
- tiene un esquema que usa el estilo de fecha en algún lugar y no puede cambiar el esquema
- tiene algunos datos XML que utilizan ese esquema y especifica alguna fecha con zona horaria (por lo tanto, es el formato
yyyy-MM-ddXXX
) - desea eliminar la parte
XXX
de la representación de la fecha en ese archivo (la fecha en sí no se envía en ninguna zona horaria, la fecha es solo un número)
así que esto podría ser un esquema de muestra:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<element name="foo">
<complexType>
<sequence>
<element name="bar" type="date" minOccurs="1" maxOccurs="1"/>
</sequence>
</complexType>
</element>
</schema>
Esto podría ser una muestra de datos:
<?xml version="1.0" encoding="UTF-8"?>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="foo.xsd">
<bar>2014-01-01+06:00</bar>
</foo>
esta es la clase anotada JAXB
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo implements Serializable
{
private static final long serialVersionUID = 1L;
@XmlElement(name = "bar")
@XmlJavaTypeAdapter(DateAdapter.class)
@XmlSchemaType(name = "date")
private Date bar;
// getters/setters
}
esto es adaptador de fecha
public class DateAdapter extends XmlAdapter<String, Date>
{
@Override
public String marshal(Date date)
{
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df.format(date);
}
@Override
public Date unmarshal(String date) throws ParseException
{
DateFormat df = new SimpleDateFormat("yyyy-MM-ddXXX");
return df.parse(date);
}
}
Este es el principal, validando contra el esquema:
public static void main(String[] args) throws JAXBException, SAXException
{
JAXBContext context = JAXBContext.newInstance(Foo.class);
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(Foo.class.getResource("/foo.xsd"));
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setSchema(schema);
Foo foo = (Foo) unmarshaller.unmarshal(Foo.class.getResource("/foo.xml"));
System.out.println("unmarshalled: " + foo.getBar());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "foo.xsd");
marshaller.setSchema(schema);
marshaller.marshal(foo, System.out);
}
y esta es la salida, la zona horaria se ha eliminado y la representación de la fecha ha cambiado obviamente
unmarshalled: Tue Dec 31 19:00:00 CET 2013
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="foo.xsd">
<bar>2013-12-31</bar>
</foo>
tal vez este cambio en la representación de la fecha no sea lo que usted esperaría, pero esto no es un problema de JAXB, la fecha representada no ha cambiado.
Estaba olvidando los enlaces para revertir generar Foo:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0">
<jaxb:globalBindings>
<xjc:javaType name="java.util.Date" xmlType="xsd:date" adapter="aaa.DateAdapter" />
</jaxb:globalBindings>
</jaxb:bindings>
FIN DE ACTUALIZACIÓN
lo siento, demasiado tiempo para un comentario ...
no puedo entender
- ¿Por qué demonios estás usando
XmlGregorianCalendar
? - ¿Por qué debería
unmarshal
/unmarshal
(serialize
/deserialize
) la misma estructura de datos? - ¿Por qué debería eliminar la zona horaria?
y
- Yo uso
java.util.Date
directo y simple -
marshal
/unmarshal
siempre debe incluirString
s (al menos para XML) - Realmente no veo una buena razón para eliminar arbitrariamente una parte de una representación de fecha. Tal vez quieras serializarlo de una manera absoluta.
sin embargo
public class DateAdapter extends XmlAdapter<String, Date>
{
@Override
public String marshal(Date date)
{
DateFormat df = DateFormat.getDateTimeInstance();
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df.format(date);
}
@Override
public Date unmarshal(String date) throws ParseException
{
DateFormat df = DateFormat.getDateTimeInstance();
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df.parse(date);
}
public static void main(String[] args) throws ParseException
{
DateAdapter adapter = new DateAdapter();
String str = adapter.marshal(new Date());
System.out.println(str); // 16-dic-2013 10.02.09 --> to gmt
Date date = adapter.unmarshal(str);
System.out.println(date); // Mon Dec 16 11:02:09 CET 2013 --> correct, i''m gmt+1
}
}
Estoy intentando crear un XmlAdapter
que toma un XMLGregorianCalendar
y genera un XMLGregorianCalendar
. El propósito es simplemente eliminar los datos de la zona horaria del elemento cuando se desasignan datos.
Se parece a esto:
public class TimezoneRemoverAdapter extends XmlAdapter<XMLGregorianCalendar, XMLGregorianCalendar> {
public XMLGregorianCalendar unmarshal(XMLGregorianCalendar xgc) {
if(xgc == null) {
return null;
}
xgc.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
return xgc;
}
public XMLGregorianCalendar marshal(XMLGregorianCalendar xgc) {
return xgc;
}
}
Esto funciona bien para el siguiente código:
public class FooElement {
@XmlElement(name="bar-date")
@XmlJavaTypeAdapter(TimezoneRemoverAdapter.class)
@XmlSchemaType(name = "date")
protected XMLGregorianCalendar barDate;
}
Desafortunadamente, cuando genero el código usando un archivo jaxb-bindings.xml
, el código anterior se ve así:
public class FooElement {
@XmlElement(name="bar-date", type=java.lang.String.class)
@XmlJavaTypeAdapter(TimezoneRemoverAdapter.class)
@XmlSchemaType(name = "date")
protected XMLGregorianCalendar barDate;
}
Establece el tipo en String
, por lo que mi método anterior no funciona. La configuración de tipo String
está anulando el tipo XMLGregorianCalendar
que debería ser. Puedo cambiarlo manualmente, pero prefiero no tener que acordarme de actualizarlo cada vez que se regeneren los archivos jaxb. ¿Alguien sabe si hay una opción para configurar manualmente el tipo @XmlElement
o lo ha ignorado?
Aquí está la parte relevante del archivo jaxb-bindings.xml
:
<jxb:bindings node=".//xs:element[@name=bar-date]">
<jxb:property>
<jxb:baseType>
<jxb:javaType name="javax.xml.datatype.XMLGregorianCalendar" adapter="foo.bar.TimezoneRemoverAdapter" />
</jxb:baseType>
</jxb:property>
</jxb:bindings>
Tienes que especificar el tipo de java de manera diferente, en tu caso:
<jxb:javaType
name="javax.xml.datatype.XMLGregorianCalendar"
xmlType="xs:date"
printMethod="foo.bar.TimezoneRemoverAdapter.marshall"
parseMethod="foo.bar.TimezoneRemoverAdapter.unmarshall"
/>
Funciona bien para mí e hice algo similar con más adaptadores:
<jaxb:globalBindings>
<xjc:serializable uid="12343" />
<jaxb:javaType name="java.util.Date" xmlType="xs:date" printMethod="com.foo.DateAdapter.printDate" parseMethod="com.foo.DateAdapter.parseDate" />
<jaxb:javaType name="java.util.Date" xmlType="xs:dateTime" printMethod="com.foo.DateAdapter.printDate" parseMethod="com.foo.DateAdapter.parseDate" />
<jaxb:javaType name="java.util.Date" xmlType="xs:time" printMethod="com.foo.TimeAdapter.printTime" parseMethod="com.foo.TimeAdapter.parseTime" />
</jaxb:globalBindings>
globalBindings
enlaces anteriores como un globalBindings
en un archivo diferente con la extensión .xjb
y lo uso en cualquier lugar donde lo necesite.