0

This question is following my question limitations of xml unit . I’m wondering about the best element qualifier.

Now I have created two sample XMLs. Unfortunately I mustn’t post the real ones. The attached ones don’t make any sense, but they are good enough to show my Problem.

In this Case I want two cars to be found as similar, if the “metainfo” node is the same in both cases. After a short look at the output, I think, that the first car in the carshop is compared with the first one in the mixed carshop. I thought, that the RecursiveElementNameAndTextQualifier should identify the correct one.

Later (again no sense, just an example) there will be some customers which look like:

<customer>
<age></age>
<gender></gender>
<db_info>
    <id></id>
    <…></…>
</customer>

and should be identical, if the id is identical.

carshop.xml

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<delivery>
<cars>
    <car>
        <number>g:ki:1675</number>
        <manufactor>npqhtgmmfh</manufactor>
        <age>2</age>
        <localcar_id>6213</localcar_id>
        <metainfo>
            <keynumber>424</keynumber>
            <colour>1</colour>
        </metainfo>
    </car>
    <car>
        <number>b:ra:5287</number>
        <manufactor>tjmeugqcar</manufactor>
        <localcar_id>625</localcar_id>
        <metainfo>
            <keynumber>3238</keynumber>
            <colour>3</colour>
        </metainfo>
    </car>
    <car>
        <number>v:eu:5387</number>
        <localcar_id>4910</localcar_id>
        <metainfo>
            <keynumber>618</keynumber>
            <colour>6</colour>
        </metainfo>
    </car>
    <car>
        <number>f:fu:8242</number>
        <manufactor>ckpoaskabi</manufactor>
        <age>9</age>
        <localcar_id>8044</localcar_id>
        <metainfo>
            <keynumber>9865</keynumber>
            <colour>6</colour>
        </metainfo>
    </car>
</cars>
</delivery>

mixedcarshop

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<delivery>
<cars>
    <car>
        <number>f:fu:8242</number>
        <manufactor>ckpoaskabi</manufactor>
        <age>9</age>
        <localcar_id>8044</localcar_id>
        <metainfo>
            <keynumber>3238</keynumber>
            <colour>3</colour>
        </metainfo>
    </car>
    <car>
        <number>b:ra:5287</number>
        <manufactor>tjmeugqcar</manufactor>
        <localcar_id>625</localcar_id>
        <metainfo>
            <keynumber>9865</keynumber>
            <colour>6</colour>
        </metainfo>
    </car>
    <car>
        <number>v:eu:5387</number>
        <localcar_id>4910</localcar_id>
        <metainfo>
            <keynumber>424</keynumber>
            <colour>1</colour>
        </metainfo>
    </car>
    <car>
        <number>g:ki:1675</number>
        <manufactor>npqhtgmmfh</manufactor>
        <age>2</age>
        <localcar_id>6213</localcar_id>
        <metainfo>
            <keynumber>618</keynumber>
            <colour>6</colour>
        </metainfo>
    </car>
</cars>
</delivery>

