Søgning i XML-databaser fra søgefelter





Søgninger i XML-filer

Søgning og ekstraktion af data er nok det de fleste forbinder med konceptet databaser, og det kan man også med XML-databaser.

Med JavaScript er det en relativt let opgave at søge og returnere oplysninger. Den løsning der gennemgås her, er ikke den eneste rigtige løsning, det er én måde at gøre det på, som fungerer.


XML-filen

XML-filen til eksemplet er et redigeret uddrag af en af XML-databaserne til et EU-projekt der hedder SAMANCTA. Den originale fil er meget længere, og indeholder også links til andre sider. Strukturen er denne:

<?xml version="1.0" encoding="UTF-8">
<HS_Numbers>

<HS_Number_text>
<HS_Chapter>0101</HS_Chapter>
<HS_SubNumber>0101.21</HS_SubNumber>
<HS_SubNumber_Title_DA><![CDATA[Heste; levende racerene avlsdyr]]></HS_SubNumber_Title_DA>
<Products_DA><![CDATA[dyr; pattedyr; heste]]></Products_DA>
</HS_Number_text>

<HS_Number_text>
<HS_Chapter>0101</HS_Chapter>
<HS_SubNumber>0101.29</HS_SubNumber>
<HS_SubNumber_Title_DA><![CDATA[Heste; andre end levende racerene avlsdyr]]></HS_SubNumber_Title_DA>
<Products_DA><![CDATA[dyr; pattedyr; heste]]></Products_DA>
</HS_Number_text>



<HS_Number_text>
<HS_Chapter>0106</HS_Chapter>
<HS_SubNumber>0106.49</HS_SubNumber>
<HS_SubNumber_Title_DA><![CDATA[Insekter, levende, ikke andetsteds tariferet i kapitel 1]]></HS_SubNumber_Title_DA>
<Products_DA><![CDATA[dyr; insekter]]></Products_DA>
</HS_Number_text>

<HS_Number_text>
<HS_Chapter>0106</HS_Chapter>
<HS_SubNumber>0106.90</HS_SubNumber>
<HS_SubNumber_Title_DA><![CDATA[Dyr, levende, ikke andetsteds tariferet i kapitel 1]]></HS_SubNumber_Title_DA>
<Products_DA><![CDATA[dyr]]></Products_DA>
</HS_Number_text>

</HS_Numbers>

Listen får navnet HS_Codes.xml, og ligger her i samme directory som HTML-filen med JavaScriptet der søger i listen.


JavaScriptet

Når man skal lave en søgning som denne, er det hensigstmæssigt at dele JavaScriptet op i flere dele. Vil man gerne gøre noget andet, af den ene eller den anden grund, er man selvfølgelig meget velkommen til dette.

JavaScriptet består af fem dele:
  1. Indlæsning af XML-filen
  2. Indlæsning af teksten der skal søges på
  3. Gennemløb af XML-filens Products_DA-felt
  4. Hvis Products_DA-feltet indeholder søgekriteriet, skrives indholdet fra felterne HS_SubNumber og HS_SubNumber_Title_DA (de to oplysninger brugerne skal bruge for ved søgning), i hver sit array, dvs. en liste.
  5. Hvis der findes et eller flere match skrives indholdet fra de to array i et skrivefelt. I modsat fald skrives en meddelelse om at der ikke er fundet noget math.

I dette eksempel deler vi opgaven op i 2 functions i den samme fil. Det er ikke strengt nødvendigt, men det er godt til at holde overblikket over opgaven, især i udviklingsfasen. Filen kalder vi SearchInProduccts.js, og den placerer vi i directoriet JavaScripts, som beskrevet på siden om interne og eksterne JavaScripts her.

De to functions kalder vi SearchProductIndex() og ShowProductResults(). Så langt ser JavaScriptet nu således ud:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() { }


function ShowProductResults() { }

</SCRIPT>

Det første der skal gøres er at indlæse XML-filen HS_Codes.xml. Til dette anvender vi JavaScriptet loadXMLDoc(). Hvordan det er lavet, kan læses her. Så ser JavaScriptet således ud:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() {
xmlDoc=loadXMLDoc("HS_Codes.xml");
}


function ShowProductResults() { }

</SCRIPT>

