Coder Social home page Coder Social logo

designliquido / xslt-processor Goto Github PK

View Code? Open in Web Editor NEW
97.0 9.0 30.0 1.43 MB

A JavaScript XSLT processor without native library dependencies

License: GNU Lesser General Public License v3.0

JavaScript 4.10% HTML 2.12% TypeScript 93.78%
xslt xsltproc xslt-stylesheet xslt-files xslt-templates xml xml-parser hacktoberfest

xslt-processor's Introduction

XSLT-processor

A JavaScript XSLT processor without native library dependencies.

How to

Install xslt-processor using npm or yarn:

npm install xslt-processor
yarn add xslt-processor

Within your ES2015+ code, import the Xslt class, the XmlParser class and use this way:

import { Xslt, XmlParser } from 'xslt-processor'

// xmlString: string of xml file contents
// xsltString: string of xslt file contents
// outXmlString: output xml string.
const xslt = new Xslt();
const xmlParser = new XmlParser();
// Either
const outXmlString = await xslt.xsltProcess(
	xmlParser.xmlParse(xmlString),
	xmlParser.xmlParse(xsltString)
);
// Or
xslt.xsltProcess(
	xmlParser.xmlParse(xmlString),
	xmlParser.xmlParse(xsltString)
).then(output => {
  // `output` is equivalent to `outXmlString` (a string with XML).
});

To access the XPath parser, you can use the instance present at Xslt class:

const xslt = new Xslt();
const xPath = xslt.xPath;

Or ou can import it like this:

import { XPath } from 'xslt-processor'

const xPath = new XPath();

If you write pre-2015 JS code, make adjustments as needed.

Xslt class options

You can pass an options object to Xslt class:

const options = {
  escape: false,
  selfClosingTags: true,
  parameters: [{ name: 'myparam', value: '123' }],
  outputMethod: 'xml'
};
const xslt = new Xslt(options);
  • cData (boolean, default true): resolves CDATA elements in the output. Content under CDATA is resolved as text. This overrides escape for CDATA content.
  • escape (boolean, default true): replaces symbols like <, >, & and " by the corresponding XML entities.
  • selfClosingTags (boolean, default true): Self-closes tags that don't have inner elements, if true. For instance, <test></test> becomes <test />.
  • outputMethod (string, default xml): Specifies the default output method. if <xsl:output> is declared in your XSLT file, this will be overridden.
  • parameters (array, default []): external parameters that you want to use.
    • name: the parameter name;
    • namespaceUri (optional): the namespace;
    • value: the value.

Direct use in browsers

You can simply add a tag like this:

<script type="application/javascript" src="https://www.unpkg.com/[email protected]/umd/xslt-processor.js"></script>

All the exports will live under globalThis.XsltProcessor and window.XsltProcessor. See a usage example here.

Breaking Changes

Version 2

Until version 2.3.1, use like the example below:

import { Xslt, XmlParser } from 'xslt-processor'

// xmlString: string of xml file contents
// xsltString: string of xslt file contents
// outXmlString: output xml string.
const xslt = new Xslt();
const xmlParser = new XmlParser();
const outXmlString = xslt.xsltProcess( // Not async.
	xmlParser.xmlParse(xmlString),
	xmlParser.xmlParse(xsltString)
);

Version 3 received <xsl:include> which relies on Fetch API, which is asynchronous. Version 2 doesn't support <xsl:include>.

Version 1

Until version 1.2.8, use like the example below:

import { Xslt, xmlParse } from 'xslt-processor'

// xmlString: string of xml file contents
// xsltString: string of xslt file contents
// outXmlString: output xml string.
const xslt = new Xslt();
const outXmlString = xslt.xsltProcess(
	xmlParse(xmlString),
	xmlParse(xsltString)
);

Version 0

Until version 0.11.7, use like the example below:

import { xsltProcess, xmlParse } from 'xslt-processor'

// xmlString: string of xml file contents
// xsltString: string of xslt file contents
// outXmlString: output xml string.
const outXmlString = xsltProcess(
	xmlParse(xmlString),
	xmlParse(xsltString)
);

and to access the XPath parser:

import { xpathParse } from 'xslt-processor'

These functions are part of Xslt and XPath classes, respectively, at version 1.x onward.

Introduction

XSLT-processor contains an implementation of XSLT in JavaScript. Because XSLT uses XPath, it also contains an implementation of XPath that can be used independently of XSLT. This implementation has the advantage that it makes XSLT uniformly available whenever the browser's native XSLTProcessor() is not available such as in Node.js or in web workers.

