回答:
非常に簡単です。XMLライブラリを使用します。そうすれば、XML仕様のビットに関する詳細な知識を必要とするのではなく、実際に正しくなります。
他の人が述べたように、XMLライブラリを使用するのが最も簡単な方法です。脱出したい場合StringEscapeUtils
は、Apache Commons Langライブラリから調べることができます。
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に喜んでシリアライズします。XML1.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からの使用が2つの優れたソリューションであり、次の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より大きいUnicode文字をエスケープしなくなりました。
これは良いことです。古い方法は、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.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はシンプルに見えますが、エンコード+エスケープの要素は暗いブードゥー教です(ウムラウトや日本語など、 " 全角数字 "(&#FF11;は1)などの奇妙な要素に遭遇するとすぐにわかります)。XMLを人間が読めるようにすることは、シーシュポスの仕事です。
XMLでのテキストのエンコードとエスケープについては、決して賢いことをしないようにしてください。しかし、それを試してみるのをやめてはいけません。それがあなたを噛むときを覚えておいてください(そしてそれはそうします)。
つまり、UTF-8のみを使用する場合は、読みやすくするために、この戦略を検討できます。
<![CDATA[ ... ]]>
私はこれをSQLエディターで使用しています。開発者は、エスケープを心配することなく、サードパーティのSQLツールからXMLにSQLを切り取って貼り付けることができます。私たちの場合、SQLにウムラウトを含めることができないため、これは機能し、安全です。
私は基本的にJon Skeetに同意しますが、外部XMLライブラリを使用するオプションがない場合があります。そして、単純な値(属性またはタグ、完全なドキュメントではない)をエスケープ/アンエスケープする2つの関数は、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文字をエスケープするための最も簡単な方法は、http://commons.apache.org/lang/からダウンロード可能なJARであるApache Commons Langプロジェクトを使用することです。
クラスはこれです:org.apache.commons.lang3.StringEscapeUtils;
「escapeXml」という名前のメソッドがあり、適切にエスケープされた文字列を返します。
あなたが仕事を成し遂げるためのライブラリを探しているなら、試してください:
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のインスタンスを作成する方法の例も含まれています。
Apache XMLシリアライザーを使用して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()
これが誰かを助けることを願っています