XHR、XPath 和自定义本地 XML 模式

XHR, XPath, and custom local XML schema

尽管在 (X)HTML5(例如 SVG)中使用 XML 扩展是可能的,而且有些常见,但解析 XHTML5 文档,使用自定义本地扩展XSD,使用 XPath 导致意外结果。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns:hp="http://homepage.org/homepage" 
      hp:schemaLocation="http://homepage.org ./schemas/homepage.xsd">
  <head>
    ...
  </head>
  <body>
    <hp:homepage title="Homepage">
    <header>
      <h1></h1>
    </header>
    ...

使用通常的 NSResolver 逻辑会导致命名空间错误:

  var hpResolver = document.createNSResolver( document.ownerDocument == null ? document.documentElement : document.ownerDocument.documentElement);

创建自定义处理程序不会导致错误,但 XPath 仍然没有 return 预期结果:

  var hpResolver = function (prefix) {
    if (prefix === 'hp') {
      return 'http://homepage.org/homepage';
    } else {
      return null;
    }
  };

XSD 与其余文件一起提供,并且作为教育练习在本地文件系统而不是服务器上进行测试。

XPath查询如下:

  var path = '/html/body/hp:homepage/header/h1';
  var headTitle = document.evaluate(path, document, hpResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

上面的sample只是作为例子简单写的

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://homepage.org/homepage"
           xmlns="http://homepage.org/homepage"
           elementFormDefault="qualified">

  <xs:element name="homepage">
    <xs:complexType>
      <xs:sequence>
        <xs:attribute name="title" type="xs:string" use="required" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

我认为模式根本不重要,因为浏览器没有支持模式的验证解析器。重要的是命名空间,如果你想使用自定义元素和命名空间,那么你需要确保正确使用 XHTML5,确保你的元素在命名空间中,确保你将文档提供为 application/xhtml+xml(因为只有这样它们才被理解命名空间的浏览器 XML 解析器解析,text/html 解析器被不支持命名空间的 HTML5 解析器解析。

基于此,我创建了示例 http://home.arcor.de/martin.honnen/html/test2015061502.xhtml,其代码为

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>XMLHttpRequest and DOM Level 3 XPath API test with 'application/xhtml+xml' document</title>
<script type="text/javascript"><![CDATA[
function test() {
  var req = new XMLHttpRequest();
  req.open('GET', 'test2015061501.xhtml', true);
  req.onload = function() {
    var doc = req.responseXML;
    var res = function(prefix) {
      if (prefix === 'xhtml') {
        return 'http://www.w3.org/1999/xhtml';
      }
      else if (prefix === 'hp') {
        return 'http://example.com/hp';
      }
      else {
        return null;
      }
    }
    var path = '/xhtml:html/xhtml:body/hp:homepage/xhtml:header/xhtml:h1';
    var val = doc.evaluate(path, doc, res, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    document.body.insertAdjacentHTML('beforeEnd', '<p>Found ' + val + '</p>');
  };
  req.send();
}

window.onload = test;
]]></script>
</head>
<body>
<h1>XMLHttpRequest and DOM Level 3 XPath API test with 'application/xhtml+xml' document</h1>
</body>
</html>

并加载 http://home.arcor.de/martin.honnen/html/test2015061501.xhtml,其中包含 XHTML 命名空间中的元素和自定义命名空间中的元素:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:hp="http://example.com/hp" 
      hp:schemaLocation="http://example.com/hp ./schemas/homepage.xsd">
  <head>
    ...
  </head>
  <body>
    <hp:homepage title="Homepage">
      <header>
        <h1>I am a heading</h1>
      </header>
    </hp:homepage>
  </body>
</html>

第一个文档中的 XPath 1.0 表达式是 /xhtml:html/xhtml:body/hp:homepage/xhtml:header/xhtml:h1 并找到 XHTML h1 HTMLHeadingElement 元素,对于 Firefox 38 和 Chrome 43。