XSLT-processor builds on Google's AJAXSLT which was written before XSLTProcessor() became available in browsers, but the code base has been updated to comply with ES2015+ and to make it work outside of browsers.

This implementation of XSLT operates at the DOM level on its input documents. It internally uses a DOM implementation to create the output document, but usually returns the output document as text stream. The DOM to construct the output document can be supplied by the application, or else an internal minimal DOM implementation is used. This DOM comes with a minimal XML parser that can be used to generate a suitable DOM representation of the input documents if they are present as text.

Tests and usage examples

New tests are written in Jest an can be run by calling: npm test.

The files xslt.html and xpath.html in the directory interactive-tests are interactive tests. They can be run directly from the file system; no HTTP server is needed. Both interactive tests and automatic tests demonstrate the use of the library functions. There is not much more documentation so far.

Conformance

A few features that are required by the XSLT and XPath standards were left out (but patches to add them are welcome). See our TODO for a list of missing features that we are aware of (please add more items by means of PRs).

So far, we have implemented XQuery functions for versions 1.0 and 2.0, but this is not complete yet.

Issues are also marked in the source code using throw-statements.

The DOM implementation is minimal so as to support the XSLT processing, and not intended to be complete.

The implementation is all agnostic about namespaces. It just expects XSLT elements to have tags that carry the xsl: prefix, but we disregard all namespace declaration for them.

There are a few nonstandard XPath functions.

HTML Conformance

HTML per se is not strict XML. Because of that, starting on version 2.0.0, this library handles HTML differently than XML:

  • For a document to be treated as HTML, it needs to have a <!DOCTYPE> tag defined with one of the following valid formats:
    • <!DOCTYPE html> (for HTML5);
    • <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> (for HTML4);
    • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> (for XHTML 1.1).
  • Tags like <hr>, <link> and <meta> don't need to be closed. The output for these tags doesn't close them (adding a / before the tag closes, or a corresponding close tag);
    • This rule doesn't apply for XHTML, which is strict XML.

References

xslt-processor's People

Contributors

berenddeboer avatar dependabot[bot] avatar dfabulich avatar hbchai avatar jasonliao-cb avatar johanneswilm avatar leonelsanchesdasilva avatar mari6274 avatar markus-ulke avatar mig82 avatar mincerafter42 avatar samuelrvg avatar theknarf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xslt-processor's Issues

Returning empty div of body.

I have been trying to figure out why this is happening and adjusting my inputs, but haven't figured how to solve the issue.

Maybe you can point me out in the direction in the code and I'll happily contribute or if you know I made a mistake somewhere...

I am trying to convert this xml: http://www.fatturapa.gov.it/export/fatturazione/sdi/fatturapa/v1.1/IT01234567890_11001.xml
using this stylesheet: http://www.fatturapa.gov.it/export/fatturazione/sdi/fatturapa/v1.1/fatturapa_v1.1.xsl

However, the html that I get back is empty:

<html><head><meta http-equiv="X-UA-Compatible" content="IE=edge"/><style type="text/css">
#fattura-container { width: 100%; position: relative; } #fattura-elettronica { font-family: sans-serif; margin-left: auto; margin-right: auto; max-width: 1280px; min-width: 930px; padding: 0; } #fattura-elettronica .versione { font-size: 11px; float:right; color: #777777; } #fattura-elettronica h1 { padding: 20px 0 0 0; margin: 0; font-size: 30px; } #fattura-elettronica h2 { padding: 20px 0 0 0; margin: 0; font-size: 20px; } #fattura-elettronica h3 { padding: 20px 0 0 0; margin: 0; font-size: 25px; } #fattura-elettronica h4 { padding: 20px 0 0 0; margin: 0; font-size: 20px; } #fattura-elettronica h5 { padding: 15px 0 0 0; margin: 0; font-size: 17px; font-style: italic; } #fattura-elettronica ul { list-style-type: none; margin: 0 !important; padding: 15px 0 0 40px !important; } #fattura-elettronica ul li {} #fattura-elettronica ul li span { font-weight: bold; } #fattura-elettronica div { padding: 0; margin: 0; } #fattura-elettronica div.page { background-color: #fff !important; position: relative; margin: 20px 0 50px 0; padding: 60px; background: -moz-linear-gradient(0% 0 360deg, #FFFFFF, #F2F2F2 20%, #FFFFFF) repeat scroll 0 0 transparent; border: 1px solid #CCCCCC; -webkitbox-shadow: 0 0 10px rgba(0, 0, 0, 0.3); -mozbox-shadow: 0 0 10px rgba(0, 0, 0, 0.3); box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); background: url('logo_sdi_trasparente.jpg') 98% 50px no-repeat; } #fattura-elettronica div.footer { padding: 50px 0 0 0; margin: 0; font-size: 11px; text-align: center; color: #777777; }
</style></head><body><div id="fattura-container"/></body></html>

