Create XML with Multiple Same-Tag Children - chilkat

I will not describe my xml structure, I have prepared an example for reproduction.
Expected result:
<?xml version="1.0" encoding="utf-8" ?>
<A>
<B>b</B>
<C>c1</C>
<C>c2</C>
</A>
Code:
Set xml = CreateObject("Chilkat_9_5_0.Xml")
xml.Tag = "A"
xml.UpdateChildContent "B", "b"
xml.UpdateChildContent "C", "c1"
xml.UpdateChildContent "C[1]", "c2"
Debug.Print xml.getxml
Result
<?xml version="1.0" encoding="utf-8" ?>
<A>
<B>b</B>
<C>c1</C>
</A>
If I change c index from 1 to 2 then get two C nodes. Why?

This problem should be fixed in the latest version of Chilkat.

Related

XSPEC: What is meaning of Expected Result 'XPath / from:' on test report?

I'm new at XSPEC
I try to run the following test:
<?xml version="1.0" encoding="UTF-8"?>
<x:description xmlns:x="http://www.jenitennison.com/xslt/xspec" stylesheet="test1.xsl">
<x:scenario label="Scenario for testing a function">
<x:context href="test1.xml"/>
<x:expect label="expext1" href="result_test1.xml"/>
</x:scenario>
</x:description>
When the content of the relevant files is:
test1.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="test1">
<h1>
<xsl:apply-templates/>
</h1>
</xsl:template>
</xsl:stylesheet>
test1.xml:
<?xml version="1.0" encoding="UTF-8"?>
<test1>text for test</test1>
result_test1.xml:
<?xml version="1.0" encoding="UTF-8"?><h1>text for test</h1>
The result after run the xspec file is fail,
As shown in the screenshot below:
Next to the expected outcome is the text:
'XPath / from:'
What is meaning of this?
Below screenshot with the result:
/ in this case means a document node.
If you run your test on XSpec v1.3.0 or later, you get more explicit output:
Result
XPath /element() from:
Expected Result
XPath /self::document-node() from:
which indicates that you expected a document node but the actual result was an element.

How to add cxml doctype using XSLT

I am generating correct cxml but doctype is missing in the beginning.
How can I add the below doc type after <?xml version="1.0" encoding="utf-8"?> and copy the remaining xml using XSLT mapping.
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.032/cXML.dtd">
Desired output should be like
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.032/cXML.dtd">
<xml>
<field>.... (followed by remaining xml structure)
Thanks,
Varun
Try
<xsl:output method="xml"
doctype-system="http://xml.cxml.org/schemas/cXML/1.2.032/cXML.dtd"
/>

xslt output xml tree without using xsl:copy

Suppose I had the following xml doc
<?xml version="1.0" ?>
<?xml-stylesheet href="file.xsl" type="text/xsl" ?>
<a>
<ab x="x"><b>Test</b><a>z</a></ab>
<z x="x"><a>z</a></z>
</a>
and I wanted to output on screen only the a elements and their attributes and values while omitting the b element and z element. In other words produce this onscreen. What is the best approach without using xsl:element or xsl:copy
<?xml version="1.0" encoding="ISO-8859-1"?>
<a>
<ab x="x"><a>z</a></ab>
</a>

xslt: get attribute from xsl itself

is it possible to read an xsl attribute from the xsl document itself? I need something like this:
mystyle.xsl
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/1999/xhtml"
id="I'm a special stylesheet">
...
<!-- Output should be: "stylesheet id: I'm a special stylesheet" -->
<xsl:text>stylesheet id:</xsl:text><xsl:value-of select="/#id"/>
...
</xsl:stylesheet>
Is that possible?
Yes, you can use <xsl:value-of select="document('')/xsl:stylesheet/#id"/>, at least as long as the stylesheet has been loaded from a URI.

xslt parse XML string into variable and use Xpath