Vi skal nu bruge fire variabler. En der læser indholdet i skrivefeltet SearchProduct, tre der læser felterne Products_DA, HS_SubNumber og HS_SubNumber_Title_DA i XML-filen. Det første felt er det vi traverserer i søgningen og de to andre er felterne der skal returneres. Derfor også de valgte navne på variablerne. Så ser koden således ud:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() {
xmlDoc=loadXMLDoc("HS_Codes.xml");

var SearchTerm = document.getElementById("SearchProduct").value;
var AllItems = xmlDoc.getElementsByTagName("Products_DA");
var ReturnItemSubNumber = xmlDoc.getElementsByTagName("HS_SubNumber");
var ReturnItemTitle = xmlDoc.getElementsByTagName("HS_SubNumber_Title_DA");

}


function ShowProductResults() { }

</SCRIPT>

Fordi det ikke giver mening at søge på et tomt felt, er det første vi gør at se efter om søgefeltet, dvs. SearchTerm, er tomt. Hvis det er, skal der poppe en fejlmeddelelse op, og ellers skal proceduren gå videre. Så ser det således ud:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() {
xmlDoc=loadXMLDoc("HS_Codes.xml");

var SearchTerm = document.getElementById("SearchProduct").value;
var AllItems = xmlDoc.getElementsByTagName("Products_DA");
var ReturnItemSubNumber = xmlDoc.getElementsByTagName("HS_SubNumber");
var ReturnItemTitle = xmlDoc.getElementsByTagName("HS_SubNumber_Title_DA");

if (SearchTerm.length < 1) {
alert("Du glemte at indtaste et søgeord!");
}

else {
}

}


function ShowProductResults() { }

</SCRIPT>

Det else der skal laves er to arrays, som vi kalder Results1 og Results2. Variablen AllItems, dvs. feltet Products_DA i XML-filen bliver traverseret. Hvis rutinen finder tekststrengen i SearchTerm bliver indholdet af felterne HS_SubNumber og HS_SubNumber_Title_DA gemt i de to arrays. Så ser koden således ud:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() {
xmlDoc=loadXMLDoc("HS_Codes.xml");

var SearchTerm = document.getElementById("SearchProduct").value;
var AllItems = xmlDoc.getElementsByTagName("Products_DA");
var ReturnItemSubNumber = xmlDoc.getElementsByTagName("HS_SubNumber");
var ReturnItemTitle = xmlDoc.getElementsByTagName("HS_SubNumber_Title_DA");

if (SearchTerm.length < 1) {
alert("Du glemte at indtaste et søgeord!");
}

else {
Results1 = new Array;
for (var i=0;i<AllItems.length;i++) {
var name = AllItems[i].lastChild.nodeValue;
var exp = new RegExp(SearchTerm,"i");
if (name.match(exp) != null) {
Results1.push(ReturnItemSubNumber[i]);
}
}

Results2 = new Array;
for (var i=0;i
var name2 = AllItems[i].lastChild.nodeValue;
var exp2 = new RegExp(SearchTerm,"i");
if (name2.match(exp2) != null) {
Results2.push(ReturnItemTitle[i]);
}
}
}

}


function ShowProductResults() { }

</SCRIPT>

Vi har nu de to lister vi skal bruge og kan nu vise dem med den function der hedder ShowProductResults(). For at gøre dette, skal vi overføre variablerne Results1, Results2 og SearchTerm til ShowProductResults(). Dette gøres således:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() {
xmlDoc=loadXMLDoc("HS_Codes.xml");

var SearchTerm = document.getElementById("SearchProduct").value;
var AllItems = xmlDoc.getElementsByTagName("Products_DA");
var ReturnItemSubNumber = xmlDoc.getElementsByTagName("HS_SubNumber");
var ReturnItemTitle = xmlDoc.getElementsByTagName("HS_SubNumber_Title_DA");

if (SearchTerm.length < 1) {
alert("Du glemte at indtaste et søgeord!");
}

else {
Results1 = new Array;
for (var i=0;i<AllItems.length;i++) {
var name = AllItems[i].lastChild.nodeValue;
var exp = new RegExp(SearchTerm,"i");
if (name.match(exp) != null) {
Results1.push(ReturnItemSubNumber[i]);
}
}

Results2 = new Array;
for (var i=0;i
var name2 = AllItems[i].lastChild.nodeValue;
var exp2 = new RegExp(SearchTerm,"i");
if (name2.match(exp2) != null) {
Results2.push(ReturnItemTitle[i]);
}
}
}

ShowProductResults(Results1, Results2, SearchTerm);
}


