diff --git a/Modules/Parser/Sources/SAX/HTMLEntityDecoder.swift b/Modules/Parser/Sources/SAX/HTMLEntityDecoder.swift
new file mode 100644
index 000000000..5f37fe593
--- /dev/null
+++ b/Modules/Parser/Sources/SAX/HTMLEntityDecoder.swift
@@ -0,0 +1,51 @@
+//
+// HTMLEntityDecoder.swift
+//
+//
+// Created by Brent Simmons on 9/14/24.
+//
+
+import Foundation
+
+public final class HTMLEntityDecoder {
+
+ static func decodedString(withEncodedString encodedString: String) -> String {
+
+ let scanner = Scanner(string: encodedString)
+ scanner.charactersToBeSkipped = nil
+ var result = ""
+ var didDecodeAtLeastOneEntity = false
+
+ while true {
+
+ var scannedString = nil
+ if scanner.scanUpToString("&" intoString: &scannedString) {
+ result.append(scannedString)
+ }
+ if scanner.isAtEnd {
+ break
+ }
+
+ let savedScanLocation = scanner.scanLocation
+
+ var decodedEntity: String? = nil
+ if scanner.scanEntityValue(&decodedEntity) {
+ result.append(decodedEntity)
+ didDecodeAtLeastOneEntity = true
+ }
+ else {
+ result.append("&")
+ scanner.scanLocation = savedScanLocation + 1
+ }
+
+ if scanner.isAtEnd {
+ break
+ }
+ }
+
+ if !didDecodeAtLeastOneEntity { // No changes made?
+ return encodedString
+ }
+ return result
+ }
+}