Note that it actually recognises something and builds <body><div id="fattura-container"/></body> but nothing more than that.

Parsing CDATA - wrong index incrementation

https://github.com/fiduswriter/xslt-processor/blob/36f2af419a559f9f1a1074cb9bd1db39393513d2/src/dom.js#L127

Hi,

Thanks for your lib. I'm using it in my xslt-action VS Code plugin. One of the users requested an issue. Parsing CDATA tags seems to work wrong. In cited line index i is incremented by 12 (correct) but for loop increment it once more and parsing continues in second char after CDATA tag instead of the first one. The same problem probably occurs with comments.

I think increment values should be 6 for comments and 11 for CDATA tags.

Unexpected output when transforming

XML:

<?xml version="1.0" encoding="UTF-8"?>
<problem/>

XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/problem">
    <div>
      <div>
        <table>
          <tr>
            <th>A</th>
            <th>B</th>
            <th>C</th>
          </tr>
          <tr>
            <td>AA</td>
            <td>BB</td>
            <td>CC</td>
          </tr>
        </table>
      </div>
    </div>
    <div>
      <div>
        should be below table rite??!
      </div>
    </div>
  </xsl:template>
</xsl:stylesheet>

output (pretty-printed for legibility):

<div>
  <div>
    <table>
      <tr>
        <th>A</th>
        <th>B</th>
        <th>C</th>
      </tr>
      <tr>
        <td>AA</td>
        <td>BB</td>
        <div>CC<div>
            should be below table rite??!
          </div>
        </div>
      </tr>
    </table>
  </div>
</div>

Is there something wrong with my XSLT? Somehow the CC ends up in a <div> tag.

I'm using [email protected] on [email protected]

Thanks!

Allow non-defined attributes

I'm looking for a way to allow empty attributes, for example, with the XML input:

<v-btn small color="info">Info</v-btn>

After processing with outXmlString = xsltProcess(xml, xslt);

The value of outXmlString will only be:

<v-btn color="info">Info</v-btn>

The small attribute is gone because it was not defined like small="true". However non-defined attributes is the standard on VUE.js (I'm using this to parse VUE components).

Is there a way to allow non-defined attributes?

bug - invalid text in the front of the transform output

Hi, the package was working fine but after we upgraded it from 2.1.4 to 2.2.0, then the output had some wired 'NoYes' text at the beginning of the output.
steps to reproduce:

const fs = require('fs');
const xsltProcessor = require('xslt-processor');

// Load the XML source and XSLT stylesheet
const xmlSource = fs.readFileSync('source.xml', 'utf-8');
const xsltStylesheet = fs.readFileSync('stylesheet.xsl', 'utf-8');

// Create an XSLT processor
const xslt = new xsltProcessor.Xslt();

// Load the stylesheet
const xmlParser = new xsltProcessor.XmlParser();

// Perform the transformation
const outXmlString = xslt.xsltProcess(
    xmlParser.xmlParse(xmlSource),
    xmlParser.xmlParse(xsltStylesheet)
);

// Save the transformed result to a destination file
fs.writeFileSync('destination.xml', outXmlString.toString());
console.log('XSLT transformation successful! Output saved to destination.xml');

before 2.2.0, the output is correct
from 2.2.0, there is some additional text YesNo at the front of the output.

can you investigate what has been injected in version 2.2.0?

Upper and Lower case

XSLT 1.0 has a MAJOR flaw in that it has no upper/lower case conversion without resorting to "translate", which only solves half the problem.

XSLT 2.0 has native functions just like Javascript which solve the whole problem.

These two functions ought to be simple to implement. Could you add them please?

Licence

Hello,

I see you changed the licence to LGPL v3.0 from the BSD 3-clause which the former ajaxslt project has. Do you have a strong reason for that? I am not a lawyer, but it will confuse people, because most of the code is still BSD licensed and only your changes are LGPL licensed.

I myself have a rewrite to TypeScript + removed custom XPath and DOM implementation in favor of xpath-ts and xmldom/jsdom. I would rather licence it under one licence to not confuse people.

PS: have a loot at https://github.com/backslash47/xslt

Circular dependencies

There are some circular dependencies in the project:

util.js -> xpath.js -> util.js
util.js -> xpath.js -> dom.js -> util.js
xpath.js -> xpathdebug.js ->xpath.js -> util.js

These circular dependencies and issues in the way the 'he' package is imported cause errors when the package is part of a bundle generation in 'iife' or 'umd' formats using rollup.

Xpath parse error

Hi,

when I try to

const XMLXRString = xsltProcess(
    xmlParse(zugferdInvoice),
    xmlParse(XSLTcii2xr)
);

with zugferdInvoice and XSLTcii2xr

I seem to get a

/viewer/node_modules/xslt-processor/dist/xslt-processor.js:1 Uncaught XPath parse error /rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID=('VA', 'VAT')]:
/
RelativeLocationPath
/
Step
[
Expr
=
(
Expr
ArgumentRemainder
)
]

