2013-06-27 3 views
1

Я пытаюсь разобрать xml на карту пар ключ-значение следующим образом.XML-анализ с использованием DocumentBuilder

Пример документа 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 Parser:

/** 
* 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", " ")))); 

выход отличается. Он принимает все CR и LF в документе xml.

Ключ: [Студенты], значение: [123 123 W

 CS203 
     CS206 



    124 
    124 W 

     CS202 
     CS204] 

Я использую баночку зависимостей для чтения файла XML, который использует DataInputStream.

У меня всегда было впечатление, что мои синтаксические анализаторы xml позаботятся о CR/LF/NewLine, похоже, что это не так. Я заменяю все CR LF и NewLines пустой строкой перед ее разбором.

Но я хотел бы знать, есть ли другие XML-парсеры, которые позаботятся о себе. Также в чем причина того, что BufferedReader пропускает CR/LF и NewLine , но в качестве DataInputStream этого не будет.

Также есть ли другой лучший способ найти предков дочернего тега, мне нужно, чтобы значение ключа было уникальным.

xml будет таким, какой он есть, и его нельзя изменить. Кроме того, xml не будет таким, как показано здесь, это будет общий XML-код с тегами , поэтому я пытаюсь создать общий XML-парсер, который анализирует теги дочерних элементов xml и помещает их в карту.

Детские теги могут быть дублированы, поэтому я использую путь к ребенку, чтобы сделать его уникальным.

Также существует способ разбора xml с помощью этих тегов (StudentA/StudentB) рекурсивно, удалив родительский тег Students.

Примечание: переменные формата xml и xml, которые я анализирую, могут меняться для каждого xml-файла. Так что я действительно не могу разобрать, как получить детей StudentA.

+0

Этот пример источника может быть хорошим началом: http://www.mkyong.com/java/how-to-read-xml-file-in-java-dom-parser/ В тех случаях, когда формат изменяется, вы можете проверить пустые узлы и просто вернуть его 0. – WilliamShatner

+0

Я могу сказать вам, что vtd-xml определенно заботится о CR/LF для вас. –

ответ

0

Пройдя длинное описание, я узнаю, что вы хотите узнать другой лучший способ анализа XML.

Ответ: Да, есть и другой лучший способ анализа XML. Используйте StAX или SAX, они бывают более быстрыми и эффективными с точки зрения памяти. Чтобы узнать больше, читайте JAXP учебника по Java.

0

DataInputStream предназначен для чтения только что написанного с использованием DataOutputStream ... т. Е. Сериализованных объектов Java. Он не предназначен для чтения ввода текста.