web-dev-qa-db-ja.com

XMLパーサーエラー:エンティティが定義されていません

私はこの問題についてstackoverflowを検索し、いくつかのトピックを見つけましたが、これに関して私にとって本当に堅実な答えはないように感じます。

ユーザーが送信するフォームがあり、フィールドの値はXMLファイルに保存されます。 XMLはUTF-8でエンコードされるように設定されています。

ユーザーはどこかからテキストをコピー/貼り付けすることがありますが、そのときに「エンティティが定義されていないエラー」が表示されます。

XMLは選択されたいくつかのエンティティのみをサポートし、それを超えるものは認識されないことを認識しています。したがって、パーサーエラーです。

私が集めたものから、私が見たいくつかのオプションがあります:

  1. すべての を見つけて交換し、 または実際のスペースと交換できます。
  2. 問題のコードをCDATAセクション内に配置できます。
  3. これらのエンティティをXMLファイルに含めることができます。

XMLファイルで私がしていることは、ユーザーがフォームにコンテンツを入力し、XMLファイルに保存し、そのコンテンツをWebページにXHTMLとして表示することです(SimpleXMLで解析)。

3つのオプション、または私が気付いていない他のオプションのうち、これらのエンティティを処理するための実際の最良の方法は何ですか?

ありがとう、ライアン