any idea anyone?

Support key

Have a (lot) of xsl with format like this:

<xsl:for-each select="//R[generate-id(.)=generate-id(key('data',c[2]))]">

I'd love to use this library to apply them to my xml but currently it's coming back with key not supported.

local-name()

One could do with local-name(), useful when dynamically creating elements and it should be simple to implement as it follows on from 'name'.
``
'local-name' (ctx) {
assert(this.args.length == 1 || this.args.length == 0);
let n;
if (this.args.length == 0) {
n = [ctx.node];
} else {
n = this.args[0].evaluate(ctx).nodeSetValue();
}

    if (n.length == 0) {
        return new StringValue('');
    } else {
        let name = n[0].nodeName;
        if(name.contains':') {
        	return new StringValue(name.slice(name.indexOf(':')+1));
        } else {
        	return new StringValue(name);
        }
    }
},

`

Feature request: distribute as transpiled output to support older browsers

As discussed in this commit conversation it would be nice to distribute the library in a transpiled way so it supports "older browsers".
The reason for our fork that moves default arguments methods into the methods was that we need to support chrome 48 which failed with a syntax error when loading this library.

Any hints for how to achieve this can be collected here, contributions seem to be welcome.

Anything to add @johanneswilm ?

Mentioning @saurabh2590 here that created the fork and commits.

Great but encodes all output

I use XSLT to convert XML to TSV but xslt-processor double-encodes all the tab entities; any chance we can have an option to stop this?

I dont want encoded data for web, that should be up to the consumer of the package really

xls:choose not working properly

in an xsl:choose statement testing an attribute for 3 different options, if I put an xsl:otherwise it always takes the otherwise path. If I remove the otherwise then it takes the correct path. Looks like xsl:otherwise is overriding all tests.

xsl:number not implemented

I apologize if this is rough. I'm a newby at node.js and using this processor. I'm trying to reimplement a project that I had working back in Win98 days.

Using a simple test app to do a transform I'm getting an error:

mbudd@TreeClimberLap:~/Documents/electron/xslt$ node --trace-uncaught index.js
Debugger attached.

node:internal/process/esm_loader:94
internalBinding('errors').triggerUncaughtException(
^
Waiting for the debugger to disconnect...
not implemented: number
Thrown at:
at loadESM (node:internal/process/esm_loader:94:31)

Node.js v17.3.0

I have isolated it down to one line in my .xslt file:
<xsl:number count="item" />

Is this something that is already known, or would a minimum example case be helpful? Is there a workaround?

Problem with xsl:choose

I have a case where xsl:choose gives unexpected results but an equivalent pair of xsl:if elements works (using a browser solution with XSLTProcessor).

NOTE: I have corrected the text here. See later comment.

A cut down stylesheet working on:

<sign gloss="simple">
  <hamnosys_sign>
    <sign2>
      <minitialconfig2>
        <handconfig2>
          <handshape2>
            <handshape1 handshapeclass="ham_flathand"/>
          </handshape2>
        </handconfig2>
      </minitialconfig2>
    </sign2>
  </hamnosys_sign>
</sign>

should yield:

<hamgestural_sign>
  <sign_manual>
    <handconfig handshape="flat"/>
  </sign_manual>
</hamgestural_sign>

but yields:

<hamgestural_sign>
  <sign_manual>
    <handconfig>flat
    </handconfig>
  </sign_manual>
</hamgestural_sign>

Here is the (failing) stylesheet - cut back a lot:

<xsl:transform version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- THESE OUTPUT SETTINGS MAY BE OVERRIDDEN BY THE H2S PROCESSOR: -->

<xsl:output method="xml" omit-xml-declaration="yes"
    indent="yes" encoding="UTF-8"/>

<!--######## handShapeValue ########-->

<xsl:template name="handShapeValue">

    <xsl:variable name="hs" select="@handshapeclass"/>

<!-- OK
    <xsl:value-of select="substring-after(concat(substring-before($hs,'hand'),$hs[not(contains(.,'hand'))]),'ham_')"/>
-->

<!-- OK
    <xsl:if test="$hs='ham_flathand'">
        <xsl:value-of select="'flat'"/>
    </xsl:if>
    <xsl:if test="$hs!='ham_flathand'">
        <xsl:value-of select="substring-after($hs,'ham_')"/>
    </xsl:if>
-->
<!-- Fails -->
    <xsl:choose>
        <xsl:when test="$hs='ham_flathand'">
            <xsl:value-of select="'flat'"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="substring-after($hs,'ham_')"/>
        </xsl:otherwise>
    </xsl:choose>

<!-- Fails
    <xsl:choose>
        <xsl:when test="$hs='ham_flathand'">
            <xsl:value-of select="'flat'"/>
        </xsl:when>
    </xsl:choose>
 -->
 
</xsl:template>

<!--######## sign ########-->

<xsl:template match="/">
    <!--
    <!ELEMENT sign (hamnosys_sign?)>
    <!ATTLIST sign gloss CDATA #IMPLIED>
    -->

    <xsl:element name="hamgestural_sign">

        <xsl:if test="@gloss">
            <xsl:attribute name="gloss">
                <xsl:value-of select="@gloss"/>
            </xsl:attribute>
        </xsl:if>

        <xsl:element name="sign_manual">
            <xsl:apply-templates select="sign/hamnosys_sign/sign2/minitialconfig2/handconfig2/handshape2/handshape1"/>
        </xsl:element>

    </xsl:element>

</xsl:template>

<!--######## handshape1 ########-->

<xsl:template match="handshape1">
    <!--
    <!ELEMENT handshape1 (
        fingernothumb*, fingershape*, fingercrossing*, thumbspecial?
    )>
    <!ATTLIST handshape1
        handshapeclass (%handshapeclass;) #REQUIRED
        fingerbending (%fingerbending;) #IMPLIED
        thumbpos (%thumbpos;) #IMPLIED
        second_handshapeclass (%handshapeclass;) #IMPLIED
        second_fingerbending (%fingerbending;) #IMPLIED
        second_thumbpos (%thumbpos;) #IMPLIED
        approx_shape %boolfalse;
    >
    -->

    <xsl:element name="handconfig">

        <xsl:variable name="hs">
            <xsl:call-template name="handShapeValue"/>
        </xsl:variable>

        <!-- handshape ATTRIBUTE -->
        <xsl:attribute name="handshape">
            <xsl:value-of select="$hs"/>
        </xsl:attribute>

    </xsl:element>

</xsl:template>

</xsl:transform>

There are several alternatives in template 'handShapeValue': One using a complex XPath expression - works; one using xsl:if - works; some using xsl:choose - don't work.

Looking at the high level code, xsl:if looks simpler and straightforward, while xsl:choose seems to use a different evaluation context, which maybe does not work in my case.

There may be other cases where xslt-processor is not working with my stylesheet as some output is duplicated. However, this seems to be a simple case where I am doing something wrong or there is an issue. I could convert all xsl:choose cases to xsl:if (even using XSLT!) but would rather not. The underlying stylesheet is very old and has been used without problems for many years - but it is several thousand lines long.

<xsl:copy-of...> generates wrong output for nodes with CDATA

For example, if the input is like this:

<testsuites>
  <testsuite>
    <testcase name="bla1" time="0" classname="bla1">
      <failure><![CDATA[very long multiline     
    at <anonymous>]]></failure>
    </testcase>
    <testcase name="bla2" time="0" classname="bla2">
      <failure><![CDATA[very long multiline    at <anonymous>]]></failure>
    </testcase>
    <testcase name="bla3" time="2.043" classname="bla3">
    </testcase>
  </testsuite>
</testsuites>

And part of the XSLT is like this:

<xsl:template match="testcase">
    <xsl:copy>
        <xsl:attribute name="name">
            <xsl:value-of select="normalize-space(substring-before(@name, @classname))"/>
        </xsl:attribute>
        <xsl:attribute name="time">
            <xsl:value-of select="number(@time) * 1000"/>
        </xsl:attribute>
        <xsl:attribute name="classname">
            <xsl:value-of select="@classname"/>
        </xsl:attribute>
        <xsl:attribute name="status">
            <xsl:value-of select="@status"/>
        </xsl:attribute>
        <xsl:attribute name="assertions">
            <xsl:value-of select="@assertions"/>
        </xsl:attribute>
        <xsl:copy-of select="failure"/>
        <xsl:copy-of select="skipped"/>
        <xsl:copy-of select="error"/>
        <xsl:copy-of select="system-out"/>
        <xsl:copy-of select="system-err"/>
    </xsl:copy>
</xsl:template>

Then the output would contain only "bla1" with /failure&gt; after ]], and without "bla2" and "bla3:

<testsuites><testsuite><testcase name="bla1" time="0" classname="bla1"><failure><![CDATA[very long multiline    
    at <anonymous>]]>/failure&gt;
    </failure></testcase></testsuite></testsuites>

CDATA in xsl not working as expected

Hi!
I'm trying to put js code in the xsl template but it is not able to resolve the CDATA tag within the xsl. You could use this code to test:

import { XmlParser, Xslt, XsltOptions } from 'xslt-processor';

// Transform template to HTML
const xsl = `
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html" version="4.0" encoding="utf-8" omit-xml-declaration="yes" />
  <xsl:template match="/">
    <html>
      <head>
        <script type="text/javascript">
          <![CDATA[
          if (1 < 2) {}
        ]]>
        </script>
      </head>
      <body>
        <h1>
          <xsl:value-of select="ReportName"/>
        </h1>
        <p>
          <xsl:value-of select="GenerationDate"/>
        </p>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
    `;
const xml = `
<XampleXml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ReportName>My first transformation in js</ReportName>
  <GenerationDate>01/06/2024</GenerationDate>
