Analiza składniowa łańcucha XML w JavaScript

204

Mam zmienny ciąg znaków, który zawiera poprawnie sformułowany i prawidłowy kod XML. Muszę użyć kodu JavaScript, aby przeanalizować ten kanał.

Jak mogę to zrobić za pomocą (zgodnego z przeglądarką) kodu JavaScript?

David Bonnici
źródło

Odpowiedzi:

90

Aktualizacja: Aby uzyskać bardziej poprawną odpowiedź, zobacz odpowiedź Tim Down .

Internet Explorer i, na przykład, przeglądarki oparte na Mozilli ujawniają różne obiekty do analizy XML, więc rozsądnie jest użyć frameworka JavaScript, takiego jak jQuery, do obsługi różnic między przeglądarkami.

Naprawdę podstawowym przykładem jest:

var xml = "<music><album>Beethoven</album></music>";

var result = $(xml).find("album").text();

Uwaga: jak wskazano w komentarzach; jQuery tak naprawdę nie wykonuje żadnej analizy XML, opiera się na metodzie DOM innerHTML i parsuje ją tak, jak każdy inny HTML, dlatego należy zachować ostrożność, używając nazw elementów HTML w pliku XML. Ale myślę, że działa całkiem dobrze w przypadku prostego „parsowania” XML, ale prawdopodobnie nie jest to sugerowane do intensywnego lub „dynamicznego” parsowania XML, w którym nie ma się z góry tego, co XML spadnie i to sprawdza, czy wszystko parsuje zgodnie z oczekiwaniami.

Szlifierka Versluys
źródło
6
Kod do wyodrębnienia różnicy w parsowaniu XML między IE a innymi przeglądarkami jest kilkoma trywialnymi liniami, więc nie warto sam dodawać 50K jQuery. Manipulowanie wynikowym DOM XML to inna sprawa.
Tim Down
7
I coś, czego nie zdawałem sobie sprawy w momencie publikowania mojego poprzedniego komentarza, to to, że jQuery nawet nie analizuje XML, po prostu przypisuje go jako innerHTMLwłaściwość elementu, co wcale nie jest wiarygodne.
Tim Down
Zauważ, że JQuery nie obsługuje przestrzeni nazw XML. Zobacz zachleat.com/web/2008/05/10/selecting-xml-with-javascript
mikemaccana
10
Ta odpowiedź jest zła. Zobacz stackoverflow.com/questions/2124924/... , stackoverflow.com/questions/2908899/... , odpowiedź @Tim Down i sama dokumentacja jQuery, w której stwierdza: „Uwaga: [ jQuery()] analizuje HTML, a nie XML”
Crescent Fresh
2
@SanderVersluys: skoro autor nie przyjmuje innej odpowiedzi, do twojej odpowiedzi dołączę notatkę zawierającą poprawną odpowiedź @ TimDown . W ten sposób ludzie nie muszą czytać wszystkich tych komentarzy, aby znaleźć prawidłową odpowiedź.
Rozsądny
321

Zaktualizowana odpowiedź na rok 2017

Poniżej parsuje ciąg XML do dokumentu XML we wszystkich głównych przeglądarkach. O ile nie potrzebujesz obsługi IE <= 8 lub jakiejś niejasnej przeglądarki, możesz użyć następującej funkcji:

function parseXml(xmlStr) {
   return new window.DOMParser().parseFromString(xmlStr, "text/xml");
}

Jeśli potrzebujesz obsługi IE <= 8, następujące zadanie będzie działać:

var parseXml;

if (typeof window.DOMParser != "undefined") {
    parseXml = function(xmlStr) {
        return new window.DOMParser().parseFromString(xmlStr, "text/xml");
    };
} else if (typeof window.ActiveXObject != "undefined" &&
       new window.ActiveXObject("Microsoft.XMLDOM")) {
    parseXml = function(xmlStr) {
        var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = "false";
        xmlDoc.loadXML(xmlStr);
        return xmlDoc;
    };
} else {
    throw new Error("No XML parser found");
}

