Estoy analizando algunos XML en JavaScript del lado del servidor. El XML se devuelve mediante una llamada a otro servidor. Estoy usando una versión modificada de una solución que encontré en Con expresiones regulares, ¿cómo puedo hacer coincidir una etiqueta XML varias veces? y probé la RegExp con el probador en http://www.regular-expressions.info/javascriptexample.html.

Se devuelven unos 1280 registros y funciona casi todo el tiempo. Pero hoy noté que alrededor de 30 registros no se analizan correctamente. Algunos campos terminan siendo nulos cuando se analizan y no puedo entender por qué.

Una muestra de una expresión regular que estoy creando en un bucle es

<field name="URL_ProProfs"><data>(.+?)<\/data><\/field>

Y un ejemplo de un registro que estoy analizando es

<record mod-id="439" record-id="6640">
    <field name="Name">
        <data>Inviting Young Children to Explore Process Art</data>
    </field>
    <field name="Byline_Presenter">
        <data> Presented by MaryAnn F. Kohl, Author, Educator, and Presenter </data>
    </field>
    <field name="Date">
        <data>11/14/2016</data>
    </field>
    <field name="URL_On_Demand">
        <data> https://www.anymeeting.com/843-066-411/E954DB85814B38 </data>
    </field>
    <field name="URL_ProProfs">
        <data> https://www.proprofs.com/quiz-school/story.php?title=quiz-18-classroommanagementwebinar20161114_3WO </data>
    </field>
    <field name="Status">
        <data>1</data>
    </field>
    <field name="URL_Blog">
        <data> http://home.edweb.net/webinar/young-children-explore-process-art/ </data>
    </field>
    <field name="Channel_1">
        <data>Arts in Education</data>
    </field>
    <field name="Channel_2">
        <data>Early Childhood Learning</data>
    </field>
    <field name="Channel_3">
        <data/>
    </field>
    <field name="Channel_4">
        <data/>
    </field>
    <field name="Name_Community">
        <data>classroommanagement</data>
    </field>
    <field name="Webinars_COMMUNITIES::Name_Long">
        <data>Classroom Management for Early Learning</data>
    </field>
    <field name="_ID_Community">
        <data>.5a1dcfde</data>
    </field>
</record>

Si utilizo esa expresión regular en el probador con esa cadena, la analiza correctamente y puedo encontrar el valor de retorno para ese campo como el segundo elemento del resultado de la matriz .exec:

https://www.proprofs.com/quiz-school/story.php?title=quiz-18-classroommanagementwebinar20161114_3WO

Pero a veces, dependiendo de alguna razón que no puedo comprender, obtengo valores nulos devueltos para diferentes campos que estoy analizando. En este caso, para el campo URL_ProfProps.

Estoy usando el siguiente ciclo para hacer un ejecutivo en RegExp para encontrar todos los valores en el registro. La función en sí se llama para cada registro.

function webinarParse(record) {
  var r = new Object();
  var fields = ["Name", "Byline_Presenter", "Date", "URL_On_Demand", "URL_Blog", "URL_ProProfs", "Name_Community", "Webinars_COMMUNITIES::Name_Long", "Channel_1", 
                "Channel_2", "Channel_3", "Channel_4", "_ID_Community"];

  for (f=0; f<fields.length; f++) {
      var re = new RegExp('<field name="' + fields[f] + '"><data>(.+?)<\/data><\/field>');
      var m = re.exec(record);
      if (m == null) {
        r[fields[f]] = "";
      } else {
        if (fields[f] == 'Date') {
            r[fields[f]] = new Date(m[1]);
        }
        else {
            if (m[1].indexOf('<data>') != -1) {
                // greedy match captured from next field when there was no data present
                r[fields[f]] = "";
            }
            else {
                r[fields[f]] = m[1];
            }
        }
      }
  }  
  return r;
}

El registro de parámetros es un registro de todos los registros XML que devolví.

El Object () r es mi valor de retorno.

Los campos Array () son una lista de valores que estoy analizando.

En el ciclo, creo una nueva RegExp para cada elemento de los campos para ver si hay un valor para devolver.

Si re.exec (registro) es nulo, simplemente establezco una cadena vacía para esa propiedad en r.

Si el campo es una cadena de fecha, establezco un objeto Date para esa propiedad.

Entonces tengo que tener cuidado porque el XML está regresando.

<data /> 

Si no hay datos, en lugar de

<data></data>

Así que verifico eso. En otras palabras, si hay datos, debería haber un

<data> 

Etiqueta. Si no lo hay, no quiero agarrar demasiado.

Estoy registrando el análisis sintáctico de cada registro y funciona aproximadamente 1250 veces de 1280. Pero para algunos registros, uno o dos de los campos no se están analizando, aunque he confirmado que hay datos en el XML.

El ejemplo anterior es uno que parece analizar correctamente en la página del probador, pero en mi ciclo, el valor de URL_ProPofs devuelve un valor nulo.

