Jak wczytać dane z pliku XML do HTML używając JavaScript?

0

Cześć,
oto mój kod: http://jsfiddle.net/kj1n8uqz/8/
Chciałbym, aby użytkownik po kliknięciu przycisku "Wczytaj" mógł wybrać sobie sam który plik chce wczytać. Dany plik jest wczytywany jako XML i uzupełniany w odpowiednie inputy/selecty i wyświetlony na stronie. Proszę nie piszcie "użyj JSON", do tego zadania mam użyć formatu XML. Jeżeli chodzi o nazwę name, które są takie same jak "choice" i "choice1" to niestety ale muszą takie zostać (przydatne jest to w innych elementach tego zadania którego tutaj nie załączyłem).

Plik XML do wczytania:

<?xml version="1.0"?>
<K1>
<punkty name="choice" value="4" checked="false"></punkty>
<punkty name="choice" value="3" checked="false"></punkty>
<punkty name="choice" value="2" checked="false"></punkty>
<punkty name="choice" value="1" checked="false"></punkty>
<punkty name="total" value="0" checked="false"></punkty>
<punkty name="choice1" value="4" checked="false"></punkty>
<punkty name="choice1" value="3" checked="false"></punkty>
<punkty name="choice1" value="2" checked="false"></punkty>
<punkty name="choice1" value="1" checked="false"></punkty>
<punkty name="total1" value="0" checked="false"></punkty>
</K1>
<P1>
<punkty value="5" id="valueOne"></punkty>
<punkty value="0" id="valueOne1"></punkty>
<punkty value="0" id="valueOne2"></punkty>
<punkty value="0" id="valueOne3"></punkty>
<punkty value="3" id="valueOne4"></punkty>
<punkty value="0" id="valueOne5"></punkty>
</P1>

Czy da się to jakoś zrobić? Jeżeli tak to w jaki sposób? Gdzie powinienem szukać rozwiązania? Trochę się z tym męczyłem ale generalnie nie za bardzo wiem od czego zacząć.
Za wszelkie uwagi/wskazówki byłbym naprawdę bardzo wdzięczny! :)

Pozdrawiam

2

Możesz do tego wykorzystać AJAX. Tutaj masz przykład

0
jawlo napisał(a):

Możesz do tego wykorzystać AJAX. Tutaj masz przykład

Bardzo pomocny link, dzięki! Tyle, że tutaj przy wczytaniu tworzy się tabelę. W jaki sposób wczytać dane w już istniejące input'y/select'y?

1

Dopiero się uczę JS i do AJAX/XML/JSON jeszcze nie doszedłem. Ale kolega wyżej podał bardzo pomocny link. Przeanalizujmy go. (Mam nadzieje, że ktoś mnie poprawi jak coś źle opiszę).

// krótko mówiąc to ta funkcja pobiera dokument, ścieżkę dokumentu podajesz w drugim atrybucie xhttp.open
function loadDoc() {
  var xhttp = new XMLHttpRequest(); // Tworzy zmienna dla zapytania HttpXML
  xhttp.onreadystatechange = function() { // Podpinamy się pod zdarzenie  on ready state change tego zapytania, czyli kiedy status gotowości się zmienni... 
    if (this.readyState == 4 && this.status == 200) { // domyślam się, że ten warunek sprawdza czy zapytanie jest już gotowe?, załadowany do zmiennej xhttp
      myFunction(this); // jeżeli jest, to wykonaj jakość funkcję której przekażesz to zapytanie
    }
  };
  xhttp.open("GET", "cd_catalog.xml", true); // utwórz/skonfiguruj zapytanie  ?
  xhttp.send(); // wyślij zapytanie do serwera
}

//następnie w funkcji 'myFunction(xml)', obrabiasz, wyciągasz sobie dane z dokumentu xml
function myFunction(xml) {
  var i;
  var xmlDoc = xml.responseXML; // tutaj do zmiennej xmlDoc pobierasz sobie swój dokument xml
  //dalej z tego co widzę operujesz jak na elementach DOM(HTML). Czyli wyciągasz informację za pomocą //getElement, querySelector, child, parent
  var table="<tr><th>Artist</th><th>Title</th></tr>";
  var x = xmlDoc.getElementsByTagName("CD"); 
  for (i = 0; i <x.length; i++) { 
    table += "<tr><td>" +
    x[i].getElementsByTagName("ARTIST")[0].childNodes[0].nodeValue +
    "</td><td>" +
    x[i].getElementsByTagName("TITLE")[0].childNodes[0].nodeValue +
    "</td></tr>";
  }
  document.getElementById("demo").innerHTML = table;
}

Zwróć uwagę jaką wygląda ten przykładowy plik XML:

<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
<CD>
<TITLE>Greatest Hits</TITLE>
<ARTIST>Dolly Parton</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>RCA</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1982</YEAR>
</CD>
<CD>
<TITLE>Still got the blues</TITLE>
<ARTIST>Gary Moore</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Virgin records</COMPANY>
<PRICE>10.20</PRICE>
<YEAR>1990</YEAR>
</CD>
<CD>
<TITLE>Eros</TITLE>
<ARTIST>Eros Ramazzotti</ARTIST>
<COUNTRY>EU</COUNTRY>
<COMPANY>BMG</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1997</YEAR>
</CD>
<CD>
<TITLE>One night only</TITLE>
<ARTIST>Bee Gees</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>Polydor</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1998</YEAR>
</CD>

P.S: Z tego co wiem to AJAX nie będzie działał lokalnie, musisz postawić sobie jakiś serwer żeby się z tym bawić ?,

0
debug napisał(a):

Dopiero się uczę JS i do AJAX/XML/JSON jeszcze nie doszedłem. Ale kolega wyżej podał bardzo pomocny link. Przeanalizujmy go. (Mam nadzieje, że ktoś mnie poprawi jak coś źle opiszę).

Generalnie nie musisz wyjaśniać po kolei co się dzieje, w miarę to jakoś ogarniam.

P.S: Z tego co wiem to AJAX nie będzie działał lokalnie, musisz postawić sobie jakiś serwer żeby się z tym bawić ?,

Testowałem ten kod bez xamppa i działa bez problemu.

Napisałem podobną wersję co jest na w3schools: https://next.plnkr.co/edit/gGs3ygTBRWa8jSahpePP?p=preview&utm_source=legacy&utm_medium=worker&utm_campaign=next&preview
Niestety wsadzenie tego w ten sposób do input'a nie daje żadnych efektów. W jaki sposób można to zrobić?

1

Zmień innerHTML na value

document.getElementById("demo").value = xmlDoc.getElementsByTagName("title")[0].childNodes[0].nodeValue;

0

Nie miałem za bardzo czasu i dopiero dzisiaj mogłem przy tym posiedzieć.

Faktycznie po zastosowaniu .value, dane dobrze się ładują, jednak w jaki sposób z tego pliku XML:

<test>
<K1>
<punkty name="choice" value="4" checked="false">4</punkty>
<punkty name="choice" value="3" checked="false"></punkty>
<punkty name="choice" value="2" checked="false"></punkty>
<punkty name="choice" value="2" checked="false"></punkty>
<punkty name="choice" value="1" checked="true"></punkty>
<punkty name="total" value="0" checked="false"></punkty>
<punkty name="choice1" value="4" checked="false"></punkty>
<punkty name="choice1" value="3" checked="false"></punkty>
<punkty name="choice1" value="2" checked="false"></punkty>
<punkty name="choice1" value="1" checked="true"></punkty>
<punkty name="total1" value="0" checked="false"></punkty>
</K1>
<P1>
<punkty value="8" id="valueOne"></punkty>
<punkty value="0" id="valueOne1"></punkty>
<punkty value="0" id="valueOne2"></punkty>
<punkty value="8" id="valueOne3"></punkty>
<punkty value="0" id="valueOne4"></punkty>
<punkty value="0" id="valueOne5"></punkty>
</P1>
</test>

załadować dane do odpowiednich checkboxów czy select'ów, tak aby dany checkbox/select był zaznaczony? Jak widać wartość do input: https://next.plnkr.co/edit/rSzSlZuFRpmykZJG
ładuje się tylko wtedy gdy między

<punkty>4</punkty> 

jest wstawiona jakaś wartość, wartości

value=4 

nie uznaje.

0

A gdzie masz funkcję checkTotal()?

0
jawlo napisał(a):

A gdzie masz funkcję checkTotal()?

Tutaj:

    var sum = 0;
        function checkTotal() {
            document.myForm.total.value = '';
            var result = [0];
            for (i=0;i<document.myForm.choice.length;i++) {
              if (document.myForm.choice[i].checked) {
                  result.push(document.myForm.choice[i].value);                
              }
			  sum = Math.max.apply(null, result);
            }
            document.myForm.total.value = sum;
			document.Form.total.value = document.myForm.total.value;
        }
        var sum1 = 0;
            function checkTotal1() {
                document.myForm.total1.value = '';
                var result = [0];
                for (i=0;i<document.myForm.choice1.length;i++) {
                  if (document.myForm.choice1[i].checked) {
                      result.push(document.myForm.choice1[i].value);                    
                  }
				  sum1 = Math.max.apply(null, result);
                }
                document.myForm.total1.value = sum1;
				document.Form.total1.value = document.myForm.total1.value;
            }
