SAXParseException: 'El atributo "" vinculado al espacio de nombres "nulo" ya se especificó para el elemento "métrico"'

StackOverflow https://stackoverflow.com/questions/1612411

Pregunta

En el trabajo, acabamos de migrar una aplicación web antigua de struts 1.1 a 1.2.9 (con suerte, los primeros pasos para pasar a 1.3), pero ahora estamos teniendo problemas con el digestor común. Struts 1.2.9 utiliza commons-digester 1.6.

Cuando intentamos analizar uno de nuestros archivos XML obtenemos la excepción:

org.xml.sax.SAXParseException: Attribute "" bound to namespace "null" was already specified for element "metric".
    at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:232)
    at org.apache.xerces.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:213)
    at org.apache.xerces.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:385)
    at org.apache.xerces.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:315)
    at org.apache.xerces.impl.dtd.XMLNSDTDValidator.startNamespaceScope(XMLNSDTDValidator.java:242)
    at org.apache.xerces.impl.dtd.XMLDTDValidator.handleStartElement(XMLDTDValidator.java:1980)
    at org.apache.xerces.impl.dtd.XMLDTDValidator.startElement(XMLDTDValidator.java:802)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:313)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(XMLNSDocumentScannerImpl.java:610)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(XMLDocumentFragmentScannerImpl.java:1608)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:346)
    at org.apache.xerces.parsers.DTDConfiguration.parse(DTDConfiguration.java:529)
    at org.apache.xerces.parsers.DTDConfiguration.parse(DTDConfiguration.java:585)
    at org.apache.xerces.parsers.XMLParser.parse(XMLParser.java:152)
    at org.apache.xerces.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1142)
    at org.apache.commons.digester.Digester.parse(Digester.java:1572)
    at com.foo.ctms.framework.metrics.parser.MetricsXMLParser$InternalDigester.parse(MetricsXMLParser.java:54)
    at com.foo.ctms.framework.metrics.parser.MetricsXMLParser.parse(MetricsXMLParser.java:40)

Al investigar este problema, he tratado de obtener un caso lo más simple posible y esto es lo que tengo actualmente:

package com.foo.ctms.framework.metrics.parser;

import org.apache.commons.digester.Digester;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.net.URL;

/**
 * Class that provides methods for parsing metrics definitions defined via XML and populating an object graph of JavaBeans
 * representing the definition.
 * @version $Revision: 41470 $
 */
public final class MetricsXMLParser {
  /**
   * The set of public identifiers, and corresponding resource names, for the versions of the configuration file DTD that we know
   * about.  The key is the name of the resource as in the XMl file, and the value is the location of the resource with respect to
   * the <code>ClassLoader</code> that this code in running in.
   */
  private static final String registrations[] = {"-//Foo Inc.//DTD Portal Metrics 1.0//EN", "metrics.dtd"};

  private MetricsXMLParser() {
  }

  /**
   * Parses a metric definition specified as an <code>InputStream</code>.
   * @param url The metrics definition to parse. Must not be <code>null</code>.
   * @throws IOException  if an I/O error occured while attempting to parse
   * @throws SAXException if an XML parsing error occured
   */
  public static MetricDefinition parse(URL url)
          throws IOException, SAXException {
    InternalDigester digester = new InternalDigester();
    return digester.parse(url);
  }

  private static final class InternalDigester {
    private final Digester digester;

    /**
     * Parses a metric definition specified as an <code>InputStream</code>.
     * @param input The metrics definition to parse. Must not be <code>null</code>.
     * @throws IOException  if an I/O error occured while attempting to parse
     * @throws SAXException if an XML parsing error occured
     */
    public MetricDefinition parse(URL input)
            throws IOException, SAXException {
      return (MetricDefinition)digester.parse(new InputSource(input.toString()));
    }

    private InternalDigester() {
      digester = new Digester();
      digester.setValidating(true);
      for (int i = 0; i < MetricsXMLParser.registrations.length; i += 2) {
        URL url = getClass().getResource(MetricsXMLParser.registrations[i + 1]);
        if (url != null) {
          digester.register(MetricsXMLParser.registrations[i], url.toString());
        }
      }

      digester.addObjectCreate("metric", MetricDefinition.class);
      digester.addSetProperties("metric");
    }
  }
}

que recibe el XML:

<?xml version='1.0' encoding='windows-1252'?>
<!DOCTYPE metric PUBLIC "-//Foo Inc.//DTD Portal Metrics 1.0//EN" "metrics.dtd">

<metric name="metricsConfig" defaultView="trials">

</metric>

El DTD está actualmente en:     

<!-- A metric element is the document root -->
<!ELEMENT metric ANY>

<!-- A metric has a name and a default view.  The default view must
     exactly match the name of one of the nested views -->
<!ATTLIST metric
    name CDATA #REQUIRED
    defaultView CDATA #IMPLIED
>

¿Alguien sabe lo que estoy haciendo mal?

Si elimino el atributo defaultView, no obtengo el error.


Según la sugerencia de sfussenegger, ahora he intentado el siguiente código (no relacionado con la digestión):

try {
  SAXParserFactory factory = SAXParserFactory.newInstance();
  factory.setNamespaceAware(false);
  factory.setValidating(true);
  SAXParser parser = factory.newSAXParser();
  XMLReader reader = parser.getXMLReader();
  reader.parse(new InputSource(url.toString()));
} catch (Exception e) {
  e.printStackTrace();
}

y no pudo reproducir el problema, pero agregar lo siguiente (lo que también hace digers-digester en XercesParser) antes de usar mi fábrica da la misma excepción:

factory.setFeature("http://apache.org/xml/features/validation/dynamic", true);
factory.setFeature("http://apache.org/xml/features/validation/schema", true);

Al final, hemos decidido probar una versión más moderna de xerces (2.7.1) y eso parece funcionar.

¿Fue útil?

Solución

El problema parece haber sido causado por una incompatibilidad entre commons-digester 1.6 y xerces (la llamada en XercesParser dice 2.2), el cambio a una versión más reciente de xerces (2.7.1) ha solucionado el problema.

Elegimos esta versión de la biblioteca porque otras aplicaciones web que ya tenemos la están utilizando.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top