我有一个xsd说request.xsd
和相应的jaxb生成的类。现在我得到了一个xml文件request.xml
,我可以解组并创建“请求”对象。
我在xml中有很多元素标签,其中一些可以多次使用。我需要创建一个java.util.List,它应该包含所有叶节点值。
例如:
下面是我的request.xml:
<Request>
<Operation>manual</Operation>
<Work>
<WorkModule>
<Name>AXN</Name>
</WorkModule>
</Work>
<Identifier>
<WorkStatus>
<WorkName>CCH</WorkName>
</WorkStatus>
<WorkStatus>
<WorkName>TMH</WorkName>
</WorkStatus>
</Identifier>
</Request>
下面是我的JAXB生成的Request类。 Simillarly还有其他类对应于每个xml元素:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"Operation",
"Work",
"Identifier"
})
@XmlRootElement(name = "Request", namespace = "http://www.sprts.com/clm/nso/mahsgd")
public class Request{
@XmlElement(name = "Operation", required = true)
protected Operation operation;
@XmlElement(name = "Work", required = true)
protected Work work;
@XmlElement(name = "Identifier", required = true)
protected Identifier identifier;
\\ getters and setters
}
因此,使用JAXB,我可以获得具有xml文件中所有值的unmarshalled Request对象。
现在,如何在不使用请求对象的getter的情况下以通用方式获取所有叶节点值(operation,name,workName),然后我可以将其放入某个集合中,例如List。我听说DOM被用来做类似的东西,但我需要使用JAXB。
(不使用来自请求对象的getter
String opertaion = request.getOperation();
或String name = request.getWork().getWorkModule().getName();
)
- 编辑 -
有人可以帮助我找到最佳解决方案。如果问题陈述不清楚,请告诉我。
- EDIT-- 与Doughan&amp;亚历山德罗斯的帮助和一些人能够达到同样的目的。不确定是否解决(将JAXB对象转换为DOM对象到InputSource)是最佳解决方案。以下是工作代码。
JAXBContext jc = JAXBContext.newInstance(JAXBObject.class);
// Create the Document
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
// Marshal the Object to a Document
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(jaxbObject, document);
XPathFactory xpf = XPathFactory.newInstance();
XPath xp = xpf.newXPath();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(document);
Result outputTarget = new StreamResult(outputStream);
TransformerFactory.newInstance().newTransformer().transform(xmlSource,outputTarget);
InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
InputSource source = new InputSource(is);
NodeList leafNodeObjects = (NodeList) xp.evaluate("//*[not(*)]", source, XPathConstants.NODESET);
for(int x=0; x<leafNodeObjects.getLength(); x++) {
System.out.print("nodeElement = ");
System.out.print(leafNodeObjects.item(x).getNodeName());
System.out.print(" and node value = ");
System.out.println(leafNodeObjects.item(x).getTextContent());
inputDtos.add(new InputDto(leafNodeObjects.item(x).getNodeName(),
leafNodeObjects.item(x).getTextContent()));
}
答案 0 :(得分:2)
来自您的赏金评论:
我想创建一个NodeObject列表,其中NodeObject具有nodeElement 和nodeValue属性。 〔实施例。如果我有一个像这样的元素 然后我将为此元素提供一个NodeObject with nodeElement = name和nodeValue = property。
您可以使用以下XPath从任何XML文档中获取叶节点(请参阅:How to select all leaf nodes using XPath expression?):
//*[not(*)]
此处使用javax.xml.xpath
API:
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
public class Demo {
public static void main(String[] args) throws Exception {
XPathFactory xpf = XPathFactory.newInstance();
XPath xp = xpf.newXPath();
InputSource xml = new InputSource("input.xml");
NodeList leafNodeObjects = (NodeList) xp.evaluate("//*[not(*)]", xml, XPathConstants.NODESET);
for(int x=0; x<leafNodeObjects.getLength(); x++) {
System.out.print("nodeElement = ");
System.out.print(leafNodeObjects.item(x).getNodeName());
System.out.print(" and node value = ");
System.out.println(leafNodeObjects.item(x).getTextContent());
}
}
}
以下是运行此演示代码的输出:
nodeElement = Operation and node value = manual
nodeElement = Name and node value = AXN
nodeElement = WorkName and node value = CCH
nodeElement = WorkName and node value = TMH
答案 1 :(得分:1)
我的问题是:您是否可以更改XSD以满足您的需求,或者XSD是否由其他人控制,您必须按原样使用它?
这很重要,因为JAXB的工作方式。基本上,JAXB将XSD转换为Java类。它也可以反过来(将Java类转换为XSD)。这里将详细介绍这种关系:http://docs.oracle.com/cd/E21764_01/web.1111/e13758/data_types.htm
在你的情况下,我假设有人写了一个你用来生成Java类的XSD,但是这些类有很多:“Something getSomething1(),Something getSomething2(),... Something getSomethingN()方法当你想要一个List getListOfSomethings()方法时。
有两种方法可以解决这个问题:
(1)更改XSD,以便“somethings”是复杂类型的一部分,这是一个序列(或任何会导致JAXB为列表生成getter的东西,根据我的原始答案)。
这并不总是可行的。如果XSD由某个外部实体控制,该实体表示“这就是我的数据,你必须忍受它,否则你的应用程序将无法读取我的数据”,那么你就无法做到这一点。为了给您一个具体的例子,假设您的应用程序想要从美国国会图书馆读取EAD数据。它的XSD在这里:http://www.loc.gov/ead/eadschema.html。这个XSD就是这样。你无法改变它。如果您更改它,您的应用程序将使用您对不同数据的定义。您必须考虑下面的方法(2),因为您无法控制XSD。
(2)不要使用JAXB。而是使用允许您查询元素的XML API。通过这种方式,您可以使用(例如)XPath查询收集所有“Somethings”(请参阅http://docs.oracle.com/javase/tutorial/jaxp/xslt/xpath.html)。
您可以创建一个加载XML的包装类,并使用List getSomethings()方法。这将是以下几点:
public class RequestWrapper {
Document doc;
public RequestWrapper(String xmlUri) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
this.doc = builder.parse(xmlUri);
}
public List<Something> getSomethings() {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile(<DEFINE A SUITABLE EXPRESSION>);
NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
List<Something> somethings = new LinkedList<Something>();
// loop over the nodelist creating instances of Something
return somethings;
}
}
这是一个很好的教程,可以使用带有Stax的XPath,它可以派上用场:http://www.vogella.com/articles/JavaXML/article.html
(3)如果您愿意放弃标准Java API,可以考虑使用一个库来控制对Java的绑定,例如Castor:http://castor.codehaus.org/xml-framework.html
最终,您的问题是数据以不方便的方式呈现,在这种情况下您必须执行(2)或(3),或者您已经定义了不方便的XSD,在这种情况下您必须执行(1)
答案 2 :(得分:0)
您是在定义XML的结构,还是有人为您提供了必须使用的固定XSD?
如果您实际定义了请求XML的结构,则可以使用注释(如@XmlElement和@XmlElementWrapper)使JAXB与集合一起使用。有关详情,请参阅此处:http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html