Java dışında bu soruya çok benzer .
Java'da bir XML çıktısı için dizeleri kodlamanın önerilen yolu nedir? Dizeler "&", "<" vb. Karakterler içerebilir.
Yanıtlar:
Çok basit: bir XML kitaplığı kullanın. Bu şekilde , XML spesifikasyonunun bitleri hakkında ayrıntılı bilgi gerektirmek yerine aslında doğru olacaktır .
Diğerlerinin de belirttiği gibi, bir XML kitaplığı kullanmak en kolay yoldur. Kendinizden kaçmak istiyorsanız StringEscapeUtils
, Apache Commons Lang kütüphanesine bakabilirsiniz .
StringEscapeUtils.escapeXml(str)
dan commons-lang
. Bunu App Engine uygulamasında kullanıyorum - bir cazibe gibi çalışıyorum. İşte bu işlev için Java Doc :
\t
, \n
ve \r
.
\t
, \n
veya \r
ihtiyaçları çıkış yapılmasını?
Sadece kullan.
<![CDATA[ your text here ]]>
Bu, son hariç tüm karakterlere izin verir
]]>
Böylece & ve> gibi yasa dışı olabilecek karakterleri ekleyebilirsiniz. Örneğin.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
Bununla birlikte, CDATA blokları onlar için kullanılamayacağından özniteliklerin öncelenmesi gerekecektir.
Bu, bir metin dizesinin çıkış karakterli bir sürümünü sağlamam için iyi çalıştı:
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();
}
}
Bunu dene:
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
.
Bu soru sekiz yaşında ve hala tam olarak doğru bir cevap değil! Hayır, bu basit görevi gerçekleştirmek için bir üçüncü taraf API'sinin tamamını içe aktarmanız gerekmemelidir. Kötü tavsiye.
Aşağıdaki yöntem:
En yaygın durum için optimize etmeye çalışırken, yine de bunun içinden / dev / random'u yönlendirip XML'de geçerli bir dize alabilmenizi sağlamaya çalıştım.
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();
}
Düzenleme: XML ile başa çıkmak için mükemmel Java API'leri varken bunun için kendi kodunuzu yazmanın aptalca olduğunu söylemeye devam edenler için, StAX API'nin Oracle Java 8'e dahil olduğunu bilmek isteyebilirsiniz (Başkalarını test etmedim) ) CDATA içeriğini doğru bir şekilde kodlayamaz: içerikteki]]> dizilerden kaçmaz. Java çekirdeğinin bir parçası olsa bile üçüncü taraf bir kitaplık her zaman en iyi seçenek değildir.
StringEscapeUtils.escapeXml()
kontrol karakterlerinden (<0x20) çıkış yapmaz. XML 1.1 kontrol karakterlerine izin verir; XML 1.0 bunu yapmaz. Örneğin, XStream.toXML()
bir Java nesnesinin kontrol karakterlerini, XML 1.0 ayrıştırıcısının reddedeceği mutlu bir şekilde XML'e serileştirir.
Apache commons-lang ile kontrol karakterlerinden çıkmak için şunu kullanın:
NumericEntityEscaper.below(0x20).translate(StringEscapeUtils.escapeXml(str))
public String escapeXml(String s) {
return s.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<").replaceAll("\"", """).replaceAll("'", "'");
}
replaceAll
aramaları, özellikle büyük dizeler için çok verimsizdir. Her çağrı, yeni bir String nesnesinin oluşturulmasına neden olur ve bu, çöp toplanana kadar burada kalır. Ayrıca, her çağrı dizede tekrar döngü yapılmasını gerektirir. Bu, her yinelemede her bir hedef karaktere karşı karşılaştırmalarla tek bir manuel döngüde birleştirilebilir.
İdealizm bir XML kitaplığı kullanmayı söylerken, IMHO XML hakkında temel bir fikriniz varsa, o zaman sağduyu ve performans bunu şablon olarak söylüyor. Muhtemelen daha okunaklı. Bir kütüphanenin kaçış rutinlerini kullanmak muhtemelen iyi bir fikirdir.
Şunu bir düşünün: XML , insanlar tarafından yazılmaktı.
XML'inizi "nesne" olarak aldığınızda, sorununuzu daha iyi modellerken, XML oluşturmak için kitaplıkları kullanın. Örneğin, takılabilir modüller bu XML'yi oluşturma sürecine katılırsa.
Düzenleme: Şablonlarda XML'den nasıl kaçılacağına escapeXml(string)
gelince, CDATA veya JSTL'den iki iyi çözüm, escapeXml(string)
şu şekilde kullanılabilir:
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<item>${fn:escapeXml(value)}</item>
StringEscapeUtils.escapeXml () davranışı Commons Lang 2.5'ten 3.0'a değiştirildi. Artık 0x7f'den büyük Unicode karakterlerinin dışına çıkmamaktadır.
Bu iyi bir şey, eski yöntem, sadece utf8 belgesine eklenebilecek varlıklardan kaçmak için biraz istekli olmaktı.
Google Guava 11.0'a dahil edilecek yeni escaper'lar da umut verici görünüyor: http://code.google.com/p/guava-libraries/issues/detail?id=799
Yazması en hızlı çözümü arayanlar için: apache commons-lang'ın yöntemlerini kullanın :
StringEscapeUtils.escapeXml10()
xml 1.0 içinStringEscapeUtils.escapeXml11()
xml 1.1 içinStringEscapeUtils.escapeXml()
artık kullanımdan kaldırıldı, ancak geçmişte yaygın olarak kullanıldıBağımlılığı eklemeyi unutmayın:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version> <!--check current version! -->
</dependency>
Not: Sorunuz hakkındadır kaçan değil, kodlama . Kaçış, ayrıştırıcının "bu bir XML komutu" ve "bu bir metindir" arasında ayrım yapmasına izin vermek için <, vb. Kullanıyor. Kodlama, XML başlığında belirttiğiniz şeylerdir (UTF-8, ISO-8859-1, vb.).
Öncelikle, herkesin söylediği gibi, bir XML kitaplığı kullanın. XML basit görünür, ancak kodlama + kaçan şeyler karanlık vududur (ki bu , çift noktalı harfler, Japonca ve " tam genişlikte rakamlar " gibi diğer garip şeylerle karşılaştığınızda hemen fark edeceksiniz (& # FF11; 1'dir)). XML'i insan tarafından okunabilir tutmak, Sisifos'un görevidir.
XML'de metin kodlama ve kaçış konusunda asla zeki olmayı denememenizi öneririm. Ama bunun denemenizi engellemesine izin vermeyin; sadece seni ne zaman ısırdığını hatırla (ve yapacak).
Bununla birlikte, işleri daha okunaklı hale getirmek için yalnızca UTF-8 kullanıyorsanız, şu stratejiyi düşünebilirsiniz:
<![CDATA[ ... ]]>
Bunu bir SQL düzenleyicide kullanıyorum ve geliştiricilerin üçüncü taraf bir SQL aracından SQL'i kesip kaçma endişesi olmadan XML'e yapıştırmasına izin veriyor. Bu işe yarar çünkü bizim durumumuzda SQL çift nokta içeremez, bu yüzden güvendeyim.
Prensip olarak Jon Skeet'e katılıyorum, ancak bazen harici bir XML kitaplığı kullanma seçeneğim yok. Ve basit bir değerden kaçış / geri alma işlevinin (öznitelik veya etiket, tam belge değil) Java'da bulunan standart XML kitaplıklarında bulunmamasını garip buluyorum.
Sonuç olarak ve burada ve başka yerlerde gördüğüm farklı yanıtlara dayanarak, işte oluşturduğum çözüm burada (hiçbir şey basit bir kopyala / yapıştır olarak işe yaramadı):
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;
}
Yukarıdakiler birkaç farklı şeyi barındırır:
Bir noktada, bu işlevin tersini yazacağım toUnescaped (). Bugün bunu yapacak vaktim yok. Bunu yaptığımda, bu cevabı kodla güncelleyeceğim. :)
null
. Eğer iki değer tanımını açıklar, Can UNICODE_LOW
ve UNICODE_HIGH
? Lütfen if
bu iki değeri kullananı tekrar okuyun . Dikkat null
( \u0000
olan (int)0
) bu iki değerin arasına girmez. Tekniği kullanarak, tıpkı UNICODE_LOW
ve UNICODE_HIGH
aralığı dışında bulunan TÜM Unicode karakterleri gibi nasıl düzgün bir şekilde "kaçtı" olduğunu okuyun &#
.
XML karakterlerinden kaçınmanın en kolay yolu, JAR adresinden indirilebilen Apache Commons Lang projesini kullanmaktır: http://commons.apache.org/lang/
Sınıf şudur: org.apache.commons.lang3.StringEscapeUtils;
Uygun şekilde öncelenmiş bir String döndüren "escapeXml" adlı bir yöntemi vardır.
İşi bitirmek için bir kütüphane arıyorsanız, şunu deneyin:
Guava 26.0 burada belgelenmiştir
return XmlEscapers.xmlContentEscaper().escape(text);
Not: Ayrıca bir
xmlAttributeEscaper()
Apache Commons Text 1.4 burada belgelenmiştir
StringEscapeUtils.escapeXml11(text)
Not: Ayrıca bir
escapeXml10()
yöntem var
İşte kolay bir çözüm ve aksanlı karakterleri kodlamak için de harika!
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);
çıktılar
Hi Lârry & Môe!
Sen kullanabilirsiniz Enterprise Security API (ESAPI) kütüphane gibi yöntemler sağlar, encodeForXML
ve encodeForXMLAttribute
. Kodlayıcı arayüzünün belgelerine bir göz atın ; ayrıca DefaultEncoder örneğinin nasıl oluşturulacağına dair örnekler de içerir .
Sadece değiştir
& with &
Ve diğer karakterler için:
> with >
< with <
\" with "
' with '
JAXP'yi kullanın ve metin işlemeyi unutun, sizin için otomatik olarak yapılacaktır.
Apache XML serileştiricisini kullanarak XML'i kodlamayı deneyin
//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());
Her yerde bir çözüm aradıktan sonra bulduğum şey şu:
Jsoup kitaplığını edinin:
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
Sonra:
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()
Umarım bu birine yardımcı olur
Sarıcımı burada oluşturdum, umarım çok yardımcı olur, Buraya tıklayın Gereksinimlerinize göre değişiklik yapabilirsiniz