자바 스크립트에서 xml 엔티티를 이스케이프하는 방법은 무엇입니까?


78

JavaScript (서버 측 nodejs)에서 xml을 출력으로 생성하는 프로그램을 작성하고 있습니다.

문자열을 연결하여 xml을 작성하고 있습니다.

str += '<' + key + '>';
str += value;
str += '</' + key + '>';

문제는 다음 value과 같습니다. '&', '>'또는 '<'? 그 캐릭터를 탈출하는 가장 좋은 방법은 무엇입니까?

또는 XML 엔티티를 이스케이프 할 수있는 자바 스크립트 라이브러리가 있습니까?

답변:


119

HTML 인코딩은 단순히 대체 &, ", ', <그리고 >자신의 엔티티 등가물로 문자를. 순서가 중요합니다. &먼저 문자를 바꾸지 않으면 일부 엔터티를 이중 인코딩합니다.

if (!String.prototype.encodeHTML) {
  String.prototype.encodeHTML = function () {
    return this.replace(/&/g, '&amp;')
               .replace(/</g, '&lt;')
               .replace(/>/g, '&gt;')
               .replace(/"/g, '&quot;')
               .replace(/'/g, '&apos;');
  };
}

@Johan BW 드 브리스가 지적한 바와 같이,이 태그 이름에 문제가있을 것이다, 나는이가 사용되었다는 가정하에 작성 명확히하고 싶습니다 value

반대로 HTML 엔터티 1 을 디코딩 &amp;하려면 &엔터티를 이중 디코딩하지 않도록 다른 모든 항목 이후에 디코딩해야합니다 .

if (!String.prototype.decodeHTML) {
  String.prototype.decodeHTML = function () {
    return this.replace(/&apos;/g, "'")
               .replace(/&quot;/g, '"')
               .replace(/&gt;/g, '>')
               .replace(/&lt;/g, '<')
               .replace(/&amp;/g, '&');
  };
}

1 개 포함뿐만 아니라 기초, &copy;©또는 다른 것들


도서관에 관한 한. Underscore.js (또는 원하는 경우 Lodash )는 _.escape이 기능을 수행 하는 방법을 제공 합니다.


2
이것은 5 개의 XML 엔티티를 거의 다룹니다. @apos가 필요합니다.
Ryan

2
이것은 동일한 문자열을 반복해서 교체하는 것처럼 보이며 많은 데이터를 처리 할 때 성능이 저하 될 수 있습니다. 더 빠른 대안이 있습니까?
Jonny

2
@Jonny, 정규 표현식은 .replace(). 두 경우 모두 중대한 문제를 파악하려면 엄청나게 방대한 양의 데이터가 있어야합니다. 더 빠른 대안은 이처럼 무시할 수있는 것에 대해 걱정하는 것보다 앱을 벤치마킹하고 실제 초크 포인트 (일반적으로 중첩 된 루프)를 찾는 것입니다.
zzzzBov

1
Google 스프레드 시트에 100-200 줄의 데이터가 있습니다. 나는 그것을 plists (xml)로 변환하고 그 xml 엔티티를 대체해야했습니다. 위의 코드를 사용하여 사용자 지정 자바 스크립트 함수를 작성했습니다. 작동했지만 매우 느 렸습니다. 스프레드 시트는 때때로 질식하지만 "한 번만"단계이기 때문에 결국 속도는 중요하지 않았습니다.
조니

4
이 답변은 오래되었다는 것을 알고 있지만 JS를 처음 접하는 사람들에게 명확하게하기 위해 일부 표준화 된 제안에 대한 polyfill이 아닌 임의의 함수를 전역 프로토 타입에 연결하는 것은 나쁜 생각입니다.
austin_ce

104

이것은 동일한 결과로 좀 더 효율적일 수 있습니다.

function escapeXml(unsafe) {
    return unsafe.replace(/[<>&'"]/g, function (c) {
        switch (c) {
            case '<': return '&lt;';
            case '>': return '&gt;';
            case '&': return '&amp;';
            case '\'': return '&apos;';
            case '"': return '&quot;';
        }
    });
}

이것은 더 나은 해결책 인 것 같습니다. 왜 상승세가 없습니까?
Victor Grazi

1
@VictorGrazi : 귀하의 권리, 50 개 중 49 개가 더 빠른 솔루션을 테스트합니다. 아마도 받아 들여진 대답보다 거의 5 년이 어리기 때문일 것입니다.
세바스찬

1
@Sebastian 아, 그게 설명하겠습니다, 감사합니다. 여기 여러분들보세요 ^ ^ ^ ^ 이것이 당신이 원하는 솔루션입니다 !!!
Victor Grazi 2015-08-12

이것은 단일 문자에 대한 일치를 찾기 위해 전체 문자열을 5 번 (연속적으로 JS 엔진 최적화의 범위를 줄임) 탐색하는 허용 된 답변보다 더 나은 솔루션이라고 생각합니다. hgoebl 의 솔루션은 입력 문자열을 한 번만 탐색하여 각 문자를 5 가지 조건 중 하나와 일치 시키려고합니다. 문제는 더 많은 비용이 드는 것입니다. 1) 문자열을 순회합니다. 또는 : 2) 각 문자를 5 개의 가능한 문자와 일치시킵니다. 내 직감은 1) 비용이 더 많이 든다는 것입니다.
Jamie Birch

