【问题标题】:how to group xml elements in java by attributes如何按属性对java中的xml元素进行分组
【发布时间】:2016-02-21 16:56:24
【问题描述】:

我需要在 Java 中对具有相同属性的 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>
 <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);

我尝试使用 Dom 解析器,但我做不到。我是 XML 新手,到处搜索,但没有找到任何东西,任何人都可以帮我解决这个问题。 注意:我不能将 JAXB 用于此解决方案。

是的,我按日期分组插槽,然后按 TimePeriod 值分组。 我正在使用的工具不支持 XSLT

【问题讨论】:

  • 考虑使用 XSLT 2.0 (w3.org/TR/xslt20/#grouping-examples) 或 XQuery 3 (w3.org/TR/xquery-30/#id-group-by) 之类的语言进行分组,这些语言在 Java 上受到 Saxon 9 的支持,开源版本来自saxon.sourceforge.net.
  • 您使用哪个 Java 版本?
  • 您能否提供一个具有单个根元素的格式良好的 XML 示例?您是否需要将Slotsdate 分组,然后再将TimePeriod value 分组?或者对于具有相同date 的所有Slots,该值是否相同?
  • 你能使用 Java 8 分组吗?

标签: java xml domparser


【解决方案1】:

首先,您的 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();
        }
      }
}

结果会是这样的:

当您可以访问您的数据时,您可以创建一个新的 XML 文件。

【讨论】:

    【解决方案2】:

    正如我在评论中所说,我认为这对于 XSLT 2.0(例如使用来自 http://mvnrepository.com/artifact/net.sf.saxon/Saxon-HEhttp://sourceforge.net/projects/saxon/files/Saxon-HE/9.6/SaxonHE9-6-0-7J.zip/download 的 Saxon 9.6 HE 的 Java 和以下 XSLT 代码来说是一件容易的事)和以下 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&lt;Element&gt;,然后再进行分组并构造新的 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());
    
        }
    
    }
    

    【讨论】:

    • 抱歉回复晚了,感谢您的回答,但我的工具不支持Java 1.8,请您在Java 1.7中提供答案
    【解决方案3】:

    感谢您的所有回答,但是我能够使用以下代码进行分组。希望它可以帮助其他寻找相同的人。

     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;
    }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-03-18
      • 2021-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多