diff --git a/core/lib/Drupal/Component/Utility/Xss.php b/core/lib/Drupal/Component/Utility/Xss.php
index 8d0d257..cfd3c19 100644
--- a/core/lib/Drupal/Component/Utility/Xss.php
+++ b/core/lib/Drupal/Component/Utility/Xss.php
@@ -54,8 +54,7 @@ public static function filter($string, $allowed_tags = array('a', 'em', 'strong'
     if (!Unicode::validateUtf8($string)) {
       return '';
     }
-    // Store the text format.
-    static::split($allowed_tags, TRUE);
+    $splitter = new XssSplitter($allowed_tags);
     // Remove NULL characters (ignored by some browsers).
     $string = str_replace(chr(0), '', $string);
     // Remove Netscape 4 JS entities.
@@ -80,7 +79,7 @@ public static function filter($string, $allowed_tags = array('a', 'em', 'strong'
       <[^>]*(>|$)       # a string that starts with a <, up until the > or the end of the string
       |                 # or
       >                 # just a >
-      )%x', '\Drupal\Component\Utility\Xss::split', $string);
+      )%x', array($splitter, 'split'), $string);
   }
 
   /**
@@ -103,184 +102,4 @@ public static function filterAdmin($string) {
     return static::filter($string, static::$adminTags);
   }
 
-  /**
-   * Processes an HTML tag.
-   *
-   * @param array $matches
-   *   An array with various meaning depending on the value of $store.
-   *   If $store is TRUE then the array contains the allowed tags.
-   *   If $store is FALSE then the array has one element, the HTML tag to process.
-   * @param bool $store
-   *   Whether to store $m.
-   *
-   * @return string
-   *   If the element isn't allowed, an empty string. Otherwise, the cleaned up
-   *   version of the HTML element.
-   */
-  protected static function split($matches, $store = FALSE) {
-    static $allowed_html;
-
-    if ($store) {
-      $allowed_html = array_flip($matches);
-      return;
-    }
-
-    $string = $matches[1];
-
-    if (substr($string, 0, 1) != '<') {
-      // We matched a lone ">" character.
-      return '&gt;';
-    }
-    elseif (strlen($string) == 1) {
-      // We matched a lone "<" character.
-      return '&lt;';
-    }
-
-    if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
-      // Seriously malformed.
-      return '';
-    }
-
-    $slash = trim($matches[1]);
-    $elem = &$matches[2];
-    $attrlist = &$matches[3];
-    $comment = &$matches[4];
-
-    if ($comment) {
-      $elem = '!--';
-    }
-
-    if (!isset($allowed_html[strtolower($elem)])) {
-      // Disallowed HTML element.
-      return '';
-    }
-
-    if ($comment) {
-      return $comment;
-    }
-
-    if ($slash != '') {
-      return "</$elem>";
-    }
-
-    // Is there a closing XHTML slash at the end of the attributes?
-    $attrlist = preg_replace('%(\s?)/\s*$%', '\1', $attrlist, -1, $count);
-    $xhtml_slash = $count ? ' /' : '';
-
-    // Clean up attributes.
-    $attr2 = implode(' ', static::attributes($attrlist));
-    $attr2 = preg_replace('/[<>]/', '', $attr2);
-    $attr2 = strlen($attr2) ? ' ' . $attr2 : '';
-
-    return "<$elem$attr2$xhtml_slash>";
-  }
-
-  /**
-   * Processes a string of HTML attributes.
-   *
-   * @param string $attributes
-   *   The html attribute to process.
-   *
-   * @return string
-   *   Cleaned up version of the HTML attributes.
-   */
-  protected static function attributes($attributes) {
-    $attributes_array = array();
-    $mode = 0;
-    $attribute_name = '';
-    $skip = FALSE;
-
-    while (strlen($attributes) != 0) {
-      // Was the last operation successful?
-      $working = 0;
-
-      switch ($mode) {
-        case 0:
-          // Attribute name, href for instance.
-          if (preg_match('/^([-a-zA-Z]+)/', $attributes, $match)) {
-            $attribute_name = strtolower($match[1]);
-            $skip = ($attribute_name == 'style' || substr($attribute_name, 0, 2) == 'on');
-            $working = $mode = 1;
-            $attributes = preg_replace('/^[-a-zA-Z]+/', '', $attributes);
-          }
-          break;
-
-        case 1:
-          // Equals sign or valueless ("selected").
-          if (preg_match('/^\s*=\s*/', $attributes)) {
-            $working = 1; $mode = 2;
-            $attributes = preg_replace('/^\s*=\s*/', '', $attributes);
-            break;
-          }
-
-          if (preg_match('/^\s+/', $attributes)) {
-            $working = 1; $mode = 0;
-            if (!$skip) {
-              $attributes_array[] = $attribute_name;
-            }
-            $attributes = preg_replace('/^\s+/', '', $attributes);
-          }
-          break;
-
-        case 2:
-          // Attribute value, a URL after href= for instance.
-          if (preg_match('/^"([^"]*)"(\s+|$)/', $attributes, $match)) {
-            $thisval = Url::filterBadProtocol($match[1]);
-
-            if (!$skip) {
-              $attributes_array[] = "$attribute_name=\"$thisval\"";
-            }
-            $working = 1;
-            $mode = 0;
-            $attributes = preg_replace('/^"[^"]*"(\s+|$)/', '', $attributes);
-            break;
-          }
-
-          if (preg_match("/^'([^']*)'(\s+|$)/", $attributes, $match)) {
-            $thisval = Url::filterBadProtocol($match[1]);
-
-            if (!$skip) {
-              $attributes_array[] = "$attribute_name='$thisval'";
-            }
-            $working = 1; $mode = 0;
-            $attributes = preg_replace("/^'[^']*'(\s+|$)/", '', $attributes);
-            break;
-          }
-
-          if (preg_match("%^([^\s\"']+)(\s+|$)%", $attributes, $match)) {
-            $thisval = Url::filterBadProtocol($match[1]);
-
-            if (!$skip) {
-              $attributes_array[] = "$attribute_name=\"$thisval\"";
-            }
-            $working = 1; $mode = 0;
-            $attributes = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attributes);
-          }
-          break;
-      }
-
-      if ($working == 0) {
-        // Not well formed; remove and try again.
-        $attributes = preg_replace('/
-          ^
-          (
-          "[^"]*("|$)     # - a string that starts with a double quote, up until the next double quote or the end of the string
-          |               # or
-          \'[^\']*(\'|$)| # - a string that starts with a quote, up until the next quote or the end of the string
-          |               # or
-          \S              # - a non-whitespace character
-          )*              # any number of the above three
-          \s*             # any number of whitespaces
-          /x', '', $attributes);
-        $mode = 0;
-      }
-    }
-
-    // The attribute list ends with a valueless attribute like "selected".
-    if ($mode == 1 && !$skip) {
-      $attributes_array[] = $attribute_name;
-    }
-    return $attributes_array;
-  }
-
 }
