[英]How can i escape special characters with using DOM
这个问题最近困扰着我很多,我似乎找不到可能的解决方案。
我正在处理一个接收XML文档进行某些处理的Web服务器。 服务器的解析器出现&,',“,<,>问题。我知道这很不好,我没有在该服务器上实现xml解析器。但是在等待补丁之前,我需要规避。
现在,在将我的XML文档上载到此服务器之前,我需要解析它并转义xml特殊字符。 我目前正在使用DOM。 问题是,如果我遍历TEXT_NODES并将所有特殊字符替换为它们的转义版本,那么在保存此文档时,
对于d'ex
我得到d&apos;ex
但我需要d'ex
这是有道理的,因为DOM会转义“&”。 但这显然不是我所需要的。
因此,如果DOM已经能够将"&"
转义为"&"
如何使它转义其他字符,例如"
to "
?
如果不能,如何保存已解析和转义的文本到其节点中,而不必在保存时重新转义它们?
这就是我转义我使用的Apache StringEscapeUtils类中的特殊字符的方式:
public String xMLTransform() throws Exception
{
String xmlfile = FileUtils.readFileToString(new File(filepath));
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(new InputSource(new StringReader(xmlfile.trim().replaceFirst("^([\\W]+)<", "<"))));
NodeList nodeList = doc.getElementsByTagName("*");
for (int i = 0; i < nodeList.getLength(); i++) {
Node currentNode = nodeList.item(i);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
Node child = currentNode.getFirstChild();
while(child != null) {
if (child.getNodeType() == Node.TEXT_NODE) {
child.setNodeValue(StringEscapeUtils.escapeXml10(child.getNodeValue()));
//Escaping works here. But when saving the final document, the "&" used in escaping gets escaped as well by DOM.
}
child = child.getNextSibling();
}
}
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
FileOutputStream fop = null;
File file;
file = File.createTempFile("escapedXML"+UUID.randomUUID(), ".xml");
fop = new FileOutputStream(file);
String xmlString = writer.toString();
byte[] contentInBytes = xmlString.getBytes();
fop.write(contentInBytes);
fop.flush();
fop.close();
return file.getPath();
}
我认为您正在寻找的解决方案是定制的XSLT解析器,您可以对其进行配置以实现其他HTML转义。
我不能肯定地说如何配置xslt文件来执行您想要的操作,但是我相当有信心可以做到。 我在下面列出了基本的Java设置:
@Test
public void testXSLTTransforms () throws Exception {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element el = doc.createElement("Container");
doc.appendChild(el);
Text e = doc.createTextNode("Character");
el.appendChild(e);
//e.setNodeValue("\'");
//e.setNodeValue("\"");
e.setNodeValue("&");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(System.out);
//This prints the original document to the command line.
transformer.transform(source, result);
InputStream xsltStream = getClass().getResourceAsStream("/characterswap.xslt");
Source xslt = new StreamSource(xsltStream);
transformer = transformerFactory.newTransformer(xslt);
//This one is the one you'd pipe to a file
transformer.transform(source, result);
}
我有一个简单的XSLT用于概念验证,它显示了您提到的默认字符编码:
characterwap.xslt
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:text> 
 Original VALUE : </xsl:text>
<xsl:copy-of select="."/>
<xsl:text> 
 OUTPUT ESCAPING DISABLED : </xsl:text>
<xsl:value-of select="." disable-output-escaping="yes"/>
<xsl:text> 
 OUTPUT ESCAPING ENABLED : </xsl:text>
<xsl:value-of select="." disable-output-escaping="no"/>
</xsl:template>
</xsl:stylesheet>
控制台是非常基本的:
<?xml version="1.0" encoding="UTF-8"?>
<Container>&</Container>
Original VALUE : <Container>&</Container>
OUTPUT ESCAPING DISABLED : &
OUTPUT ESCAPING ENABLED : &
您可以从XSLT执行中获取活动节点并执行特定的字符替换。 我可以找到多个示例,但是我很难让它们在我的环境中工作。
XSLT字符串替换是一个不错的起点。
这与我对XSLT的了解程度有关,我希望它能帮助您解决问题。
祝你好运。
我正在进一步考虑,解决方案可能不仅是XSLT。 从您的描述中,我得到的印象是,您正在寻找一整套html编码 ,而不是xml10 编码 。
按照这些思路,如果我们采用您当前的节点文本转换:
if (child.getNodeType() == Node.TEXT_NODE) {
child.setNodeValue(StringEscapeUtils.escapeXml10(child.getNodeValue()));
}
并明确期望我们需要HTML编码:
if (child.getNodeType() == Node.TEXT_NODE) {
//Capture the current node value
String nodeValue = child.getNodeValue();
//Decode for XML10 to remove existing escapes
String decodedNode = StringEscapeUtils.unescapeXml10(nodeValue);
//Then Re-encode for HTML (3/4/5)
String fullyEncodedHTML = StringEscapeUtils.escapeHtml3(decodedNode);
//String fullyEncodedHTML = StringEscapeUtils.escapeHtml4(decodedNode);
//String fullyEncodedHTML = StringEscapeUtils.escapeHtml5(decodedNode);
//Then place the fully-encoded HTML back to the node
child.setNodeValue(fullyEncodedHTML);
}
我认为现在可以用您想要的所有HTML转义对xml进行完全编码。
现在,将其与XSLT结合使用以进行转义(从上面),并且将文档写到文件时,文档将不会进行任何进一步的转换。
我喜欢这种解决方案,因为它限制了XSLT文件中包含的逻辑。 无需管理整个String查找/替换,您只需要确保复制了整个节点并复制了禁用输出转义的text()即可 。
从理论上讲,这似乎可以满足我对您目标的理解。
需要再次说明的是,我对XSLT不满意,因此示例xslt文件可能仍需要进行一些调整。 我认为这种解决方案减少了未知的工作量。
我见过人们使用正则表达式来做类似的事情
从复制( 用Java中的特殊字符替换为特殊字符 )
String newSearch = search.replaceAll("(?=[]\\\\[+&|!(){}^\\"~*?:\\\\\\\\-])", "\\\\\\\\");
那个古怪的正则表达式是一个“前瞻性”-一个无法捕获的断言,即后面的字符与某些字符匹配-在这种情况下为字符类。
请注意,除了[]以外,您无需在字符类中转义字符(即使减号也不需要转义,无论是第一个还是最后一个)。
\\\\\\\\
是编码正则表达式文字\\的方式(对于Java,一次转义,对于regex一次转义)
这是对此工作的测试:
public static void main(String[] args) { String search = "code:xy"; String newSearch = search.replaceAll("(?=[]\\\\[+&|!(){}^\\"~*?:\\\\\\\\-])", "\\\\\\\\"); System.out.println(newSearch); }
输出:
code\\:xy
这与这个问题密切相关( 如何通过转义&lt;&gt; $ amp;等特殊字符来从URL下载XML文件? )。
这篇文章有一个类似的案例,其中代码下载了具有解析/转义内容的XML。
据我了解,您读取文件,解析文件并转义字符。 在保存期间,XML再次被“转义”。 虽然您可以使用DOM来检查格式正确的XML或架构,但是基于文件的转义操作可以帮助您转义XML和HTML特殊字符。 文章中的代码示例引用了IOUtils和StringUtils的用法。 希望这可以帮助 !
我会在这里使用StringEscapeUtils.escapeXml10()...详细信息。 https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringEscapeUtils.html#ESCAPE_XML10
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.