Java中保留XML结构替换属性特殊字符的实现方案
问题
我需要处理XML内容,要求遍历所有节点(节点和属性名称都不固定),只对属性值应用正则替换(保留A-Za-z0-9#&',-.这些字符,其余删掉),然后重建XML。直接对XML字符串用正则的方法行不通,会误删节点名里的冒号(比如<XYZ:CompanyCd>里的冒号),之前试的字符串转义+正则替换完全没用,求Java里的可行实现方案。
XML样本:
<AccountNumberId>JY00000830</AccountNumberId> <XYZ:CompanyCd>DOC</XYZ:CompanyCd> <XYZ:MultiPolicyDiscountCd>0</XYZ:MultiPolicyDiscountCd> <QuestionAnswer> <QuestionCd>XYZ:1</QuestionCd> <YesNoCd>No</YesNoCd> </QuestionAnswer> <TransactionSeqNumber/> <PersApplicationInfo> <ApplicationWrittenDt>2023-02-26</ApplicationWrittenDt> <KnownSinceDt>2007-02-05</KnownSinceDt> </PersApplicationInfo> <XYZ:TaxExemptionInd>0</XYZ:TaxExemptionInd> </PersPolicy> <Location id="LOC-1"> <ItemIdInfo> <XYZ:FixedId>8001</XYZ:FixedId> </ItemIdInfo> <Addr> <Addr1>`**`1234 $$$RIVERWOOD !!<GATE SUITE> 136`**`</Addr1> ...
之前尝试的无效代码:
var escapedXml = StringEscapeUtils.escapeXml(xmlString); var replaceSplChars = escapedXml .replaceAll("[^A-Za-z0-9#&',-.\n<>]", "") .replace("\t", ""); var toXML = StringEscapeUtils.unescapeXml(replaceSplChars);
Java实现方案
用Java标准库的DOM解析来处理,精准遍历每个元素的属性,只修改属性值,不会破坏节点名或文本内容,完美解决正则误改XML结构的问题。
1. 编写属性值清理工具方法
先封装一个专门过滤属性值的方法,按要求保留指定字符:
private static String cleanAttrValue(String value) { if (value == null) return null; // 仅保留允许的字符,其余全部移除 return value.replaceAll("[^A-Za-z0-9#&',-.]", ""); }
2. 遍历XML节点处理属性
通过DOM解析XML,递归遍历所有元素节点,逐个处理属性值:
import org.w3c.dom.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.StringReader; import java.io.StringWriter; public class XmlAttrCleaner { public static String processXml(String rawXml) throws Exception { // 初始化DOM解析器,开启命名空间支持(兼容XYZ:这类带前缀的节点) DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new InputSource(new StringReader(rawXml))); // 递归遍历所有节点,清理属性值 traverseNodes(doc.getDocumentElement()); // 将修改后的Document转换回XML字符串 TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); // 不需要XML声明则保留此行,需要则删除 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); // 可选:设置输出缩进,提升可读性 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); DOMSource source = new DOMSource(doc); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); transformer.transform(source, result); return writer.toString(); } private static void traverseNodes(Node node) { // 仅处理元素节点 if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) node; NamedNodeMap attrs = element.getAttributes(); // 遍历当前元素的所有属性 for (int i = 0; i < attrs.getLength(); i++) { Attr attr = (Attr) attrs.item(i); String cleanedValue = cleanAttrValue(attr.getValue()); attr.setValue(cleanedValue); } } // 递归处理子节点,覆盖所有层级 NodeList childNodes = node.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { traverseNodes(childNodes.item(i)); } } private static String cleanAttrValue(String value) { if (value == null) return null; return value.replaceAll("[^A-Za-z0-9#&',-.]", ""); } }
3. 使用示例
直接调用工具类处理你的XML字符串:
public static void main(String[] args) { try { String originalXml = "你的XML内容"; String processedXml = XmlAttrCleaner.processXml(originalXml); System.out.println(processedXml); } catch (Exception e) { e.printStackTrace(); } }
关键说明
- 开启
setNamespaceAware(true),确保带命名空间前缀的节点(如XYZ:)能被正常解析,原有XML结构完全保留。 - 仅对属性值执行正则替换,节点名称、文本内容均不修改,彻底解决字符串正则误删冒号的问题。
- 递归遍历所有节点,无论节点或属性名称是否固定,都能全覆盖处理。
内容的提问来源于stack exchange,提问作者manrk
相关产品推荐
相关产品推荐

