XSLT related tags by attribute on the same output string

Attempted to do this conversion but couldn't find an answer online and in the documentation (newbe here)

Just trying to do something like this:

<Info>
        <Type p="1">MyType1</Type>
        <Type p="2">MyType2</Type>
        <Type p="3">MyType3</Type>
        <Values>
            <r p="1">MyValue1</r>
            <r p="2">MyValue2</r>
            <r p="3">MyValue3</r>
        </Values>
</Info>

      

Appears as a plain text transformation as follows:

MyType1;MyValue1
MyType2;MyValue3
MyType3;MyValue3

      

Being two output fields connected by the "p" attribute, is this possible?

+3


source to share


4 answers


Here's a pretty simple approach

<xsl:template match="/">

  <xsl:variable name="newline">
    <xsl:text>&#xa;</xsl:text>
  </xsl:variable>

  <xsl:for-each select="/Info/Type" >
    <xsl:variable name="p" select="@p" />
    <xsl:value-of select="." />
    <xsl:text>;</xsl:text>
    <xsl:value-of select=" /Info/Values/r[@p=$p] " />
    <xsl:if test=" position() != last() ">
      <xsl:value-of select="$newline" />
    </xsl:if>
  </xsl:for-each>
</xsl:template>

      



This will only select the first matching / r node values ​​for each of the type nodes. Thus, it is assumed that any other Values ​​/ r nodes with the same @p should be ignored.

+1


source


XSLT has a built-in cross-referencing engine ; it would be better to use it:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />

<xsl:key name="value" match="r" use="@p" />

<xsl:template match="/Info">
    <xsl:for-each select="Type">
        <xsl:value-of select="."/>
            <xsl:text>;</xsl:text>
            <xsl:for-each select="key('value', @p)">
                <xsl:value-of select="."/>
                <xsl:if test="position()!= last()">
                    <xsl:text>;</xsl:text>
                </xsl:if>
            </xsl:for-each>     
        <xsl:if test="position()!= last()">
            <xsl:text>&#10;</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

      



It is assumed that:

  • Each record is Type

    unique;
  • There can be more than one value in the same type; for example the following input:

    <Info>
    <Type p="1">MyType1</Type>
    <Type p="2">MyType2</Type>
    <Type p="3">MyType3</Type>
    <Values>
        <r p="1">MyValue1</r>
        <r p="2">MyValue2a</r>
        <r p="2">MyValue2b</r>
        <r p="3">MyValue3</r>
    </Values>
    
          

    will return:

    MyType1;MyValue1
    MyType2;MyValue2a;MyValue2b
    MyType3;MyValue3
    
          

+4


source


One possible solution is to use a pattern that matches Type

the print value Type

, followed by the value of the corresponding element, r

and an empty pattern that matches Values

, to avoid printing Values

twice like this:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
 <xsl:strip-space elements="*"/>
 <xsl:template match="Type">
 <xsl:variable name="current" select="@p"/>
   <xsl:value-of select="."/>
   <xsl:value-of select="concat(';',//Values/r[@p=$current])"/>
   <xsl:if test="position() != last()">
     <xsl:text>&#xa;</xsl:text>
   </xsl:if>
 </xsl:template>
 <xsl:template match="Values"/>
</xsl:transform>

      

The following output is generated for your input:

MyType1;MyValue1
MyType2;MyValue2
MyType3;MyValue3

      

+1


source


Use this simple and short XSLT 1.0 solution :

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kRByP" match="r" use="@p"/>

 <xsl:template match="Type/text()">
  <xsl:value-of select="concat(.,';',key('kRByP', ../@p), '&#xA;')"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

      

When this transformation is applied to the provided original XML document :

<Info>
    <Type p="1">MyType1</Type>
    <Type p="2">MyType2</Type>
    <Type p="3">MyType3</Type>
    <Values>
        <r p="1">MyValue1</r>
        <r p="2">MyValue2</r>
        <r p="3">MyValue3</r>
    </Values>
</Info>

      

required, the correct result is obtained :

MyType1;MyValue1
MyType2;MyValue2
MyType3;MyValue3

      

Explanation

  • Key usage, pattern matching, and how the XSLT processing model works. Only the required text nodes are selected, the rest are ignored ("deleted").
  • The value of an attribute p

    is expected to uniquely identify the element r

    or Type

    to which the attribute belongs.
+1


source







All Articles