My (simplified) input XML file contains the following:
<?xml version="1.0" encoding="UTF-8"?>
<main>
<DATA_RECORD>
<MESSAGE><pd>
<cdhead version="13"/>
</pd></MESSAGE>
</DATA_RECORD>
</main>
The MESSAGE element value is a character-escaped XML instance. It represents the following XML:
<pd>
<cdhead version="13"/>
</pd>
I would like to apply an xsl transformation on the input XML and somehow parse the MESSAGE contents into a variable and use Xpath expressions to access its details.
I tried adding a javascript function as below, but the object returned by the script apparently is of an incorrect DOM subclass (see result underneath). For completeness, I added an extra function that returns the DOM contents as a string.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:my="http://example.com/my"
exclude-result-prefixes="ms my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<ms:script language="JScript" implements-prefix="my">
<![CDATA[
function parseToDOM (input) {
var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
doc.loadXML (input);
return doc.documentElement;
};
function parseToXMLString (input) {
var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
doc.loadXML (input);
return doc.documentElement.xml;
};
]]>
</ms:script>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="DATA_RECORD">
<xsl:variable name="DOM"><xsl:copy-of select="my:parseToDOM (MESSAGE)"/></xsl:variable>
<xsl:variable name="XML"><xsl:copy-of select="my:parseToXMLString (MESSAGE)"/></xsl:variable>
<msg1><xsl:value-of select="$XML"/></msg1>
<msg2><xsl:value-of select="$XML" disable-output-escaping="yes"/></msg2>
<dom><xsl:copy-of select="$DOM"/></dom>
<version><xsl:value-of select="$DOM/pd/cdhead/#version"/></version>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<msg1><pd>
<cdhead version="13"/>
</pd></msg1>
<msg2><pd>
<cdhead version="13"/>
</pd></msg2>
<dom/>
<version></version>
</root>
How can I make the Jscript function return a result that allows the use of Xpath?
By the way, is there some XSLT 1.0 function available that allows parsing the escaped XML string to a result that allows the use of Xpath?
ADDITION
I have been trying some variations and got closer to a solution. First, Altova XMLSpy allows choosing the xsl processor, and the above resulted when using the built-in one. Of course I need MSXML 6.0 and when choosing that one, errors occurred as I had to parse input.text instead. But I only succeeded in being able to use Xpath expressions in the result after doing extra stuff in the javascript. It transpired that while < and the like are parsed into < etcetera, this is not enough to arrive at the proper DOM result. So I resorted to unescaping the input string first.
But I hit another snag: where the below works fine, it does not when I use input.text instead of the literal below.
See below the xslt.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:my="http://example.com/my"
exclude-result-prefixes="ms my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<ms:script language="JScript" implements-prefix="my">
<![CDATA[
function parseToDOM (input) {
var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
doc.loadXML (unescapeXML ('<pd>
<cdhead version="13"/>
</pd>'));
//doc.loadXML (unescapeXML (input.text));
return doc;
};
function unescapeXML (str) {
var ostr = str;
ostr = ostr.replace (/"/g, '"');
ostr = ostr.replace (/</g, '<');
ostr = ostr.replace (/=/g, '=');
ostr = ostr.replace (/>/g, '>');
return ostr;
};
]]>
</ms:script>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="DATA_RECORD">
<xsl:variable name="msg" select="my:parseToDOM (MESSAGE)"/>
<tst><xsl:value-of select="$msg/pd/cdhead/#version"/></tst>
</xsl:template>
</xsl:stylesheet>
Now results in
<?xml version="1.0" encoding="UTF-8"?>
<root>
<tst>13</tst>
</root>
Which is exactly what I want.
But as remarked above, when I comment the parsing of the literal and use the input instead, like so:
//doc.loadXML (unescapeXML ('<pd>
<cdhead version="13"/>
</pd>'));
doc.loadXML (unescapeXML (input.text));
I get the following error (in Altova XML Spy with MSXML 6.0 as xslt parser):
XSL transformation failed due to following error:
Microsoft JScript runtime error
'undefined' is null or not an object
line = 10, col = 3 (line is offset from the start of the script block).
Error returned from property or method call.
Which points at the first javascript replace statement.
And also, IE9 cannot process the following properly:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<main>
<DATA_RECORD>
<MESSAGE><pd>
<cdhead version="13"/>
</pd></MESSAGE>
</DATA_RECORD>
</main>
When I open this file in IE9 (where test.xslt is the version of the transformation where the input is ignored and instead a literal is processed, hence the one that is OK in XML Spy), I get a processing error:
XML5001: Applying Integrated XSLT Handling.
XSLT8690: XSLT processing failed.
Why is all this and how can I correct it?
Starting from the ADDITION above, I reached a solution by finetuning it a little.
To avoid having to do input.text and use plain input instead, the xsl has to contain a conversion of the element to a string by applying the xslt string function (I thought it was a string already, but apparently that is not the case). In addition, it was not necessary any more to apply the replace statements now.
Thus
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:my="http://example.com/my"
exclude-result-prefixes="ms my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<ms:script language="JScript" implements-prefix="my">
<![CDATA[
function parseToDOM (input) {
var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
doc.loadXML (input);
return doc;
};
]]>
</ms:script>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="DATA_RECORD">
<xsl:variable name="msg" select="my:parseToDOM (string(MESSAGE))"/>
<tst><xsl:value-of select="$msg/pd/cdhead/#version"/></tst>
</xsl:template>
</xsl:stylesheet>
works: when applied on
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<main>
<DATA_RECORD>
<MESSAGE><pd>
<cdhead version="13"/>
</pd></MESSAGE>
</DATA_RECORD>
</main>
the result is
<?xml version="1.0" encoding="UTF-8"?>
<root>
<tst>13</tst>
</root>
Unluckily, IE9 still fails in loading the XML with referred XSLT; and I discovered why.
I had to tick the box in Internet Options/Advanced/Security/Allow active content to run in files on My Computer - and also restart IE - this makes IE9 process the file correctly. Of course, the result not being html means that the result can only be viewed in F12/Script tab, but this was just an example and I will incorporate it in an xslt that generates proper html.