JAVA Code:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.Difference;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;



 public class Arbeiter {

private File quelle, vergleich; 

public Arbeiter(File quelle, File vergleich) {
    this.quelle=quelle; 
    this.vergleich=vergleich;
}

public void vergleichen()
{
    long tbevore = System.currentTimeMillis();
    XMLUnit.setIgnoreAttributeOrder(Boolean.TRUE);
    XMLUnit.setIgnoreWhitespace(Boolean.TRUE);
    String f1 = lesen(quelle);
    String f2 = lesen(vergleich);

    try {
        Diff diff = new Diff(f1, f2);
        diff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
        List<String>liste = new ArrayList<String>();
        liste.add("number");
        liste.add("manufactor");
        liste.add("age");
        liste.add("localcar_id");
        //diff.overrideDifferenceListener(new IgnoreNamedElementsDifferenceListener(findSVSW_ID(quelle)));
        diff.overrideDifferenceListener(new IgnoreNamedElementsDifferenceListener(liste));
        DetailedDiff dd = new DetailedDiff(diff);
        boolean result = dd.similar();

        StringBuilder sb = new StringBuilder(); 

        sb.append("Die Dateien "+quelle.getName() +" und "+vergleich.getName()+" wurden miteinander verglichen \n \n");
        if (result ==true)
        {
            sb.append("Die Dateien sind inhaltsgleich \n");
        }
        else
        {
            sb.append("Die Dateien unterscheiden sich \n \n");
            List<Difference>list = dd.getAllDifferences();
            for (Difference aktuell : list)
            {
                if (!aktuell.isRecoverable())
                {
                    sb.append("Der Ausdruck "+aktuell.getControlNodeDetail().getValue()+" wurde gesucht \n");
                    sb.append("Der Ausdruck "+aktuell.getTestNodeDetail().getValue()+" wurde gefunden \n");
                    sb.append("Xpath: "+aktuell.getTestNodeDetail().getXpathLocation()+"\n \n");

                }
            }
        }
        long tafter = System.currentTimeMillis();
        String dauer = Long.toString((tafter-tbevore)/1000);
        sb.append("Die Bearbeitung dauerte " +dauer+" Sekunden \n");
        speichern(sb.toString());
        System.out.println("Bearbeitung abgeschlossen. Die Ausgabedatei wurde unter " +quelle.getParent()+"/ausgabe.txt abgelegt");

    }
    catch (Exception e)
    {
        e.printStackTrace();
    }




}

private String lesen(File datei)
{
    String result ="";
    try {
        BufferedReader leser = new BufferedReader(new FileReader(datei));
        StringBuilder sb = new StringBuilder();
        String gelesen = leser.readLine();
        while (gelesen!=null)
        {
            sb.append(gelesen);
            gelesen=leser.readLine();
        }
        result=sb.toString();
        leser.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return result;
}

private List<String> findSVSW_ID(File datei)
{
    List<String>liste = new ArrayList<String>();
    liste.add("AUFTRAGSCHLUESSEL");
    liste.add("LIEFERUNGSCHLUESSEL");
    try {
        BufferedReader leser = new BufferedReader(new FileReader(datei));
        String gelesen = leser.readLine();
        while (gelesen!=null)
        {
            if (gelesen.contains("SVSW_ID"))
            {
                String [] teile = gelesen.split(">");
                String temp = teile[0].replaceAll("<", "");
                if (!liste.contains(temp))
                {
                    String t2=temp.replaceAll(" ", "");
                    liste.add(t2);
                }

            }
            gelesen=leser.readLine();
        }


    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


    return liste;
}

private void speichern(String text)
{
    File datei = new File(quelle.getParent()+"/ausgabe.txt");
    try {
        BufferedWriter schreiber = new BufferedWriter(new FileWriter(datei));
        schreiber.write(text);
        schreiber.flush();
        schreiber.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}

thanks for help

Community
  • 1
  • 1
Michael Konz
  • 170
  • 15

1 Answers1

0

RecursiveElementNameAndTextQualifier is one of the most cited ElementQualifiers around, but it is almost never the one that you need. It matches two elements if their names match and the names of all their children (in correct order) match and the nested text of all children (in correct order) match. It will not be restricted to the metainfo child, but use the nested texts of all children.

ElementQualifier is invoked on the child elements of a given node and you need to have it pick the "correct" choice close enough to the root of the document. In your case when comparing the car elements. For those you'd need an ElementQualifier that accepts two elements as comparable if their metainfo/keynumber child's nested text matches.

There is no built-in ElementQualifer that would be selective enough, you'd have to write that yourself. What's even worse is that this custom ElementQualifier won't work for any of the other elements (there is no metainf/keynumber child for them) but still you must use a single ElementQualifier for the whole document. This means your custom implementation will become even more complex.

In XMLUnit 2.x there is a different solution as you can compose ElementSelectors (roughly equivalent to ElementQualifier in 1.x) and there is a conditional builder. Something like

ElementSelectors.conditionalBuilder()
  .whenElementIsNamed("car").thenUse(ElementSelectors.byXPath("./metainfo/keynumber", ElementSelectors.byNameAndText))
  .elseUse(ElementSelectors.byName)
  .build();

would probably work.

Stefan Bodewig
  • 3,260
  • 15
  • 22