2016-07-20 3 views
4

Эта проблема в последнее время сильно меня подслушивала, и я не могу найти возможное решение.Как я могу избежать специальных символов с помощью DOM

Я имею дело с веб-сервером, который получает XML-документ для обработки. Анализатор сервера имеет проблемы с & ",", <,>. Я знаю, что это плохо, я не выполнил XML-парсер на этом сервере. Но прежде, чем ждет патч мне нужно обойти.

сейчас перед загрузкой моего XML-документа на этот сервер мне нужно проанализировать его и избежать специальных символов xml. В настоящее время я использую DOM. Проблема в том, что если я повторяю TEXT_NODES и заменяет все специальные символы на свои экранированные версии, когда Я сохранить этот документ,

для d'ex я получаю d&amp;apos;ex, но мне нужно d&apos;ex

Это имеет смысл, так как, DOM escapes "&". Но, очевидно, это не то, что мне нужно.

Так что, если 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

возможно'

+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

0

Я бы использовал StringEscapeUtils.escapeXml10() ... подробнее здесь. https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringEscapeUtils.html#ESCAPE_XML10

+0

Если вы посмотрите на мой пост и код, вы заметите, что я использовал StringEscapeUtils. Проблема выше StringEscapeUtils, а скорее в DOM или других синтаксических анализах XML. – Undisputed007

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 encoding вы ищете полный набор html-кодировки.

Вдоль этих линий, если мы примем ваш текущий текстовый узел преобразования:

if (child.getNodeType() == Node.TEXT_NODE) { 
    child.setNodeValue(StringEscapeUtils.escapeXml10(child.getNodeValue())); 
} 

И явно ожидать, что мы хотим, чтобы HTML-Encoding:

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.Вместо того, чтобы управлять всем поиском/заменой String, вам просто нужно убедиться, что вы скопируете весь свой узел и скопируете текст () с отключенным выходом.

Теоретически, похоже, что это выполнит мое понимание вашей цели.

Caveat снова в том, что я слаб с XSLT, поэтому пример файла XSLT может еще нужны настройки. Это решение уменьшает эту неизвестную работу количество, на мой взгляд.