# XML Document Parsen und Ausgeben mit Suchfunktion



## Stiffler (29. Mrz 2019)

Hallo ins Forum,

ich muss vorweg gestehen ich habe mich die Komplette letzte Woche erst mit Java beschäftigt. (bitte nehmt es mir also nicht Krum wie die Frage vielleicht Blöd ist.)

Da ich gesucht habe bei Google und auch hier im Forum und nicht so richtig fündig geworden bin kommt hier mal meine Frage.

Ich habe ein Projekt wo ich aus einem kleinen Tool (zugänglich leider nur für 2 Personen) mir die Informationen in ein *.xml Dokument exportieren kann.
Dieses Dokument da es glaube über 15k Zeilen hat wollte ich Parsen und das dann vielleicht über eine GUI oder über WEB Seiten Zugriff mit einem Suchfeld Durchsuchen und dann nur den einzelnen Wert + Child Elemente ausgeben.

Ich scheitere aber nun einfach schon beim Einlesen. 

```
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.util.ArrayList;

public class AdminTool3Shape {
    //Pfad und Name der XML Datei die Geparst werden soll
    private static String XMLDateiName = "\\\\xxx.xxx.xxx.xxx\\xxxxx\\xxxxxxx\\xxxxxx\\07 - Projekte\\06 - Java\\3ShapeExport.xml";
    private static String Site, Description, Dongle, Application, Attribute ;
    private static ArrayList<String> liste;
    private static ArrayList<SiteList> liste2;

    public static void main(String[] args) throws Exception, Exception {
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         DocumentBuilder builder = factory.newDocumentBuilder();
         // Uebergebene XML-Datei parsen
         Document dokument = builder.parse(new File(XMLDateiName));
         dokument.getDocumentElement();
         getAlleSite(dokument);
         getAlleDescription(Dongle, Application, Attribute, dokument);
        
         // DOM Baum durchlaufen und ausgeben
         traversieren(dokument.getDocumentElement(), "");
        
    }
    private static void traversieren(Element d, String dongle) {       
        System.out.println(dongle + d.getNodeName());
        // Kindelemente des uebergebenen Elements ermitteln
        NodeList children = d.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node knoten = children.item(i);
            // Knoten ist ein ELEMENT_NODE
            if (knoten.getNodeType() == Node.ELEMENT_NODE)
                // Rekursiver Aufruf von traversieren für aktuelles Element
                traversieren((Element) knoten, dongle + " ");
            // Knoten ist ein TEXT_NODE
            else if (knoten.getNodeType() == Node.TEXT_NODE) {
                    String inhalt = knoten.getTextContent();
                    if (inhalt.trim().length() > 0) // leerer Inhalt?
                    System.out.println(dongle + " :" + inhalt);
        } else
        // kein ELEMENT_NODE, kein TEXT_NODE
        System.out.println(dongle + knoten);
        }
    }
    private static ArrayList<String> getAlleSite(Document dokument) {
        // Alle Kindelemente mit dem Site Description einsammeln
        NodeList siteNodes = dokument.getElementsByTagName("Site");
        liste = new ArrayList<String>(siteNodes.getLength());
            for (int i=0; i<siteNodes.getLength(); i++) {
        // Node nach Element casten
                Element siteElement = (Element) siteNodes.item(i);
        // Neue Instanz von Site anlegen
                Site abschnitt = new Site(null, Site, Description, Dongle, Application, Attribute, XMLDateiName);
        // Kindelemente Description suchen, den Textinhalt als Description nehmen
                NodeList node1 = siteElement.getElementsByTagName("Description");
                Site.setDescription(node1.item(0).getTextContent());
        // Analog für Dongle
                NodeList node2 = siteElement.getElementsByTagName("Dongle");
                Site.setDongle(node2.item(0).getTextContent());
        
                Description=Site.getDescription();
                Dongle=Site.getDongle();
                liste.add(Description+" "+Dongle);
    
        }
        
        // Kontroll Ausgabe der Liste auf der Konsole
        System.out.println("*** All Site ***");
        System.out.println(liste);
        return liste;
    }
    public static ArrayList<SiteList> getAdressenDaten(String Site, String Description, Document dokument){
        NodeList site= dokument.getElementsByTagName("Site");     
        NodeList description= dokument.getElementsByTagName("Description");
        NodeList Dongle= dokument.getElementsByTagName("Dongle");
        NodeList Application=dokument.getElementsByTagName("Application");
        NodeList Attribute=dokument.getElementsByTagName("Attribute");
        
        liste2 = new ArrayList<SiteList>(liste.size());
        for (int i =0;i<liste.size();i++){
        String pSite=site.item(i).getTextContent();
        String pDescription=description.item(i).getTextContent();             
        String pDongle=Dongle.item(i).getTextContent();
        String pApplication=Application.item(i).getTextContent();
        String pAttribute=Attribute.item(i).getTextContent();
        
        
        SiteList s= new SiteList();
        s.setSite(pSite);
        s.setDescription(pDescription);
        s.setDongle(pDongle);
        s.setApplication(pApplication);
        s.setAttribute(pAttribute);       
        liste2.add(site);
        }
       }
        System.out.println(liste2);
        return liste2;
                
    }
    public static void getAlleDescription (Document dokument) {
        NodeList Site= dokument.getElementsByTagName("Site");     
        NodeList Description= dokument.getElementsByTagName("Description");
        liste = new ArrayList<String> (Site.getLength());
        
        for (int i=0; i<Site.getLength();i++){
            Site.item(i).getTextContent();
            Description.item(i).getTextContent();
        liste.add(Site+" " +Description); 
        }
        
    }   
    private static void getAlleDescription(String dongle2, String application2, String attribute2, Document dokument) {       
        
    }
    public static String getXMLDateiName() {
        return XMLDateiName;
    }
    public static void setXMLDateiName(String xMLDateiName) {
        XMLDateiName = xMLDateiName;
    }
    public static String getSite() {
        return Site;
    }
    public static void setSite(String site) {
        Site = site;
    }
    public static String getDescription() {
        return Description;
    }
    public static void setDescription(String description) {
        Description = description;
    }
    public static String getDongle() {
        return Dongle;
    }
    public static void setDongle(String dongle) {
        Dongle = dongle;
    }
    public static String getApplication() {
        return Application;
    }
    public static void setApplication(String application) {
        Application = application;
    }
    public static String getAttribute() {
        return Attribute;
    }
    public static void setAttribute(String attribute) {
        Attribute = attribute;
    }    
}
```


