【问题标题】:JAXB with XPATH Flexibility to modify Objects at runtime具有 XPATH 的 JAXB 在运行时灵活地修改对象
【发布时间】:2016-02-06 19:44:23
【问题描述】:

我想修改 JAXB 加载的对象(来自 XML),以便我可以用更新的 XML 将它们编组回磁盘。

现在举个例子:

<Customers>
  <Customer id="1" name="Jack">
    <Address type="Residence">
      <FirstLine>1 saxon Court</FirstLine>
      <City>CY</City>
    </Address>
  </Customer>
    <Customer id="2" name="Iain">
    <Address type="Residence">
      <FirstLine>104 Bank Road</FirstLine>
      <City>NY</City>
    </Address>
  </Customer>
</Customers>

现在我有多个客户,我想使用 XPATH 功能来获取 Customer[@id=2] 对象的句柄,我可以在其中添加/更新地址。 如果我不使用类似 XPATH 的功能,那么 JAXB 生成的类将具有“List&lt;Customer&gt; customer”,我将不得不遍历客户列表以匹配我想要的 Customer[@id=2]

谁能告诉我如何使用 XPATH 获取 JAXB 生成的对象的对象实例句柄,以便我可以将其编组回来以更新磁盘上的实际 XML。 如果不能通过 JAXB 完成,那么使用具有 XPATH 灵活性的 java 对象读写 XML 的替代解决方案是什么。

使用示例代码更新问题:

以下是示例代码,它显示了我想用 Moxy/JAXB 实现的目标。

package org.soc.test.customers.moxy;

import java.io.File;
import java.util.List;
import javax.xml.bind.*;

public class UnmarshalDemo {
    public static void main(String[] args) throws Exception {
        org.eclipse.persistence.jaxb.JAXBContext jc =    (org.eclipse.persistence.jaxb.JAXBContext)     JAXBContext.newInstance(Customer.class);
        File instanceDoc = new File("input.xml");
        Customer customer = (Customer) jc.createUnmarshaller() .unmarshal(instanceDoc);
        List<PhoneNumber>  phones = jc.getValueByXPath(customer, "phone-number[@id=\"12\"]", null, List.class);
        String customerId = jc.getValueByXPath(customer, "@id", null, String.class);
        System.out.println("Customerid " + customerId + "  ,  phone " + (phones==null?"0":phones.size()));
        jc.setValueByXPath(customer, "phone-number[@id=\"12\"]/area-code/text()", null, "555");
    jc.createMarshaller().marshal(customer, System.out);
    }
}

输入 XML:

<?xml version="1.0" encoding="UTF-8"?>
<customer id="1141">
    <first-name>Jon</first-name>
    <last-name>Smith</last-name>
    <phone-number id="11">
        <area-code>515</area-code>
        <number>2726652</number>
    </phone-number>
    <phone-number id="12">
        <area-code>515</area-code>
        <number>2726652</number>
    </phone-number>
</customer>

XSD:

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
     elementFormDefault="unqualified"
     attributeFormDefault="unqualified">
    <xs:element name="customer">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="first-name" type="stringMaxSize5"/>
                <xs:element name="last-name" type="stringMaxSize5"/>
                <xs:element ref="phone-number" maxOccurs="2"/>
            </xs:sequence>
            <xs:attribute name="id" type="xs:string"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="phone-number">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="area-code" type="stringMaxSize5"/>
                <xs:element name="number" type="xs:string"/>
            </xs:sequence>
            <xs:attribute name="id" type="xs:string"/>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="stringMaxSize5">
        <xs:restriction base="xs:string">
            <xs:maxLength value="5"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

jaxb.properties:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

输出: 客户 ID 1141,电话 0

我希望电话号码的列表大小为 1,但它返回 null。

希望这有助于理解我面临的问题。

谢谢 文卡特

【问题讨论】:

  • 感谢您向我推荐链接。我已经尝试过使用 Moxy,但尝试不成功。
  • 我已经修改了这个问题,以便更好地理解我所面临的问题。提前致谢。

标签: java xml xpath jaxb


【解决方案1】:

Moxy 不支持。 org.eclipse.persistence.internal.oxm.Context 仅支持方括号中的数字索引。虽然XPathFragment 理解它并创建适当的谓词,但Context 在搜索匹配时会忽略这些谓词。我要么提出一个错误,要么寻找其他工具。

查看Context 源代码(提交7cedaac6cdf9384ae9a06129d6f9abd607f9e3c4,从第371 行开始)了解正在发生的事情。

【讨论】:

  • 感谢您的确认。我们知道 JAXB 无法支持完整的 xpath 功能,请有人建议我可以用于此要求的其他替代方案/api 是什么?理想情况下,我希望在处理 XML 时同时具有对象级访问和 XPATH 灵活性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 2017-12-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多