</XampleXml>
    `;

const options: XsltOptions = {
  cData: true,
  escape: false,
  selfClosingTags: false,
};
const xslt = new Xslt(options);
const xmlParser = new XmlParser();
xslt
  .xsltProcess(xmlParser.xmlParse(xml), xmlParser.xmlParse(xsl))
  .then((output) => {
    console.log(output);
  });
//OUTPUT: <html><head><script type="text/javascript"></script></head><body><h1>My first transformation in js</h1><p>01/06/2024</p></body></html>

As you can see, the content of the script (CDATA content) does not appear in the output.

Another curious thing is that if we add xsl:text around it, the following happens:

import { XmlParser, Xslt, XsltOptions } from 'xslt-processor';

// Transform template to HTML
const xsl = `
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html" version="4.0" encoding="utf-8" omit-xml-declaration="yes" />
  <xsl:template match="/">
    <html>
      <head>
        <script type="text/javascript">
          <xsl:text disable-output-escaping="yes">
            <![CDATA[
          if (1 < 2) {}
        ]]>
          </xsl:text>
        </script>
      </head>
      <body>
        <h1>
          <xsl:value-of select="ReportName"/>
        </h1>
        <p>
          <xsl:value-of select="GenerationDate"/>
        </p>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
    `;
const xml = `
<XampleXml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ReportName>My first transformation in js</ReportName>
  <GenerationDate>01/06/2024</GenerationDate>