Ich zeig euch Exemplarisch auch mal die Exportierte *.xml



```
<?xml version="1.0"?>
<SiteExport Version="1.0">
  <CustomerName>Firma</CustomerName>
  <SiteList>
    <Site ID="09051">
      <Description>000_XXX_1271101190</Description>
      <ResellersCustomerNo></ResellersCustomerNo>
      <ResellersCustomID1 Label="Custom ID 1"></ResellersCustomID1>
      <ResellersCustomID2 Label="Custom ID 2"></ResellersCustomID2>
      <ResellersCustomID3 Label="Custom ID 3"></ResellersCustomID3>
      <Notes></Notes>
      <CanReceive>True</CanReceive>
      <Dongles>
        <Dongle Number="1271101190">
          <Application Name="DentalDesigner Premium">
            <Attribute>Expired</Attribute>
            <Attribute>Saves limited</Attribute>
            <Attribute>Client points: 1</Attribute>
            <Attribute>Installed version: 2.8.8.4</Attribute>
          </Application>
          <Application Name="DentalManager">
            <Attribute>Encryption enabled</Attribute>
            <Attribute>Expired</Attribute>
            <Attribute>Client points: 3</Attribute>
            <Attribute>Options: Abutments OBSOLETE from 2010</Attribute>
            <Attribute>Installed version: 2.8.8.4</Attribute>
          </Application>
          <Application Name="DentalManager Inbox module">
            <Attribute>Expired</Attribute>
            <Attribute>Client points: 3</Attribute>
          </Application>
          <Application Name="ScanIt Impression">
            <Attribute>Saves limited</Attribute>
          </Application>
          <Application Name="Abutment Designer Module Save Limited DEMO">
            <Attribute>Saves limited</Attribute>
          </Application>
          <Application Name="Removable Design Module">
            <Attribute>Saves limited</Attribute>
            <Attribute>Client points: 1</Attribute>
          </Application>
          <Application Name="Implant Bars/Bridge Design Module">
            <Attribute>Saves limited</Attribute>
            <Attribute>Client points: 1</Attribute>
          </Application>
          <Application Name="Model Builder (TRIOS scans only)">
            <Attribute>Saves limited</Attribute>
            <Attribute>Client points: 1</Attribute>
          </Application>
          <Application Name="Model Builder (3rd Party scans)">
            <Attribute>Saves limited</Attribute>
            <Attribute>Client points: 1</Attribute>
          </Application>
          <Application Name="Model Builder (Impression scans)">
            <Attribute>Saves limited</Attribute>
            <Attribute>Client points: 1</Attribute>
          </Application>
        </Dongle>
      </Dongles>
      <Connections>
        <Connection ReceiverSiteID="14065">
          <Notes></Notes>
          <CreateDate>2012-06-25</CreateDate>
        </Connection>
      </Connections>
      <Options>
        <Option Name="RawSTL" Description="Raw STL CAD Output for all customers"/>
        <Option Name="RK" Description="RÃ¼beling und Klar CAD Output for all customers"/>
        <Option Name="3DPrinter" Description="3D Printer CAD Output for all customers"/>
        <Option Name="RestorationMill" Description="RestorationMill CAD Output for all customers"/>
        <Option Name="BEGO" Description="BEGO CAD Output"/>
        <Option Name="DentMill" Description="DentMill CAD Output for all customers"/>
        <Option Name="RawSTLExceptLocked" Description="Raw STL (except locked) OBSOLETE! for all customers"/>
        <Option Name="GeneralRPMachine" Description="RP machine with supports CAD Output for all customers"/>
        <Option Name="Mandatory 1" Description="Mandatory 1"/>
        <Option Name="WielandZeno40" Description="Zeno CAM 4.0 CAD Output"/>
        <Option Name="3IImplantSignature1" Description="3I Implant Signature 1 for all customers"/>
        <Option Name="FollowMe" Description="Follow Me CAD Output for all customers"/>
        <Option Name="BEGO-Semados" Description="BEGO abutment kit"/>
        <Option Name="SII_STLOutput" Description="ScanIt Impression STL output"/>
        <Option Name="RawDCM" Description="Raw DCM CAD Output for all customers"/>
        <Option Name="SIR_STLOutput" Description="ScanIt Restoration STL output"/>
        <Option Name="Wieland-Abutments" Description="Wieland abutment kit for all customers"/>
        <Option Name="VisualizationOutput" Description="Visualization output for all customers"/>
        <Option Name="Camlog" Description="Camlog Implant Kit for all customers"/>
        <Option Name="Neoss" Description="Neoss Implant Kit for all customers"/>
        <Option Name="Avinent Protech Implant Library" Description="Avinent Protech Implant Library (Option D) for all customers"/>
        <Option Name="BioHorizons" Description="Implantlibrary of BioHorizons for all customers"/>
        <Option Name="ZimmerAbutmentKit" Description="Zimmer Abutment Kit (Option B) for all customers"/>
        <Option Name="ZimmerImplantSignature1" Description="Zimmer Implant Signature 1 (Option B) for all customers"/>
        <Option Name="Core3d Implant library" Description="Core3d Implant library (Option D) for all customers"/>
        <Option Name="Jorge Test" Description="Jorge Test for all customers"/>
        <Option Name="BEGOCrownLibrary" Description="BEGO Crown Library"/>
        <Option Name="RawSTL" Description="Raw STL CAD Output"/>
        <Option Name="GlidewellHybridKit" Description="GlidewellHybridKit for all customers"/>
        <Option Name="GlidewellBarKit" Description="GlidewellBarKit for all customers"/>
        <Option Name="BegoAbutmentKit" Description="BegoAbutmentKit for all customers"/>
        <Option Name="GlidewellAnatomyLibrary" Description="GlidewellAnatomyLibrary for all customers"/>
        <Option Name="Unlimited Implant Scanning" Description="Unlimited Implant Scanning"/>
        <Option Name="TriosInbox" Description="Trios Inbox enabling option for all customers"/>
        <Option Name="VertexDental Quint Denture SmileLibrary" Description="VertexDental Quint Denture SmileLibrary (Option C) for all customers"/>
        <Option Name="Pala Smile library" Description="PalaÂ® Smile library (Option D) for all customers"/>
      </Options>
    </Site>
</SiteList>
```

