SAXParseException:“属性”“绑定到命名空间“null”已经为元素“metric”指定了

发布于 2024-08-08 21:24:55 字数 6041 浏览 5 评论 0原文

在工作中,我们刚刚将一个旧的 Web 应用程序从 struts 1.1 迁移到 1.2.9(希望是迁移到 1.3 的第一步),但我们现在在公共消化器方面遇到了问题。 Struts 1.2.9 使用 commons-digester 1.6。

当我们尝试解析一个 XML 文件时,我们得到了异常:

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)

在调查这个问题时,我试图得到一种最简单的可能情况,这就是我目前所拥有的:

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");
    }
  }
}

给出了 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>

DTD 目前为:

<!-- 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
>

有谁知道我做错了什么?

如果我删除 defaultView 属性,我不会收到错误。


根据 sfussenegger 的建议,我现在尝试了以下(非消化器)代码:

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();
}

并且无法重现问题,但在使用我的工厂之前添加以下内容(commons-digester 也在 XercesParser 中执行此操作)给出了相同的异常:

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

最后,我们决定尝试更现代的 xerces 版本(2.7.1),这似乎有效。

At work, we have just migrated an old web-app from struts 1.1 to 1.2.9 (hopefully first steps to moving to 1.3), but we are now having problems with the commons digester. Struts 1.2.9 uses commons-digester 1.6.

When we try to parse one of our XML files we get the exception:

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)

In investigating this issue I have tried to get a simplest possible case and this is what I currently have:

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");
    }
  }
}

which is given the 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>

The DTD is currently down to:

<!-- 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
>

Does anyone know what I am doing wrong?

If I remove the defaultView attribute I do not get the error.


As per sfussenegger's suggestion I've now tried the following (non-digester) code:

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();
}

and couldn't reproduce the problem, but adding the following (which commons-digester also does in XercesParser) prior to using my factory gives the same exception:

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

In the end we have decided to try out a more modern version of xerces (2.7.1) and that seems to work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

那小子欠揍 2024-08-15 21:24:55

问题似乎是由 commons-digester 1.6 和 xerces 之间的不兼容引起的(调用 XercesParser 说 2.2),迁移到更新版本的 xerces (2.7.1) 已经解决了该问题。

我们选择这个版本的库是因为我们的其他 Web 应用程序已经在使用它。

Problem appears to have been caused by an incompatibility between commons-digester 1.6 and xerces (call in XercesParser says 2.2), moving to a more recent version of xerces (2.7.1) has fixed the problem.

We chose this version of the library because other web applications we have are already using it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文