根据架构中的子元素验证XML

时间:2019-04-28 02:29:02

标签: java xml jaxb

我有一个XSD架构,它可以接受XML文件,其根元素为<EnvioBOLETA>。因此,正确的XML必须如下所示:

<EnvioBOLETA version="1.0" ns="..."> <!-- Attributes are irrelevant -->
   <SetDte>
      <Caratula>
         <RutEmisor>11111111-1</RutEmisor>
         <RutEnvia>66666666-6</RutEnvia>
         <RutReceptor>11111111-1</RutReceptor>
         <FchResol>2010-10-10</FchResol>
         <NroResol>0</NroResol>
         <SubTotDTE>
            <TpoDte>39</TpoDte>
            <NroDte>1</NroDte>
         </SubTotDTE>
      </Caratula>
      <DTE version="1.0"xmlns:siid="http://www.sii.cl/SiiDte">
         <Documento>
            <!--Elements with it's attributes-->
         </Documento>
         <Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <!--DTE's xmlsignature-->
         </Signature>
      </DTE>
   </SetDte>
   <Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
       <!--EnvioBOLETA's xmlsignature-->
   </Signature>
</EnvioBOLETA>

如果我使用JAXB,它将从整个模式创建类。结果类如下:

/* EnvioBOLETA */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "setDTE",
    "signature"
})
@XmlRootElement(name = "EnvioBOLETA")
public class EnvioBOLETA {

    @XmlElement(name = "SetDTE", required = true)
    protected EnvioBOLETA.SetDTE setDTE;
    @XmlElement(name = "Signature", namespace = "http://www.w3.org/2000/09/xmldsig#", required = true)
    protected SignatureType signature;
    @XmlAttribute(name = "version", required = true)
    protected BigDecimal version;

    /* Getters and Setters */

    /* SetDTE*/
    public static class SetDTE {

        @XmlElement(name = "Caratula", required = true)
        protected EnvioBOLETA.SetDTE.Caratula caratula;

        @XmlElement(name = "DTE", required = true)
        protected List<BOLETADefType> dte;

        @XmlAttribute(name = "ID", required = true)
        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
        @XmlID
        @XmlSchemaType(name = "ID")
        protected String id;

        /* Getters and Setters and other static classes*/
    }
}

/* DTE */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BOLETADefType", propOrder = {
    "documento",
    "signature"
})
public class BOLETADefType {

    @XmlElement(name = "Documento", required = true)
    protected BOLETADefType.Documento documento;
    @XmlElement(name = "Signature", namespace = "http://www.w3.org/2000/09/xmldsig#", required = true)
    protected SignatureType signature;
    @XmlAttribute(name = "version", required = true)
    protected BigDecimal version;

    /* Getters and Setters */
}

我正在开发一个Java程序,该程序将获取仅包含<DTE>元素以及其中所有元素的XML文件,因为不需要其余标签。另外,<DTE>元素没有其签名,因为我的程序必须使用<DTE>元素中的内容以及PFX文件和PEM文件的内容来创建它(两者均与该问题无关)

我尝试了以下步骤来实现上述要求:

  1. 将注释@XmlRootElement(name = "DTE")添加到类BOLETADefType中。结果:当尝试使用以下代码解组输入XML时:
JAXBContext context = JAXBContext.newInstance(BOLETADefType.class);
Unmarshaller unMarshaller = context.createUnmarshaller();
InputStream xmlStream = new FileInputStream(args[0]);
Reader xmlReader = new InputStreamReader(xmlStream, "ISO-8859-1");
BOLETADefType dte = (BOLETADefType)unMarshaller.unmarshal(xmlReader);

它引发以下异常:

javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"DTE"). Expected elements are <{http://www.sii.cl/SiiDte}DTE>

  1. 与第一步相同,只是根据对{{的问题的@dcbyers的解决方案],在类@XMLRootElement的定义的BOLETADefType批注中将名称空间设置为空字符串。 3}}。那就是:
/* DTE */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "DTE", namespace="")
@XmlType(name = "BOLETADefType", propOrder = {
    "documento",
    "signature"
})
public class BOLETADefType {
   //...
}

结果:避免使用上述的javax.xml.bind.UnmarshalException,但是对象dte的属性documentosignature的值为null

  1. 与步骤1相同,但使用整个包而不是类创建Unmarshaller。此步骤基于@lexicore为javax.xml.bind.UnmarshalException: unexpected element (uri:
  2. 中的问题提供的解决方案
JAXBContext context = JAXBContext.newInstance(BOLETADefType.class.getPackage().getName());

结果:它给出以下异常:

javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"DTE"). Expected elements are <{http://www.sii.cl/SiiDte}DTE>,<{http://www.w3.org/2000/09/xmldsig#}Signature>
  1. 与第2步相同,但在@XmlType批注而不是@XmlRootElement批注中设置名称空间:
/* DTE */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "DTE")
@XmlType(name = "BOLETADefType", namespace="", propOrder = {
    "documento",
    "signature"
})
public class BOLETADefType {
   //...
}

结果:与步骤1相同。

  1. 不要使用@XmlRootElement批注,而应按照另一个站点中的说明定义BOLETADefType对象:
JAXBElement<BOLETADefType> jaxbElement = (JAXBElement<BOLETADefType>) unMarshaller.unmarshal(new StreamSource(xmlReader), BOLETADefType.class);
BOLETADefType dte = jaxbElement.getValue();

结果:与步骤2相同。

问题:

  1. 是否有一种方法可以解组XML输入文件,以使Documento对象没有使用JAXB的null值?
  2. 如果没有,是否有一种方法可以在不使用JDOM库的情况下将XML加载到对象中,因为使用它会成为我最糟糕的情况?

谢谢。

0 个答案:

没有答案