1
입력이 HTML 인 경우 @RanLottem 디코딩은 훨씬 더 복잡합니다 . Wikipedia를 참조하세요 . 파서 (XML 또는 문서)를 사용하는 것이 좋습니다.
hgoebl

21

jQuery가있는 경우 다음은 간단한 솔루션입니다.

  String.prototype.htmlEscape = function() {
    return $('<div/>').text(this.toString()).html();
  };

다음과 같이 사용하십시오.

"<foo&bar>".htmlEscape(); -> "&lt;foo&amp;bar&gt"


1
나는이 기술이 "브라우저가하게하는"태도를 좋아한다. 이것이 DOM API를 거치기 때문에 성능 저하 이외의 단점이 있습니까?
avernet

이 기술에서는 작은 따옴표와 큰 따옴표를 이스케이프하지 않습니다 $('<div/>').text('<&\'>"').html() .-> "&lt;&amp;'&gt;""
majgis

1
일반적으로 작은 따옴표와 큰 따옴표는 이스케이프 할 필요가 없습니다.
lambshaanxy 2015 년

7

아래 방법을 사용할 수 있습니다. 쉽게 액세스 할 수 있도록 프로토 타입에 추가했습니다. 나는 또한 부정적인 미리보기를 사용했기 때문에 메소드를 두 번 이상 호출하면 일을 엉망으로 만들지 않을 것입니다.

용법:

 var original = "Hi&there";
 var escaped = original.EncodeXMLEscapeChars();  //Hi&amp;there

디코딩은 XML 파서에서 자동으로 처리됩니다.

방법 :