¿Alguna idea sobre mi RegExp o bucle haciendo esto? Simplemente no puedo entender por qué a veces simplemente no encuentra el valor.

Gracias.

0
Doug Lerner 3 ene. 2017 a las 12:06
2
Sin siquiera leer la pregunta completa, le advierto que no use expresiones regulares para analizar XML. En su lugar, utilice un analizador XML.
 – 
Tim Biegeleisen
3 ene. 2017 a las 12:07
1
Nunca use patrones de coincidencia de puntos con lenguajes de marcado. Nunca confíe en expresiones regulares al analizar (X) HTML.
 – 
Wiktor Stribiżew
3 ene. 2017 a las 12:09
Pero hubo una respuesta aceptada para esto que lo hace en stackoverflow.com/questions/4341421/… y solo estoy siguiendo esa pista.
 – 
Doug Lerner
3 ene. 2017 a las 12:11
2
@DougLerner: Una respuesta aceptada a menudo puede ser una respuesta incorrecta. Hace algunos días, arreglé una de las respuestas de mi hijo de 2 años que no tenía sentido, pero fue aceptada. Si ve .*? / .* o .+? / .+ en una expresión regular que está destinada a analizar HTML, sepa que ya no es seguro si hay contexto en ambos lados, ya que en tu caso. Porque . coincide con < y > y cualquier carácter que no sean caracteres de salto de línea. Además, la expresión regular <tag>(.*?)</tag> puede congelar la ejecución de su código en caso de que el texto sea enorme y haya <tag> sin </tag> en el texto (cuando HTML está roto).
 – 
Wiktor Stribiżew
3 ene. 2017 a las 12:14
Citando el viejo chiste, si preguntas qué zapato usar para clavar un clavo, no obtendrás información útil de todos modos.
 – 
Álvaro González
3 ene. 2017 a las 12:22

1 respuesta

La mejor respuesta

La respuesta corta: use XPath / XQuery para consultar y acceder a datos en un documento XML, le dará mucha más flexibilidad y eliminará los casos específicos como además han sido diseñados para ese propósito.

En cuanto a la expresión regular, '.' no coincide con las líneas nuevas, por lo que debe agregar \r y \n y también agregar coincidencias para lo que pueda estar entre <field...> y <data...> así como entre </data> y </field>.

Con todo eso, terminarás con una expresión regular como esta

<field name="URL_ProProfs">[\s\n\r]*?<data>((?:.|[\n\r])*?)<\/data>[\s\r\n]*?<\/field>

Aquí hay un ejemplo de trabajo: https://regex101.com/r/07xgks/4 pero tenga en cuenta que esto solo funcionará mientras no tenga datos anidados en datos, el xml sea válido y así sucesivamente ...

2
Foxtrot 3 ene. 2017 a las 17:46
Gracias. Creo que funciona. En algunas partes de su expresión regular, incluso puede ser excesivo, pero lo he probado y parece funcionar tanto en el sitio de prueba como cuando lo reemplazo en mi propio código. Revisaré XPath / XQuery y veré si se puede usar en mi sistema. Pero mientras tanto, su nueva expresión funciona, e incluso (en su mayoría) es comprensible para mí. En este caso particular, definitivamente no tengo datos anidados y se me garantiza un XML válido. Así que gracias.
 – 
Doug Lerner
3 ene. 2017 a las 18:12
Tengo una pregunta rápida sobre su solución, que funciona. Podemos cambiar a conversación privada si lo prefiere. Entiendo el \ s \ n \ r] *? parte antes de la etiqueta de datos y después de la etiqueta de datos /. Esas son las partes que probablemente sean exageradas para mi caso, pero seguro que no duelen. Y entiendo el [\ n \ r]) *? expresión dentro del campo de datos. Y conozco el | es OR. Pero, ¿qué hace el?:. expresión significa? Sé el período que hay para cualquier personaje excepto para las nuevas líneas. Y ? es evitar partidos codiciosos. ¿Pero no entiendo?:. y el propósito de: dos puntos. Gracias.
 – 
Doug Lerner
4 ene. 2017 a las 03:08
El ?: indica un grupo que no captura a la expresión regular, básicamente indica que (?:.|[\n\r]) se debe a que, de lo contrario, obtendría un grupo adicional con el último carácter de la coincidencia debido al |. Ahora que releí mi respuesta, creo que puedes simplificarlo a <field name="URL_ProProfs">[\s\S]*?data>([\s\S]*?)<\/data>[\s\S]*?<\/field>. El [\s\S]*? coincidirá con cualquier número de espacios en blanco \s o no espacios en blanco \S tan pocas veces como sea posible.
 – 
Foxtrot
4 ene. 2017 a las 10:12
Gracias por la explicación adicional. Creo entender. Para tu nueva versión te refieres a <field name="URL_ProProfs">[\s\S]*?<data>([\s\S]*?)<\/data>[\s\S]*?<‌​\/field> ¿verdad? En tu comentario no tenías un < antes del data>.
 – 
Doug Lerner
4 ene. 2017 a las 10:28