xslt - How can I copy an XML structure into another one except some attributes or nodes -
with xml structure below:
<root foo1="bar1" foo2="bar2" foo3="bar3"> <foo1 foo1="bar1" /> <data> <foo1>bar1</foo1> <foo2>bar2</foo2> <foo3>bar3</foo3> </data> </root>
i copy xml structure 1 exception on attributes and/or node() names , following result using xslt 1.0:
<root foo1="bar1" foo2="bar2"> <data> <foo1>bar1</foo1> <foo3>bar3</foo3> </data> </root>
my rules are:
1) copy every root attributes except foo3
2) copy every child nodes()
unless ones named foo1 , foo2
my actual xsl stylesheet. managed root attributes restriction working :
<xsl:template match="root"> <root> <xsl:for-each select="./@*"> <xsl:variable name="name" select="name()" /> <xsl:if test="name() != 'foo3'"> <xsl:attribute name="{$name}"><xsl:value-of select="." /></xsl:attribute> </xsl:if> </xsl:for-each> </root> </xsl:template>
also, 1 harder question: if want matches attributes , nodes dynamically. specify server-side attributes , nodes()
remove. it's generating string used in <xsl:if>
. don't know if that's possible.
thank you.
i copy xml structure 1 exception [...]
my rules are:
1) copy every root attributes except foo3
2) copy every child nodes() unless ones named foo1 , foo2
update comments:
hi, work. except data/foo1 should copied
this stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="root/@foo3|root/foo1|foo2"/> </xsl:stylesheet>
output:
<root foo1="bar1" foo2="bar2"> <data> <foo1>bar1</foo1> <foo3>bar3</foo3> </data> </root>
note: overwriting identity rule empty templates
with node names in parameter, stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:param name="pstrip" select="'root/@foo3|root/foo1|foo2'"/> <xsl:template match="node()|@*" name="identity"> <xsl:param name="pstrippaths" select="concat($pstrip,'|')"/> <xsl:param name="pnodepath"> <xsl:call-template name="path"/> <xsl:text>|</xsl:text> </xsl:param> <xsl:variable name="vstrippath" select="substring-before($pstrippaths,'|')"/> <xsl:choose> <xsl:when test="not($pstrippaths)"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:when> <xsl:when test="contains($pnodepath,concat('/',$vstrippath,'|'))"/> <xsl:otherwise> <xsl:call-template name="identity"> <xsl:with-param name="pstrippaths" select="substring-after($pstrippaths,'|')"/> <xsl:with-param name="pnodepath" select="$pnodepath"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="node()" name="path" mode="path"> <xsl:apply-templates select="parent::*" mode="path"/> <xsl:value-of select="concat('/', substring('@', 1 div (count(.|../@*) = count(../@*))), name())"/> </xsl:template> </xsl:stylesheet>
output:
<root foo1="bar1" foo2="bar2"> <data> <foo1>bar1</foo1> <foo3>bar3</foo3> </data> </root>
note: in xml, element name refers schema, defining hierarchie position, yours not case.
edit: fun, xslt 2.0 solution:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:xs="http://www.w3.org/2001/xmlschema" xmlns:local="http://localhost"> <xsl:param name="pstrip" select="'root/@foo3|root/foo1|foo2'"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*[local:match($pstrip,.)]|@*[local:match($pstrip,.)]"/> <xsl:function name="local:match" as="xs:boolean"> <xsl:param name="pstrippaths" as="xs:string"/> <xsl:param name="pnode" as="item()"/> <xsl:variable name="vnodepath" select="string-join(($pnode /ancestor::node() /name(), if ($pnode instance of attribute()) concat('@',name($pnode)) else name($pnode)), '/')"/> <xsl:sequence select="some $path in tokenize($pstrippaths,'\|') satisfies ends-with($vnodepath, concat('/',$path))"/> </xsl:function> </xsl:stylesheet>
edit 2: stylesheet following same string pattern.
Comments
Post a Comment