//String Extenstion to format string for xml content.
//Replces xml escape chracters to their equivalent html notation.
String.prototype.EncodeXMLEscapeChars = function () {
    var OutPut = this;
    if ($.trim(OutPut) != "") {
        OutPut = OutPut.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
        OutPut = OutPut.replace(/&(?!(amp;)|(lt;)|(gt;)|(quot;)|(#39;)|(apos;))/g, "&amp;");
        OutPut = OutPut.replace(/([^\\])((\\\\)*)\\(?![\\/{])/g, "$1\\\\$2");  //replaces odd backslash(\\) with even.
    }
    else {
        OutPut = "";
    }
    return OutPut;
};

3
저평가 된 우수한 솔루션. 악명 높은 & amp; amp; amp; 출력의 문자열이 아름답습니다.
Steve Westbrook

이 코드를 사용 하여 모든 응용 프로그램에서 String의 모든 인스턴스를 편집했습니다. 예를 들어이 let a = 'foo'코드의 영향을받습니다. 프로토 타입을 확장하는 대신 도우미 함수를 더 잘 만듭니다.
Lukas Liesis

충돌을 일으키기 때문에 내장 객체를 변경하지 마십시오.
slikts

1

나는 원래 프로덕션 코드에서 받아 들여진 대답을 사용했으며 실제로 많이 사용하면 실제로 느리다는 것을 알았습니다. 다음은 훨씬 더 빠른 솔루션입니다 (두 배 이상의 속도로 실행).

   var escapeXml = (function() {
        var doc = document.implementation.createDocument("", "", null)
        var el = doc.createElement("temp");
        el.textContent = "temp";
        el = el.firstChild;
        var ser =  new XMLSerializer();
        return function(text) {
            el.nodeValue = text;
            return ser.serializeToString(el);
        };
    })();

console.log(escapeXml("<>&")); //&lt;&gt;&amp;

이것은 당신이 document물건 을 가지고 있다고 가정 합니다. 나는 그것을 가지고 있지 않다.
Lukas Liesis

1

시도해 볼 수 있습니다.

function encodeXML(s) {
  const dom = document.createElement('div')
  dom.textContent = s
  return dom.innerHTML
}

참고


1

주의, XML 내부에 XML이 있으면 모든 정규식이 좋지 않습니다.
대신 문자열을 한 번 반복하고 모든 이스케이프 문자를 대체하십시오.
그렇게하면 같은 캐릭터를 두 번 넘을 수 없습니다.

function _xmlAttributeEscape(inputString)
{
    var output = [];

    for (var i = 0; i < inputString.length; ++i)
    {
        switch (inputString[i])
        {
            case '&':
                output.push("&amp;");
                break;
            case '"':
                output.push("&quot;");
                break;
            case "<":
                output.push("&lt;");
                break;
            case ">":
                output.push("&gt;");
                break;
            default:
                output.push(inputString[i]);
        }


    }

    return output.join("");
}


0

이전에서 탈출 한 것이 있으면 다른 많은 사람처럼 이중 탈출이되지 않으므로 시도해 볼 수 있습니다.

function escape(text) {
    return String(text).replace(/(['"<>&'])(\w+;)?/g, (match, char, escaped) => {
        if(escaped) 
            return match

        switch(char) {
            case '\'': return '&quot;'
            case '"': return '&apos;'
            case '<': return '&lt;'
            case '>': return '&gt;'
            case '&': return '&amp;'
        }
    })
}

-1

이것은 간단합니다.

sText = ("" + sText).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;");

1
위의 대체 방법에 비해이 '간단한'세계는 어디입니까?
Sam Holder

쓰기가 간단하고 위의 것보다 간단하다고 말하지 않았습니다. 그냥 다른
당 고쉬

4
나는 더 나쁜 해결책을 생각하려고 애 쓰고있다
developerbmw

당신이 방법을 추가하지 않고 jQuery를 사용하지 않는 경우 @developerbmw,이 최상의 솔루션 중 하나입니다
당 고쉬

1
가독성을 위해 @developerbmw, 때로는 위에서 아래로 기능을 읽을 수 있도록 코드를 작성하는 것이 더 좋습니다. 동적 언어는 읽기 어렵게 만들기가 매우 쉽습니다. 상황에 따라 다릅니다. 또한 다른 시나리오에서 사용되며 자체 논리가 필요한 구성 요소를 사용합니다. 로직이 한 가지 방법에서만 사용되는 경우 작은 구성 요소에는 기능이 필요하지 않을 수 있습니다. 저는 C ++ 개발자이고 많은 C를 코딩 해 왔습니다. C는 읽기가 매우 쉽습니다. 왜 그런지 알고 있다면 이것에 대한 제 주장을 알고
계십니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.