2015-11-19 3 views
2

У меня есть требование для группировки элементов XML с тем же атрибутом в Java.Как группировать элементы xml в java по атрибутам

Ниже мой обновленный вход:

<root> 
<Slots date="2015-11-17"> 
    <TimePeriod value="8-17"> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298451</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
    </TimePeriod> 
</Slots> 
<Slots date="2015-11-17"> 
    <TimePeriod value="8-17"> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298452</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
    </TimePeriod> 
</Slots> 
<Slots date="2015-11-18"> 
    <TimePeriod value="2-8"> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298451</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
    </TimePeriod> 
</Slots> 
<Slots date="2015-11-18"> 
    <TimePeriod value="2-8"> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298452</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
    </TimePeriod> 
</Slots> 

Мне нужен выход, как показано ниже:

<root> 
<Slots date="2015-11-17"> 
    <TimePeriod value="8-17"> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298451</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298452</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
    </TimePeriod> 
</Slots> 
<Slots date="2015-11-18"> 
    <TimePeriod value="2-8"> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298451</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298452</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
    </TimePeriod> 
</Slots> 
</root> 

Я пытался что-то вроде ниже:

HashSet<String> set = new HashSet<String>(); 
    if(node!= null && node.getLength() > 0) { 


     for(int i=0;i<node.getLength();i=i+1) 
     { 
       Node slots = node.item(i); 
       set.add(slots.getAttributes().getNamedItem("date").getNodeValue()); 
     } 
    } 
    System.out.println("slots dates are --- **** "+ set); 
    ArrayList<Node> deleteList = new ArrayList<Node>(); 
    for(String date : set) 
    { System.out.println("slots dates is --- **** "+ "2015-11-18"); 
      Node remainingNode = null; 
      for(int i=0;i<node.getLength();i=i+1) 
      { 
       Node slotnode = node.item(i); 
       if(slotnode.getAttributes() != null && slotnode.getAttributes().getNamedItem("date")!= null && "2015-11-18".equals(slotnode.getAttributes().getNamedItem("date").getNodeValue())) 
       {System.out.println("inside time 18"); 
         if(remainingNode == null) 
          remainingNode = slotnode; 
         else { 
          NodeList nodeps = slotnode.getChildNodes(); 
          for(int j=0;j<nodeps.getLength();j=i+1) { 
            remainingNode.appendChild(nodeps.item(j)); 
          } 
          deleteList.add(slotnode); 
         } 
       } 
      } 
      NodeList nodesItems = doc1.getElementsByTagName("root"); 
      nodesItems.item(0).appendChild(remainingNode); 

I попробовал с использованием Dom par ser, но я не мог этого сделать. Я новичок в XML, искал везде, но ничего не нашел, может ли кто-нибудь помочь мне в этом. Примечание: Я не могу использовать JAXB для этого решения.

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

+0

Рассмотрим сделать группировку в языке, как XSLT 2.0 (http://www.w3.org/TR/xslt20/#grouping-examples) или XQuery 3 (http://www.w3.org/TR/xquery-30/# id-group-by), которые на Java поддерживаются, например, Saxon 9, доступными в версии с открытым исходным кодом из http://saxon.sourceforge.net/. –

+0

Какую версию Java вы используете? –

+0

Можете ли вы предоставить хорошо сформированный образец XML с одним корневым элементом? Вам нужно сгруппировать «Слоты» по «дате», а затем дополнительно «значение TimePeriod»? Или это значение одинаково для всех «слотов» с той же «датой»? –

ответ

0

Во-первых, ваш XML-файл не является корректным. Это хорошо сформированная версия:

<root> 
<Slots date="2015-11-17"> 
    <TimePeriod value="8-17"> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298451</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
    </TimePeriod> 
</Slots> 
<Slots date="2015-11-17"> 
    <TimePeriod value="8-17"> 
     <ContractorAvailable ContractorID="H4CONT07"> 
      <GroupId>298452</GroupId> 
      <OfferToken>10315009</OfferToken> 
      <Capacity>99</Capacity> 
     </ContractorAvailable> 
    </TimePeriod> 
</Slots> 
</root> 

Это пример, чтобы показать, как получить доступ к данным в файле XML:

import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.DocumentBuilder; 
import org.w3c.dom.Document; 
import org.w3c.dom.NodeList; 
import org.w3c.dom.Node; 
import org.w3c.dom.Element; 
import java.io.File; 

public class XMLParser { 
    public static void main(String argv[]) { 
     try { 
     File fXmlFile = new File("C:/test.xml"); 
     DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
     DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); 
     Document doc = dBuilder.parse(fXmlFile); 
     doc.getDocumentElement().normalize(); 
     System.out.println("Root element in this XML file is :" + doc.getDocumentElement().getNodeName()); 
     NodeList nList = doc.getElementsByTagName("ContractorAvailable"); 
     System.out.println("----------------------------"); 
     for (int i = 0; i < nList.getLength(); i++) { 
      Node nNode = nList.item(i);  
      System.out.println("\nCurrent Element :" + nNode.getNodeName());  
      if (nNode.getNodeType() == Node.ELEMENT_NODE) { 
       Element eElement = (Element) nNode; 
       System.out.println("Contractor ID : " + eElement.getAttribute("ContractorID")); 
      } 
     } 
     } catch (Exception e) { 
     e.printStackTrace(); 
     } 
     } 
} 

Результат будет выглядеть следующим образом:

The result

Когда у вас есть доступ к вашим данным, вы можете создать новый XML-файл.

0

Как я уже сказал в комментарии, я думаю, что это легкая работа для XSLT 2.0 (доступна для Java, например, с помощью Saxon 9.6 HE из http://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE соответственно http://sourceforge.net/projects/saxon/files/Saxon-HE/9.6/SaxonHE9-6-0-7J.zip/download) и следующий код XSLT:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="/*"> 
     <xsl:copy> 
      <xsl:for-each-group select="Slots" group-by="@date"> 
       <Slots date="{current-grouping-key()}"> 
        <xsl:for-each-group select="current-group()/TimePeriod" group-by="@value"> 
         <TimePeriod value="{current-grouping-key()}"> 
          <xsl:copy-of select="current-group()/ContractorAvailable"/> 
         </TimePeriod> 
        </xsl:for-each-group> 
       </Slots> 
      </xsl:for-each-group> 
     </xsl:copy> 
    </xsl:template> 

</xsl:transform> 

Если вы хотите сделать группировку в Java, то Java 8 имеет поддержку для этого, но DOM не совсем правильная структуры данных, так что вам нужно будет построить List<Element>, а затем группы и построить и новый DOM:

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.stream.Collectors; 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 
import org.w3c.dom.Document; 
import org.w3c.dom.Element; 
import org.w3c.dom.NodeList; 
import org.w3c.dom.ls.DOMImplementationLS; 
import org.w3c.dom.ls.LSSerializer; 
import org.xml.sax.SAXException; 


public class DOMGroupBy1 { 


    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { 
     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     dbf.setNamespaceAware(true); 

     DocumentBuilder db = dbf.newDocumentBuilder(); 

     Document inputDoc = db.parse("input.xml"); 

     Document outputDoc = db.newDocument(); 
     outputDoc.appendChild(outputDoc.createElement("root")); 

     NodeList domSlots = inputDoc.getElementsByTagName("Slots"); 

     List<Element> slots = new ArrayList<>(); 

     for (int i = 0; i < domSlots.getLength(); i++) { 
      slots.add((Element) domSlots.item(i)); 
     } 

     List<Element> groups 
       = slots 
       .stream() 
       .collect(Collectors.groupingBy(slot -> slot.getAttribute("date"))) 
       .entrySet() 
       .stream() 
       .map(entry -> { 
        Element newSlot = outputDoc.createElement("Slots"); 
        newSlot.setAttribute("date", entry.getKey()); 
        entry 
          .getValue() 
          .stream() 
          .collect(Collectors.groupingBy(slot -> ((Element) slot.getElementsByTagName("TimePeriod").item(0)).getAttribute("value"))) 
          .entrySet() 
          .forEach(time -> { 
           Element timeEl = outputDoc.createElement("TimePeriod"); 
           timeEl.setAttribute("value", time.getKey()); 
           newSlot.appendChild(timeEl); 
           time.getValue().forEach(el -> { 
            NodeList cas = el.getElementsByTagName("ContractorAvailable"); 
            for (int j = 0; j < cas.getLength(); j++) { 
             timeEl.appendChild(outputDoc.importNode(cas.item(j), true)); 
            } 

           }); 
          }); 

        return newSlot; 
       }) 
       .collect(Collectors.toList()); 

     LSSerializer serializer = ((DOMImplementationLS) db.getDOMImplementation()).createLSSerializer(); 
     serializer.getDomConfig().setParameter("format-pretty-print", true); 

     groups.forEach(slot -> outputDoc.getDocumentElement().appendChild(slot)); 

     System.out.println(serializer.writeToString(outputDoc)); // could of course write a file here instead with e.g. serializer.writeToURI(outputDoc, new File("result.xml").toURI().toString()); 

    } 

} 
+0

Извините за поздний ответ, спасибо за ваш ответ, но мой инструмент не поддерживает Java 1.8, можете ли вы предоставить ответ в java 1.7 –

0

Спасибо всем ваши ответы, однако я смог сгруппировать с помощью следующего кода. Надеюсь, это может помочь другим, кто ищет то же самое.

package beans; 

import java.io.IOException; 
import java.io.StringReader; 
import java.io.StringWriter; 
import java.util.ArrayList; 
import java.util.TreeSet; 

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.transform.OutputKeys; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerException; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 

import org.w3c.dom.Document; 
import org.w3c.dom.Element; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 
import org.xml.sax.InputSource; 
import org.xml.sax.SAXException; 


public class Grouping { 


/** 
* Gets the first child element of a node. 
* @param node the node to get the child from 
* @return the first element child of the given Node 
* 
*/ 
public static Element getFirstChildElement(Node node) 
{ 
    node = node.getFirstChild(); 
    while (node != null && node.getNodeType() != Node.ELEMENT_NODE) 
    { 
     node = node.getNextSibling(); 
    } 
    return (Element)node; 
} 

/** 
* Groups the Given Nodes based on the tag value. Tag should be present in as attribute in the root tag. 
* @ NodeList List of Nodes for which grouping needs to be done 
* @String  Group Tag name based on its values, the nodes will be grouped 
* @return boolean true/false. 
* 
*/ 

public static boolean groupNodes(NodeList slotNodes, String strGroupTag) 
{ 

    // Start checking the unique Values for grouping 
      TreeSet<String> slotdates = new TreeSet<String>(); 
      if(slotNodes!= null && slotNodes.getLength() > 0) { 


       for(int i=0;i<slotNodes.getLength();i++) 
       { 
        Node slots = slotNodes.item(i); 

        if(slots != null && slots.getAttributes() != null) 
        { 
         String strDate = slots.getAttributes().getNamedItem(strGroupTag).getNodeValue(); 
         slotdates.add(strDate); 
        }        
       } 
      } 
    // Ends : checking the unique Values for grouping 

    // Starts Grouping based on dates 
      ArrayList<Node> deleteSlotList = new ArrayList<Node>(); 
      for(String slotdate : slotdates) 
      { 
       Node remainingSlotNode = null; 
       for(int i=0;i<slotNodes.getLength();i++) 
       { 
        Node slotnode = slotNodes.item(i); 

        if(slotnode.getAttributes() != null && slotnode.getAttributes().getNamedItem(strGroupTag)!= null) 
        { 
         String strDateValue = slotnode.getAttributes().getNamedItem(strGroupTag).getNodeValue(); 

         if(strDateValue != null && strDateValue.equalsIgnoreCase(slotdate)) 
         { 
          if(remainingSlotNode == null) 
          { 
           remainingSlotNode = slotnode; 
          } 
          else { 
           Node NodeTime = getFirstChildElement(slotnode); 
           if(NodeTime != null) 
           { 

            remainingSlotNode.appendChild(NodeTime); 

           } 
           deleteSlotList.add(slotnode); 
          } 
         } 

        } 
       } 

       slotNodes.item(0).getParentNode().appendChild(remainingSlotNode);        

      } 

      for(Node deletedNode: deleteSlotList) 
      { 
       deletedNode.getParentNode().removeChild(deletedNode); 

      } 
      // Ends Grouping based on dates 
      return true; 
} 

public static DOMSource groupingUtil(String xml) throws TransformerException, SAXException, IOException, ParserConfigurationException { 

    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
    DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); 

    Document doc = dBuilder.parse(new InputSource(new StringReader(xml))); 
    NodeList slotNodes = doc.getElementsByTagName("Slots"); 



    if(groupNodes(slotNodes, "date")) 
    { 
     slotNodes = doc.getElementsByTagName("Slots"); 
     for(int i=0;i<slotNodes.getLength();i++) 
     { 
      Node slot = slotNodes.item(i); 
      NodeList timeNodes = slot.getChildNodes(); 
      groupNodes(timeNodes, "value"); 
     } 
    }  

    Transformer transformer = TransformerFactory.newInstance().newTransformer(); 
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");     
    StreamResult result = new StreamResult(new StringWriter()); 

    DOMSource source = new DOMSource(doc); 
    transformer.transform(source, result); 

    return source; 
} 
}