답변:
아주 간단하게 : XML 라이브러리를 사용하십시오. 그렇게 하면 XML 사양에 대한 자세한 지식을 요구하는 대신 실제로 옳습니다 .
다른 사람들이 언급했듯이 XML 라이브러리를 사용하는 것이 가장 쉬운 방법입니다. 스스로 탈출하고 싶다면 Apache Commons Lang 라이브러리 StringEscapeUtils에서 살펴볼 수 있습니다.
StringEscapeUtils.escapeXml(str)에서 commons-lang. App Engine 애플리케이션에서 사용합니다. 매력처럼 작동합니다. 이 함수에 대한 Java 문서 는 다음과 같습니다 .
\t, \n하고 \r.
\t, \n또는 \r이스케이프해야합니까?
그냥 사용하십시오.
<![CDATA[ your text here ]]>
이것은 끝을 제외한 모든 문자를 허용합니다
]]>
따라서 & 및>와 같이 불법적 인 문자를 포함 할 수 있습니다. 예를 들면.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
그러나 CDATA 블록을 사용할 수 없으므로 속성을 이스케이프해야합니다.
이것은 텍스트 문자열의 이스케이프 버전을 제공하는 데 잘 작동했습니다.
public class XMLHelper {
/**
* Returns the string where all non-ascii and <, &, > are encoded as numeric entities. I.e. "<A & B >"
* .... (insert result here). The result is safe to include anywhere in a text field in an XML-string. If there was
* no characters to protect, the original string is returned.
*
* @param originalUnprotectedString
* original string which may contain characters either reserved in XML or with different representation
* in different encodings (like 8859-1 and UFT-8)
* @return
*/
public static String protectSpecialCharacters(String originalUnprotectedString) {
if (originalUnprotectedString == null) {
return null;
}
boolean anyCharactersProtected = false;
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < originalUnprotectedString.length(); i++) {
char ch = originalUnprotectedString.charAt(i);
boolean controlCharacter = ch < 32;
boolean unicodeButNotAscii = ch > 126;
boolean characterWithSpecialMeaningInXML = ch == '<' || ch == '&' || ch == '>';
if (characterWithSpecialMeaningInXML || unicodeButNotAscii || controlCharacter) {
stringBuffer.append("&#" + (int) ch + ";");
anyCharactersProtected = true;
} else {
stringBuffer.append(ch);
}
}
if (anyCharactersProtected == false) {
return originalUnprotectedString;
}
return stringBuffer.toString();
}
}
이 시도:
String xmlEscapeText(String t) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < t.length(); i++){
char c = t.charAt(i);
switch(c){
case '<': sb.append("<"); break;
case '>': sb.append(">"); break;
case '\"': sb.append("""); break;
case '&': sb.append("&"); break;
case '\'': sb.append("'"); break;
default:
if(c>0x7e) {
sb.append("&#"+((int)c)+";");
}else
sb.append(c);
}
}
return sb.toString();
}
t==null.
이 질문은 8 년이 지났지 만 아직 완전히 정답이 아닙니다! 아니요,이 간단한 작업을 수행하기 위해 전체 타사 API를 가져올 필요는 없습니다. 나쁜 충고.
다음 방법은 다음과 같습니다.
나는 가장 일반적인 경우에 최적화하려고 노력했지만 여전히 이것을 통해 / dev / random을 파이프하고 XML에서 유효한 문자열을 얻을 수 있는지 확인했습니다.
public static String encodeXML(CharSequence s) {
StringBuilder sb = new StringBuilder();
int len = s.length();
for (int i=0;i<len;i++) {
int c = s.charAt(i);
if (c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
c = ((c-0xd7c0)<<10) | (s.charAt(++i)&0x3ff); // UTF16 decode
}
if (c < 0x80) { // ASCII range: test most common case first
if (c < 0x20 && (c != '\t' && c != '\r' && c != '\n')) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("�"); // Unicode replacement character
} else {
switch(c) {
case '&': sb.append("&"); break;
case '>': sb.append(">"); break;
case '<': sb.append("<"); break;
// Uncomment next two if encoding for an XML attribute
// case '\'' sb.append("'"); break;
// case '\"' sb.append("""); break;
// Uncomment next three if you prefer, but not required
// case '\n' sb.append(" "); break;
// case '\r' sb.append(" "); break;
// case '\t' sb.append("	"); break;
default: sb.append((char)c);
}
}
} else if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("�"); // Unicode replacement character
} else {
sb.append("&#x");
sb.append(Integer.toHexString(c));
sb.append(';');
}
}
return sb.toString();
}
편집 : XML을 처리 할 수있는 완벽하게 좋은 Java API가있을 때이를위한 자체 코드를 작성하는 것이 어리 석다고 계속 주장하는 사람들에게는 Oracle Java 8에 포함 된 StAX API를 알고 싶을 것입니다. ) CDATA 콘텐츠를 올바르게 인코딩하지 못합니다. 콘텐츠의]]> 시퀀스를 이스케이프하지 않습니다. Java 코어의 일부인 타사 라이브러리라도 항상 최상의 옵션은 아닙니다.
StringEscapeUtils.escapeXml()제어 문자를 이스케이프하지 않습니다 (<0x20). XML 1.1은 제어 문자를 허용합니다. XML 1.0은 그렇지 않습니다. 예를 들어 XStream.toXML()는 Java 객체의 제어 문자를 XML로 직렬화하므로 XML 1.0 구문 분석기가 거부합니다.
Apache commons-lang으로 제어 문자를 이스케이프하려면 다음을 사용하십시오.
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
replaceAll호출은 특히 큰 문자열의 경우 매우 비효율적입니다. 모든 호출은 새로운 String 객체가 생성되고 가비지가 수집 될 때까지 계속됩니다. 또한 각 호출은 문자열을 다시 반복해야합니다. 이것은 모든 반복에서 각 대상 문자와 비교하여 하나의 단일 수동 루프로 통합 될 수 있습니다.
이상주의는 XML 라이브러리를 사용한다고 말하지만, XML에 대한 기본 아이디어가 있다면 IMHO는 상식과 성능에 따라 템플릿을 끝까지 말합니다. 틀림없이 더 읽기 쉽습니다. 라이브러리의 이스케이프 루틴을 사용하는 것이 좋습니다.
이것을 고려하십시오 : XML 은 사람이 작성하기위한 것입니다.
XML을 "객체"로 사용하여 문제를 더 잘 모델링 할 때 XML 생성을 위해 라이브러리를 사용하십시오. 예를 들어 플러그 형 모듈이이 XML을 빌드하는 프로세스에 참여하는 경우입니다.
편집 : 템플릿에서 실제로 XML을 이스케이프하는 방법에 대해서는 CDATA 또는 escapeXml(string)JSTL을 사용하는 것이 두 가지 좋은 솔루션이며 escapeXml(string)다음과 같이 사용할 수 있습니다.
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<item>${fn:escapeXml(value)}</item>
StringEscapeUtils.escapeXml ()의 동작이 Commons Lang 2.5에서 3.0으로 변경되었습니다. 이제 더 이상 0x7f보다 큰 유니 코드 문자를 이스케이프하지 않습니다.
이것은 좋은 것입니다. 예전 방법은 utf8 문서에 삽입 할 수있는 엔티티를 이스케이프하려는 열망이었습니다.
Google Guava 11.0에 포함될 새로운 이스케이프도 유망 해 보입니다. http://code.google.com/p/guava-libraries/issues/detail?id=799
가장 빠른 작성 솔루션을 찾는 사람들을 위해 : apache commons-lang의 메소드를 사용하십시오 .
StringEscapeUtils.escapeXml10() xml 1.0 용StringEscapeUtils.escapeXml11() xml 1.1 용StringEscapeUtils.escapeXml() 이제는 더 이상 사용되지 않지만 과거에는 일반적으로 사용되었습니다.종속성을 포함해야합니다.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version> <!--check current version! -->
</dependency>
참고 : 귀하의 질문은 인코딩이 아닌 이스케이프 에 관한 것 입니다. 이스케이프는 <등을 사용하여 파서가 "이것은 XML 명령입니다"와 "이것은 텍스트입니다"를 구분할 수 있도록합니다. 인코딩은 XML 헤더 (UTF-8, ISO-8859-1 등)에 지정하는 항목입니다.
우선 다른 사람들이 말했듯이 XML 라이브러리를 사용하십시오. XML은 단순 해 보이지만 인코딩과 이스케이프 처리는 어둡습니다 (움라우트와 일본어 및 " 전폭 숫자 "(& # FF11;은 1) 와 같은 다른 이상한 요소를 만나는 즉시 알 수 있습니다 ). XML을 사람이 읽을 수 있도록 유지하는 것은 Sisyphus의 작업입니다.
XML에서 텍스트 인코딩 및 이스케이프에 대해 영리하지 않도록 권장합니다. 그러나 그것이 당신이 시도하는 것을 멈추게하지 마십시오. 그것이 당신을 물었을 때를 기억하십시오 (그리고 그렇게 될 것입니다).
즉, UTF-8 만 사용하는 경우 더 읽기 쉽게 만들기 위해 다음 전략을 고려할 수 있습니다.
<![CDATA[ ... ]]>나는 이것을 SQL 편집기에서 사용하고 있으며 개발자가 이스케이프에 대해 걱정하지 않고 타사 SQL 도구에서 XML로 SQL을 잘라내어 붙여 넣을 수 있습니다. 이것은 SQL이 우리의 경우 움라우트를 포함 할 수 없기 때문에 작동하므로 안전합니다.
원칙적으로 Jon Skeet에 동의하지만 때로는 외부 XML 라이브러리를 사용할 수있는 옵션이 없습니다. 그리고 Java에 포함 된 표준 XML 라이브러리에서는 간단한 값 (속성 또는 태그, 전체 문서가 아님)을 이스케이프 / 이스케이프 해제하는 두 가지 기능을 사용할 수 없다는 점이 특이합니다.
결과적으로 여기와 다른 곳에 게시 된 다른 답변을 기반으로 한 솔루션은 다음과 같습니다 (간단한 복사 / 붙여 넣기로 작동하지 않음).
public final static String ESCAPE_CHARS = "<>&\"\'";
public final static List<String> ESCAPE_STRINGS = Collections.unmodifiableList(Arrays.asList(new String[] {
"<"
, ">"
, "&"
, """
, "'"
}));
private static String UNICODE_LOW = "" + ((char)0x20); //space
private static String UNICODE_HIGH = "" + ((char)0x7f);
//should only use for the content of an attribute or tag
public static String toEscaped(String content) {
String result = content;
if ((content != null) && (content.length() > 0)) {
boolean modified = false;
StringBuilder stringBuilder = new StringBuilder(content.length());
for (int i = 0, count = content.length(); i < count; ++i) {
String character = content.substring(i, i + 1);
int pos = ESCAPE_CHARS.indexOf(character);
if (pos > -1) {
stringBuilder.append(ESCAPE_STRINGS.get(pos));
modified = true;
}
else {
if ( (character.compareTo(UNICODE_LOW) > -1)
&& (character.compareTo(UNICODE_HIGH) < 1)
) {
stringBuilder.append(character);
}
else {
stringBuilder.append("&#" + ((int)character.charAt(0)) + ";");
modified = true;
}
}
}
if (modified) {
result = stringBuilder.toString();
}
}
return result;
}
위의 내용은 여러 가지를 수용합니다.
어느 시점에서 나는이 함수의 반전 인 toUnescaped ()를 작성할 것입니다. 오늘은 그렇게 할 시간이 없습니다. 내가 할 때 나는이 답변을 코드로 업데이트 할 것입니다. :)
XML 문자를 이스케이프하려면 가장 쉬운 방법은 Apache Commons Lang 프로젝트 ( http://commons.apache.org/lang/ 에서 다운로드 할 수있는 JAR)를 사용하는 것입니다 .
클래스는 다음과 같습니다. org.apache.commons.lang3.StringEscapeUtils;
적절하게 이스케이프 된 문자열을 반환하는 "escapeXml"이라는 메서드가 있습니다.
작업을 완료하기 위해 라이브러리를 찾고 있다면 다음을 시도하십시오.
여기에 문서화 된 Guava 26.0
return XmlEscapers.xmlContentEscaper().escape(text);
참고 : 또한
xmlAttributeEscaper()
여기에 문서화 된 Apache Commons Text 1.4
StringEscapeUtils.escapeXml11(text)
참고 :
escapeXml10()방법 도 있습니다.
여기에 쉬운 해결책이 있으며 악센트 부호가있는 문자를 인코딩하는데도 좋습니다!
String in = "Hi Lârry & Môe!";
StringBuilder out = new StringBuilder();
for(int i = 0; i < in.length(); i++) {
char c = in.charAt(i);
if(c < 31 || c > 126 || "<>\"'\\&".indexOf(c) >= 0) {
out.append("&#" + (int) c + ";");
} else {
out.append(c);
}
}
System.out.printf("%s%n", out);
출력
Hi Lârry & Môe!
당신이 사용할 수있는 엔터프라이즈 보안 API (ESAPI) 라이브러리 등의 방법 제공 encodeForXML및 encodeForXMLAttribute. Encoder 인터페이스 의 문서를 살펴보십시오 . 또한 DefaultEncoder 인스턴스를 만드는 방법에 대한 예제도 포함되어 있습니다 .
JAXP를 사용 하고 텍스트 처리를 잊어 버리면 자동으로 수행됩니다.
Apache XML serializer를 사용하여 XML 인코딩 시도
//Serialize DOM
OutputFormat format = new OutputFormat (doc);
// as a String
StringWriter stringOut = new StringWriter ();
XMLSerializer serial = new XMLSerializer (stringOut,
format);
serial.serialize(doc);
// Display the XML
System.out.println(stringOut.toString());
해결책을 찾기 위해 모든 곳에서 검색 한 결과 다음과 같습니다.
Jsoup 라이브러리를 가져옵니다.
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
그때:
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Entities
import org.jsoup.parser.Parser
String xml = '''<?xml version = "1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV = "http://www.w3.org/2001/12/soap-envelope"
SOAP-ENV:encodingStyle = "http://www.w3.org/2001/12/soap-encoding">
<SOAP-ENV:Body xmlns:m = "http://www.example.org/quotations">
<m:GetQuotation>
<m:QuotationsName> MiscroSoft@G>>gle.com </m:QuotationsName>
</m:GetQuotation>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'''
Document doc = Jsoup.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")), "UTF-8", "", Parser.xmlParser())
doc.outputSettings().charset("UTF-8")
doc.outputSettings().escapeMode(Entities.EscapeMode.base)
println doc.toString()
이것이 누군가에게 도움이되기를 바랍니다.