问题描述
如标题所述,我想忽略文档中元素名称的大小写.
As stated in the title I want to ignore casing of element names in a document.
static class XY433 { @XmlAttribute(name = "C200") String c200; @XmlAttribute(name = "C215") String c215; @XmlAttribute(name="F001") String f001; @XmlAttribute(name="f001") String lcf001; // I want to avoid this duplication }
我尝试使用 Blaise Doughan 发布的代码:
I tried to use the code posted by Blaise Doughan:
private static class ToLowerCaseNamesStreamReaderDelegate extends StreamReaderDelegate { public ToLowerCaseNamesStreamReaderDelegate(XMLStreamReader xsr) { super(xsr); } @Override public String getAttributeLocalName(int index) { return super.getAttributeLocalName(index).toLowerCase(); } @Override public String getLocalName() { return super.getLocalName().toLowerCase(); } } @XmlRootElement(name="doc") static class Doc { @XmlElement(name="element") List<Element> elements; } static class Element { @XmlAttribute(name = "abc") String abc; } public static void main(String[] args) throws Exception { XMLInputFactory xif = XMLInputFactory.newInstance(); XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("LowerCaseElementNamesFilterTest.xml")); Unmarshaller u = JAXBContext.newInstance(Doc.class).createUnmarshaller(); //Do unmarshalling Doc doc = (Doc) u.unmarshal(new ToLowerCaseNamesStreamReaderDelegate(xsr)); System.out.println(doc.elements.get(0).abc); System.out.println(doc.elements.get(1).abc); System.out.println(doc.elements.get(2).abc); }
这实际上不起作用.
null 2 Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 2, Size: 2 at java.util.ArrayList.RangeCheck(ArrayList.java:546) at java.util.ArrayList.get(ArrayList.java:321) at com.hre.commons.tec.xml.LowerCaseElementNamesFilter.main(LowerCaseElementNamesFilter.java:58)
对于这个 XML:
<doc> <Element ABC="1"></Element> <element Abc="1"></element> <element abc="2"></element> </doc>
推荐答案
您可以将所有属性映射到小写节点名称,然后包装一个 XMLStreamReader 以在它返回的所有属性/元素名称上调用 toLowerCase().然后从那个 XMLStreamReader 解组.
You could map all your properties to lower case node names, and then wrap an XMLStreamReader to call toLowerCase() on all attribute/element names it returned. Then unmarshal from that XMLStreamReader.
我最近为此问题添加了 EclipseLink JAXB (MOXy) 的增强请求,请随时提供更多信息:
I have recently added an enhance request for EclipseLink JAXB (MOXy) for this issue, feel free to provide additional information:
- https://bugs.eclipse.org/bugs/show_bug.cgi?id=331241
对象模型
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Customer { private int id; private String name; private Address address; @XmlAttribute public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } } public class Address { private String street; public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } }
演示代码
import java.io.FileInputStream; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.util.StreamReaderDelegate; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); XMLInputFactory xif = XMLInputFactory.newInstance(); XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("input.xml")); xsr = new MyStreamReaderDelegate(xsr); Unmarshaller unmarshaller = jc.createUnmarshaller(); Customer customer = (Customer) unmarshaller.unmarshal(xsr); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(customer, System.out); } private static class MyStreamReaderDelegate extends StreamReaderDelegate { public MyStreamReaderDelegate(XMLStreamReader xsr) { super(xsr); } @Override public String getAttributeLocalName(int index) { return super.getAttributeLocalName(index).toLowerCase(); } @Override public String getLocalName() { return super.getLocalName().toLowerCase(); } } }
将阅读这些 XML 文档:
Will read these XML documents:
<CUSTOMER ID="1"> <NAME>Jane Doe</NAME> <ADDRESS> <STREET>123 A Street</STREET> </ADDRESS> </CUSTOMER> <CuSToMeR Id="1"> <NaMe>Jane Doe</NAME> <AdDrEsS> <STREET>123 A Street</STREET> </AdDRrEsS> </CuSToMeR>
并编写以下 XML:
<customer id="1"> <address> <street>123 A Street</street> </address> <name>Jane Doe</name> </customer>
以下是更详细示例的链接:
Below is a link to a more detailed example:
- http://bdoughan.blogspot.com/2010/12/不区分大小写的unmarshalling.html
更新
您的代码在我的环境中工作(JDK 1.6.0_20 与包含的 JAXB 和 EclipseLink JAXB (MOXy) 2.2,我也使用 StAX 的默认实现).当我运行您的示例时:
Your code works in my environment (JDK 1.6.0_20 with both the included JAXB, and EclipseLink JAXB (MOXy) 2.2, I'm also using the default implementation of StAX). When I run your example:
import java.io.FileInputStream; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.util.StreamReaderDelegate; public class Example { private static class ToLowerCaseNamesStreamReaderDelegate extends StreamReaderDelegate { public ToLowerCaseNamesStreamReaderDelegate(XMLStreamReader xsr) { super(xsr); } @Override public String getAttributeLocalName(int index) { return super.getAttributeLocalName(index).toLowerCase(); } @Override public String getLocalName() { return super.getLocalName().toLowerCase(); } } @XmlRootElement(name="doc") static class Doc { @XmlElement(name="element") List<Element> elements; } static class Element { @XmlAttribute(name = "abc") String abc; } public static void main(String[] args) throws Exception { XMLInputFactory xif = XMLInputFactory.newInstance(); XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("LowerCaseElementNamesFilterTest.xml")); Unmarshaller u = JAXBContext.newInstance(Doc.class).createUnmarshaller(); //Do unmarshalling Doc doc = (Doc) u.unmarshal(new ToLowerCaseNamesStreamReaderDelegate(xsr)); System.out.println(doc.elements.get(0).abc); System.out.println(doc.elements.get(1).abc); System.out.println(doc.elements.get(2).abc); } }
我得到以下输出:
1 1 2
更新 #2
到地址:
线程main"中的异常javax.xml.bind.UnmarshalException -有链接的例外:[javax.xml.bind.UnmarshalException:命名空间 URI 和本地名称unmarshaller 需要被实习.] 在com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:425)在com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:362)在com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:332)
Exception in thread "main" javax.xml.bind.UnmarshalException - with linked exception: [javax.xml.bind.UnmarshalException: Namespace URIs and local names to the unmarshaller needs to be interned.] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:425) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:362) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:332)
您是否尝试过修改委托?:
Have you tried modifying the delegate?:
@Override public String getAttributeLocalName(int index) { return super.getAttributeLocalName(index).toLowerCase().intern(); } @Override public String getLocalName() { return super.getLocalName().toLowerCase().intern(); }