Java 使用JAXB解析Xml叶节点元素值

Java 使用JAXB解析Xml叶节点元素值,java,xml-parsing,jaxb,unmarshalling,xmlnode,Java,Xml Parsing,Jaxb,Unmarshalling,Xmlnode,我有一个xsd sayrequest.xsd和相应的jaxb生成的类。现在我得到了一个xml文件request.xml,我可以将其解组并创建“request”对象 我有许多xml元素标记,其中一些可以多次使用。我需要创建一个java.util.List,它应该包含所有叶节点值 例如: 下面是我的request.xml: <Request> <Operation>manual</Operation> <Work> <WorkM

我有一个xsd say
request.xsd
和相应的jaxb生成的类。现在我得到了一个xml文件
request.xml
,我可以将其解组并创建“request”对象

我有许多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,我可以获得xml文件中所有值的非编组请求对象

现在,我如何以一种通用的方式获取所有叶节点值(操作、名称、工作名称),而不使用来自请求对象的getter,然后我可以将每个getter放入某个集合(比如列表)中。我听说DOM被用来做类似的事情,但我需要使用JAXB来做同样的事情

(不使用来自请求对象的getter,如
String operation=request.getOperation();
String name=request.getWork().getWorkModule().getName();

--编辑--

有人能帮我找到一个最佳的解决方案吗。如果问题陈述不清楚,请告诉我

--编辑-- 在Doughan&Alexandros的帮助下,周围的一些人也可以实现同样的目标。不确定变通方法(将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()));
   }
JAXBContext jc=JAXBContext.newInstance(JAXBObject.class);
//创建文档
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
Document Document=db.newDocument();
//将对象封送到文档
Marshaller=jc.createMarshaller();
marshaller.marshall(jaxbObject,文档);
XPathFactory xpf=XPathFactory.newInstance();
XPath xp=xpf.newXPath();
ByteArrayOutputStream outputStream=新建ByteArrayOutputStream();
Source xmlSource=新的DOMSource(文档);
结果输出目标=新的流结果(outputStream);
TransformerFactory.newInstance().newTransformer().transform(xmlSource,outputTarget);
InputStream is=newbytearrayinputstream(outputStream.toByteArray());
InputSource source=新的InputSource(is);
NodeList leavenodeobjects=(NodeList)xp.evaluate(“//*[非(*)]”,源代码,XPathConstants.NODESET);

对于(intx=0;x您是在定义XML的结构,还是有人向您提供了必须使用的固定XSD


如果您实际上是在定义请求XML的结构,那么可以使用@XmlElement和@XmlElementWrapper之类的注释让JAXB处理集合。有关更多信息,请参见此:

我的问题是:您是否能够更改XSD以满足您的需要,或者XSD是否由其他人控制,并且您必须按原样使用它

这一点很重要,因为JAXB的工作方式。基本上,JAXB将XSD转换为Java类。它也可以执行相反的操作(将Java类转换为XSD)。这里详细描述了这种关系:

在您的例子中,我假设有人编写了一个XSD,您使用它来生成Java类,但是这些类有很多:“something1(),something2(),…somethingn()方法,而您更喜欢使用List getListOfSomethings()方法

有两种方法可以解决此问题:

(1) 更改XSD,使“somethings”成为复杂类型的一部分,该复杂类型是一个序列(或者根据我最初的回答,任何可能导致JAXB为列表生成getter的内容)

这并不总是可能的。如果XSD由某个外部实体控制,该实体表示“这就是我的数据的样子,您必须接受它,否则您的应用程序将无法读取我的数据“你不能这么做。给你一个具体的例子,假设你的应用程序想从美国国会图书馆读取EAD数据。这里的XSD是:这个XSD就是它。你不能改变它。如果你改变它,你的应用程序将与你对数据的定义不同。你必须考虑方法(2)。因为您对XSD没有控制权

(2) 不要使用JAXB。而是使用允许查询元素的XML API。这样,您可以通过(例如)XPath查询收集所有“某物”(请参阅)

您可以创建一个包装器类,该类加载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;
    }
}
公共类RequestWrapper{
文件文件;
公共请求包装器(字符串xmlUri){
DocumentBuilderFactory工厂=DocumentBuilderFactory.newInstance();
DocumentBuilder=factory.newDocumentBuilder();
this.doc=builder.parse(xmlUri);
}
公共列表getSomethings(){
XPathFactory XPathFactory=XPathFactory.newInstance();
XPath=xPathfactory.newXPath();
XPathExpression expr=xpath.compile();
NodeList nl=(NodeList)expr.evaluate(doc,XPathConstants.NODESET);
列出一些东西=新建LinkedList();
//在节点列表上循环创建某个对象的实例
回报一些东西;
}
}
下面是一个将XPath与Stax结合使用的很好的教程,它可能会派上用场:

(3)如果您愿意放弃java java标准API,您可以考虑一个库,它可以让您更有效地控制绑定到Java,比如Casor:


最终,您的问题是,要么数据以不方便的方式呈现,在这种情况下,您必须执行(2)或(3),要么您定义了不方便的XSD,在这种情况下,您必须执行(1)。

来自您的赏金评论:

我想创建一个NodeObject列表,其中NodeObject包含nodeElement 如果我有一个元素,比如 Anil那么这个元素将有一个NodeObject 使用nodeElement=name和nodeValue=property

您可以使用以下XPath从
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;
    }
}
//*[not(*)]
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