Reputation: 75
I have input XML-document like this or different:
<X3D version="3.2">
<Scene>
<Background skyColor="1 1 1"/>
<Viewpoint position="0 0 4"/>
<Transform DEF="body_0">
<Inline url="body_0.x3d"/>
<Transform DEF="body_1" translation="0,0.2,0">
<Inline url="body_1.x3d"/>
<Transform DEF="body_2" translation="0,0,0">
<Inline url="body_2.x3d"/>
<Transform DEF="body_3" translation="0,0,0">
<Inline url="body_3.x3d"/>
<Transform DEF="body_4" translation="0.5,0,0">
<Inline url="body_4.x3d"/>
<Transform DEF="body_5" translation="0,0,0">
<Inline url="body_5.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
<Transform DEF="body_6" translation="0,0,0">
<Inline url="body_6.x3d"/>
<Transform DEF="body_7" translation="0,0,0">
<Inline url="body_7.x3d"/>
<Transform DEF="body_8" translation="0.5,0,0">
<Inline url="body_8.x3d"/>
<Transform DEF="body_9" translation="0,0,0">
<Inline url="body_9.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Scene>
</X3D>
I need to wrap node with certain attribure DEF to one more node . For example, attribute calculates in variable $find. So I have xslt-stylesheet:
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="find" select="concat('body_','3')"/>
<xsl:for-each-group select="//Transform"
group-adjacent="@DEF = $find">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<Transform rotation="1 0 0 1.57">
<xsl:sequence select="current-group()"/>
</Transform>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
I hope to see output document whith next code:
<X3D version="3.2">
<Scene>
<Background skyColor="1 1 1"/>
<Viewpoint position="0 0 4"/>
<Transform DEF="body_0">
<Inline url="body_0.x3d"/>
<Transform DEF="body_1" translation="0,0.2,0">
<Inline url="body_1.x3d"/>
<Transform DEF="body_2" translation="0,0,0">
<Inline url="body_2.x3d"/>
<Transform rotation="1 0 0 1.57">
<Transform DEF="body_3" translation="0,0,0">
<Inline url="body_3.x3d"/>
<Transform DEF="body_4" translation="0.5,0,0">
<Inline url="body_4.x3d"/>
<Transform DEF="body_5" translation="0,0,0">
<Inline url="body_5.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
<Transform DEF="body_6" translation="0,0,0">
<Inline url="body_6.x3d"/>
<Transform DEF="body_7" translation="0,0,0">
<Inline url="body_7.x3d"/>
<Transform DEF="body_8" translation="0.5,0,0">
<Inline url="body_8.x3d"/>
<Transform DEF="body_9" translation="0,0,0">
<Inline url="body_9.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Scene>
</X3D>
but stylesheet has not any effect or there is too much nodes. I understand that a lot depends on the parameters that I specify in the select attribute, but I still have not been able to find the solution How can I rich it?
Next I try to give an examplse of use it. In the following code I use a list of strings that is formed in tamplate "getlistOfBodies"
<xsl:variable name="listOfBodies">
<xsl:call-template name="getlistOfBodies">
</xsl:call-template>
</xsl:variable>
<xsl:template match="*[Transform]">
<xsl:call-template name="wrap">
<xsl:with-param name="search" select="$listOfBodies" />
<!-- examples of $listOfBodies: "'body_2', 'body_5','body_6'" -->
</xsl:call-template>
</xsl:template>
<xsl:template name="wrap" >
<xsl:param name="search" select="0"/>
<xsl:copy>
<xsl:for-each-group select="* | @*" group-adjacent="@DEF = $search">
<!-- ... ->
So I want to see next output depending on the $search: (let $search = "'body_2','body_6'")
<?xml version="1.0" encoding="UTF-8"?>
<X3D version="3.2">
<Scene>
<Background skyColor="1 1 1"/>
<Viewpoint position="0 0 4"/>
<Transform DEF="body_0">
<Inline url="body_0.x3d"/>
<Transform DEF="body_1" translation="0,0.2,0">
<Inline url="body_1.x3d"/>
<Transform rotation="1 0 0 1.57">
<Transform DEF="body_2" translation="0,0,0">
<Inline url="body_2.x3d"/>
<Transform DEF="body_3" translation="0,0,0">
<Inline url="body_3.x3d"/>
<Transform DEF="body_4" translation="0.5,0,0">
<Inline url="body_4.x3d"/>
<Transform DEF="body_5" translation="0,0,0">
<Inline url="body_5.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
<Transform rotation="1 0 0 1.57">
<Transform DEF="body_6" translation="0,0,0">
<Inline url="body_6.x3d"/>
<Transform DEF="body_7" translation="0,0,0">
<Inline url="body_7.x3d"/>
<Transform DEF="body_8" translation="0.5,0,0">
<Inline url="body_8.x3d"/>
<Transform DEF="body_9" translation="0,0,0">
<Inline url="body_9.x3d"/>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Transform>
</Scene>
</X3D>
If $search = "'body_2','body_3'" then should be wrap two nodes (DEF='body_2', DEF='body_3') with two different Translates. If the number of strings in the variable is 6, then six nodes should be wrap with six Transforms. It's something like this...
Upvotes: 0
Views: 40
Reputation: 167506
If you use your grouping at the right level and handle the rest by the identity transformation (for instance in XSLT 3 with xsl:mode on-no-match="shallow-copy"
) then you get
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:param name="search" as="xs:string">body_3</xsl:param>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*[Transform/@DEF = $search]">
<xsl:copy>
<xsl:for-each-group select="*" group-adjacent="@DEF = $search">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<Transform rotation="1 0 0 1.57">
<xsl:apply-templates select="current-group()"/>
</Transform>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Based on your comments and edits it sounds as if you don't want to wrap adjacent elements at all but simply want to wrap certain elements into a new Transform
, as the following code does:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:param name="def-list" as="xs:string*" select="'body_2','body_3'"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Transform[@DEF = $def-list]">
<Transform rotation="1 0 0 1.57">
<xsl:next-match/>
</Transform>
</xsl:template>
</xsl:stylesheet>
So the parameter is now a sequence of strings (xs:string*
) and any Transform
element having a DEF
attribute equal to one of the values in the sequence is wrapped into a new Transform
element.
Online sample at https://xsltfiddle.liberty-development.net/gWcDMeu
Upvotes: 1