Ich hoffe ich hab nur ein Vertipper drin oder ich bin doch total Blöd  

Freu mich auf ein bissel Hilfe  
Sollte ich euch im Bezug auf Mediendesign oder gar bei der Fotografie helfen können immer her mit euren Fragen.


----------



## mihe7 (29. Mrz 2019)

Interessant wäre, wonach Du die Datei durchsuchen willst und was in welchem Fall wie ausgegeben werden soll.


----------



## Stiffler (31. Mrz 2019)

Ich möchte am Ende des Projektes nach der Dongle Nummer suchen und mir dann Ausgeben lassen was unter Dongle steht <Application> & <Attribute>


----------



## mihe7 (31. Mrz 2019)

Wenn Du nur einmal etwas aus der Datei lesen willst, könntest Du es mit XPath versuchen. Ansonsten würde ich einen SAXParser bevorzugen, sieht dann in etwa so aus:

```
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

import java.util.*;
import java.io.*;

public class Test {
    static class Application {
        private final String name;
        private final List<String> attributes;
    
        public Application(String name, List<String> attributes) {
            this.name = name;
            this.attributes = attributes;
        }
    }

    static class Dongle {
        private final String name;
        private final List<Application> applications;

        public Dongle(String name, List<Application> applications) {
            this.name = name;
            this.applications = applications;
        }
    }

    static class DongleHandler extends DefaultHandler {
        boolean getText = false;
        StringBuilder text;
        String dongleName;
        String applicationName;
        List<String> applicationAttributes = new ArrayList<>();
        List<Application> applications = new ArrayList<>();
        List<Dongle> dongles = new ArrayList<>();

        public List<Dongle> getDongles() { return dongles; }

        public void startElement(String uri, String localName, String qName, 
                Attributes atts) throws SAXException {    
            switch(qName) {
                case "Dongle": 
                    dongleName = atts.getValue("Number"); 
                    applications = new ArrayList<>();
                    break;
                case "Application": 
                    applicationName = atts.getValue("Name");
                    applicationAttributes = new ArrayList<>();
                    break;
                case "Attribute":
                    text = new StringBuilder();
                    getText = true;
                    break;
                default: break;
            }
        }

        public void characters(char[] ch, int start, int length) {
            if (getText) {
                text.append(ch, start, length);
            }
        }

        public void endElement(String uri, String localName, String qName) {
            switch(qName) {
                case "Attribute": 
                    applicationAttributes.add(text.toString());
                    getText = false;
                    break;
                case "Application":
                    applications.add(new Application(applicationName, applicationAttributes));
                    break;
                case "Dongle":
                    dongles.add(new Dongle(dongleName, applications));
                    break;
                    
            }
        }
    }

    public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser parser = spf.newSAXParser();
        DongleHandler handler = new DongleHandler();

        XMLReader reader = parser.getXMLReader();        
        reader.setContentHandler(handler);
        reader.parse(Test.class.getResource("test.xml").toString());

        Map<String, Dongle> dongles = new HashMap<>();        
        for (Dongle dongle : handler.getDongles()) {
            dongles.put(dongle.name, dongle);
        }

        Scanner sc = new Scanner(System.in);
        System.out.print("Dongle number: ");
        String number = sc.nextLine().trim();
        Dongle dongle = dongles.get(number);
        if (dongle != null) {
            for (Application app : dongle.applications) {
                System.out.println(app.name + " has " + app.attributes.size() + " attributes");
            }
        } else {
            System.out.println("No such dongle");
        }
    }
}
```
Deine Datei liegt hier einfach als test.xml neben der Test.class.


