คล้ายกับคำถามนี้มากยกเว้น Java
วิธีที่แนะนำในการเข้ารหัสสตริงสำหรับเอาต์พุต XML ใน Java คืออะไร สตริงอาจมีอักขระเช่น "&", "<" เป็นต้น
คล้ายกับคำถามนี้มากยกเว้น Java
วิธีที่แนะนำในการเข้ารหัสสตริงสำหรับเอาต์พุต XML ใน Java คืออะไร สตริงอาจมีอักขระเช่น "&", "<" เป็นต้น
คำตอบ:
ง่ายมาก: ใช้ไลบรารี XML วิธีนี้จะถูกต้องแทนที่จะต้องมีความรู้โดยละเอียดเกี่ยวกับบิตของข้อกำหนด XML
ดังที่คนอื่น ๆ กล่าวถึงการใช้ไลบรารี XML เป็นวิธีที่ง่ายที่สุด หากคุณต้องการหนีตัวเองคุณสามารถดูได้StringEscapeUtils
จากห้องสมุดApache Commons Lang
StringEscapeUtils.escapeXml(str)
จากcommons-lang
. ฉันใช้มันในแอปพลิเคชัน App Engine - ทำงานได้อย่างมีเสน่ห์ นี่คือJava Docสำหรับฟังก์ชันนี้:
\t
, และ\n
\r
\t
, \n
หรือ\r
ความต้องการที่จะหนีออกมา?
เพียงแค่ใช้.
<![CDATA[ your text here ]]>
วิธีนี้จะอนุญาตให้มีอักขระใด ๆ ยกเว้นตอนจบ
]]>
ดังนั้นคุณสามารถใส่อักขระที่อาจผิดกฎหมายเช่น & และ> ตัวอย่างเช่น.
<element><![CDATA[ characters such as & and > are allowed ]]></element>
อย่างไรก็ตามแอตทริบิวต์จะต้องถูกหลีกเลี่ยงเนื่องจากไม่สามารถใช้บล็อก CDATA ได้
สิ่งนี้ได้ผลดีสำหรับฉันในการจัดเตรียมสตริงข้อความเวอร์ชันที่ใช้ Escape:
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
แต่มันควรที่จะพิจารณากรณีที่
คำถามนี้มีอายุแปดขวบแล้วและยังไม่ใช่คำตอบที่ถูกต้อง! ไม่คุณไม่ควรนำเข้า API ของบุคคลที่สามทั้งหมดเพื่อทำงานง่ายๆนี้ คำแนะนำที่ไม่ดี
วิธีการต่อไปนี้จะ:
ฉันพยายามเพิ่มประสิทธิภาพสำหรับกรณีที่พบบ่อยที่สุดในขณะที่ยังคงมั่นใจว่าคุณสามารถไพพ์ / dev / สุ่มผ่านสิ่งนี้และรับสตริงที่ถูกต้องใน 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();
}
แก้ไข: สำหรับผู้ที่ยังคงยืนยันว่ามันโง่ที่จะเขียนโค้ดของคุณเองสำหรับสิ่งนี้เมื่อมี Java API ที่ดีอย่างสมบูรณ์ในการจัดการกับ XML คุณอาจต้องการทราบว่า StAX API รวมอยู่ใน Oracle Java 8 (ฉันยังไม่ได้ทดสอบคนอื่น ) ล้มเหลวในการเข้ารหัสเนื้อหา CDATA อย่างถูกต้อง: ไม่ได้หลบหนี]]> ลำดับในเนื้อหา ไลบรารีของบุคคลที่สามแม้แต่ไลบรารีที่เป็นส่วนหนึ่งของคอร์ Java ก็ไม่ใช่ตัวเลือกที่ดีที่สุดเสมอไป
StringEscapeUtils.escapeXml()
ไม่หนีอักขระควบคุม (<0x20) XML 1.1 อนุญาตให้ใช้อักขระควบคุม XML 1.0 ไม่ได้ ตัวอย่างเช่น,XStream.toXML()
จะทำให้อักขระควบคุมของออบเจ็กต์ Java เป็นอนุกรมอย่างมีความสุขซึ่งตัวแยกวิเคราะห์ 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 แต่ IMHO หากคุณมีแนวคิดพื้นฐานเกี่ยวกับ XML สามัญสำนึกและประสิทธิภาพก็จะบอกว่าเทมเพลตได้ตลอดทาง มันอ่านง่ายกว่าด้วย แม้ว่าการใช้กิจวัตรการหลบหนีของห้องสมุดอาจเป็นความคิดที่ดี
พิจารณาสิ่งนี้: 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 ตอนนี้ไม่หนีอักขระ Unicode ที่มากกว่า 0x7f อีกต่อไป
นี่เป็นสิ่งที่ดีวิธีการเดิมคือการกระตือรือร้นที่จะหลบหนีเอนทิตีที่สามารถแทรกลงในเอกสาร utf8 ได้
Escapers ใหม่ที่จะรวมอยู่ใน Google Guava 11.0 ก็มีแนวโน้มเช่นกัน: http://code.google.com/p/guava-libraries/issues/detail?id=799
สำหรับผู้ที่มองหาวิธีการเขียนที่รวดเร็วที่สุด: ใช้วิธีการจากapache commons-lang :
StringEscapeUtils.escapeXml10()
สำหรับ xml 1.0StringEscapeUtils.escapeXml11()
สำหรับ xml 1.1StringEscapeUtils.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 ดูเรียบง่าย แต่สิ่งที่เข้ารหัส + หลบหนีนั้นเป็นลัทธิวูดูมืด (ซึ่งคุณจะสังเกตเห็นได้ทันทีที่คุณพบ umlauts และภาษาญี่ปุ่นและสิ่งแปลก ๆ อื่น ๆ เช่น " ตัวเลขเต็มความกว้าง " (& # FF11; คือ 1)) การรักษา XML ที่มนุษย์สามารถอ่านได้เป็นงานของ Sisyphus
ฉันขอแนะนำว่าอย่าพยายามฉลาดเกี่ยวกับการเข้ารหัสข้อความและการหลบหนีใน XML แต่อย่าปล่อยให้สิ่งนั้นหยุดคุณจากความพยายาม แค่จำไว้ว่าเมื่อไหร่ที่มันกัดคุณ (และมันจะ)
ที่กล่าวว่าหากคุณใช้เพียง UTF-8 เพื่อให้อ่านง่ายขึ้นคุณสามารถพิจารณากลยุทธ์นี้:
<![CDATA[ ... ]]>
ฉันใช้สิ่งนี้ในโปรแกรมแก้ไข SQL และช่วยให้นักพัฒนาสามารถตัดและวาง SQL จากเครื่องมือ SQL ของบุคคลที่สามลงใน XML ได้โดยไม่ต้องกังวลเกี่ยวกับการหลบหนี สิ่งนี้ได้ผลเนื่องจาก SQL ไม่สามารถมีเครื่องหมาย umlauts ในกรณีของเราดังนั้นฉันจึงปลอดภัย
แม้ว่าฉันจะเห็นด้วยกับ Jon Skeet โดยหลักการแล้วบางครั้งฉันก็ไม่มีตัวเลือกในการใช้ไลบรารี XML ภายนอก และฉันพบว่ามันแปลกที่ทั้งสองฟังก์ชั่นในการ Escape / unescape ค่าธรรมดา (แอตทริบิวต์หรือแท็กไม่ใช่เอกสารฉบับเต็ม) ไม่มีอยู่ในไลบรารี XML มาตรฐานที่มาพร้อมกับ Java
ด้วยเหตุนี้และจากคำตอบต่างๆที่ฉันเห็นโพสต์ไว้ที่นี่และที่อื่น ๆ นี่คือวิธีแก้ปัญหาที่ฉันได้สร้างขึ้น (ไม่มีอะไรทำงานเป็นสำเนา / วางแบบธรรมดา):
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;
}
ข้างต้นรองรับหลายสิ่งหลายอย่าง:
ในบางจุดฉันจะเขียนการผกผันของฟังก์ชันนี้เป็น Unescaped () ฉันไม่มีเวลาทำแบบนั้นในวันนี้ เมื่อฉันทำฉันจะมาอัปเดตคำตอบนี้พร้อมรหัส :)
null
อักขระ คุณสามารถอธิบายคำจำกัดความของค่าสองค่าUNICODE_LOW
และUNICODE_HIGH
? โปรดอ่านซ้ำif
ว่าใช้ค่าทั้งสองนี้ ข้อสังเกตnull
( \u0000
ซึ่งก็คือ(int)0
) ไม่อยู่ระหว่างสองค่านี้ อ่านว่ามันกลายเป็น "Escape" อย่างถูกต้องได้อย่างไรเช่นเดียวกับอักขระ Unicode ทั้งหมดที่มีอยู่นอกช่วงUNICODE_LOW
และUNICODE_HIGH
ช่วงโดยใช้&#
เทคนิค
หากต้องการหลีกเลี่ยงอักขระ XML วิธีที่ง่ายที่สุดคือใช้โครงการ Apache Commons Lang ซึ่งสามารถดาวน์โหลด JAR ได้จาก: http://commons.apache.org/lang/
คลาสคือ: org.apache.commons.lang3.StringEscapeUtils;
มันมีเมธอดชื่อ "escapeXml" ซึ่งจะส่งคืนสตริงที่ใช้ Escape อย่างเหมาะสม
หากคุณกำลังมองหาห้องสมุดเพื่อทำงานให้เสร็จลอง:
เอกสาร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!
คุณสามารถใช้ไลบรารี Enterprise Security API (ESAPI)ซึ่งมีวิธีการเช่นencodeForXML
encodeForXMLAttribute
และ ดูเอกสารของอินเทอร์เฟซตัวเข้ารหัส ก็ยังมีตัวอย่างของวิธีการสร้างตัวอย่างของDefaultEncoder
เพียงแค่แทนที่
& with &
และสำหรับตัวละครอื่น ๆ :
> with >
< with <
\" with "
' with '
พยายามเข้ารหัส XML โดยใช้ 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());
นี่คือสิ่งที่ฉันพบหลังจากค้นหาทุกที่เพื่อหาวิธีแก้ปัญหา:
รับไลบรารี 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()
หวังว่านี่จะช่วยใครบางคนได้
ฉันได้สร้างเสื้อคลุมของฉันที่นี่หวังว่ามันจะช่วยได้มากคลิกที่นี่คุณสามารถแก้ไขได้ตามความต้องการของคุณ