具有XPATH的JAXB灵活地在运行时修改对象

时间:2016-02-06 19:44:24

标签: java xml xpath jaxb

我想修改加载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生成的类将具有“L ist<Customer> customer”,我将不得不遍历客户列表以匹配我想要的Customer[@id=2]

任何人都可以告诉我如何使用XPATH获取JAXB生成的对象的Object实例句柄,因此我可以将其编组以更新磁盘上的实际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

输出: Customerid 1141,电话0

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

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

由于 Venkat

1 个答案:

答案 0 :(得分:0)

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

请参阅Context源代码(提交7cedaac6cdf9384ae9a06129d6f9abd607f9e3c4,第371行)以了解具体情况。