JAXB接受重复标签

问题描述 投票:0回答:2

在我们的应用程序中,用户正在发送一个XML,如下图所示。

<Decl>
  <MessageHeader>
     <A>Info</A>
     <B>Info2</B>
  </MessageHeader>
</Decl>

我们使用JABX unmarshller来填充java对象,但问题是当用户发送消息时,客户要求产生错误,如下图所示。

<Decl>
  <MessageHeader>
     <A>Info</A>
     <B>Info2</B>
  </MessageHeader>
<MessageHeader>
     <A>Info3</A>
     <B>Info4</B>
  </MessageHeader>
</Decl>

JAXB成功地解开了xml的marshling,并用第二个MessageHeader对象填充了对象。请注意MessageHeader不是List类型。由于某些原因,我们不能在解析前使用xml的schema验证,但是有什么办法可以让JAXB停止这样的行为,并且抛出ParingException。但有什么办法可以让JAXB解析器检查目标类型是否为list,并抛出错误。

先谢谢你了。

java xml xsd jaxb unmarshalling
2个回答
0
投票

JAXB是一种为XML Schema模型生成Java类的技术,因此,JAXB执行的任何验证都将使用XML Schema验证。因此,JAXB执行的任何验证都会使用XML Schema验证。

有什么办法可以阻止JAXB这样的行为,它应该抛出ParsingException。

不,除非您在JAXB unmarshaller中启用模式验证。

由于某些原因,我们不能在解析前使用xml的模式验证。

你应该提供原因,或者不提。这是一个非常奇怪的规则,因为JAXB是一种XML Schema技术,而Java对XSD验证有本地支持。

请注意MessageHeader不是List类型。

列表类型是用于 简单的 类型。MessageHeader是基于一个复杂的类型。

我建议你忽略 "没有schema validation "的规则。在MessageHeader上设置maxOccurs=1,并在JAXB unmarshaller上启用schema validation。


0
投票

正如已经指出的,方法是使用模式验证。生成一个模式并在MessageHeader上设置maxOccurs="1"。你可以用模式设置。

unmarshaller.setSchema(schema);

如果因为一些奇怪的原因你绝对不能使用模式验证 你可以做一个丑陋的黑客,当一个重复的MessageHeader被处理的时候,你可以用 Unmarshaller.Listener

unmarshaller.setListener(new Unmarshaller.Listener() {

    boolean messageHeaderAlreadyPresent = false;

    @Override
    public void beforeUnmarshal(Object target, Object parent) {
        // When <Decl> is encountered, set to false
        if (target instanceof Decl) {
            messageHeaderAlreadyPresent = false;
        } else if (target instanceof MessageHeader) {
            if (messageHeaderAlreadyPresent) {
                throw new RuntimeException("duplicate MessageHeader");
            }
            messageHeaderAlreadyPresent = true;
        }
    }
});

虽然这应该是可行的,但我坚持认为你应该重新考虑模式验证。

另外,请注意,unmarshaller会默默地忽略一些事件,例如当遇到没有映射的en元素时。这不是你的情况,因为在你的用例中不存在映射问题,但是,举例来说,如果你收到消息。

<Decl>
  <MessageHeader>
     <A>Info1</A>
     <C>Info3</C>
  </MessageHeader>
</Decl>

与元素 <C> 而不是 <B>,您将以A=Info1和B=null的值结束,因为JAXB会默默地忽略元素 <C>.

你可以捕获这些事件并抛出一个异常,设置一个 ValidationEventHandler 返回 false

unmarshaller.setEventHandler(new ValidationEventHandler() {
    @Override
    public boolean handleEvent(ValidationEvent event) {
        // log event ....
        return false;
    }
});
© www.soinside.com 2019 - 2024. All rights reserved.