estrai tutto il contenuto di testo in htmlcollection nell'array con javascript

Sep 08 2020

Ecco i dati grezzi

anycasestr = "<div style="color: rgb(51, 51, 51); background-color: rgb(253, 246, 227); font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-size: 12px; line-height: 18px;"><div>refinement</div><div>decent</div><div>elegant</div></div>";

per estrarre tutto il contenuto di testo in un array come ["raffinatezza", "decente", "elegante"]

Ho scritto questo codice (jquery è stato incluso)

htmlObject = $(anycasestr);
arr = Array.prototype.slice.call(htmlObject[0].getElementsByTagName("div"));
arr_page = [];
for (i = 0; i < 3; i++) {
    arr_page.push(arr[i].textContent);
}

Produce quello che voglio.

Sono solo preoccupato se è implementato in modo elegante. Qualcuno potrebbe dargli un'occhiata?

Ad esempio, avrei dovuto usare xpath o qualcosa del genere, in termini di problemi di calcolo?

Risposte

3 CertainPerformance Sep 08 2020 at 08:12

Dichiara le tue variabili : ogni volta che assegni o fai riferimento a una variabile senza prima definirla, (1) creerai implicitamente una proprietà sull'oggetto globale (che può causare strani bug), o (2) genererai un errore, se tu stai eseguendo in modalità rigorosa. Al momento non stai definendo nessuna delle tue variabili. Risolvilo mettendo const(o, quando necessario, let) davanti a loro quando li assegni per la prima volta, ad es const htmlObject = $(anycasestr);.

Metodi jQuery o DOM? Stai usando jQuery per trasformare la stringa in una raccolta di elementi jQuery, ma poi stai usando getElementsByTagNameper selezionare i bambini. Se stai usando jQuery, puoi essere conciso e coerente per usarlo per selezionare i <div>figli .. Per trovare i figli di un elemento che corrispondono a un particolare nome di tag, chiama .findla raccolta jQuery - quindi, puoi usare .mapper trasformare il trovato jQuery in una raccolta del solo testo degli elementi:

const $parent = $(anycasestr); const arr = $parent.find('div')
  .map((_, child) => child.textContent)
  .get(); // turn the jQuery collection of strings into an array of strings

const anycasestr = `<div style="color: rgb(51, 51, 51); background-color: rgb(253, 246, 227); font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-size: 12px; line-height: 18px;"><div>refinement</div><div>decent</div><div>elegant</div></div>`;
const $parent = $(anycasestr);
const arr = $parent.find('div')
  .map((_, child) => child.textContent)
  .get(); // turn the jQuery collection of strings into an array of strings
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

In alternativa, puoi utilizzare DOMParser. L'utilizzo di DOMParser anziché jQuery per trasformare il testo in una raccolta di elementi può evitare l'esecuzione accidentale di script dannosi. Exploit di esempio utilizzando jQuery:

const anycasestr = `<img src="" onerror="alert('evil')">`;
const $parent = $(anycasestr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Con DOMParser:

const anycasestr = `<div style="color: rgb(51, 51, 51); background-color: rgb(253, 246, 227); font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-size: 12px; line-height: 18px;"><div>refinement</div><div>decent</div><div>elegant</div></div>`;
const doc = new DOMParser().parseFromString(anycasestr, 'text/html');
const arr = [...doc.querySelectorAll('div > div')]
  .map(div => div.textContent);
console.log(arr);

La stringa di query div > divseleziona gli <div>elementi che sono figli diretti di un altro <div>. Funziona esattamente allo stesso modo dei selettori CSS. querySelectorAllè un ottimo strumento per la selezione concisa di elementi: può essere più facile scrivere e capire a colpo d'occhio rispetto ad altri metodi (come l'originale htmlObject[0].getElementsByTagName("div")).

Array.prototype.slice.callè un po 'prolisso: su ambienti non antichi, puoi invece usare la sintassi diffusa, come ho fatto sopra. Creare un array tutto in una volta mediante mappatura è anche un po 'più elegante che dichiarare un array e poi .pushinserirlo su di esso.

Se avessi più <div>figli e volessi prendere solo il testo dai primi 3 di essi, sarebbe più funzionale .sliceall'array di elementi invece di inserire un conteggio delle iterazioni in un forciclo:

const anycasestr = `<div style="color: rgb(51, 51, 51); background-color: rgb(253, 246, 227); font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-size: 12px; line-height: 18px;">
  <div>refinement</div>
  <div>decent</div>
  <div>elegant</div>
  <div>don't include me</div>
  <div>don't include me</div>
  <div>don't include me</div>
</div>`;
const doc = new DOMParser().parseFromString(anycasestr, 'text/html');
const arr = [...doc.querySelectorAll('div > div')]
  .slice(0, 3)
  .map(div => div.textContent);
console.log(arr);

in termini di preoccupazioni computazionali?

A meno che le cose che devono essere analizzate non siano irragionevolmente grandi , le prestazioni per questo genere di cose non sono un problema; meglio scrivere codice pulito, leggibile e manutenibile. Se in seguito si scopre che l'esecuzione di qualcosa richiede più tempo del previsto, è possibile identificare il collo di bottiglia e quindi capire come risolverlo. (Ma questo quasi certamente non sarà il collo di bottiglia.)