使用DocumentBuilder进行XML解析
我想将xml解析为键值对的映射,如下所示。使用DocumentBuilder进行XML解析
示例XML文档:
<Students>
<StudentA>
<Id>123</Id>
<Address>123 W </Address>
<Courses>
<Course1>CS203</Course1>
<Course2>CS206</Course2>
</Courses>
</StudentA>
<StudentB>
<Id>124</Id>
<Address>124 W </Address>
<Courses>
<Course1>CS202</Course1>
<Course2>CS204</Course2>
</Courses>
</StudentB>
</Students>
XML解析器代码:
/**
* Parse the given xml data.
* @param xmlString The xml string to be parsed.
* @return Non-null list of {@link DiscreteDataEntry} values, may be empty.
*/
Map<String, String> parseXML(final String xmlString)
{
final String xmlDataToParse = xmlString;
parentNode = "";
try
{
final InputStream inputStream = new ByteArrayInputStream(xmlDataToParse.getBytes());
final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
final Document document = documentBuilder.parse(inputStream);
final Map<String, String> data = createMapOfAttributeValuesKeyedByName(document.getDocumentElement());
}
catch (final Exception exception)
{
System.out.println("Exception:" + exception);
}
return data;
}
/**
* A recursive method which will loop through all the xml nodes.
* @param node The node.
* @return Non-null map of test values keyed by test name, may be empty.
*/
Map<String, String> createMapOfAttributeValuesKeyedByName(final Node node)
{
final Map<String, String> attributeValuesKeyedByName = new LinkedHashMap<String, String>();
final NodeList nodeList = node.getChildNodes();
for (int index = 0; index < nodeList.getLength(); index++)
{
final Node currentNode = nodeList.item(index);
if (node.getFirstChild() != null && node.getFirstChild().getNodeType() == Node.ELEMENT_NODE)
{
parentNode = getAncestralOrigin(currentNode);
attributeValuesKeyedByName.putAll(createMapOfAttributeValuesKeyedByName(currentNode));
}
else if (node.getFirstChild() != null && node.getFirstChild().getNodeType() == Node.TEXT_NODE)
{
final String attributeName = parentNode.length() > 0 ? parentNode + "." + node.getNodeName().trim() : node.getNodeName().trim();
final String attributeValue = node.getTextContent().trim();
attributeValuesKeyedByName.put(attributeName, attributeValue);
parentNode = "";
}
}
return attributeValuesKeyedByName;
}
/**
* Parses a give node and finds all its ancestors.
* @param node The node whose ancestors have to be found.
* @return A non-null but possible empty string built using the ancestors of the node.
*/
final String getAncestralOrigin(final Node node)
{
String ancestralOrigin = "";
final Node currentParentNode = node.getParentNode();
if (currentParentNode != null && currentParentNode.getNodeType() != Node.DOCUMENT_NODE)
{
ancestralOrigin = currentParentNode.getNodeName();
final String ancestor = getAncestralOrigin(currentParentNode);
if (ancestor.length() > 0)
{
ancestralOrigin = ancestor + "." + ancestralOrigin;
}
}
return ancestralOrigin;
}
地图的输出是:
Key:[Students.StudentA.Id], Value:[123]
Key:[Students.StudentA.Address], Value:[123 W]
Key:[Students.StudentA.Courses.Course1], Value:[CS203]
Key:[Students.StudentA.Courses.Course2], Value:[CS206]
Key:[Students.StudentB.Id], Value:[124]
Key:[Students.StudentB.Address], Value:[124 W]
Key:[Students.StudentB.Courses.Course1], Value:[CS202]
Key:[Students.StudentB.Courses.Course2], Value:[CS204]
但这输出工作正常,如果该文件是正在阅读
final BufferedReader bufferedReader = new BufferedReader(new FileReader(new File(url.getFile().replaceAll("%20", " "))));
如果同一个文件中被读出以
DataInputStream is = new DataInputStream(new FileInputStream(new File(url.getFile().replaceAll("%20", " "))));
输出是不同的。它确实在xml文档中使用了所有的CR和LF。
键:[学生],值:123 123W¯¯
CS203
CS206
124
124 W
CS202
CS204]
我使用的是依赖罐子阅读这DataInputStream所使用的XML文件。
我总是觉得我的xml解析器会照顾CR/LF/NewLine看起来不像它。 我将在分析之前用空字符串替换所有CR LF和NewLines。
但我想知道是否有其他的XML解析器会自己照顾自己。还有什么是BufferedReader跳过CR/LF和NewLine 的原因,但DataInputStream不会。
还有没有其他更好的方法来找到子标签的祖先,我需要他们使关键值独一无二。
xml将保持原样并且无法更改。此外,XML将不会像这里显示的那样,它将是一个带有标签 更改的通用XML,所以我正在尝试制作一个通用的XML解析器,用于解析xml子标记并将它们放入地图中。
孩子标签可以重复,所以我使用孩子的路径使其独特。
也有一种方法来解析xml只有这些标签(StudentA/StudentB)通过删除父标签学生递归。
注意:xml格式发生变化,我解析的xml可能会更改为每个xml文件。 所以我真的不能解析像得到StudentA的孩子。
经过长篇描述之后,我了解到,您想了解其他更好的解析XML的方法。
答案是,是的,还有其他一些更好的方法来解析XML。使用StAX
或SAX
,这些是快速和更高的内存效率。要了解更多,请阅读Java教程的JAXP
。
DataInputStream
旨在仅读取使用DataOutputStream
...写成的东西,即序列化的Java对象。它不适用于阅读文本输入。
此示例源代码可能是一个好开始:http://www.mkyong.com/java/how-to-read-xml-file-in-java-dom-parser/在格式更改的情况下,你可以检查空的节点,只是它返回一个0. – WilliamShatner
我可以告诉你,vtd-xml肯定会照顾你的CR/LF。 –