2016-07-20 51 views
4

最近這個問題一直困擾着我,我似乎無法找到一個可能的解決方案。我如何使用DOM轉義特殊字符

我正在處理一個Web服務器,它接收一個XML文檔來做一些處理。服務器的解析器有問題&,',「,<,>我知道這是不好的,我沒有在該服務器上實現xml解析器,但在等待補丁之前,我需要繞過。 ,在將我的XML文檔上傳到此服務器之前,我需要解析它並轉義xml特殊字符。我現在使用的是DOM。問題是,如果我遍歷TEXT_NODES並用它們的轉義版本替換所有特殊字符,我保存這個文件,

d'ex我得到d&amp;apos;ex,但我需要d&apos;ex

這是有道理的,因爲DOM逃脫「&」。但顯然這不是我所需要的。

因此,如果DOM已經能夠逃脫"&""&amp;"我怎麼能讓其他字符如"&quot;

如果不能,我如何將已解析和轉義的文本保存在其節點中,而不必在保存時重新轉義它們?

我這是怎麼逃過特殊字符我使用的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(); 


     } 
+0

maybe' <![CDATA ['?我認爲你應該發佈你的轉義代碼。 –

+0

@RC。我添加了代碼:) – Undisputed007

回答

1

我見過的人使用正則表達式做同樣的事情

從(Replace special character with an escape preceded special character in Java

String newSearch = search.replaceAll("(?=[]\\[+&|!(){}^\"~*?:\\\\-])", "\\\\");複製

這個令人毛骨悚然的正則表達式是一個「向前看」 - 一個非捕獲斷言,以下char匹配一些東西 - 在這種情況下是一個字符類。

注意你不需要在字符類中轉義字符,除了a](即使是減號,如果第一個或最後一個都不需要轉義)。

\\\\是你如何編寫一個正則表達式文字\(用於Java逃脫一次,一次爲正則表達式)

下面是這個工作的一個測試:

public static void main(String[] args) { String search = "code:xy"; String newSearch = search.replaceAll("(?=[]\\[+&|!(){}^\"~*?:\\\\-])", "\\\\"); System.out.println(newSearch); }

輸出:

code\:xy

1

這與這個問題密切相關(how to Download a XML file from a URL by Escaping Special Characters like &lt; &gt; $amp; etc?)。

這篇文章有類似的情況,其中的代碼下載XML與解析/轉義的內容。

據我所知,你讀文件,解析它並轉義字符。在保存期間XML再次被「轉義」。雖然可以使用DOM檢查格式良好的XML或模式,但基於文件的操作可以幫助您轉義XML和HTML特殊字符。該帖子中的代碼示例是指使用IOUtils和StringUtils來完成它。希望這可以幫助 !

3

我認爲您正在尋找的解決方案是一個自定義的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我使用的概念驗證,顯示編碼你提到的默認字符:

characterswap.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> &#xa; Original VALUE : </xsl:text> 
    <xsl:copy-of select="."/> 
    <xsl:text> &#xa; OUTPUT ESCAPING DISABLED : </xsl:text> 
     <xsl:value-of select="." disable-output-escaping="yes"/> 
     <xsl:text> &#xa; 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>&amp;</Container> 

    Original VALUE : <Container>&amp;</Container> 
    OUTPUT ESCAPING DISABLED : & 
    OUTPUT ESCAPING ENABLED : &amp; 

您可以從XSLT執行中獲取活動節點並執行特定的字符替換。有很多例子我都能找到,但我很難讓他們在我的背景下工作。

XSLT string replace 是一個良好的開端。

這是關於我和XSLT知識的程度,我希望它可以幫助您解決問題。

祝你好運。


我正在考慮這一點,並且解決方案可能不僅僅是XSLT。從你的描述,我有一個,而不是XML10編碼,你有種找全套HTML編碼的印象。

沿着這一思路,如果我們把當前的節點文本的轉換:

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

我認爲,XML配置將現在所有的 HTML逃脫你想的完全編碼。

現在,將其與XSLT結合起來用於輸出轉義(從上面),並且文檔在寫入文件時不會進行任何進一步轉換。

我喜歡這個解決方案,因爲它限制了XSLT文件中包含的邏輯。而不是管理整個字符串查找/替換,您只需確保複製整個節點並複製文本()並禁用輸出轉義。

從理論上講,這看起來好像會實現我對你的目標的理解。

再次警告說我對XSLT很虛弱,所以示例xslt文件可能 仍然需要一些調整。在我看來,這種解決方案減少了未知工作量。