----------



## Stiffler (1. Apr 2019)

mihe7 hat gesagt.:


> Wenn Du nur einmal etwas aus der Datei lesen willst, könntest Du es mit XPath versuchen. Ansonsten würde ich einen SAXParser bevorzugen, sieht dann in etwa so aus:
> 
> Deine Datei liegt hier einfach als test.xml neben der Test.class.



Danke für deine Hilfe  Wahnsinn es funktioniert.
Nur eine Frage hab ich noch die Attribute werden jetzt ja nur gezählt.
Wenn ich mir die Attribute aber anzeigen lassen möchte muss ich den 

```
public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser parser = spf.newSAXParser();
        DongleHandler handler = new DongleHandler();

        XMLReader reader = parser.getXMLReader();       
        reader.setContentHandler(handler);
        reader.parse(Test.class.getResource("test.xml").toString());

        Map<String, Dongle> dongles = new HashMap<>();       
        for (Dongle dongle : handler.getDongles()) {
            dongles.put(dongle.name, dongle);
        }

        Scanner sc = new Scanner(System.in);
        System.out.print("Dongle number: ");
        String number = sc.nextLine().trim();
        Dongle dongle = dongles.get(number);
        if (dongle != null) {
            for (Application app : dongle.applications) {
                System.out.println(app.name + " has " + app.attributes.size() + " attributes");
            }
        } else {
            System.out.println("No such dongle");
        }
    }
```
 teil des Codes noch anpassen richtig?


----------



## mihe7 (1. Apr 2019)

Ja, die Attribute werden im Application-Objekt in der Liste attributes gespeichert. Du musst also lediglich darüber iterieren:

```
for (Application app : dongle.applications) {
                System.out.println(app.name);
                for (String attr : app.attributes) {
                    System.out.println("    " + attr);
                }
            }
```


----------



## Stiffler (3. Apr 2019)

Nun versuche ich schon seit zwei Tagen eine GUI drum herum zu Bauen und verzweifele.


```
Scanner sc = new Scanner(System.in);
        System.out.print("Dongle number: ");
        String number = sc.nextLine().trim();
        Dongle dongle = dongles.get(number);
        if (dongle != null) {
            for (Application app : dongle.applications) {
                System.out.println(app.name);
                for (String attr : app.attributes) {
                    System.out.println("    " + attr);
                }
            }
        } else {
            System.out.println("No such dongle");
        }
    }
```

Eigentlich möchte ich ja nur diesen Teil des Codes in ein JFrame mit einem JNumberfield was die Eingabe der Dongle Number übernehmen soll und eine JTextArea welche mir die Ergebnisse Anzeigen soll. Ich bin glaube echt zu dumm für Java


----------



## mihe7 (3. Apr 2019)

Meinst Du sowas?


Spoiler: Test.java





