如何避免修改XML后persistence-unit元素被添加xmlns=""属性?
解决persistence.xml修改后xmlns属性导致的验证错误
我来帮你搞定这个头疼的问题——你用DOM修改persistence.xml的jta-data-source后,persistence-unit被自动加上了空的xmlns属性,导致XML验证失败对吧?这是因为DOM操作时没正确处理命名空间,下面给你两种不用Transformer的解决方案:
方案1:用ShrinkWrap的PersistenceDescriptor直接操作(推荐)
虽然你之前的提问还没收到回复,但其实ShrinkWrap本身就支持从现有persistence.xml构建描述器,然后直接修改配置,完全绕开手动DOM操作的坑:
JavaArchive jarArchive = Maven.configureResolver().workOffline() .resolve("richtercloud:project1-jar:jar:1.0-SNAPSHOT") .withoutTransitivity().asSingle(JavaArchive.class); // 从jar里的现有persistence.xml加载描述器 PersistenceDescriptor persistenceDescriptor = PersistenceDescriptor.createFrom( jarArchive.get("META-INF/persistence.xml").getAsset().openStream()); // 遍历所有持久化单元,修改jta-data-source的值 persistenceDescriptor.getPersistenceUnits().forEach(pu -> pu.jtaDataSource("jdbc/project1-test-db")); // 把修改后的配置写回jar包 jarArchive.delete("META-INF/persistence.xml"); jarArchive.addAsResource( new StringAsset(persistenceDescriptor.exportAsString()), "META-INF/persistence.xml");
这种方法完全利用ShrinkWrap的API来处理XML的命名空间和结构,不会出现莫名其妙的xmlns属性问题。
方案2:修复DOM操作的命名空间处理
如果你更倾向于继续用DOM操作,那必须开启命名空间支持,并且用带命名空间的XPath来定位节点,这样就不会生成空的xmlns属性了:
JavaArchive jarArchive = Maven.configureResolver().workOffline() .resolve("richtercloud:project1-jar:jar:1.0-SNAPSHOT") .withoutTransitivity().asSingle(JavaArchive.class); Node persistenceXml = jarArchive.get("META-INF/persistence.xml"); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); // 关键:开启命名空间感知,这是避免空xmlns属性的核心 documentBuilderFactory.setNamespaceAware(true); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document persistenceXmlDocument = documentBuilder.parse(persistenceXml.getAsset().openStream()); XPathFactory xPathfactory = XPathFactory.newInstance(); XPath xpath = xPathfactory.newXPath(); // 给XPath设置命名空间上下文,对应persistence.xml的标准命名空间 xpath.setNamespaceContext(new NamespaceContext() { @Override public String getNamespaceURI(String prefix) { if ("pers".equals(prefix)) { return "http://xmlns.jcp.org/xml/ns/persistence"; } return XMLConstants.NULL_NS_URI; } @Override public String getPrefix(String namespaceURI) { return "pers"; } @Override public Iterator<String> getPrefixes(String namespaceURI) { return Collections.singleton("pers").iterator(); } }); // 使用带命名空间前缀的XPath表达式定位节点 XPathExpression expr = xpath.compile("//pers:persistence-unit/pers:jta-data-source"); org.w3c.dom.Node persistenceXmlDataSourceNode = (org.w3c.dom.Node) expr.evaluate(persistenceXmlDocument, XPathConstants.NODE); persistenceXmlDataSourceNode.setTextContent("jdbc/project1-test-db"); // 用DOM的LSSerializer输出XML,替代Transformer,避免命名空间问题 DOMImplementationLS domImplLS = (DOMImplementationLS) persistenceXmlDocument.getImplementation(); LSSerializer serializer = domImplLS.createLSSerializer(); // 可选:如果不需要XML声明,可以设置为false serializer.getDomConfig().setParameter("xml-declaration", false); String persistenceUnit = serializer.writeToString(persistenceXmlDocument); // 写回jar包 jarArchive.delete("META-INF/persistence.xml"); jarArchive.addAsResource(new StringAsset(persistenceUnit), "META-INF/persistence.xml");
为什么会出现这个错误?
你遇到的cvc-complex-type.2.4.a错误,本质是命名空间不匹配:persistence.xml的schema要求persistence-unit节点必须属于http://xmlns.jcp.org/xml/ns/persistence命名空间,但你的DOM操作没开启命名空间支持,修改后节点被加上了xmlns="",表示它不属于任何命名空间,这就和schema的要求冲突了,所以验证失败。
内容的提问来源于stack exchange,提问作者Kalle Richter
相关产品推荐
相关产品推荐

