Java中的XML库是一个雷区。 操作和读取XML所需的代码量令人震惊,使用不同的库遇到类路径问题的风险很大,并且对名称空间的处理带来许多混乱和错误。 最糟糕的是,情况似乎并没有改善。
一位同事让我意识到JOOX库。 这是解决这些问题的一个很好的尝试。 我发现JOOX有一些缺点,这使我想探索替代方法,自然地我最终编写了自己的库 (就像您一样)。 我希望该库允许对XML的轻松操作,并且在判断不足的情况下,我将库命名为EAXY。 这是一个非常糟糕的名字,因此我很乐意提出改进建议。
这是我要解决的问题:
- 用Java代码创建相当复杂的XML树应该很容易
- 使用名称空间应该简单明了。 (这是JOOX让我失败的地方)
- 从XML结构中读取值应该很容易。
- 使用文件结构或类路径中的现有XML文档应该很容易
- 库应该更喜欢引发异常而不是静默失败。
- 另外,我想通过添加便利功能来使其更易于处理(X)HTML。
1.创建一个XML文档
XML文档只是一棵树。 如何将树与Java语法树对齐。 例如,假设您想以编程方式想对本文进行一些反馈:
Element email = Xml.el("message",Xml.el("recipients",Xml.el("recipent",Xml.attr("type", "email"),Xml.attr("role", "To"),Xml.text("mailto:johannes@brodwall.com")),Xml.el("recipent", Xml.attr("type", "email"),Xml.attr("role", "Cc"),Xml.text("mailto:contact@brodwall.com"))),Xml.el("subject", "EAXY feedback"),Xml.el("contents", "I think this is an interesting library"));
每个元素(Xml.el)都有一个标记名称,并且可以嵌套其他元素,属性(Xml.attr)或文本(Xml.text)。 如果元素仅包含文本,则甚至不需要调用Xml.text。 语法经过了优化,因此,如果要在Xml。*上进行静态导入,可以编写如下代码:
Element email = el("message",el("recipients",el("recipent",attr("type", "email"),attr("role", "to"),text("mailto:johannes@brodwall.com")),el("recipent",attr("type", "email"),attr("role", "cc"),text("mailto:contact@brodwall.com"))),el("subject", "EAXY feedback"),el("content", "I think this is an interesting library"));
2.读取XML
用Java代码读取XML可能是一个挑战。 DOM API使得任何事情都变得极其繁琐。 您使用的是XPath,但在紧凑方面可能有点过多,并且当您做错了什么时,结果只是简单地得到了一个空集合或一个空值。 我认为我们可以对此进行改进。
考虑以下:
System.out.println(email.find("recipients", "recipient").texts());
我下调XML树结构并获取上一条消息的所有收件人电子邮件地址。 但是,等等-运行此代码将返回一个空列表。 EAXY允许我们避免为此挠头:
System.out.println(email.find("recipients", "recipient").check().texts());
现在,我得到以下异常:
org.eaxy.NonMatchingPathException: Can't find {recipient} below [message, recipients].Actual elements: [Element{recipent}, Element{recipent}]
如您所见,我们在邮件中拼写了“收件人”。 让我们稍后再讨论这个问题,但是现在,让我们解决它以创建一些有意义的东西:
for (Element recipient : email.find("recipients", "recipent")) {if ("to".equals(recipient.attr("role"))) {System.out.println(recipient.text());}
}
同样,我认为这与Java语法所允许的一样流畅。
3.验证和名称空间
因此,我们收到一条消息,其中元素名称之一拼写错误。 如果您拥有要使用的XML的XSD文档,则可以对此进行验证。 但是,您可能已经习惯了Java XML库,执行此验证的动作完全隐藏在复杂的API之后。 因此,我提供了一些帮助:
Xml.validatorFromResource("mailmessage.xsd").validate(email);
这将从类路径中读取mailmessage.xsd,这对我来说是最常见的用例。
当然,大多数架构都不会引用空名称空间中的元素。 使用验证时,通常必须在特定的名称空间中构造元素。 在大多数用于处理XML的Java库中,很难且容易出错,尤其是在混合名称空间时。 我已经将名称空间作为Eaxy库的主要功能:
Namespace MSG_NS = new Namespace("http://eaxy.org/test/mailmessage", "msg");
Element email = MSG_NS.el("message",MSG_NS.el("recipients",MSG_NS.el("recipient",MSG_NS.attr("type", "email"),attr("role", "cc"),text("mailto:contact@brodwall.com"))));
请注意,“类型”和“角色”属性属于不同的名称空间-这种情况在其他库中尤其难以实现。
4.模板化
从类路径中读取XSD启发了另一种用法:如果我们在类路径中有一个XML文档作为模板,然后使用Java代码操作该文档,该怎么办。 这对于XHTML尤其方便:
Document doc = Xml.readResource("testdocument.html");
Element peopleElement = doc.select("#peopleForm");peopleElement.add(el("input",attr("type", "text"),attr("name", "firstName"),attr("value", "Johannes")));
peopleElement.add(el("input", attr("type", "text"), attr("name", "lastName"),attr("value", "Brodwall")));
此代码从类路径中读取文件testdocument.html,选择ID为“ peopleForm”的元素,并向其中添加两个输入元素。
5. HTML的便利性
在上面的代码中,我们设置了HTML输入元素的类型,名称和值属性。 这些是HTML操作中最常用的属性之一。 为了使此操作更容易,我向Eaxy添加了一些便捷方法:
peopleElement.add(el("input").type("text").name("firstName").val("Johannes"));
peopleElement.add(el("input").type("text").name("lastName").val("Brodwall"));
我要优化的最后一种情况是处理HTML中的表单。 这是一些可以在将表单发送给用户之前对其进行处理的代码。
HtmlForm form = new HtmlForm(peopleElement);
form.set("firstName", "Johannes");
form.set("lastName", "Brodwall");doc.writeTo(req.getWriter());
在这里,我直接设置表单内容。 如果参数名称拼写错误,代码将引发异常,因此很容易确保您正确使用它。
结论
我有五个示例,说明如何使用Eaxy轻松完成大多数Java XML库所难以实现的工作:使用纯Java代码创建文档树,读取和操作XML树的各个部分,使用命名空间和验证,模板化和处理(X)HTML文档和表单。
该库现在不稳定,但是对于XML库来说,不稳定可能不是很危险的情况,因为大多数错误在生产前很容易就可以检测到。
我希望您可能会发现尝试在代码中使用此库来处理XML和(X)HTML操作很有用。 我希望一些用户可以帮助我消除错误,并使Eaxy更加易于使用。
哦,如果您想出一个更好的名字,请告诉我。
翻译自: https://www.javacodegeeks.com/2013/11/announcing-eaxy-making-xml-easier-in-java.html