Using XSLT to transform ReqIF to UML - xslt

I'm trying to transform one XML document (REQ-IF) into another XML document (UML-Class-Diagram document) using XSLT.
My Problem now is the following:
REQ-IF provides datatypes as:
<Datatypes>
<DATATYPE-DEFINITION-STRING IDENTIFIER="xyz" LONG-NAME="ABC"
</Datatypes>
and Objects as:
<SPEC-OBJECTS>
<VALUES>
<ATTRIBUTE-VALUE-STRING THE-VALUE="some-value">
<DEFINITION>
<ATTRIBUTE-DEFINITION-STRING-REF>xyz</ATTRIBUTE-DEFINITION-STRING-REF>
</DEFINITION>
</ATTRIBUTE-VALUE-STRING>
</VALUES
<SPEC-OBJECTS>
This is resembled in my UML representation as:
<ownedAttribute xmi:id="some-ID" name="ABC" type="some-ID">
please note the ABC and xyz.
I therefore use <xsl:for-each> to loop through the Objects and another <xsl:for-each> to loop through the values.
Now I have to take the Datatype-ID from the value, find out which Datatype it is and write the Datatype-name into the output file.
How do I do that?
Thank you so much in advance

Try /Datatypes[DATATYPE-DEFINITION-STRING/#IDENTIFIER = current()/ATTRIBUTE-VALUE-STRING/DEFINITION/ATTRIBUTE-DEFINITION-STRING-REF]/DATATYPE-DEFINITION-STRING/#LONG-NAME.
I admit I didn't actually test this, but you'll probably get the idea. The point of current is to access the XSLT context (the VALUES element) as opposed to the current XPath context that is active in the filter.

Related

XSLT -- detect if node has already been copied to the result tree

Using xsltproc to clean up input XML.
Think about a part number referencing a part description from random locations in the document. My XML input is poorly designed and it has part number references to part descriptions all over with no real pattern as to where they are located. Some references are text in elements, some in attributes, sometimes the attribute changes meaning depending on context. The attribute containing the part number does not have a consistent name, the name used alters depending on the value of other attributes. Maybe I could build a key selecting the dozen varying places containing part number but it would be a mess. I would also worry about inadvertently selecting the wrong items with complex patterns.
So my goal is to only copy the referenced part descriptions to the output document once (not all descriptions are referenced). I can insert tests in all of the various templates to detect the part number in context. The very simple solution would be to just test if it has already been copied to the result tree and not copy it again. But there is no way to track this?
Plan B is to copy it multiple times to the result tree and then do a second pass over the output document to remove the duplicates.
The use of temporal language in the question ("has already been") is a good clue that you're thinking about this the wrong way. In a declarative language, you shouldn't be thinking in terms of the order of processing.
What you're probably looking for is something like this:
<xsl:variable name="first-of-a-kind-part-references" as="node()*">
<xsl:for-each-group select="f:all-part-references(/)"
group-by="f:get-referenced-part(.)/#id">
<xsl:sequence select="current-group()[1]"/>
</xsl:for-each-group>
</xsl:variable>
and then when processing a part reference
<xsl:if test=". intersect $first-of-a-kind-part-references">
...
</xsl:if>

XSLT 2.0: Limit the ancestor axes to a certain element/s level up the document tree

I'm seeing a quite odd behaviour, when trying to limit the results given by applying ancestor::* to an element I always get an extra ancestor although is expressly excluded by the predicate.
Here the code:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<level_a>
<level_b>
<level_c>
<level_d>
<level_e/>
</level_d>
</level_c>
</level_b>
</level_a>
<level_b>
<level_c>
<level_d>
<level_d>
<level_e/>
</level_d>
</level_d>
</level_c>
</level_b>
</root>
XPath:
(//level_d[not(level_d)])[last()]/ancestor::*[level_c|level_b]
so basically I'm selecting the level_d elements that doesn't have another level_d element nested, getting the last one of them and trying to get all the ancestors up to element level_b.
But the result I'm seeing using Altova XMLSpy 2011 is:
level_a
level_b
I don't quite understand why I'm getting that result and how can I improve my xpath to limit effectively the ancestors up to level_b (i.e. level_c and level_b).
Any hint is greatly appreciated!
Regards
Vlax
Well ancestor::*[level_c|level_b] selects all elements on the ancestor axis that have a level_c or level_b child.
You might want (//level_d[not(level_d)])[last()]/ancestor::*[self::level_c|self::level_b].
Or with your textual description "to limit effectively the ancestors to level_b" you simply want (//level_d[not(level_d)])[last()]/ancestor::level_b.
I think you get right result because clause ancestor::*[level_c|level_b] I read as "all ancestors containing element level_b or level_c". So, level_b is ok because it contains level_c and level_a is ok too because it contains level_b.
So if I change your XPath into (//level_d[not(level_d)])[last()]/ancestor::*[level_c] it results into level_b only.
Probably it is not exactly what you asking for but I'm not sure if I understand well the purpose of your XPath :-)

Update XML nodevalue with C++

I have an XML as below
<ROOT>
<Device>
<host>localhost</host>
<Port>52000</Port>
</Device>
<DeviceHost>
<Server>Server.exe</Server>
<Port>81</Port>
</DeviceHost>
<Settings>
<Flag1>100</Flag1>
<Flag2>2000</Flag2>
</Settings>
</ROOT>
How can I update the Flag1 and Flag2 to 200 and 4000 respectively without changing other values using VC++?
I have two function wrote using api MSXML.
doc.LoadXml(Data);//for loading the xml data
doc.Save(FilePath);//for saving the xml data
But my issue is before saving how can i update two node values
You would need to get the correct node by calling getElementsByTagName (which should return a NodeList containing one item) and then call put_nodeValue to write the value -- there are some MSDN samples here and here
EDIT: you should also be able to use doc.selectSingleNode("/ROOT/Flag1", &pNode) as per this MSDN article

Copying an element (xsl:function) from the stylesheet to the "result" XML

First, I should say that I am a beginner in terms of XSLT.
Although the exact context may not be so relevant (and might be too confusing), I will provide it below.
I have a chained transformation, which looks like this:
Input.xml is the input file for this transformation, which is performed using transform.xsl. The result of this transformation is output.xml. transform.xml contains a classic custom xsl:function:
xsl:function name="my:f"
xsl:sequence select=".. xpath .."
xsl:function
The result from step 1 (output.xml) is, for step 2, a new transformer (transform2.xsl), which will be using some other XML input (let's say input2.xml).
What I would like to do is to copy the xsl:function node entirely (present in the transform.xsl in step 1) to the output.xml, so that it can be used in step 2.
No updates / changes are needed in this case for the xsl:function while copying it (just a simple node copy).
Note that I do not want to copy the xsl:function only when a given input element (from input.xml) is present. But rather, I want to copy it always, no matter what the input.xml is.
Now I know this can be made by having a separate file which contains my xsl:function, and then using xsl:import to include this file from both transformations (transform.xml and transform2.xml).
But I would like to know if there are other ways of accomplishing this (..without having a separate file where the function is declared / defined)?
Thanks in advance,
M.
You can access the stylesheet document using document('') so doing e.g.
<xsl:template match="/*">
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:copy-of select="document('')/xsl:stylesheet/xsl:function"/>
<xsl:apply-templates/>
</xsl:stylesheet>
</xsl:template>
should copy any xsl:function elements in the stylesheet to the result tree.
[edit]
After the edit it seems you want to copy a function of a certain name: if you want to copy the function of certain name then you could do e.g.
<xsl:copy-of select="document('')/xsl:stylesheet/xsl:function[
resolve-QName(#name, .) eq QName('http://example.com/ns', 'f')]"/>
where f is the local name of the function and http://example.com/ns is the namespace the function is defined in.
You can use the document() built-in function which wil return the stylesheet document for an emtpy URI. Then you can just copy the element to the output.

XSLT 2.0 How to change default formatting for numbers?

In XSLT 1.0 (using Xalan), outputting the result of:
<xsl:variable name="source0" select="number(num3)"/>
<xsl:value-of select="$source0"/>
was the number spelled out as 2011234. But in XSLT 2.0 (using Saxon), it shows up as 2.011234E6. I want it to always display as 2011234 in the Saxon/2.0 case.
Is there a way to set the default picture string for whenever it outputs a number?
I saw decimal-format, but that just affects picture strings, it doesn't set number formatting. I can't just throw format-number everywhere since then I'd have to check datatypes everywhere and... it would be a mess.
There is no way to express in XSLT 2.0 (or XSLT 1.0) that every time a number value is output it must be in a "default" format, without ussing fn:format-number() or xsl:decimal-format or op:cast or built-in type constructors. The only way that every number will be consider of some specific type is that a schema has been declared for the input (so it's a PSVI) and you run the transformation with schema-awere processor.