```
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

import java.util.*;
import java.io.*;

import java.awt.BorderLayout;
import java.awt.Font;
import javax.swing.*;

public class Test {
    static class Application {
        private final String name;
        private final List<String> attributes;
    
        public Application(String name, List<String> attributes) {
            this.name = name;
            this.attributes = attributes;
        }
    }

    static class Dongle {
        private final String name;
        private final List<Application> applications;

        public Dongle(String name, List<Application> applications) {
            this.name = name;
            this.applications = applications;
        }
    }

    static class DongleHandler extends DefaultHandler {
        boolean getText = false;
        StringBuilder text;
        String dongleName;
        String applicationName;
        List<String> applicationAttributes = new ArrayList<>();
        List<Application> applications = new ArrayList<>();
        List<Dongle> dongles = new ArrayList<>();

        public List<Dongle> getDongles() { return dongles; }

        public void startElement(String uri, String localName, String qName, 
                Attributes atts) throws SAXException {    
            switch(qName) {
                case "Dongle": 
                    dongleName = atts.getValue("Number"); 
                    applications = new ArrayList<>();
                    break;
                case "Application": 
                    applicationName = atts.getValue("Name");
                    applicationAttributes = new ArrayList<>();
                    break;
                case "Attribute":
                    text = new StringBuilder();
                    getText = true;
                    break;
                default: break;
            }
        }

        public void characters(char[] ch, int start, int length) {
            if (getText) {
                text.append(ch, start, length);
            }
        }

        public void endElement(String uri, String localName, String qName) {
            switch(qName) {
                case "Attribute": 
                    applicationAttributes.add(text.toString());
                    getText = false;
                    break;
                case "Application":
                    applications.add(new Application(applicationName, applicationAttributes));
                    break;
                case "Dongle":
                    dongles.add(new Dongle(dongleName, applications));
                    break;
                    
            }
        }
    }

    private final Map<String, Dongle> dongles;

    public Test(Map<String, Dongle> dongles) {
        this.dongles = dongles;
    }

    public void createAndShowGUI() {
        JTextArea output = new JTextArea(30, 60);
        output.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
        JTextField tf = new JTextField(20);
        tf.addActionListener(e -> {
            String query = tf.getText().trim();
            Dongle dongle = dongles.get(query);
            String text = dongle != null ? dongleToString(dongle) : 
                String.format("Kein Dongle mit Nummer \"%s\" gefunden.\n", query);
            output.setText(text);
        });
        JPanel input = new JPanel();
        input.add(new JLabel("Suche: "));
        input.add(tf);

        JPanel content = new JPanel(new BorderLayout(10,10));
        content.add(input, BorderLayout.NORTH);
        content.add(new JScrollPane(output));

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setContentPane(content);
        frame.pack();
        frame.setVisible(true);    
    }

    private String dongleToString(Dongle dongle) {
        StringBuilder b = new StringBuilder();
        for (Application app : dongle.applications) {
            b.append(app.name).append('\n');
            char[] sep = new char[app.name.length()];
            Arrays.fill(sep, '-');
            b.append(new String(sep)).append('\n');
            for (String attr : app.attributes) {
                b.append(attr).append('\n');
            }
        }
        return b.toString();
    }


    public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser parser = spf.newSAXParser();
        DongleHandler handler = new DongleHandler();

        XMLReader reader = parser.getXMLReader();        
        reader.setContentHandler(handler);
        reader.parse(Test.class.getResource("test.xml").toString());

        Map<String, Dongle> dongles = new HashMap<>();        
        for (Dongle dongle : handler.getDongles()) {
            dongles.put(dongle.name, dongle);
        }

        SwingUtilities.invokeLater(() -> new Test(dongles).createAndShowGUI());
    }
}
```



Gesucht wird mit der Return-Taste.


----------



## Stiffler (22. Mai 2019)

Hallo @mihe7 ,

nun muss ich das kleine Tool noch ein bisschen weiterführen.
Kannst du mir noch mal unter die Arme greifen? Und es mir vielleicht noch mal erklären?

Ich hab nun noch folgende Anforderungen an das kleine Tool
- bei der Suche müsste aus der *.xml noch die  

```
<Site ID="0815">
      <Description>000_XXX_123456789</Description>
```
 beiden Elemente durchsucht werden können.