</XampleXml>
    `;

const options: XsltOptions = {
  cData: true,
  escape: false,
  selfClosingTags: false,
};
const xslt = new Xslt(options);
const xmlParser = new XmlParser();
xslt
  .xsltProcess(xmlParser.xmlParse(xml), xmlParser.xmlParse(xsl))
  .then((output) => {
    console.log(output);
  });
//OUTPUT:
//
//
//
// if (1 < 2) {}
//
// <html><head><script type="text/javascript"></script></head><body><h1>My first transformation in js</h1><p>01/06/2024</p></body></html>

The script appears at the beginning of the resulting html.

Could you investigate to resolve that?

Thank you!

node-set() function

Is there any implementation of the node-set function?

I'm able to convert an xml variable to node-set with the exsl extension, but i read that xslt-processor doesn't support extensions..

Below an example:

<xsl:output method="xml" indent="yes" />

<xsl:param name="x">
   <A>
      <B id="1"></B>
      <B id="2"></B>
   </A>
</xsl:param>

<xsl:param name="y" select="exsl:node-set($x)/A"/>

<xsl:template match="/">
   <xsl:copy-of select="$y" />
</xsl:template>  

Parsing XPath expression in Node.js

Can't figure out how to use this to parse an XPath expression in Node.js. If I just do this:

var xsltProc = require("xslt-processor")
console.log(xsltProc)

This is all that comes out:

Object {xmlParse: function(), xsltProcess: function()}

Just an object with two functions of which none is the xpathParse function tested here. Can you please shed some light on how to do this? The description of the package states:

Because XSLT uses XPath, it also contains an implementation of XPath that can be used independently of XSLT

So I'm assuming it's possible.

Input namespace not used

Thank you for creating and sharing this great library! ๐Ÿ˜ƒ

I have a lot of already programmed xsl-scripts, which use namespaces like this. They could be successfully processed with xsltproc, but not with this processor, see the following example:

Input string:

<?xml version="1.0" encoding="ISO-8859-1"?>
<ClinicalDocument xmlns="http://testnamespace">
    <test name="test1" />
    <test name="test2" />
    <test name="test3" />
    <test name="test5" />
</ClinicalDocument>

With the following xsl-script, I got the excepted output with xsltproc:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:n="http://testnamespace">
    <xsl:template match="/">
        <xsl:copy-of select="n:ClinicalDocument/n:test" />
    </xsl:template>
</xsl:stylesheet>

Output:

<?xml version="1.0"?>
<test xmlns="http://testnamespace" name="test1"/><test xmlns="http://testnamespace" name="test2"/><test xmlns="http://testnamespace" name="test3"/><test xmlns="http://testnamespace" name="test5"/>

But with the xslt-processor it only works like this (so only without namespace):

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:n="http://testnamespace">
    <xsl:template match="/">
        <xsl:copy-of select="ClinicalDocument/test" />
    </xsl:template>
</xsl:stylesheet>

How could I apply the namespace correctly so that I do not have to change all xsl-scripts?

Would be nice to get some reply!

Thank you and best!

does not obey 'disable-output-escaping'=yes

I want to turn xml into html. I want to have <!DOCTYPE html> to start the file. Tthe following works with other xml/xsl converters:

xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" indent="yes"/>
    <xsl:template match="/">
        <xsl:text disable-output-escaping="yes">&lt;!DOCTYPE html&gt;</xsl:text>
    </xsl:template>
    </xsl:output>
</xsl:stylesheet>

However this module doesn't properly render the DOCTTYPE tag. I get:

&amp;lt;!DOCTYPE html&amp;gt;

So 'disable-output-escaping' isn't being honored because it converts '&' to '& also it does't properly convert < to '<' (but this might be do to the escaping issue).

Implement <xsl:key>

Should work this way:

<xsl:key name="term-key" match="mark" use="concat(@term, ../../@id)"/>
<xsl:template match="marks">
  <xsl:variable name="unique-term" select="mark[generate-id()=generate-id(key('term-key', concat(@term, ../../@id)))]/@term"/>
</xsl:template>

Thank you

Multiple match

In case of multiple node matches, instead of applying to the closest match all of the matches are applied at the same time.

e.g:

	<xsl:template match="*">
		<node name="{name(.)" />
		<xsl:apply-templates select="@*" />
		<xsl:apply-templates select="*" />
	</xsl:template>

	<xsl:template match="creationTime" />

	<xsl:template match="/*/submissionTime">
		<foo>bar</foo>
		<xsl:apply-templates select="*" />
	</xsl:template>

In this case

  • <node name="creationTime" /> is created
  • creationTime descendant nodes are considered
  • <node name="submissionTime" /> is created
  • submissionTime descendant nodes are considered twice

I also tried by assigning priority to template matches, but it didn't solve the issue.

xhtml

Hi, thank you for sharing the code.

I found that the xslt processor will convert my XSLT string to XHTML standard.
That is, it will change my code from <div class="logo"></div> to <div class="logo" />

Is it by design or can the processor stop doing this?

Lack of error messages

Possibly the most infuriating thing is that there are no error messages. If it doesn't like your stylesheet, it just fails silently and produces an empty output. Not nice! XSLT can get quite complicated -- it would be preferable if there was a message or maybe a line number and column number to show you where it balked.

Implement <xsl:import>

I get en error when i use a style with "import" tag:

not implemented: import

It seems, it needs to be implemented

TypeError: e.match is not a function

TypeError: e.match is not a function

Code:

const fs = require('fs');
const path = require('path');
const { xsltProcess, xmlParse } = require('xslt-processor');

const readFile = filePath => {
  return fs.readFileSync(path.resolve(__dirname, filePath));
};

const xmlString = readFile('./Sample.xml');
const xsltString = readFile('./Outbound.xsl');

const outputString = xsltProcess(xmlParse(xmlString), xmlParse(xsltString));

console.log(outputString);

Error:

/Users/test/node_modules/xslt-processor/dist/xslt-processor.js:1
(function (exports, require, module, __filename, __dirname) { "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var commonjsGlobal="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function createCommonjsModule(e,r){return e(r={exports:{}},r.exports),r.exports}var he=createCommonjsModule(function(e,r){!function(t){var a=r,n=e&&e.exports==a&&e,o="object"==typeof commonjsGlobal&&commonjsGlobal;o.global!==o&&o.window!==o||(t=o);var s=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,i=/[\x01-\x7F]/g,l=/[\x01-\t\x0B\f\x0E-\x1F\x7F\x81\x8D\x8F\x90\x9D\xA0-\uFFFF]/g,u=/<\u20D2|=\u20E5|>\u20D2|\u205F\u200A|\u219D\u0338|\u2202\u0338|\u2220\u20D2|\u2229\uFE00|\u222A\uFE00|\u223C\u20D2|\u223D\u0331|\u223E\u0333|\u2242\u0338|\u224B\u0338|\u224D\u20D2|\u224E\u0338|\u224F\u0338|\u2250\u0338|\u2261\u20E5|\u2264\u20D2|\u2265\u20D2|\u2266\u0338|\u2267\u0338|\u2268\uFE00|\u2269\uFE00|\u

TypeError: e.match is not a function
    at xmlParse (/Users/rmkanda/test/node_modules/xslt-processor/dist/xslt-processor.js:1:71118)
    at Object.<anonymous> (/Users/rmkanda/test/index.js:12:34)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)

Wrong output at processing

Hi. First of all, thank you for your effort. It's really nice to find an XSLT processor with no dependencies.

I'm getting different outputs from processing the same xml/xslt using the library I want to move away from (libxslt) and this one. I'm pretty sure the one libxslt provides is the correct one because I have compared it with some tools developed in Java.

What I'm expecting looks like this:

||3.3|1234|2018-06-03T16:16:36|02|1234567890|25862.07|MXN|1|30000.00|I|PUE|83240|ASS010101A12|Aligator Service, SAPI|601|DCS030303W09|Defenseless Canary, S.A. de C.V.|G03|43211508|DELL123|3|EA|Laptop DELL XPS 13|8620.689655|25862.07|25862.07|002|Tasa|0.160000|4137.93|0.00|002|Tasa|0.160000|4137.93|4137.93||

And what I'm getting is the exact same string but with 3 additional pipes at the beginning.

|||||3.3|1234|2018-06-03T16:16:36|02|1234567890|25862.07|MXN|1|30000.00|I|PUE|83240|ASS010101A12...

I set up a repo with a unit test so you can easily reproduce it: https://github.com/javorosas/test-xslt

If you need me to add the libxslt implementation to the repo, please let me know.

Thanks in advance.

Is there a way to provide arguments?

The .NET equivalent XSLT transformer allows you to provide arguments to satisfy <xsl:param name="..."> in the XSLT doc.

public void Transform(System.Xml.XmlReader input, System.Xml.Xsl.XsltArgumentList? arguments, System.IO.TextWriter results);

I'm wondering if there's any equivalent with xslt-processor or a work-around?

How to use in Node.js

I'm trying to use this library in Node.js to parse an XML file. Here's what I'm doing.

const fs = require('fs-extra');
const xmlParse = require('xslt-processor').xmlParse;
const xml = await fs.readFile('path/to/file.xml');
xmlParse(xml);

I'm getting this error:

(node:14628) UnhandledPromiseRejectionWarning: TypeError: xml.match is not a function
    at xmlParse (/Users/miguelangel/my-node-projects/viskit/node_modules/xslt-processor/dist/xslt-processor.js:490:13)
    at validateProject (/Users/miguelangel/my-node-projects/viskit/controllers/validate-project.js:7:12)
(node:14628) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:14628) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I don't think I'm requireing this correctly. How do I make this work in Node?

Nodes with no parents defined

dado:

<lmht><cabeca><titulo>Listagem de clientes</titulo></cabeca><corpo><titulo1>Clientes</titulo1><tabela><cabeca-tabela><linha><celula>Id</celula><celula>Nome</celula></linha></cabeca-tabela><corpo-tabela><linha><celula>1</celula><celula>Italo</celula></linha><linha><celula>2</celula><celula>Leonel</celula></linha></corpo-tabela></tabela></corpo></lmht>

image

Error:
image

Status of this project: only handles trivial cases it seems

So far every template I've tried has failed. I have 2 decades of experience with XSLT and I think 99% of my templates would not be handled properly by this library. But there's no warning anywhere about the status of this project, and the TODO list is basically empty. See for example #39: that's a major issue.

I can go on and on, but I think this project should demonstrate it can run much more of the XSLT spec before it is ready for production use.

It's a shame, as this is the only attempt at a nodejs native implementation I've found.

Anyway, I think the project should put up some huge warning signs to save people time as probably nothing they'll try will work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.