function ShowProductResults() { }

</SCRIPT>


Vi skal nu have de tre variabler læst ind i ShowProductResults(), og vi skal se om der blev fundet et eller flere match ved søgningen. For at se om der blev fundet noget eller ej, spørges der på om variablen Results1 er tom. Så ser koden således ud:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() {
xmlDoc=loadXMLDoc("HS_Codes.xml");

var SearchTerm = document.getElementById("SearchProduct").value;
var AllItems = xmlDoc.getElementsByTagName("Products_DA");
var ReturnItemSubNumber = xmlDoc.getElementsByTagName("HS_SubNumber");
var ReturnItemTitle = xmlDoc.getElementsByTagName("HS_SubNumber_Title_DA");

if (SearchTerm.length < 1) {
alert("Du glemte at indtaste et søgeord!");
}

else {
Results1 = new Array;
for (var i=0;i<AllItems.length;i++) {
var name = AllItems[i].lastChild.nodeValue;
var exp = new RegExp(SearchTerm,"i");
if (name.match(exp) != null) {
Results1.push(ReturnItemSubNumber[i]);
}
}

Results2 = new Array;
for (var i=0;i
var name2 = AllItems[i].lastChild.nodeValue;
var exp2 = new RegExp(SearchTerm,"i");
if (name2.match(exp2) != null) {
Results2.push(ReturnItemTitle[i]);
}
}
}

ShowProductResults(Results1, Results2, SearchTerm);
}


function ShowProductResults(Results1, Results2, SearchTerm) {
if (Results1.length > 0) {
}

else {
}

}


</SCRIPT>

Hvis der er fundet et match, består det at returnere et læsevenligt svar i at gribe fat i feltet der skal skrives til med getElementById() og sætte indholdet på med appendChild(). For at få det sat pænt op, bygger man det op med tags via createElement() og styling af disse med style.cssText. Vær opmærksom på, at når man skal tilføje tekst med koder skal man bruge innerHTML i stedet for createTextNode(), for ellers bliver ens kode vist i tekstfeltet i stedet for at blive brugt til formateringen. Så ser koden således ud:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() {
xmlDoc=loadXMLDoc("HS_Codes.xml");

var SearchTerm = document.getElementById("SearchProduct").value;
var AllItems = xmlDoc.getElementsByTagName("Products_DA");
var ReturnItemSubNumber = xmlDoc.getElementsByTagName("HS_SubNumber");
var ReturnItemTitle = xmlDoc.getElementsByTagName("HS_SubNumber_Title_DA");

if (SearchTerm.length < 1) {
alert("Du glemte at indtaste et søgeord!");
}

else {
Results1 = new Array;
for (var i=0;i<AllItems.length;i++) {
var name = AllItems[i].lastChild.nodeValue;
var exp = new RegExp(SearchTerm,"i");
if (name.match(exp) != null) {
Results1.push(ReturnItemSubNumber[i]);
}
}

Results2 = new Array;
for (var i=0;i
var name2 = AllItems[i].lastChild.nodeValue;
var exp2 = new RegExp(SearchTerm,"i");
if (name2.match(exp2) != null) {
Results2.push(ReturnItemTitle[i]);
}
}
}

ShowProductResults(Results1, Results2, SearchTerm);
}


function ShowProductResults(Results1, Results2, SearchTerm) {
if (Results1.length > 0) {

var ResultsProduct = document.getElementById("ResultsProduct");
while(ResultsProduct.firstChild)ResultsProduct.removeChild(ResultsProduct.firstChild)
var Header = document.createElement("H5");
var List = document.createElement("DIV");
List.style.cssText = 'margin-left:20px';
var SearchedFor = document.createTextNode("Dokumenter med nøgleordet \""+SearchTerm+"\":");
ResultsProduct.appendChild(Header);
Header.appendChild(SearchedFor);
ResultsProduct.appendChild(List);
for (var i=0;i<Results1.length;i++) {
var ListItem = document.createElement("DIV");
ListItem.style.cssText = 'font-weight:bold';
var ChapterItem = document.createTextNode(Results1[i].lastChild.nodeValue);
var TextItem = document.createTextNode(": ");
var SubtitleDiv = document.createElement("SPAN");
SubtitleDiv.innerHTML = Results2[i].lastChild.nodeValue;
SubtitleDiv.style.cssText = "font-weight:normal";
List.appendChild(ListItem);
ListItem.appendChild(ChapterItem);
ListItem.appendChild(TextItem);
ListItem.appendChild(SubtitleDiv);
}
}

else {
}

}


