从XML / XSL

时间:2017-07-10 12:28:07

标签: xml xslt-1.0

我正在编写一个应用程序来可视化几个数据库的内容。这个应用程序应该尽可能简单地安装和使用,所以我决定使用XML文件作为数据库,并通过浏览器使用XSL充分转换它们。现在,XSL文件被编程为创建每个数据库的汇总表,并通过单击每行的第一个单元格,显示整个条目的更完整描述。这意味着该页面包含数据库中每条记录的每个完整描述,但这种情况会减慢页面的加载速度,这需要最多5秒才能加载数百条记录。由于我计划在未来大量扩展数据库,这个问题注定会变得更糟。为了减少负载,下一个明显的步骤是采用某种延迟加载,或者使用AJAX或iframe(现在不是那么重要而不是问题的重点),但是我遇到了一些困难。我的想法是直接调用这样的XML文件:

file:///path/to/file/transform.xml?id=23

使用transform.xml:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="transform.xsl"?>
<content />

并且transform.xsl是:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <xsl:output method="html" version="5" doctype-system="about:legacy-compat" indent="yes" />
    <xsl:param name="url" />

    <xsl:template match="/">
        <html>
            <body><xsl:value-of select="$url" /></body>
        </html>
    </xsl:template>
</xsl:stylesheet>

现在这仅仅是一个概念证明,但这一部分是所有后续的基石,如果它不起作用,那么继续这样做是没有用的。

我现在所能看到的只是一个空白页面。我还尝试将参数名称更改为id,但页面仍为空。

我知道这可以通过PHP或其他服务器端解决方案轻松实现,MySQL会更高效,但我真的需要这个应用程序在下载结束时才可用。如果我的用户必须安装* AMP服务器,他们可能不会。公共服务器也不是解决方案,因为我需要将此应用程序脱机运行。另一方面,JavaScript / jQuery解决方案是完全可以接受的,因为它是客户端的。

编辑:我的大部分工作都基于this question,它似乎有效,但很老,该示例包含ASP页面的URL。

2 个答案:

答案 0 :(得分:0)

使用xml-stylesheet处理指令调用转换不提供任何为转换提供参数的方法。因此参数将采用其默认值,即零长度字符串。

很抱歉,但这个设计不会飞。

我认为唯一的方法是在HTML页面中使用Javascript代码以编程方式调用转换。

一种选择是使用Saxon-JS而不是依赖浏览器提供的XSLT引擎。这将使您可以访问XSLT 2.0 / 3.0功能而不是1.0,而在2.0中,样式表可以使用document-uri()函数访问源文档的URI。

答案 1 :(得分:0)

由于将URL参数传递给XSL似乎不切实际,我通过AJAX找到了另一种方法。 Javascript导入XML和XSL文件,然后过滤XML文件,以便只剩下一个元素,然后将XSL文件应用于剩余的XML结构。

对于那些寻求类似问题灵感的人,我将留下我正在使用的代码的简化示例。这个代码需要jQuery,但它可以完美地运行。

page.js(从here无耻地复制):

function expand_box(id, tag_to_isolate, XML_file, XSL_file, container) {
    if($('div#' + id).length == 0) { //first opening
        var XML = $.ajax({url: XML_file, async: false, dataType: 'xml'}).responseXML.activeElement;
        var XSL = $.ajax({url: XSL_file, async: false, dataType: 'xml'}).responseXML.activeElement;
        if(XSL.getElementsByTagName('xsl:include').length == 1) { //bonus, see below*
            var XSL_temp = $.ajax({url: 'templates.xsl', async: false, dataType: 'xml'}).responseXML.activeElement;
            $(XSL.getElementsByTagName('xsl:include')).replaceWith(XSL_temp.childNodes);
        }
        XML = $(XML).find(tag_to_isolate + '[id=' + id + ']')[0];
        if (window.ActiveXObject) { // code for IE
            var result = XML.transformNode(XSL);
        }
        else if (document.implementation && document.implementation.createDocument) { // code for Chrome, Firefox, Opera, etc.
            var xsltProcessor = new XSLTProcessor();
            xsltProcessor.importStylesheet(XSL);
            var result = xsltProcessor.transformToFragment(XML, document);
        }
        $('div#' + panel).append(result);
        //other code here, e.g. to apply all jQuery functions bound to clicks, ...
    }
    $('#' + id).slideDown();
}

*奖励:我发现javascript xsltProcessor无法处理xsl:include标签,因此我必须手动导入它们。这里的代码非常简单,因为我只使用一个xsl文件来包含所有共享模板,因此替换是自动的,但它可以很容易地适应更灵活。

database.xml(与上面显示的XML文件不同):

<?xml version="1.0" encoding="UTF-8"?>
<elements>
    <element id="1">
        ...
    </element>
    ...
</elements>

transform.xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <xsl:template match="/elements/element">
        ...
    </xsl:template>
    <xsl:include href="templates.xsl" />
</xsl:stylesheet>

根据使用的数据库,您可以根据需要创建任意数量的匹配项。

我不得不说我的浏览器警告我主线程上的同步AJAX请求因为对用户的负面影响而被弃用,并且可能在将来被禁用,所以答案可能会得到改善,但我选择了目的为了获得同步请求,因为我的计算机上发生了一切,无论文件有多大,请求都很快。在远程服务器上,需要异步请求。