如何使用Java获取所有XML分支。
例如,如果我有以下XML:
<?xml version="1.0" encoding="UTF-8"?>
<addresses xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation='test.xsd'>
<address>
<name>Joe Tester</name>
<street>Baker street 5</street>
</address>
<person>
<name>Joe Tester</name>
<age>44</age>
</person>
</addresses>
我想获得以下分支:
addresses
addresses_address
addresses_address_name
addresses_address_street
addresses_person
addresses_person_name
addresses_person_age
感谢。
答案 0 :(得分:0)
您可以使用任何模板引擎轻松获取XML root,其节点和子节点名称。即Velocity,FreeMarker和其他FreeMarker具有强大的XML处理新功能。您可以将XML文档放入数据模型中,模板可以通过各种方式从中提取数据,例如使用XPath表达式。 FreeMarker,作为XML转换工具,采用万维网联盟(W3C)颁布的better-known XSLT stylesheet方法。
FrerMarker支持XPath使用jaxen,XPath表达式需要Jaxen。 downlaod
FreeMarker将使用Xalan,除非您通过从Java调用freemarker.ext.dom.NodeModel.useJaxenXPathSupport()来选择Jaxen。
只需要一个模板,它将根据输入XML生成所有XML分支。确实将任何XML运行时放到数据模型中,freemarker将处理模板并生成与该XML结构相对应的XML分支。如果您的XML结构将发生变化,则无需更改Java代码。即使您想要更改输出,然后更改将出现在模板文件中,因此无需重新编译Java代码。
只需更改模板,即可获得更改。
FTL文件[用于创建xml分支名称的多个XML文档的一个模板]
<#list doc ['/*' ] as rootNode>
<#assign rootNodeValue="${rootNode?node_name}">
${rootNodeValue}
<#list doc ['/*/*' ] as childNodes>
<#if childNodes?is_node==true>
${rootNodeValue}-${childNodes?node_name}
<#list doc ['/*/${childNodes?node_name}/*' ] as subNodes>
${rootNodeValue}-${childNodes?node_name}-${subNodes?node_name}
</#list>
</#if>
</#list>
</#list>
用于流程模板的XMLTest.Java
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import freemarker.ext.dom.NodeModel;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class XMLTest {
public static void main(String[] args) throws SAXException, IOException,
ParserConfigurationException, TemplateException {
Configuration config = new Configuration();
config.setClassForTemplateLoading(XMLTest.class, "");
config.setObjectWrapper(new DefaultObjectWrapper());
config.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
Map<String, Object> dataModel = new HashMap<String, Object>();
//load xml
InputStream stream = XMLTest.class.getClassLoader().getResourceAsStream(xml_path);
// if you xml sting then then pass it from InputSource constructor, no need of load xml from dir
InputSource source = new InputSource(stream);
NodeModel xmlNodeModel = NodeModel.parse(source);
dataModel.put("doc", xmlNodeModel);
Template template = config.getTemplate("test.ftl");
StringWriter out = new StringWriter();
template.process(dataModel, out);
System.out.println(out.getBuffer().toString());
}
}
最终OutPut
addresses
addresses-address
addresses-address-name
addresses-address-street
addresses-person
addresses-person-name
addresses-person-age
的文档
的Downlaod Jaxen
答案 1 :(得分:0)
有许多方法可以从XML中提取数据并在Java中使用它。您选择的那个将取决于您想要如何使用数据。
有些情况是:
对于场景#3 ,最好的选择是一些内存高效的基于流的解析器,例如 SAX 或带有 StAX API。
如果你主要阅读(而不是写作),你也可以将它用于场景#2 ,但基于DOM的API可能更容易使用。您可以使用标准的 DOM org.w3c.dom
API或类似Java的API,例如 JDOM 或 DOM4J 。如果您希望将XML文件与Java对象同步,您还可能希望使用完整的 Java-XML映射框架,例如 JAXB 。
DOM API也适用于方案#1 ,但在许多情况下,使用 XSLT (通过javax.xml.transform
TrAX可能更简单 Java中的API)。如果使用DOM,也可以使用XPath选择节点。
我将向您展示如何使用标准DOM API(org.w3c.dom
)以及使用XPath(javax.xml.xpath
)提取文件的各个节点的示例。
<强> 1。设置强>
初始化解析器:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
将文件解析为文档对象模型:
Document source = builder.parse(new File("src/main/resources/addresses.xml"));
<强> 2。选择J2SE DOM的节点
使用getDocumentElement()
获取根元素:
Element addresses = source.getDocumentElement();
从那里你可以使用getChildNodes()
来获取子节点,但这将返回所有子节点,其中包括文本节点(元素之间的空白)。 addresses.getChildNodes().item(0)
会在<addresses>
标记之后和<address>
标记之前返回空格。要获得元素,您必须选择第二个项目。更简单的方法是使用getElementsByTagName
,它返回一个节点集并获取第一个项目:
Element addresses_address = (Element)addresses.getElementsByTagName("address").item(0);
许多DOM方法返回org.w3c.dom.Node
个对象,你必须抛出这些对象。有时它们可能不是Element
个对象,所以你必须检查。节点集不会自动转换为数组。它们是org.w3c.dom.NodeList
所以你必须使用.item(0)
而不是[0]
(如果你使用其他DOM API,如JDOM或DOM4J,它会更直观)。
您可以使用addresses.getElementsByTagName
来获取所需的所有元素,但是您必须处理两个<name>
元素的上下文。所以更好的方法是在适当的上下文中调用它:
Element addresses_address = (Element)addresses.getElementsByTagName("address").item(0);
Element addresses_address_name = (Element)addresses_address.getElementsByTagName("name").item(0);
Element addresses_address_street = (Element)addresses_address.getElementsByTagName("street").item(0);
Element addresses_person = (Element)addresses.getElementsByTagName("person").item(0);
Element addresses_person_name = (Element)addresses_person.getElementsByTagName("name").item(0);
Element addresses_person_age = (Element)addresses_person.getElementsByTagName("age").item(0);
这将为您的文件提供所有Element
个节点(或您调用它们的分支)。如果你想要文本节点(作为实际的Node
对象),你需要把它作为第一个孩子:
Node textNode = addresses2_address_street.getFirstChild();
如果您想要String
内容,可以使用:
String street = addresses2_address_street.getTextContent();
第3。选择具有XPath的节点
选择节点的另一种方法是使用XPath。您将需要DOM源,您还需要初始化XPath处理器:
XPath xPath = XPathFactory.newInstance().newXPath();
您可以像这样提取根节点:
Element addresses = (Element)xPath.evaluate("/addresses", source, XPathConstants.NODE);
所有其他节点使用类似路径的语法:
Element addresses_address = (Element)xPath.evaluate("/addresses/address", source, XPathConstants.NODE);
Element addresses_address_name = (Element)xPath.evaluate("/addresses/address/name", source, XPathConstants.NODE);
Element addresses_address_street = (Element)xPath.evaluate("/addresses/address/street", source, XPathConstants.NODE);
您还可以使用相对路径,选择不同的元素作为根:
Element addresses_person = (Element)xPath.evaluate("person", addresses, XPathConstants.NODE);
Element addresses_person_name = (Element)xPath.evaluate("person/name", addresses, XPathConstants.NODE);
Element addresses_person_age = (Element)xPath.evaluate("age", addresses_person, XPathConstants.NODE);
您可以像以前一样获取文本内容,因为您有Element
个对象:
String addressName = addresses_address_name.getTextContent();
但是你也可以使用上面相同的方法直接完成它而没有最后一个参数(默认为string)。这里我使用不同的相对和绝对XPath表达式:
String addressName = xPath.evaluate("name", addresses_address);
String addressStreet = xPath.evaluate("address/street", addresses);
String personName = xPath.evaluate("name", addresses_person);
String personAge = xPath.evaluate("/addresses/person/age", source);