function oblicz(){            
	document.Form.totalResult.value=document.myForm.total.value*document.myForm.total1.value;
}

Ale nie zamieszczałem jej gdyż w napotkanym problemie nie jest ona potrzebna a powoduje kod bardziej nieczytelnym.

1
<punkty name="choice" value="3" checked="false"></punkty>

Potraktuj to jak by to był elmente DOM, tak samo jak byś miał np.

<input id="demo1" name="choice" type="checkbox" value="4">

id, name, type, value - są to atrybuty elementu, są dwa sposoby żeby wyciągnąć takie atrybuty pierwszy to element.getAttribute('nazwa atrybutu') link do strony gdzie jest to wytłumaczone https://www.w3schools.com/jsref/met_element_getattribute.asp
Drugi sposób to: element.attributes[i].value. gdzie i określa który atrybut chcesz np w przypadku twojego elementu punkty to: 0 - name, 1 - value, 2 - checked

w praktyce u ciebie wyglądało by to tak:

const ele = xmlDoc.getElementsByTagName("punkty")[0];
    ele.attributes[1].value; // pobierze wartość atrybutu value;
//lub
    ele.getAttribute('value'); // pobierze wartość atrybutu value;
0
debug napisał(a):

w praktyce u ciebie wyglądało by to tak:

const ele = xmlDoc.getElementsByTagName("punkty")[0];
    ele.attributes[1].value; // pobierze wartość atrybutu value;
//lub
    ele.getAttribute('value'); // pobierze wartość atrybutu value;

No ok, dzięki! Zrobiłem to tak:
https://next.plnkr.co/edit/VHsLOHVtSD8eCxEq?preview

Dlaczego checkbox'y nie są zaznaczone? Czy może to trzeba zrobić w jakiś inny sposób. Jeżeli tak, to jaki?

2
document.getElementById("demo3").value = xmlDoc.getElementsByTagName('punkty')[2].getAttribute( 'checked' )

W powyższym kodzie, zmieniasz wartość atrybutu value, który nie jest odpowiedzialny za zaznaczanie checbox'a.
Prosty przykład:

document.getElementById("demo3").checked = true// zaznaczy checkboxa
document.getElementById("demo3").checked = false // odznaczy checkboxa

Jest jeszcze pytanie, to czy checkbox mam być zaznaczony czy nie, też masz pobierać z XML ?.
Jeżeli tak, to musisz pobrać wartość atrybut checked z XML:

xmlDoc.getElementsByTagName('punkty')[2].getAttribute( 'checked' );

I w zależności od tego co dostaniesz ustawić input.chcecked na true lub false. Zwróć uwagę na to, że getAttribute( 'checked') zwróci Ci stringa a każdy string oprócz pustego = true;

0
debug napisał(a):

Jest jeszcze pytanie, to czy checkbox mam być zaznaczony czy nie, też masz pobierać z XML ?.
Jeżeli tak, to musisz pobrać wartość atrybut checked z XML:

xmlDoc.getElementsByTagName('punkty')[2].getAttribute( 'checked' );

I w zależności od tego co dostaniesz ustawić input.chcecked na true lub false. Zwróć uwagę na to, że getAttribute( 'checked') zwróci Ci stringa a każdy string oprócz pustego = true;

Tak, w zależności od tego co siedzi w XML, dany checkbox jest ustawiany na true/false.
Poprawiłem kod i wygląda następująco: https://next.plnkr.co/edit/eYtsAzp1aflIceBf

Mimo tego że w konsoli otrzymuje wyniki true/false oba checkbox'y są zaznaczone. Pytanie dlaczego?
Jeżeli wpisuje wartości true/false ręcznie wszystko działa jak należy.

Checkbox'y są zaznaczone (błędnie) tylko wtedy gdy program odpalam na firefox'ie. Gdy odpalam na Operze czy Chrome nic nie jest zaznaczone. Z czego to wynika?
Czy może problem trzeba obejść w inny sposób?

0

Ok, myślę, że poprzedni problem już rozwiązałem.
https://next.plnkr.co/edit/HEH78KZFV1GDo9Mv
Ten kod nie jest do końca uaktualniony, chodzi mi o coś innego. O możliwość wczytania tego pliku przez użytkownika, a nie w kodzie podając jego nazwę. Aby było czytelniej:
Kod, który ładuje się na stronie:

<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        myFunction(this);
    }
};
xhttp.open("GET", "data.xml", true);
xhttp.send();