</SCRIPT>

Hvis der ikke bliver fundet et match, skal der returneres en besked om at man ikke har fundet noget på det søgte. Dette bygges op på samme måde som når man har fundet noget, blot i en simplere form. Så ser den færdige kode således ud:

<SCRIPT TYPE="text/javascript">

function SearchProductIndex() {
xmlDoc=loadXMLDoc("HS_Codes.xml");

var SearchTerm = document.getElementById("SearchProduct").value;
var AllItems = xmlDoc.getElementsByTagName("Products_DA");
var ReturnItemSubNumber = xmlDoc.getElementsByTagName("HS_SubNumber");
var ReturnItemTitle = xmlDoc.getElementsByTagName("HS_SubNumber_Title_DA");

if (SearchTerm.length < 1) {
alert("Du glemte at indtaste et søgeord!");
}

else {
Results1 = new Array;
for (var i=0;i<AllItems.length;i++) {
var name = AllItems[i].lastChild.nodeValue;
var exp = new RegExp(SearchTerm,"i");
if (name.match(exp) != null) {
Results1.push(ReturnItemSubNumber[i]);
}
}

Results2 = new Array;
for (var i=0;i
var name2 = AllItems[i].lastChild.nodeValue;
var exp2 = new RegExp(SearchTerm,"i");
if (name2.match(exp2) != null) {
Results2.push(ReturnItemTitle[i]);
}
}
}

ShowProductResults(Results1, Results2, SearchTerm);
}


function ShowProductResults(Results1, Results2, SearchTerm) {
if (Results1.length > 0) {

var ResultsProduct = document.getElementById("ResultsProduct");
while(ResultsProduct.firstChild)ResultsProduct.removeChild(ResultsProduct.firstChild)
var Header = document.createElement("H5");
var List = document.createElement("DIV");
List.style.cssText = 'margin-left:20px';
var SearchedFor = document.createTextNode("Dokumenter med nøgleordet \""+SearchTerm+"\":");
ResultsProduct.appendChild(Header);
Header.appendChild(SearchedFor);
ResultsProduct.appendChild(List);
for (var i=0;i<Results1.length;i++) {
var ListItem = document.createElement("DIV");
ListItem.style.cssText = 'font-weight:bold';
var ChapterItem = document.createTextNode(Results1[i].lastChild.nodeValue);
var TextItem = document.createTextNode(": ");
var SubtitleDiv = document.createElement("SPAN");
SubtitleDiv.innerHTML = Results2[i].lastChild.nodeValue;
SubtitleDiv.style.cssText = "font-weight:normal";
List.appendChild(ListItem);
ListItem.appendChild(ChapterItem);
ListItem.appendChild(TextItem);
ListItem.appendChild(SubtitleDiv);
}
}

else {

var ResultsProduct = document.getElementById("ResultsProduct");
while(ResultsProduct.firstChild)ResultsProduct.removeChild(ResultsProduct.firstChild)
var Para = document.createElement("P");
var NotFound = document.createTextNode("Desværre ingen dokumenter med nøgleordet \""+SearchTerm +"\" tilgængelig!");
ResultsProduct.appendChild(Para);
Para.appendChild(NotFound);
}

}


</SCRIPT>

Der er nu taget høde for alle typer udfald af søgningen, og vi er klar til at læse, søge og skrive.


Læse- og skrivefelterne

Til læsning og skrivning, skal vi bruge en FORM med et felt til input, her givet ID="SearchProduct", og en knap der eksekverer JavaScriptet SearchProductIndex(). Derefter skal der bruges et felt til output, her en DIV med ID="ResultsProduct".

Som kode ser det således ud:

<B>Produkttype</B><BR>

<FORM ONSUBMIT="searchProductIndex(); return false;" ACTION="">
<INPUT TYPE="text" ID="SearchProduct">
<INPUT TYPE="submit" VALUE="Søg" ONCLICK="SearchProductIndex(); return false;">
</FORM>
<BR><BR>

<B>Liste over procedurekort for prøveudtagning</B><BR>
<DIV ID="ResultsProduct"></DIV>
<BR><BR>


På skærmen kommer det til at se således ud:

Produkttype


Liste over procedurekort for prøveudtagning