hier stellt sich mir die Frage macht es Sinn da dann eher eine zweite Text Suchzeile zu machen oder beide Suchvarianten in einem Suchfeld abzuarbeiten? Ich glaube aber zwecks der Rückgabe werte (Zahl // Buchstabe) ist das ein Problem oder?
Ich hoffe ich habe das richtig erklärt?

Gruß Steve


----------



## mihe7 (22. Mai 2019)

Wonach soll gesucht werden? (z. B. Description komplett, Teil davon, Anfang?) Was soll ausgegeben werden?


----------



## Stiffler (23. Mai 2019)

Bei der Description wäre es glaube ich am sinnvollsten diese Komplett zu durchsuchen da es in der XML Teilweise doppelte Standort namen gibt bzw einem Standort mehrere Dongle IDs zugewiesen sein können.


----------



## mihe7 (23. Mai 2019)

Spoiler: Test.java





```
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

import java.util.*;
import java.io.*;

import java.awt.BorderLayout;
import java.awt.Font;
import javax.swing.*;

public class Test {
    static class Application {
        private final String name;
        private final List<String> attributes;
    
        public Application(String name, List<String> attributes) {
            this.name = name;
            this.attributes = attributes;
        }
    }

    static class Dongle {
        private final String name;
        private final List<Application> applications;

        public Dongle(String name, List<Application> applications) {
            this.name = name;
            this.applications = applications;
        }
    }

    static class Site {
        private final String description;
        private final List<Dongle> dongles;

        public Site(String description, List<Dongle> dongles) {
            this.description = description;
            this.dongles = dongles;
        }
    }

    static class DongleHandler extends DefaultHandler {
        boolean getText = false;
        StringBuilder text;
        String dongleName;
        String applicationName;
        String description;
        List<String> applicationAttributes = new ArrayList<>();
        List<Application> applications = new ArrayList<>();
        List<Dongle> dongles = new ArrayList<>();
        List<Dongle> siteDongles = new ArrayList<>();
        Map<String, List<Dongle>> descriptions = new HashMap<>();

        public List<Dongle> getDongles() { return dongles; }
        public Map<String, List<Dongle>> getDescriptionIndex() { return descriptions; }

        public void startElement(String uri, String localName, String qName, 
                Attributes atts) throws SAXException {    
            switch(qName) {
                case "Site":
                    description = "";
                    siteDongles = new ArrayList<>();
                    break;
                case "Description":
                    text = new StringBuilder();
                    getText = true;
                    break;
                case "Dongle": 
                    dongleName = atts.getValue("Number"); 
                    applications = new ArrayList<>();
                    break;
                case "Application": 
                    applicationName = atts.getValue("Name");
                    applicationAttributes = new ArrayList<>();
                    break;
                case "Attribute":
                    text = new StringBuilder();
                    getText = true;
                    break;
                default: break;
            }
        }

        public void characters(char[] ch, int start, int length) {
            if (getText) {
                text.append(ch, start, length);
            }
        }

        public void endElement(String uri, String localName, String qName) {
            switch(qName) {
                case "Attribute": 
                    applicationAttributes.add(text.toString());
                    getText = false;
                    break;
                case "Application":
                    applications.add(new Application(applicationName, applicationAttributes));
                    break;
                case "Dongle":
                    Dongle dongle = new Dongle(dongleName, applications);
                    dongles.add(dongle);
                    siteDongles.add(dongle);
                    break;
                case "Description":
                    getText = false;
                    description = text.toString();
                    break;
                case "Site":                    
                    descriptions.computeIfAbsent(description, d -> new ArrayList<>())
                            .addAll(siteDongles);
                    break;
            }
        }
    }

    private final Map<String, Dongle> dongles;
    private final Map<String, List<Dongle>> descriptions;

    public Test(Map<String, Dongle> dongles, Map<String, List<Dongle>> descriptions) {
        this.dongles = dongles;
        this.descriptions = descriptions;
    }

    public void createAndShowGUI() {
        JTextArea output = new JTextArea(30, 60);
        output.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
        JTextField tf = new JTextField(20);
        tf.addActionListener(e -> searchForDongles(tf.getText().trim(), output));
        JPanel input = new JPanel();
        input.add(new JLabel("Suche: "));
        input.add(tf);

        JPanel content = new JPanel(new BorderLayout(10,10));
        content.add(input, BorderLayout.NORTH);
        content.add(new JScrollPane(output));

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setContentPane(content);
        frame.pack();
        frame.setVisible(true);    
    }

    private void searchForDongles(String query, JTextArea output) {
        List<Dongle> found = donglesByNumber(query);
        if (found.isEmpty()) {
            found = donglesByDescription(query);
        }

        String text;
        if (found.isEmpty()) {
            text = String.format("Zu \"%s\" wurden keine passenden Dongles gefunden", query);
        } else {
            StringJoiner j = new StringJoiner("\n");
            for (Dongle d : found) {
                j.add(dongleToString(d));
            }
            text = j.toString();
        }
        output.setText(text);
    }

    private List<Dongle> donglesByDescription(String query) {
        List<Dongle> result = new ArrayList<>();
        for (Map.Entry<String, List<Dongle>> entry : descriptions.entrySet()) {
            if (entry.getKey().indexOf(query) != -1) {
                result.addAll(entry.getValue());
            }
        }
        return result;
    }

    private List<Dongle> donglesByNumber(String query) {
        List<Dongle> result = new ArrayList<>();
        Dongle dongle = dongles.get(query);
        if (dongle != null) {
            result.add(dongle);
        }
        return result;
    }

    private String dongleToString(Dongle dongle) {
        StringBuilder b = new StringBuilder();
        for (Application app : dongle.applications) {
            b.append(app.name).append('\n');
            char[] sep = new char[app.name.length()];
            Arrays.fill(sep, '-');
            b.append(new String(sep)).append('\n');
            for (String attr : app.attributes) {
                b.append(attr).append('\n');
            }
        }
        return b.toString();
    }


    public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser parser = spf.newSAXParser();
        DongleHandler handler = new DongleHandler();

        XMLReader reader = parser.getXMLReader();        
        reader.setContentHandler(handler);
        reader.parse(Test.class.getResource("test.xml").toString());

        Map<String, Dongle> dongles = new HashMap<>();        
        for (Dongle dongle : handler.getDongles()) {
            dongles.put(dongle.name, dongle);
        }

        SwingUtilities.invokeLater(() -> new Test(dongles, handler.getDescriptionIndex())
                .createAndShowGUI());
    }
}
```


----------



## Stiffler (23. Mai 2019)

Mega  kann man auch in den Ergebnissen die Description mit ausgeben?


----------



## mihe7 (23. Mai 2019)

Spoiler: Test.java





```
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

import java.util.*;
import java.io.*;

import java.awt.BorderLayout;
import java.awt.Font;
import javax.swing.*;

public class Test {
    static class Application {
        private final String name;
        private final List<String> attributes;
    
        public Application(String name, List<String> attributes) {
            this.name = name;
            this.attributes = attributes;
        }
    }

    static class Dongle {
        private final String name;
        private final List<Application> applications;

        public Dongle(String name, List<Application> applications) {
            this.name = name;
            this.applications = applications;
        }
    }

    static class Site {
        private final String description;
        private final List<Dongle> dongles;

        public Site(String description, List<Dongle> dongles) {
            this.description = description;
            this.dongles = dongles;
        }
    }

    static class DongleHandler extends DefaultHandler {
        boolean getText = false;
        StringBuilder text;
        String dongleName;
        String applicationName;
        String description;
        List<String> applicationAttributes = new ArrayList<>();
        List<Application> applications = new ArrayList<>();
        List<Dongle> dongles = new ArrayList<>();
        List<Dongle> siteDongles = new ArrayList<>();
        Map<String, List<Dongle>> descriptions = new HashMap<>();

        public List<Dongle> getDongles() { return dongles; }
        public Map<String, List<Dongle>> getDescriptionIndex() { return descriptions; }

        public void startElement(String uri, String localName, String qName, 
                Attributes atts) throws SAXException {    
            switch(qName) {
                case "Site":
                    description = "";
                    siteDongles = new ArrayList<>();
                    break;
                case "Description":
                    text = new StringBuilder();
                    getText = true;
                    break;
                case "Dongle": 
                    dongleName = atts.getValue("Number"); 
                    applications = new ArrayList<>();
                    break;
                case "Application": 
                    applicationName = atts.getValue("Name");
                    applicationAttributes = new ArrayList<>();
                    break;
                case "Attribute":
                    text = new StringBuilder();
                    getText = true;
                    break;
                default: break;
            }
        }

        public void characters(char[] ch, int start, int length) {
            if (getText) {
                text.append(ch, start, length);
            }
        }

        public void endElement(String uri, String localName, String qName) {
            switch(qName) {
                case "Attribute": 
                    applicationAttributes.add(text.toString());
                    getText = false;
                    break;
                case "Application":
                    applications.add(new Application(applicationName, applicationAttributes));
                    break;
                case "Dongle":
                    Dongle dongle = new Dongle(dongleName, applications);
                    dongles.add(dongle);
                    siteDongles.add(dongle);
                    break;
                case "Description":
                    getText = false;
                    description = text.toString();
                    break;
                case "Site":                    
                    descriptions.computeIfAbsent(description, d -> new ArrayList<>())
                            .addAll(siteDongles);
                    break;
            }
        }
    }

    private final Map<String, Dongle> dongles;
    private final Map<String, List<Dongle>> descriptions;

    public Test(Map<String, Dongle> dongles, Map<String, List<Dongle>> descriptions) {
        this.dongles = dongles;
        this.descriptions = descriptions;
    }

    public void createAndShowGUI() {
        JTextArea output = new JTextArea(30, 60);
        output.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
        JTextField tf = new JTextField(20);
        tf.addActionListener(e -> searchForDongles(tf.getText().trim(), output));
        JPanel input = new JPanel();
        input.add(new JLabel("Suche: "));
        input.add(tf);

        JPanel content = new JPanel(new BorderLayout(10,10));
        content.add(input, BorderLayout.NORTH);
        content.add(new JScrollPane(output));

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setContentPane(content);
        frame.pack();
        frame.setVisible(true);    
    }

    private void searchForDongles(String query, JTextArea output) {
        Map<String, List<Dongle>> found = donglesByNumber(query);
        if (found.isEmpty()) {
            found = donglesByDescription(query);
        }

        String text = "";
        if (found.isEmpty()) {
            text = String.format("Zu \"%s\" wurden keine passenden Dongles gefunden", query);
        } else {
            for (Map.Entry<String,List<Dongle>> entry : found.entrySet()) {
                String description = entry.getKey();
                StringJoiner j = new StringJoiner("\n");
                for (Dongle d : entry.getValue()) {
                    j.add(dongleToString(d, description));
                }
                text = j.toString();
            }
        }
        output.setText(text);
    }

    private Map<String, List<Dongle>> donglesByDescription(String query) {
        Map<String, List<Dongle>> result = new HashMap<>();
        for (Map.Entry<String, List<Dongle>> entry : descriptions.entrySet()) {
            String description = entry.getKey();
            if (description.indexOf(query) != -1) {
                result.put(description, entry.getValue());
            }
        }
        return result;
    }

    private Map<String, List<Dongle>> donglesByNumber(String query) {
        Map<String, List<Dongle>> result = new HashMap<>();
        Dongle dongle = dongles.get(query);
        if (dongle != null) {
            result.put("", Collections.singletonList(dongle));
        }
        return result;
    }

    private String dongleToString(Dongle dongle, String description) {
        StringBuilder b = new StringBuilder();
        if (!description.isEmpty()) {
            b.append("Description: ").append(description).append('\n');
        }
            
        for (Application app : dongle.applications) {
            b.append(app.name).append('\n');
            char[] sep = new char[app.name.length()];
            Arrays.fill(sep, '-');
            b.append(new String(sep)).append('\n');
            for (String attr : app.attributes) {
                b.append(attr).append('\n');
            }
        }
        return b.toString();
    }


    public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser parser = spf.newSAXParser();
        DongleHandler handler = new DongleHandler();

        XMLReader reader = parser.getXMLReader();        
        reader.setContentHandler(handler);
        reader.parse(Test.class.getResource("test.xml").toString());

        Map<String, Dongle> dongles = new HashMap<>();        
        for (Dongle dongle : handler.getDongles()) {
            dongles.put(dongle.name, dongle);
        }

        SwingUtilities.invokeLater(() -> new Test(dongles, handler.getDescriptionIndex())
                .createAndShowGUI());
    }
}
```


----------



## Stiffler (23. Mai 2019)

Die Suche findet immer nur ein Ergebnis richtig? Oder kann die Suche auch mehrere Ergebnisse finden? Wenn zum Beispiel zwei mal in der XML im abschnitt Description 2 mal "Leipzig" vorkommt listet die suche nur einmal auf. Quasi müsste man noch so eine Art weitersuchen machen? Der Parser geht ja von oben nach unten und hört auf sobald er ein Ergebnis gefunden hat auf?


----------



## mihe7 (23. Mai 2019)

Stiffler hat gesagt.:


> Die Suche findet immer nur ein Ergebnis richtig? Oder kann die Suche auch mehrere Ergebnisse finden? Wenn zum Beispiel zwei mal in der XML im abschnitt Description 2 mal "Leipzig" vorkommt listet die suche nur einmal auf.


Kleiner Fehler. Verwende die Methode:

```
private void searchForDongles(String query, JTextArea output) {
        Map<String, List<Dongle>> found = donglesByNumber(query);
        if (found.isEmpty()) {
            found = donglesByDescription(query);
        }

        String text = "";
        if (found.isEmpty()) {
            text = String.format("Zu \"%s\" wurden keine passenden Dongles gefunden", query);
        } else {
            StringJoiner j = new StringJoiner("\n");
            for (Map.Entry<String,List<Dongle>> entry : found.entrySet()) {
                String description = entry.getKey();
                for (Dongle d : entry.getValue()) {
                    j.add(dongleToString(d, description));
                }
            }
            text = j.toString();
        }
        output.setText(text);
    }
```


----------



## Stiffler (21. Jun 2019)

Ich stehe schon wieder vor der völligen Verzweiflung 
Wenn ich in der Suche nun nach der Description Suche Listet es mir ja auch die Description mit auf. Soweit so gut.
Nun wollte ich einfach nur bei der DongleNummer Suche auch das mir die Description mit ausgegeben wird.

Entweder schaffe ich es das der Code gar nicht mehr funktioniert oder er funktioniert zeigt mir aber nicht das gewünschte Ergebnis. 

```
private void searchForDongles(String query, JTextArea output) {
        Map<String, List<Dongle>> found = donglesByNumber(query);
        if (found.isEmpty()) {
            found = donglesByDescription(query);
        }

        String text = "";
        if (found.isEmpty()) {
            text = String.format("Zu \"%s\" wurden keine passenden Dongles gefunden", query);
        } else {
            StringJoiner j = new StringJoiner("\n");
            for (Map.Entry<String,List<Dongle>> entry : found.entrySet()) {
                String description = entry.getKey();
                for (Dongle d : entry.getValue()) {
                    j.add(dongleToString(d, description));
                }
            }
            text = j.toString();
        }
        output.setText(text);
    }
```

Von meinem Verständnis her muss ich doch in diesem Teil des Codes noch die Variable hinzufügen richtig?


----------



## mihe7 (21. Jun 2019)

Stiffler hat gesagt.:


> Listet es mir ja auch die Description mit auf. Soweit so gut.
> Nun wollte ich einfach nur bei der DongleNummer Suche auch das mir die Description mit ausgegeben wird.


Wenn sie aufgelistet wird, dann wird sie doch bereits ausgegeben.


----------



## Stiffler (21. Jun 2019)

mihe7 hat gesagt.:


> Wenn sie aufgelistet wird, dann wird sie doch bereits ausgegeben.


Wenn ich per Texteingabe suche "Leipzig" zum beispiel Listet mir die Suche die Description mit auf.
Suche jedoch nach einer Dongle Nummer, bekomme ich nur die Anzeige der Dongle // Application // Attribute - bei dieser Suchvariante wäre es aber auch gut die Description mit angezeigt zu bekommen da in der Description die Standort mit drin stehen und man so eine Dongle Nummer dem Standort direkt zuteilen kann.

Umständlich ich weis ....


----------



## Stiffler (24. Jun 2019)




----------



## mihe7 (24. Jun 2019)

Ja, das liegt daran, dass bei donglesByNumber keine Description gesetzt wird. In der main-Methode werden die IDs auf Dongles abgebildet. Dongles haben habe keine Beschreibung, weil die in der Site steckt. Das müsstest Du entsprechend anpassen.


----------



## Stiffler (25. Jun 2019)

Ich hatte einen Denkfehler aber dein Text hat mich gerettet  danke dir


----------

