全ての結論
SpringのXML設定をコピーした後に開始タグで解析エラーが出たら、属性の前の空白がU+00A0になっていないか確認します。
事象
当時、EclipseでSpringの app-context.xml を別プロジェクトへコピーしたところ、beans:beans の後に属性指定か > または /> が必要だというエラーが出ました。配布の broken.xml では、開始タグ名と xmlns:beans の間をU+00A0にしています。
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"/>原因
U+00A0は改行を禁止する空白で、見た目が通常の空白と似ています。XML 1.0で属性の区切りとして認められるのは、U+0020の空白、タブ、LF、CRです。U+00A0が開始タグ名の直後にあると、パーサーは属性の区切りとして読めません。この段階ではBeanの登録やXMLスキーマの検証まで進んでいません。

対応
エラー箇所の直前にある空白を削除し、属性との区切りを半角スペースで入力し直します。属性値や要素の本文にも意図したU+00A0がある場合があるため、置換は構文上の区切りに絞ります。
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"/>具体的な話
エディターの文字コード表示で、壊れた側はU+00A0、修正側はU+0020と確認できます。次の検証コードはJDK 17のXMLパーサーを使い、同じタグの区切り1文字だけで結果が変わることを確かめます。
import java.nio.file.Files;
import java.nio.file.Path;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class XmlWhitespaceCheck {
public static void main(String[] args) throws Exception {
Path broken = Path.of("broken.xml");
Path fixed = Path.of("fixed.xml");
String original = Files.readString(broken);
String repaired = Files.readString(fixed);
String tag = "<beans:beans";
if (original.codePointAt(tag.length()) != 0x00A0
|| repaired.codePointAt(tag.length()) != 0x0020
|| !original.replace(tag + "\u00a0", tag + " ").equals(repaired)) {
throw new AssertionError("expected one change to the tag's attribute separator");
}
try {
parse(broken);
throw new AssertionError("U+00A0 was accepted as XML syntax whitespace");
} catch (SAXParseException expected) {
System.out.printf("broken.xml: U+00A0 rejected (line %d)%n", expected.getLineNumber());
}
parse(fixed);
System.out.println("fixed.xml: U+0020 accepted");
}
private static void parse(Path path) throws Exception {
var factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new DefaultHandler() {
@Override
public void fatalError(SAXParseException error) throws SAXParseException {
throw error;
}
});
builder.parse(path.toFile());
}
}javac XmlWhitespaceCheck.java
java XmlWhitespaceCheck
# broken.xml: U+00A0 rejected (line 1)
# fixed.xml: U+0020 accepted 