Po Documentuzyskaniu przez parseXml, możesz użyć zwykłych metod / właściwości przejścia DOM, takich jak childNodesi, getElementsByTagName()aby uzyskać żądane węzły.

Przykładowe użycie:

var xml = parseXml("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);

Jeśli używasz jQuery, od wersji 1.5 możesz użyć jego wbudowanej parseXML()metody, która jest funkcjonalnie identyczna z powyższą funkcją.

var xml = $.parseXML("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);
Tim Down
źródło
56
Zgadzam się, ta odpowiedź powinna zostać zaakceptowana. Moja odpowiedź jest tak stara od samego początku, że zawsze jest ciekawa, że ​​wciąż zyskuje aprobatę. Czy ktoś popiera usunięcie mojej zaakceptowanej odpowiedzi? I czy system głosowania jest wadliwy? Głosuj za tym ludem!
Sander Versluys,
@SanderVersluys: Czy jesteś w stanie usunąć swoją odpowiedź?
Witman
1
Musiałem zlekceważyć cię za powiedzenie, że „nie ma innych przyzwoitych odpowiedzi”. @SanderVersluys odpowiedź działała dobrze w moim przypadku. Co nie jest w tym przyzwoitego, nie wiem.
eryczny
2
@EricTurner: Stoję przy tym, a sam Sander nie zgadza się z odpowiedzią. Dokumenty jQuery mówią, aby nie używać $()do analizowania XML . Przeczytaj uważniej komentarze: po prostu nie działa w wielu sytuacjach.
Tim Down
1
@DWoldrich: Widziałem to w obie strony w sieci i podejrzewam, że działa w obie strony. Najbardziej wiarygodną odpowiedzią jest msdn.microsoft.com/en-us/library/ms761398(v=vs.85).aspx , która mówi, że należy użyć logiki. Jednak i jak wiele wartości umieścisz w tym, zależy wyłącznie od Ciebie, metoda jQueryparseXML() używa łańcucha. Nieufnie zmieniam odpowiedź, ponieważ nie mam teraz łatwego sposobu na przetestowanie jej.
Tim Down
19

Większość przykładów w Internecie (i niektóre przedstawione powyżej) pokazują, jak załadować XML z pliku w sposób zgodny z przeglądarką. Jest to łatwe, z wyjątkiem Google Chrome, który nie obsługuje tej document.implementation.createDocument()metody. Podczas korzystania z Chrome, aby załadować plik XML do obiektu XmlDocument, musisz użyć wbudowanego obiektu XmlHttp, a następnie załadować plik, przekazując jego identyfikator URI.

W twoim przypadku scenariusz jest inny, ponieważ chcesz załadować XML ze zmiennej łańcuchowej , a nie adresu URL. Jednak w przypadku tego wymagania Chrome działa podobnie jak Mozilla (a przynajmniej tak słyszałem) i obsługuje metodę parseFromString ().

Oto funkcja, której używam (jest to część biblioteki zgodności przeglądarki, którą obecnie tworzę):

function LoadXMLString(xmlString)
{
  // ObjectExists checks if the passed parameter is not null.
  // isString (as the name suggests) checks if the type is a valid string.
  if (ObjectExists(xmlString) && isString(xmlString))
  {
    var xDoc;
    // The GetBrowserType function returns a 2-letter code representing
    // ...the type of browser.
    var bType = GetBrowserType();

    switch(bType)
    {
      case "ie":
        // This actually calls into a function that returns a DOMDocument 
        // on the basis of the MSXML version installed.
        // Simplified here for illustration.
        xDoc = new ActiveXObject("MSXML2.DOMDocument")
        xDoc.async = false;
        xDoc.loadXML(xmlString);
        break;
      default:
        var dp = new DOMParser();
        xDoc = dp.parseFromString(xmlString, "text/xml");
        break;
    }
    return xDoc;
  }
  else
    return null;
}
Cerebrus
źródło
16
Zdaję sobie sprawę z kontrowersyjnych opinii dotyczących wąchania przeglądarki i dlatego nie zawarłem tutaj tej funkcji. Jednak nie ustalono, że jest on NIEPRAWIDŁOWY. W każdym razie jest to sugestywny przykład.
Cerebrus
1
Uważam, że to jest złe, ponieważ nie możesz zagwarantować, że jest to właściwe. Każdy może sfałszować ciągi znaków UA i wątpliwe jest, aby KAŻDY przeglądarka inna niż IE obsługuje DOMParser, i że twoje wąchanie przeglądarki jest IDEALNE. Poza tym dużo łatwiej jest to zrobić we właściwy sposób:if(window.ActiveXObject){...}
1j01
Więc teraz IE9 + obsługuje DOMParser , jak zamierzasz to obsługiwać? -1 za to, co mówi @ 1j01. Wszystko, co musisz sprawdzić, to var dp; try{ dp = new DOMParser() } catch(e) { }; if(dp) { // DOMParser supported } else { // alert('you need to consider upgrading your browser\nOr pay extra money so developer can support the old versions using browser sniffing (eww)') }.
Annie
13

Marknote to niezły, lekki, parser JavaScript XML. Jest zorientowany obiektowo i zawiera wiele przykładów, a interfejs API jest udokumentowany. Jest dość nowy, ale jak dotąd ładnie sprawdził się w jednym z moich projektów. Jedną z rzeczy, które lubię w tym, jest to, że będzie czytać XML bezpośrednio z ciągów lub adresów URL i możesz go również użyć do konwersji XML na JSON.

Oto przykład tego, co możesz zrobić z Marknote:

var str = '<books>' +
          '  <book title="A Tale of Two Cities"/>' +
          '  <book title="1984"/>' +
          '</books>';

var parser = new marknote.Parser();
var doc = parser.parse(str);

var bookEls = doc.getRootElement().getChildElements();

for (var i=0; i<bookEls.length; i++) {
    var bookEl = bookEls[i];
    // alerts "Element name is 'book' and book title is '...'"
    alert("Element name is '" + bookEl.getName() + 
        "' and book title is '" + 
        bookEl.getAttributeValue("title") + "'"
    );
}
Mike McMillien
źródło
Wygląda na to, że marknote implementuje czysty parser javascript. Oznacza to, że powinien być kompatybilny z dowolnym silnikiem javascript, niezależnie od tego, gdzie jest używany w przeglądarce, w node.js lub w samodzielnym silniku javascript ...
Coyote
8

Zawsze stosowałem poniższe podejście, które działa w IE i Firefox.

Przykładowy XML:

<fruits>
  <fruit name="Apple" colour="Green" />
  <fruit name="Banana" colour="Yellow" />
</fruits>

JavaScript:

function getFruits(xml) {
  var fruits = xml.getElementsByTagName("fruits")[0];
  if (fruits) {
    var fruitsNodes = fruits.childNodes;
    if (fruitsNodes) {
      for (var i = 0; i < fruitsNodes.length; i++) {
        var name = fruitsNodes[i].getAttribute("name");
        var colour = fruitsNodes[i].getAttribute("colour");
        alert("Fruit " + name + " is coloured " + colour);
      }
    }
  }
}
John Topley
źródło
Jak byś wziął wartość, gdybyś miał taką sytuację <fruit> wartość </fruit>?
Siblja
1
@Siblja musisz użyć innerTextzamiastgetAttribute()
Manux22
2

Proszę spojrzeć na XML DOM Parser ( W3Schools ). Jest to samouczek na temat analizy XML DOM. Rzeczywisty analizator składni DOM różni się w zależności od przeglądarki, ale interfejs API DOM jest znormalizowany i pozostaje taki sam (mniej więcej).

Alternatywnie użyj E4X, jeśli możesz ograniczyć się do Firefoksa. Jest stosunkowo łatwiejszy w użyciu i jest częścią JavaScript od wersji 1.6. Oto przykładowe użycie ...

//Using E4X
var xmlDoc=new XML();
xmlDoc.load("note.xml");
document.write(xmlDoc.body); //Note: 'body' is actually a tag in note.xml,
//but it can be accessed as if it were a regular property of xmlDoc.
Samouk
źródło
0
<script language="JavaScript">
function importXML()
{
    if (document.implementation && document.implementation.createDocument)
    {
            xmlDoc = document.implementation.createDocument("", "", null);
            xmlDoc.onload = createTable;
    }
    else if (window.ActiveXObject)
    {
            xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.onreadystatechange = function () {
                    if (xmlDoc.readyState == 4) createTable()
            };
    }
    else
    {
            alert('Your browser can\'t handle this script');
            return;
    }
    xmlDoc.load("emperors.xml");
}

function createTable()
{
    var theData="";
    var x = xmlDoc.getElementsByTagName('emperor');
    var newEl = document.createElement('TABLE');
    newEl.setAttribute('cellPadding',3);
    newEl.setAttribute('cellSpacing',0);
    newEl.setAttribute('border',1);
    var tmp = document.createElement('TBODY');
    newEl.appendChild(tmp);
    var row = document.createElement('TR');
    for (j=0;j<x[0].childNodes.length;j++)
    {
            if (x[0].childNodes[j].nodeType != 1) continue;
            var container = document.createElement('TH');
            theData = document.createTextNode(x[0].childNodes[j].nodeName);
            container.appendChild(theData);
            row.appendChild(container);
    }
    tmp.appendChild(row);
    for (i=0;i<x.length;i++)
    {
            var row = document.createElement('TR');
            for (j=0;j<x[i].childNodes.length;j++)
            {
                    if (x[i].childNodes[j].nodeType != 1) continue;
                    var container = document.createElement('TD');
                    var theData = document.createTextNode(x[i].childNodes[j].firstChild.nodeValue);
                    container.appendChild(theData);
                    row.appendChild(container);
            }
            tmp.appendChild(row);
    }
    document.getElementById('writeroot').appendChild(newEl);
}
</script>
</HEAD>

<BODY onLoad="javascript:importXML();">
<p id=writeroot> </p>
</BODY>

Aby uzyskać więcej informacji, zapoznaj się z tym http://www.easycodingclub.com/xml-parser-in-javascript/javascript-tutorials/

easycodingclub
źródło
0

Oświadczenie : Stworzyłem szybki parser xml

Utworzyłem szybki parser xml do analizowania łańcucha XML w obiekcie JS / JSON lub pośrednim obiekcie przechodzenia. Oczekuje się, że będzie kompatybilny we wszystkich przeglądarkach (jednak testowany tylko w Chrome, Firefox i IE).

Stosowanie

var options = { //default
    attrPrefix : "@_",
    attrNodeName: false,
    textNodeName : "#text",
    ignoreNonTextNodeAttr : true,
    ignoreTextNodeAttr : true,
    ignoreNameSpace : true,
    ignoreRootElement : false,
    textNodeConversion : true,
    textAttrConversion : false,
    arrayMode : false
};

if(parser.validate(xmlData)){//optional
    var jsonObj = parser.parse(xmlData, options);
}

//Intermediate obj
var tObj = parser.getTraversalObj(xmlData,options);
:
var jsonObj = parser.convertToJson(tObj);

Uwaga : Nie używa parsera DOM, ale analizuje ciąg za pomocą RE i przekształca go w obiekt JS / JSON.

Wypróbuj online , CDN

Amit Kumar Gupta
źródło
-1

Możesz także użyć funkcji jquery ($. ParseXML), aby manipulować łańcuchem xml

przykładowy javascript:

var xmlString = '<languages><language name="c"></language><language name="php"></language></languages>';
var xmlDoc = $.parseXML(xmlString);
$(xmlDoc).find('name').each(function(){
    console.log('name:'+$(this).attr('name'))
})
użytkownik6016338
źródło