function myFunction(xml) {
    var xmlDoc = xml.responseXML;   
	
	document.getElementById("input1K1S1").value = xmlDoc.getElementsByTagName('punktyk1')[0].getAttribute( 'value' );
	document.getElementById("input1K1S1").checked = (xmlDoc.getElementsByTagName('punktyk1')[0].getAttribute( 'checked' )== 'true');
	
	document.getElementById("valueOne").value = xmlDoc.getElementsByTagName('punktyp1')[0].getAttribute( 'value' );
	
}
</script>

A tutaj kod wybrania pliku z dysku:

<script>
function readSingleFile(e) {
  var file = e.target.files[0];
  if (!file) {
    return;
  }
  var reader = new FileReader();
  reader.onload = function(e) {
    var contents = e.target.result;
  };
  reader.readAsText(file);
}

function displayContents(contents) {
  var element = document.getElementById('file-content');
  element.textContent = contents;
}

document.getElementById('file-input')
  .addEventListener('change', readSingleFile, false);
</script>
<input type="file" id="file-input" />


W miejsce "data.xml" chciałem wstawić "readSingleFile" ale to nie pomogło. W jaki sposób to połączyć? W jaki sposób sprawić aby plik, który wybierzemy z pulpitu załadował się tak samo jak "data.xml"?

0

Prośba o pomoc. Mam funkcję, którą wyciągam poszczególne powtarzalne sekcje xmla (tutaj zmienna text) oznaczone przykładowo tagiem "book"
Następnie z wyodrębnionych sekcji mogę wyciągać poszczególne elementy np oznaczone tagiem "title" i przypisywać ich wartości do zmiennym a1, a2 itd.
Wszystko działa ok jeśli w każdej sekcji "book" element "title" zawsze wystąpi. Ale zakładam przypadek, że może nie wystąpić. Wtedy zmienna a(n) nie powinna być tworzona. Myślałem, że załatwi to poniższy sposób z warunkiem ale pojawia się błąd "x[i].getElementsByTagName(...)[0</a> is undefined". W przykładzie dwie powtarzalne sekcje, z czego w pierwszej nie występuje element "title", a w drugiej już tak.

var parser, xmlDoc;
var text = "<bookstore><book><author>Giada De Laurentiis</author><year>2005</year></book><book><title>Everyday1 Italian</title><author>Giada De Laurentiis</author><year>2005</year></book></bookstore>";

parser = new DOMParser();
xmlDoc = parser.parseFromString(text,"text/xml");
var x = xmlDoc.getElementsByTagName("book");
for (i = 0; i <x.length; i++) { 
  
   if (x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue !== undefined) //tu jak rozumiem problem
   {
    var name= "a" + (i+1);
   window[name] = x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue
    }

}
console.log(a2)
1

Sprawdź taki warunek:

if (x[i].getElementsByTagName("title")[0] !== undefined)
0

@jawlo: Super. Dzięki Wielkie. Działa.
A czy jest jakiś sposób na przypadek gdy w XMLu pojawi się zapis: "<title></title>".
Proponowane przez Ciebie rozwiązanie skutkuje:

"<a class='gotoLine' href='#177:21] TypeError: x[i].getElementsByTagName(...)[0].childNodes[0'>177:21] TypeError: x[i].getElementsByTagName(...)[0].childNodes[0</a> is undefined"

2

Jeśli nie obchodzi cię IE 11 i FF < 74 to możesz użyć Optional chaining i po prostu dodać znaki zapytania tam gdzie nie jesteś pewien że coś będzie:

if (x[i].getElementsByTagName("title")[0]?.childNodes[0]?.nodeValue !== undefined)

możesz też użyć babel lub typescriptu żeby przekonwertować taki kod na kompatybilny ze starszymi przeglądarkami albo po prostu wszędzie sprawdzać po każdym kroku czy coś jest undefined, czyli tak jak powyżej:

if (x[i].getElementsByTagName("title")[0] !== undefined)

a potem

if (x[i].getElementsByTagName("title")[0].childNodes[0] !== undefined)

itp (oczywiście możesz to połączyć w jeden if, albo przypisać części do zmiennej żeby nie powtarzać kodu)

1
Pesob napisał(a):

A czy jest jakiś sposób na przypadek gdy w XMLu pojawi się zapis: "<title></title>".
Proponowane przez Ciebie rozwiązanie skutkuje:

"<a class='gotoLine' href='#177:21] TypeError: x[i].getElementsByTagName(...)[0].childNodes[0'>177:21] TypeError: x[i].getElementsByTagName(...)[0].childNodes[0</a> is undefined"

Jeżeli znacznik <title></title> jest "pusty" to jego wartość jest undefined.
Możemy to przetestować:

if( x[i].getElementsByTagName("title")[0].childNodes[0] === undefined )

1 użytkowników online, w tym zalogowanych: 0, gości: 1