Sangat mirip dengan pertanyaan ini , kecuali untuk Java.
Apa cara yang direkomendasikan untuk mengenkode string untuk keluaran XML di Java. String tersebut mungkin berisi karakter seperti "&", "<", dll.
Sangat mirip dengan pertanyaan ini , kecuali untuk Java.
Apa cara yang direkomendasikan untuk mengenkode string untuk keluaran XML di Java. String tersebut mungkin berisi karakter seperti "&", "<", dll.
Jawaban:
Sangat sederhana: gunakan pustaka XML. Dengan cara itu sebenarnya akan benar alih-alih membutuhkan pengetahuan rinci tentang bit dari spesifikasi XML.
Seperti yang telah disebutkan orang lain, menggunakan pustaka XML adalah cara termudah. Jika Anda memang ingin melarikan diri, Anda dapat melihat StringEscapeUtils
dari perpustakaan Apache Commons Lang .
StringEscapeUtils.escapeXml(str)
dari commons-lang
. Saya menggunakannya di aplikasi App Engine - bekerja dengan sangat baik. Berikut adalah Java Doc untuk fungsi ini:
\t
, \n
dan \r
.
\t
, \n
atau \r
perlu di-escape?
Gunakan saja.
<![CDATA[ your text here ]]>
Ini akan mengizinkan karakter apa pun kecuali akhiran
]]>
Jadi, Anda dapat menyertakan karakter yang ilegal seperti & dan>. Sebagai contoh.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
Namun, atribut harus di-escape karena blok CDATA tidak dapat digunakan untuknya.
Ini telah bekerja dengan baik bagi saya untuk memberikan versi escape dari string teks:
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();
}
}
Coba ini:
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
.
Pertanyaan ini sudah berusia delapan tahun dan masih belum merupakan jawaban yang sepenuhnya benar! Tidak, Anda tidak perlu mengimpor seluruh API pihak ketiga untuk melakukan tugas sederhana ini. Saran yang buruk.
Metode berikut akan:
Saya telah mencoba mengoptimalkan untuk kasus yang paling umum, sambil tetap memastikan Anda dapat menyalurkan / dev / random melalui ini dan mendapatkan string yang valid dalam 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();
}
Sunting: bagi mereka yang terus bersikeras bahwa itu bodoh untuk menulis kode Anda sendiri untuk ini ketika ada Java API yang sangat bagus untuk menangani XML, Anda mungkin ingin tahu bahwa StAX API disertakan dengan Oracle Java 8 (saya belum menguji yang lain ) gagal untuk mengenkode konten CDATA dengan benar: tidak lolos]]> urutan dalam konten. Pustaka pihak ketiga, bahkan yang merupakan bagian dari inti Java, tidak selalu merupakan pilihan terbaik.
StringEscapeUtils.escapeXml()
tidak lolos dari karakter kontrol (<0x20). XML 1.1 memungkinkan karakter kontrol; XML 1.0 tidak. Misalnya, XStream.toXML()
dengan senang hati akan membuat serialisasi karakter kontrol objek Java ke dalam XML, yang akan ditolak oleh parser XML 1.0.
Untuk keluar dari karakter kontrol dengan Apache commons-lang, gunakan
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
replaceAll
panggilan sangat tidak efisien, terutama untuk string besar. Setiap panggilan menghasilkan objek String baru yang dibuat, yang akan bertahan sampai sampah dikumpulkan. Juga, setiap panggilan membutuhkan pengulangan melalui string lagi. Ini dapat dikonsolidasikan ke dalam satu loop manual dengan perbandingan terhadap setiap karakter target di setiap iterasi.
Sementara idealisme mengatakan menggunakan perpustakaan XML, IMHO jika Anda memiliki ide dasar tentang XML maka akal sehat dan kinerja mengatakan templat itu sepenuhnya. Ini bisa dibilang lebih mudah dibaca juga. Meskipun menggunakan rutinitas melarikan diri dari perpustakaan mungkin adalah ide yang bagus.
Pertimbangkan ini: XML dulu dimaksudkan untuk ditulis oleh manusia.
Gunakan pustaka untuk menghasilkan XML saat menjadikan XML Anda sebagai "objek" yang lebih baik dalam membuat model masalah Anda. Misalnya, jika modul yang dapat dicolok berpartisipasi dalam proses pembuatan XML ini.
Sunting: tentang bagaimana benar-benar melarikan diri dari XML dalam template, penggunaan CDATA atau escapeXml(string)
dari JSTL adalah dua solusi yang baik, escapeXml(string)
dapat digunakan seperti ini:
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<item>${fn:escapeXml(value)}</item>
Perilaku StringEscapeUtils.escapeXml () telah berubah dari Commons Lang 2.5 menjadi 3.0. Sekarang tidak lagi lolos dari karakter Unicode yang lebih besar dari 0x7f.
Ini adalah hal yang baik, metode lama akan sedikit bersemangat untuk keluar dari entitas yang baru saja disisipkan ke dalam dokumen utf8.
Escaper baru yang akan disertakan dalam Google Guava 11.0 juga tampak menjanjikan: http://code.google.com/p/guava-libraries/issues/detail?id=799
Bagi mereka yang mencari solusi tercepat untuk menulis: gunakan metode dari apache commons-lang :
StringEscapeUtils.escapeXml10()
untuk xml 1.0StringEscapeUtils.escapeXml11()
untuk xml 1.1StringEscapeUtils.escapeXml()
sekarang tidak digunakan lagi, tetapi digunakan secara umum di masa laluIngatlah untuk memasukkan ketergantungan:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version> <!--check current version! -->
</dependency>
Catatan: Pertanyaan Anda adalah tentang pelolosan , bukan penyandiaksaraan . Melarikan diri menggunakan <, dll. Untuk memungkinkan pengurai membedakan antara "ini adalah perintah XML" dan "ini adalah beberapa teks". Enkode adalah hal-hal yang Anda tentukan di header XML (UTF-8, ISO-8859-1, dll).
Pertama-tama, seperti yang orang lain katakan, gunakan perpustakaan XML. XML terlihat sederhana tetapi encoding + escaping adalah voodoo gelap (yang akan Anda lihat segera setelah Anda menemukan umlaut dan bahasa Jepang dan hal-hal aneh lainnya seperti " digit lebar penuh " (& # FF11; adalah 1)). Menjaga agar XML dapat dibaca manusia adalah tugas Sisyphus.
Saya menyarankan untuk tidak pernah mencoba menjadi pintar tentang pengkodean teks dan melarikan diri dalam XML. Tetapi jangan biarkan hal itu menghentikan Anda untuk mencoba; ingatlah kapan itu menggigit Anda (dan itu akan terjadi).
Karena itu, jika Anda hanya menggunakan UTF-8, agar lebih mudah dibaca, Anda dapat mempertimbangkan strategi ini:
<![CDATA[ ... ]]>
Saya menggunakan ini di editor SQL dan memungkinkan pengembang untuk memotong & menempelkan SQL dari alat SQL pihak ketiga ke XML tanpa khawatir akan kabur. Ini berfungsi karena SQL tidak dapat berisi umlaut dalam kasus kami, jadi saya aman.
Meskipun pada prinsipnya saya setuju dengan Jon Skeet, terkadang saya tidak memiliki opsi untuk menggunakan pustaka XML eksternal. Dan saya merasa aneh dua fungsi untuk melarikan diri / unescape nilai sederhana (atribut atau tag, bukan dokumen lengkap) tidak tersedia di pustaka XML standar yang disertakan dengan Java.
Akibatnya dan berdasarkan jawaban berbeda yang saya lihat diposting di sini dan di tempat lain, berikut adalah solusi yang akhirnya saya buat (tidak ada yang berfungsi sebagai salin / tempel sederhana):
public final static String ESCAPE_CHARS = "<>&\"\'";
public final static List<String> ESCAPE_STRINGS = Collections.unmodifiableList(Arrays.asList(new String[] {
"<"
, ">"
, "&"
, """
, "'"
}));
private static String UNICODE_NULL = "" + ((char)0x00); //null
private static String UNICODE_LOW = "" + ((char)0x20); //space
private static String UNICODE_HIGH = "" + ((char)0x7f);
//should only be used 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 {
//Per URL reference below, Unicode null character is always restricted from XML
//URL: https://en.wikipedia.org/wiki/Valid_characters_in_XML
if (character.compareTo(UNICODE_NULL) != 0) {
stringBuilder.append("&#" + ((int)character.charAt(0)) + ";");
}
modified = true;
}
}
}
if (modified) {
result = stringBuilder.toString();
}
}
return result;
}
Hal di atas mengakomodasi beberapa hal berbeda:
Pada titik tertentu, saya akan menulis inversi fungsi ini, toUnescaped (). Saya hanya tidak punya waktu untuk melakukan itu hari ini. Ketika saya melakukannya, saya akan memperbarui jawaban ini dengan kode. :)
null
karakternya. Bisakah Anda menjelaskan definisi kedua nilai, UNICODE_LOW
dan UNICODE_HIGH
? Harap baca ulang if
yang menggunakan dua nilai tersebut. Perhatikan null
( \u0000
yang mana (int)0
) tidak berada di antara kedua nilai ini. Bacalah bagaimana itu menjadi "lolos" dengan benar seperti SEMUA karakter Unicode yang ada di luar rentang UNICODE_LOW
dan UNICODE_HIGH
, dengan menggunakan &#
teknik ini.
Untuk menghindari karakter XML, cara termudah adalah dengan menggunakan proyek Apache Commons Lang, JAR dapat diunduh dari: http://commons.apache.org/lang/
Kelasnya adalah ini: org.apache.commons.lang3.StringEscapeUtils;
Ini memiliki metode bernama "escapeXml", yang akan mengembalikan String yang di-escape dengan tepat.
Jika Anda mencari perpustakaan untuk menyelesaikan pekerjaan, coba:
Jambu biji 26.0 didokumentasikan di sini
return XmlEscapers.xmlContentEscaper().escape(text);
Catatan: Ada juga file
xmlAttributeEscaper()
Apache Commons Text 1.4 didokumentasikan di sini
StringEscapeUtils.escapeXml11(text)
Catatan: Ada juga
escapeXml10()
metode
Berikut adalah solusi yang mudah dan bagus untuk mengenkode karakter beraksen juga!
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);
Keluaran
Hi Lârry & Môe!
Anda dapat menggunakan pustaka Enterprise Security API (ESAPI) , yang menyediakan metode seperti encodeForXML
dan encodeForXMLAttribute
. Lihat dokumentasi antarmuka Encoder ; itu juga berisi contoh bagaimana membuat sebuah instance dari DefaultEncoder .
Ganti saja
& with &
Dan untuk karakter lain:
> with >
< with <
\" with "
' with '
Gunakan JAXP dan lupakan tentang penanganan teks, itu akan dilakukan untuk Anda secara otomatis.
Cobalah untuk menyandikan XML menggunakan Apache XML serializer
//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());
Inilah yang saya temukan setelah mencari di mana-mana mencari solusi:
Dapatkan perpustakaan Jsoup:
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
Kemudian:
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()
Semoga ini bisa membantu seseorang