[〜#〜] update [〜#〜]

素晴らしいフィードバックに感謝します。実際にエンティティエラーの原因を特定しました。すべての提案により、私はそれをより深く調べました!

いくつかのテキストボックスは単純な古いテキストボックスですが、私のテキストエリアはTinyMCEで強化されました。よく見ると、PHP警告は常にTinyMCE拡張テキストエリアのデータを参照していることがわかりました。後でPCですべての文字が削除されていることに気付きました。しかし、MACでは、その文字のユニコード番号を参照する小さな四角いボックスを見ることができました。そもそもMACで四角に表示された理由は、 UTFで、他の解析エラーを防止します(TinyMCEにも何らかの関係があります)。

これらすべての解決策は非常に簡単でした。

TinyMCE.initにentity_encoding : "utf-8"という行を追加しました。これで、すべてのキャラクターが想定どおりに表示されます。

私が理解できない唯一のことは、文字がテキストボックスに配置されたときにまだ文字が表示される理由だと思います。何も文字をUTFに変換しないためですが、TinyMCEでは問題でした。

30
NightHawk

これは純粋にエンコードの問題であることに同意します。 PHPでは、これがこの問題の解決方法です。

  1. Html-fragmentをSimpleXMLElementコンストラクターに渡す前に、_html_entity_decode_を使用してデコードしました。

  2. 次に、utf8_encode()を使用してさらにエンコードします。

_$headerDoc = '<temp>' . utf8_encode(html_entity_decode($headerFragment)) . '</temp>'; 
$xmlHeader = new SimpleXMLElement($headerDoc);
_

これで、上記のコードはndefined entityエラーをスローしません。

22
Gaurav Arya

テキストをHTML解析し、それぞれの数値エンティティのみで再エスケープすることができます(例:&nbsp;&#160;)。いずれにせよ—単にusing消毒されていないユーザー入力は悪い考えです。

すべての数値エンティティはXMLで使用できますが、HTMLから既知の名前付きエンティティのみが機能しません(&amp;&quot;&lt;&gt;&apos;)。

ほとんどの場合、実際の文字(&ouml;ö)をXMLファイルに追加するため、エンティティ参照を使用する必要はまったくありません。 DOM APIを使用してXMLを操作している場合(そうするべきです!)、これが最も安全な方法です。

最後に(これは怠zyな開発者ソリューションです)、壊れたXMLファイル(つまり、整形式ではなく、エンティティエラーがあります)を構築し、必要な修正のために tidyを介して渡す これは、全体が壊れているだけでhowによって機能するか、失敗する可能性があります。私の経験では、整頓はかなり賢明ですが、多くのことで逃げることができます。

15
Tomalak

1。すべての[&nbsp;?]を見つけて置き換え、[&#160;?]または実際のスペースと交換できます。

これは堅牢な方法ですが、すべてのHTMLエンティティの表(貼り付けられた入力はHTMLから来ていると仮定します)を持ち、エンティティ参照のために貼り付けられたテキストを解析する必要があります。

2。問題のコードをCDATAセクション内に配置できます。

つまり、セクション全体の解析を無効にしますか?次に、他の方法で解析する必要があります。できた。

3。これらのエンティティをXMLファイルに含めることができます。

エンティティ定義を含めるということですか? XMLファイルをかなり大きくしてもかまわないなら、これは簡単で堅牢な方法だと思います。メインのXMLファイルの上部から参照する外部エンティティである「インクルード」ファイル(Web上で見つける)を作成できます。

1つの欠点は、使用するXMLパーサーが外部エンティティを処理するものでなければならないことです(すべてのパーサーがそうする必要はありません)。また、外部エンティティの(おそらく相対的な)URLをアクセス可能なものに正しく解決する必要があります。これはそれほど悪くはありませんが、処理ツールの制約が増える可能性があります。

4。貼り付けられたコンテンツで非XMLを禁止できます。とりわけ、これにより、XMLで事前定義されていないエンティティ参照(Tomalakが言及した5つ)またはコンテンツ自体で定義されているエンティティ参照が禁止されます。ただし、ユーザーがHTMLをそこに貼り付ける必要がある場合、これはアプリケーションの要件に違反する可能性があります。

5。 someDiv.innerHTML = thePastedContent;を設定すると、貼り付けられたコンテンツをHTMLとしてDOMツリーに解析できます。つまり、どこかにdivを作成します(デバッグを除き、おそらくdisplay = none)。このdiv要素を保持するjavascript変数myDivと、入力テキストフィールドである要素を保持する別の変数myFieldがあるとします。次に、javascriptであなたがします

myDiv.innerHTML = myField.value;

myFieldから未解析のテキストを取得し、それをHTML DOMツリーに解析し、HTMLコンテンツとしてmyDivに貼り付けます。

次に、ブラウザベースのメソッドを使用して、DOMツリーをXMLにシリアル化(「解析解除」)します。たとえば、 この質問 を参照してください。次に、結果をXMLとしてサーバーに送信します。

この修正をブラウザーで行うかサーバーで行うか(@Hannesが提案したとおり)は、データのサイズ、応答の速さ、サーバーの性能、ハッカーの送信を気にするかどうかによって異なりますわざと整形式でないXML。

4
LarsH

すべての文字を変換したい場合、これはあなたを助けるかもしれません(私はしばらく前に書きました):

http://www.lautr.com/convert-all-applicable-characters-to-numeric-entities-for-use-in-xml

function _convertAlphaEntitysToNumericEntitys($entity) {
  return '&#'.ord(html_entity_decode($entity[0])).';';
}

$content = preg_replace_callback(
  '/&([\w\d]+);/i',
  '_convertAlphaEntitysToNumericEntitys',
  $content);

function _convertAsciOver127toNumericEntitys($entity) {
  if(($asciCode = ord($entity[0])) > 127)
    return '&#'.$asciCode.';';
  else
    return $entity[0];
}

$content = preg_replace_callback(
  '/[^\w\d ]/i',
  '_convertAsciOver127toNumericEntitys', $content);
1
Hannes

この質問は、XMLまたはJSONを解析するすべての言語(つまり、基本的にすべての言語)の一般的な問題です。

上記の答えはPHP向けですが、Perlソリューションは次のように簡単です...

my $excluderegex =
    '^\n\x20-\x20' .   # Don't Encode Spaces
       '\x30-\x39' .   # Don't Encode Numbers
       '\x41-\x5a' .   # Don't Encode Capitalized Letters
       '\x61-\x7a' ;   # Don't Encode Lowercase Letters

    # in case anything is already encoded
$value = HTML::Entities::decode_entities($value);

    # encode properly to numeric
$value = HTML::Entities::encode_numeric($value, $excluderegex);
0
HoldOffHunger