使用 XSL(Chrome、Firefox 和 IE 8/11)跨浏览器 XML 操作和解析
Crossbrowser XML manipulation and parse with XSL (Chrome, Firefoz and IE 8/11)
我有一个表单,其中我得到一个 XML
,在用户填写表单时对其进行操作,并最终将此操作的 XML
转换为 XSL
。我需要此解决方案在没有兼容模式的 Chrome、Firefox 和 Internet Explorer 8 到 11 中工作。
我用我在 IE 9(或至少没有用户抱怨)、Chrome 和 Firefox 上成功运行的代码编写了一个 JSFiddle。但我在 IE 11 上遇到问题。当我的代码尝试从 ActiveXObject
执行 transformNode
时。我已经尝试了一些我在几个站点(包括此处)中找到的建议,但是当我的代码试图操纵 XML
时,有些根本不起作用或开始抛出异常。所以我需要帮助让这段代码正常工作。
这是 JSFiddle:https://jsfiddle.net/mfedatto/6nsc5bf1/
HTML
<div id="wrapper"></div>
<div id="console"></div>
JavaScript
try {
function getXmlDom(content) {
var xmlDom;
if (typeof window.DOMParser != "undefined") {
trace.push("Creating DOMParser");
xmlDom = (new window.DOMParser()).parseFromString(content, "text/xml");
trace.push("DOMParser created");
}
else if (typeof window.ActiveXObject != "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) {
try {
trace.push("Creating MSXML2.DOMDocument.6.0");
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.6.0");
trace.push("MSXML2.DOMDocument.6.0 created");
}
catch (ex) {
trace.push("Creating Microsoft.XMLHTTP");
xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
trace.push("Microsoft.XMLHTTP created");
}
xmlDom.async = "false";
try { xmlDoc.responseType = "msxml-document"; } catch (ex) { }
trace.push("Loading XML content");
xmlDom.loadXML(content);
trace.push("XML content loaded");
}
else {
throw new Error("No XML parser found");
}
return xmlDom;
}
function xslTransformTo(xsl, xml, wrapper) {
if ((window.ActiveXObject) || "ActiveXObject" in window) {
trace.push("Transforming with ActiveXObject");
wrapper.innerHTML = xml.transformNode(xsl);
trace.push("Transformed with ActiveXObject");
}
else if (document.implementation && document.implementation.createDocument) {
trace.push("Transforming with XSLTProcessor");
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
wrapper.appendChild(xsltProcessor.transformToFragment(xml, document));
trace.push("Transformed with XSLTProcessor");
}
else {
throw new Error("No XSL parser found");
}
}
function xmlString(xml) {
return (new XMLSerializer()).serializeToString(xml);
}
function showError(ex) {
var console = document.getElementById("console");
showTrace();
console.appendChild(document.createTextNode("ERROR!!! " + ex.message));
}
function showTrace() {
var console = document.getElementById("console");
for (var i = 0; i < trace.length; i++) {
console.appendChild(document.createTextNode(trace[i]));
console.appendChild(document.createElement("br"));
}
}
var trace = [];
var strXml = "<root>\n"
+ " <fc>\n"
+ " <sc>\n"
+ " <i />\n"
+ " <i />\n"
+ " <i />\n"
+ " <i />\n"
+ " </sc>\n"
+ " </fc>\n"
+ "</root>";
trace.push("XML string defined");
var strXsl = "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
+ " <xsl:template match=\"/root\">\n"
+ " <ul>\n"
+ " <xsl:for-each select=\"fc/sc/i\">\n"
+ " <li>[<xsl:value-of select=\"position()\" />]</li>\n"
+ " </xsl:for-each>\n"
+ " </ul>\n"
+ " </xsl:template>\n"
+ "</xsl:stylesheet>";
trace.push("XSL string defined");
var strWrapperId = "wrapper";
trace.push("Parsing XML");
var xmlDoc = getXmlDom(strXml);
trace.push("XML parsed");
trace.push("Parsing XSL");
var xslDoc = getXmlDom(strXsl);
trace.push("XML parsed");
var domWrapper = document.getElementById(strWrapperId);
var xmlItemList = xmlDoc.getElementsByTagName("i");
trace.push("All variables loaded");
trace.push("Iterating item positions");
try {
for (var i = 0; i < xmlItemList.length; i++) {
xmlItemList[i].setAttribute("p", i);
}
}
catch (ex) {
showError(ex);
return;
}
trace.push("Itens positions iterared");
trace.push("Transforming XML with XSL to wrapper");
try {
xslTransformTo(xslDoc, xmlDoc, domWrapper);
}
catch (ex) {
showError(ex);
return;
}
showTrace();
}
catch (ex) {
alert(ex.message);
}
P.S.: 与我使用的代码的唯一区别是跟踪和基于字符串内容的 loadXML
,事实上我使用 load
方法和可访问的 uri
.
编辑 1 - 23/fev/16
我尝试 运行 Martin Honnen 在 IE 11 上发布的 JSFiddle
,它显示 ERROR!!! No XSL parser found
。我使用他建议的 MSDN 页面上的说明进行了一些重构。那篇文章指示尝试,而不是测试,因为某些插件可能被实例化但未被检测到。然后我的 IE 11 使用 DOMParser
创建并加载我的 XML
和 XSL
对象和内容,但无法同时使用 transformNode
和 XSLTProcessor
进行转换。正如在:http://jsfiddle.net/mfedatto/6nsc5bf1/38
编辑 2 - 25/fev/16
由于某种原因,该解决方案不适用于 JSFiddle,我将对此进行一些挖掘。但是有了 Martin Honnen 的回答,我可以加载我的外部 XML
和 XSL
文件跨浏览器,包括 IE 11。这是我使用的最终代码:
function loadXmlFile(path) {
var xmlDoc;
if (loadXmlFile.cache === undefined) {
loadXmlFile.cache = { };
}
if (loadXmlFile.cache[path] === undefined) {
try {
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.6.0");
}
catch (e) {
try {
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");
}
catch (e2) {
xmlDoc = new XMLHttpRequest();
xmlDoc.responseType = "application/xml";
}
}
try {
xmlDoc.open("GET", path, false);
xmlDoc.send();
loadXmlFile.cache[path] = xmlDoc.responseXML;
}
catch (ex) {
xmlDoc.async = false;
xmlDoc.load(path);
loadXmlFile.cache[path] = xmlDoc;
}
}
return loadXmlFile.cache[path];
}
function xslTransformTo(xsl, xml, wrapper) {
if (typeof xml.transformNode != "undefined") {
wrapper.innerHTML = xml.transformNode(xsl);
}
else if (typeof XSLTProcessor != "undefined") {
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
wrapper.appendChild(xsltProcessor.transformToFragment(xml, document));
}
}
请参阅 https://msdn.microsoft.com/en-us/library/dn423948(v=vs.85).aspx,在 IE 11 中,您需要在 try/catch 中使用 new ActiveXObject('program.id')
,window 属性 的检查不起作用.
此外,您在 IE 中使用 DOMParser 创建的本机 IE DOM 文档不支持 transformNode
,因此如果您知道需要 XML DOM 文件在 IE 中进行 XSLT 转换然后你需要确保你创建一个 MSXML DOM 文件 new ActiveXObject
并且你需要首先在你的代码中尝试这样做使用 try/catch,在您尝试实例化 DOMParser.
之前
所以对于 XML 从字符串解析我会使用
function getXmlDom(content) {
var xmlDom;
try {
xmlDom = new ActiveXObject('Msxml2.DOMDocument.6.0');
xmlDom.loadXML(content);
}
catch (e) {
try {
xmlDom = new ActiveXObject('Msxml2.DOMDocument.3.0');
xmlDom.loadXML(content);
}
catch (e2) {
xmlDom = (new DOMParser()).parseFromString(content, 'application/xml');
}
}
return xmlDom;
}
如 http://home.arcor.de/martin.honnen/javascript/2016/test2016022301.html 中所做的那样。
我有一个表单,其中我得到一个 XML
,在用户填写表单时对其进行操作,并最终将此操作的 XML
转换为 XSL
。我需要此解决方案在没有兼容模式的 Chrome、Firefox 和 Internet Explorer 8 到 11 中工作。
我用我在 IE 9(或至少没有用户抱怨)、Chrome 和 Firefox 上成功运行的代码编写了一个 JSFiddle。但我在 IE 11 上遇到问题。当我的代码尝试从 ActiveXObject
执行 transformNode
时。我已经尝试了一些我在几个站点(包括此处)中找到的建议,但是当我的代码试图操纵 XML
时,有些根本不起作用或开始抛出异常。所以我需要帮助让这段代码正常工作。
这是 JSFiddle:https://jsfiddle.net/mfedatto/6nsc5bf1/
HTML
<div id="wrapper"></div>
<div id="console"></div>
JavaScript
try {
function getXmlDom(content) {
var xmlDom;
if (typeof window.DOMParser != "undefined") {
trace.push("Creating DOMParser");
xmlDom = (new window.DOMParser()).parseFromString(content, "text/xml");
trace.push("DOMParser created");
}
else if (typeof window.ActiveXObject != "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) {
try {
trace.push("Creating MSXML2.DOMDocument.6.0");
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.6.0");
trace.push("MSXML2.DOMDocument.6.0 created");
}
catch (ex) {
trace.push("Creating Microsoft.XMLHTTP");
xmlDoc = new ActiveXObject("Microsoft.XMLHTTP");
trace.push("Microsoft.XMLHTTP created");
}
xmlDom.async = "false";
try { xmlDoc.responseType = "msxml-document"; } catch (ex) { }
trace.push("Loading XML content");
xmlDom.loadXML(content);
trace.push("XML content loaded");
}
else {
throw new Error("No XML parser found");
}
return xmlDom;
}
function xslTransformTo(xsl, xml, wrapper) {
if ((window.ActiveXObject) || "ActiveXObject" in window) {
trace.push("Transforming with ActiveXObject");
wrapper.innerHTML = xml.transformNode(xsl);
trace.push("Transformed with ActiveXObject");
}
else if (document.implementation && document.implementation.createDocument) {
trace.push("Transforming with XSLTProcessor");
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
wrapper.appendChild(xsltProcessor.transformToFragment(xml, document));
trace.push("Transformed with XSLTProcessor");
}
else {
throw new Error("No XSL parser found");
}
}
function xmlString(xml) {
return (new XMLSerializer()).serializeToString(xml);
}
function showError(ex) {
var console = document.getElementById("console");
showTrace();
console.appendChild(document.createTextNode("ERROR!!! " + ex.message));
}
function showTrace() {
var console = document.getElementById("console");
for (var i = 0; i < trace.length; i++) {
console.appendChild(document.createTextNode(trace[i]));
console.appendChild(document.createElement("br"));
}
}
var trace = [];
var strXml = "<root>\n"
+ " <fc>\n"
+ " <sc>\n"
+ " <i />\n"
+ " <i />\n"
+ " <i />\n"
+ " <i />\n"
+ " </sc>\n"
+ " </fc>\n"
+ "</root>";
trace.push("XML string defined");
var strXsl = "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
+ " <xsl:template match=\"/root\">\n"
+ " <ul>\n"
+ " <xsl:for-each select=\"fc/sc/i\">\n"
+ " <li>[<xsl:value-of select=\"position()\" />]</li>\n"
+ " </xsl:for-each>\n"
+ " </ul>\n"
+ " </xsl:template>\n"
+ "</xsl:stylesheet>";
trace.push("XSL string defined");
var strWrapperId = "wrapper";
trace.push("Parsing XML");
var xmlDoc = getXmlDom(strXml);
trace.push("XML parsed");
trace.push("Parsing XSL");
var xslDoc = getXmlDom(strXsl);
trace.push("XML parsed");
var domWrapper = document.getElementById(strWrapperId);
var xmlItemList = xmlDoc.getElementsByTagName("i");
trace.push("All variables loaded");
trace.push("Iterating item positions");
try {
for (var i = 0; i < xmlItemList.length; i++) {
xmlItemList[i].setAttribute("p", i);
}
}
catch (ex) {
showError(ex);
return;
}
trace.push("Itens positions iterared");
trace.push("Transforming XML with XSL to wrapper");
try {
xslTransformTo(xslDoc, xmlDoc, domWrapper);
}
catch (ex) {
showError(ex);
return;
}
showTrace();
}
catch (ex) {
alert(ex.message);
}
P.S.: 与我使用的代码的唯一区别是跟踪和基于字符串内容的 loadXML
,事实上我使用 load
方法和可访问的 uri
.
编辑 1 - 23/fev/16
我尝试 运行 Martin Honnen 在 IE 11 上发布的 JSFiddle
,它显示 ERROR!!! No XSL parser found
。我使用他建议的 MSDN 页面上的说明进行了一些重构。那篇文章指示尝试,而不是测试,因为某些插件可能被实例化但未被检测到。然后我的 IE 11 使用 DOMParser
创建并加载我的 XML
和 XSL
对象和内容,但无法同时使用 transformNode
和 XSLTProcessor
进行转换。正如在:http://jsfiddle.net/mfedatto/6nsc5bf1/38
编辑 2 - 25/fev/16
由于某种原因,该解决方案不适用于 JSFiddle,我将对此进行一些挖掘。但是有了 Martin Honnen 的回答,我可以加载我的外部 XML
和 XSL
文件跨浏览器,包括 IE 11。这是我使用的最终代码:
function loadXmlFile(path) {
var xmlDoc;
if (loadXmlFile.cache === undefined) {
loadXmlFile.cache = { };
}
if (loadXmlFile.cache[path] === undefined) {
try {
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.6.0");
}
catch (e) {
try {
xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");
}
catch (e2) {
xmlDoc = new XMLHttpRequest();
xmlDoc.responseType = "application/xml";
}
}
try {
xmlDoc.open("GET", path, false);
xmlDoc.send();
loadXmlFile.cache[path] = xmlDoc.responseXML;
}
catch (ex) {
xmlDoc.async = false;
xmlDoc.load(path);
loadXmlFile.cache[path] = xmlDoc;
}
}
return loadXmlFile.cache[path];
}
function xslTransformTo(xsl, xml, wrapper) {
if (typeof xml.transformNode != "undefined") {
wrapper.innerHTML = xml.transformNode(xsl);
}
else if (typeof XSLTProcessor != "undefined") {
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
wrapper.appendChild(xsltProcessor.transformToFragment(xml, document));
}
}
请参阅 https://msdn.microsoft.com/en-us/library/dn423948(v=vs.85).aspx,在 IE 11 中,您需要在 try/catch 中使用 new ActiveXObject('program.id')
,window 属性 的检查不起作用.
此外,您在 IE 中使用 DOMParser 创建的本机 IE DOM 文档不支持 transformNode
,因此如果您知道需要 XML DOM 文件在 IE 中进行 XSLT 转换然后你需要确保你创建一个 MSXML DOM 文件 new ActiveXObject
并且你需要首先在你的代码中尝试这样做使用 try/catch,在您尝试实例化 DOMParser.
所以对于 XML 从字符串解析我会使用
function getXmlDom(content) {
var xmlDom;
try {
xmlDom = new ActiveXObject('Msxml2.DOMDocument.6.0');
xmlDom.loadXML(content);
}
catch (e) {
try {
xmlDom = new ActiveXObject('Msxml2.DOMDocument.3.0');
xmlDom.loadXML(content);
}
catch (e2) {
xmlDom = (new DOMParser()).parseFromString(content, 'application/xml');
}
}
return xmlDom;
}
如 http://home.arcor.de/martin.honnen/javascript/2016/test2016022301.html 中所做的那样。