3

我正在用 Java 为一个简单的 xml 结构编写一个 XML 解析器,该结构的结构以

<Document xmlns="some value" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

除了这一行之外,我能够很好地阅读整个 XML 结构。我能够使用没有 xmlns 属性的 JAXB 解析和读入相应的 JAVA POJO。但是,如果我添加解析器会引发异常。

我试过的,

@XmlRootElement(name = "Document")
static class UserMetaData {
    @XmlAttribute(name = "xmlns:xsi", required = true)
    String xmlnsXsi;
    @XmlAttribute(name = "xmlns", required = true)
    String xmlns;
    @XmlElement(name = "User", required = true, nillable = false)
    User userRecord;
}
4

1 回答 1

2

编辑

成功使用以下代码:

@Test
public void unmarshal() throws JAXBException {
    JAXBContext context = JAXBContext.newInstance(UserData.class);
    Unmarshaller unmarshaler = context.createUnmarshaller();
    StringReader reader = new StringReader("<Document xmlns=\"urn:iso:std:iso:20022:tech:xsd:pain.002.001.03\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><User/></Document>");
    UserData result = (UserData) unmarshaler.unmarshal(reader);
    System.out.println(result.userRecord);
}

还有豆子:

@XmlRootElement(name = "Document", namespace="urn:iso:std:iso:20022:tech:xsd:pain.002.001.03")
public class UserData {
    @XmlElement(name = "User", required = true, nillable = false)
    public  User userRecord;
}

假设你有:

<Document xmlns="http://test.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

删除这些:

@XmlAttribute(name = "xmlns:xsi", required = true)
String xmlnsXsi;
@XmlAttribute(name = "xmlns", required = true)
String xmlns;

您不需要将命名空间映射为属性。

您需要使用命名空间定义根元素:

@XmlRootElement(name = "Document", namespace= "http://test.com")

进一步解释一下。想象一下,在 XML 中,您有 2 种不同类型的用户。一个用户是具有名称、登录名和密码的 DB 用户,另一个用户具有名称和证书。

您可以创建如下内容:

<user name="">
    <login></login>
    <password></password>
    <cert></cert>
</user>

但这样的结构不符合要求。用户定义不同。因此,您可能想要创建 2 个定义:

<user name="">
    <login></login>
    <password></password>
</user>

<user name="">
    <cert></cert>
</user>

但是如何区分同一个 XML 中的这两个定义呢?这就是命名空间的目的。它们允许在同一个 XML 文档中使用名称相同但内容不同的标签:

<Document>
    <user name="" xmlns="http://user1.com">
        <login></login>
        <password></password>
    </user>

    <user name="" xmlns="http://user2.com">
        <cert></cert>
    </user>
</Document>

第一个用户标签定义在http://user1.com命名空间中,第二个用户标签定义在http://user2.com命名空间中。它们不再冲突,并被视为具有不同定义的 2 个不同名称。

但是,为每个标签提及 xmlns="http://user1.com" 或 xmlns="http://user2.com" 很乏味。命名空间别名在这里很有帮助。您可以在根元素中定义任何命名空间别名,并将别名用作标签前缀。对于我们的示例,我们将定义 2 个别名 user1 和 user2 并将它们用作前缀:

<Document xmlns:user1="http://user1.com" xmlns:user2=xmlns="http://user2.com">
    <user1:user name="">
        <login></login>
        <password></password>
    </user>

    <user2:user name="">
        <cert></cert>
    </user>
</Document>

这种方式的 XML 定义更短更清晰。

但请记住,别名只是帮手。XML 解析器和验证器总是用完整的命名空间替换别名,例如http://user1.com " 或http://user2.com用于标签比较。

在您的示例中,添加 xmlns="something" 将 XML 默认命名空间的根元素的默认命名空间重新定义为“something”。

当 JAXB 尝试解组您的对象时,它在 XML 中查找空名称空间中的 Document 并且找不到它,因为 Document 是在“something”名称空间中定义的。

于 2018-06-19T18:42:36.370 回答