diff --git a/core/lib/Drupal/Component/Utility/XssSplitter.php b/core/lib/Drupal/Component/Utility/XssSplitter.php
new file mode 100644
index 0000000..a683db6
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/XssSplitter.php
@@ -0,0 +1,199 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\XssSplitter.
+ */
+
+namespace Drupal\Component\Utility;
+
+/**
+ * This is a helper class for Xss, it has no use alone.
+ */
+class XssSplitter {
+
+  /**
+   * The keys are the allowed HTML tags.
+   *
+   * @var array
+   */
+  protected $allowedHtml;
+
+  function __construct(array $allowed_html) {
+    $this->allowedHtml = $allowed_html;
+  }
+
+  /**
+   * Processes an HTML tag.
+   *
+   * @param array $matches
+   *   An array with various meaning depending on the value of $store.
+   *   If $store is TRUE then the array contains the allowed tags.
+   *   If $store is FALSE then the array has one element, the HTML tag to process.
+   * @param bool $store
+   *   Whether to store $m.
+   *
+   * @return string
+   *   If the element isn't allowed, an empty string. Otherwise, the cleaned up
+   *   version of the HTML element.
+   */
+  public function split($matches, $store = FALSE) {
+    $string = $matches[1];
+
+    if (substr($string, 0, 1) != '<') {
+      // We matched a lone ">" character.
+      return '&gt;';
+    }
+    elseif (strlen($string) == 1) {
+      // We matched a lone "<" character.
+      return '&lt;';
+    }
+
+    if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
+      // Seriously malformed.
+      return '';
+    }
+
+    $slash = trim($matches[1]);
+    $elem = &$matches[2];
+    $attrlist = &$matches[3];
+    $comment = &$matches[4];
+
+    if ($comment) {
+      $elem = '!--';
+    }
+
+    if (!isset($this->allowedHtml[strtolower($elem)])) {
+      // Disallowed HTML element.
+      return '';
+    }
+
+    if ($comment) {
+      return $comment;
+    }
+
+    if ($slash != '') {
+      return "</$elem>";
+    }
+
+    // Is there a closing XHTML slash at the end of the attributes?
+    $attrlist = preg_replace('%(\s?)/\s*$%', '\1', $attrlist, -1, $count);
+    $xhtml_slash = $count ? ' /' : '';
+
+    // Clean up attributes.
+    $attr2 = implode(' ', $this->attributes($attrlist));
+    $attr2 = preg_replace('/[<>]/', '', $attr2);
+    $attr2 = strlen($attr2) ? ' ' . $attr2 : '';
+
+    return "<$elem$attr2$xhtml_slash>";
+  }
+
+  /**
+   * Processes a string of HTML attributes.
+   *
+   * @param string $attributes
+   *   The html attribute to process.
+   *
+   * @return string
+   *   Cleaned up version of the HTML attributes.
+   */
+  protected function attributes($attributes) {
+    $attributes_array = array();
+    $mode = 0;
+    $attribute_name = '';
+    $skip = FALSE;
+
+    while (strlen($attributes) != 0) {
+      // Was the last operation successful?
+      $working = 0;
+
+      switch ($mode) {
+        case 0:
+          // Attribute name, href for instance.
+          if (preg_match('/^([-a-zA-Z]+)/', $attributes, $match)) {
+            $attribute_name = strtolower($match[1]);
+            $skip = ($attribute_name == 'style' || substr($attribute_name, 0, 2) == 'on');
+            $working = $mode = 1;
+            $attributes = preg_replace('/^[-a-zA-Z]+/', '', $attributes);
+          }
+          break;
+
+        case 1:
+          // Equals sign or valueless ("selected").
+          if (preg_match('/^\s*=\s*/', $attributes)) {
+            $working = 1; $mode = 2;
+            $attributes = preg_replace('/^\s*=\s*/', '', $attributes);
+            break;
+          }
+
+          if (preg_match('/^\s+/', $attributes)) {
+            $working = 1; $mode = 0;
+            if (!$skip) {
+              $attributes_array[] = $attribute_name;
+            }
+            $attributes = preg_replace('/^\s+/', '', $attributes);
+          }
+          break;
+
+        case 2:
+          // Attribute value, a URL after href= for instance.
+          if (preg_match('/^"([^"]*)"(\s+|$)/', $attributes, $match)) {
+            $thisval = Url::filterBadProtocol($match[1]);
+
+            if (!$skip) {
+              $attributes_array[] = "$attribute_name=\"$thisval\"";
+            }
+            $working = 1;
+            $mode = 0;
+            $attributes = preg_replace('/^"[^"]*"(\s+|$)/', '', $attributes);
+            break;
+          }
+
+          if (preg_match("/^'([^']*)'(\s+|$)/", $attributes, $match)) {
+            $thisval = Url::filterBadProtocol($match[1]);
+
+            if (!$skip) {
+              $attributes_array[] = "$attribute_name='$thisval'";
+            }
+            $working = 1; $mode = 0;
+            $attributes = preg_replace("/^'[^']*'(\s+|$)/", '', $attributes);
+            break;
+          }
+
+          if (preg_match("%^([^\s\"']+)(\s+|$)%", $attributes, $match)) {
+            $thisval = Url::filterBadProtocol($match[1]);
+
+            if (!$skip) {
+              $attributes_array[] = "$attribute_name=\"$thisval\"";
+            }
+            $working = 1; $mode = 0;
+            $attributes = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attributes);
+          }
+          break;
+      }
+
+      if ($working == 0) {
+        // Not well formed; remove and try again.
+        $attributes = preg_replace('/
+          ^
+          (
+          "[^"]*("|$)     # - a string that starts with a double quote, up until the next double quote or the end of the string
+          |               # or
+          \'[^\']*(\'|$)| # - a string that starts with a quote, up until the next quote or the end of the string
+          |               # or
+          \S              # - a non-whitespace character
+          )*              # any number of the above three
+          \s*             # any number of whitespaces
+          /x', '', $attributes);
+        $mode = 0;
+      }
+    }
+
+    // The attribute list ends with a valueless attribute like "selected".
+    if ($mode == 1 && !$skip) {
+      $attributes_array[] = $attribute_name;
+    }
+    return $attributes_array;
+  }
+
+}
