2

I need to concatenate values of XML based on this following:

Here is my XML:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Parent>
    <Name>Father 1</Name>
    <Child>
      <Name>F1 - Child 1</Name>
      <Age>2</Age>
    </Child>
    <Child>
      <Name>F1- Child 2</Name>
      <Age>4</Age>
    </Child>
  </Parent>
  <Parent>
    <Name>Father 2</Name>
    <Child>
      <Name>F2 - Child 1</Name>
      <Age>2</Age>
    </Child>
    <Child>
      <Name>F2 - Child 2</Name>
      <Age>4</Age>
    </Child>
  </Parent>
</Root>

And here is my XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match ="Root">
    <xsl:apply-templates select ="Parent/Name" />
    <xsl:apply-templates select ="Parent/Child" />

  </xsl:template>

  <xsl:template match ="Parent/Name">
    <FatherName>
      <xsl:value-of select ="."/>
    </FatherName>
  </xsl:template>

  <xsl:template match ="Parent/Child">
    <ChildNames>
      <xsl:for-each select="Name">
        <xsl:value-of select="." />
        <xsl:if test="position()!=last()">
          <xsl:text>, </xsl:text>
        </xsl:if>
      </xsl:for-each>
    </ChildNames>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Which results to this

<?xml version="1.0" encoding="utf-8"?>
<FatherName>Father 1</FatherName>
<FatherName>Father 2</FatherName>
<ChildNames>F1 - Child 1</ChildNames>
<ChildNames>F1- Child 2</ChildNames>
<ChildNames>F2 - Child 1</ChildNames>
<ChildNames>F2 - Child 2</ChildNames>

But the result I need is something like this:

<FatherName>Father 1</FatherName>
<ChildNames>F1 - Child 1, F1- Child 2</ChildNames>
<FatherName>Father 2</FatherName>
<ChildNames>F2 - Child 1, F2 - Child 2</ChildNames>

Can anyone help me to get the result I need?

2 Answers 2

3

Essentially, what you need to do is move the line <xsl:apply-templates select ="Parent/Child" /> out of the current template, and into the template that matches Parent/Name. Something like this:

<xsl:template match="Parent/Name">
  <FatherName>
    <xsl:value-of select ="."/>
  </FatherName>
  <ChildNames>
      <xsl:apply-templates select ="../Child" />
  </ChildNames>
</xsl:template>

The .. here is to go back up to the Parent node so you can then select the child nodes. Note, you also don't need the xsl:for-each in the template matching child.

Actually, it might be easier to match on the Parent node than the Parent/name node.

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="Root">
    <xsl:apply-templates select="Parent" />
  </xsl:template>

  <xsl:template match="Parent">
    <FatherName>
      <xsl:value-of select ="Name"/>
    </FatherName>
    <ChildNames>
       <xsl:apply-templates select ="Child" />
    </ChildNames>
  </xsl:template>

  <xsl:template match="Child">
      <xsl:if test="position()!=1">
        <xsl:text>, </xsl:text>
      </xsl:if>
      <xsl:value-of select="Name" />
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

Comments

0

came up with this

  <xsl:template match="/">
    <good>
      <xsl:for-each select="Root/Parent">
        <FatherName>
          <xsl:value-of select="Name"/>
        </FatherName>
        <xsl:variable name="childCount" select="count(.//Child)"/>
        <ChildNames>
          <xsl:variable name="data">
            <xsl:for-each select=".//Child">
              <xsl:value-of select="Name"/>
              <xsl:if test="not(position()=$childCount)">
                <xsl:text>, </xsl:text>
              </xsl:if>
            </xsl:for-each>
          </xsl:variable>
          <xsl:value-of select="$data"/>
        </ChildNames>
      </xsl:for-each>
    </good>
  </xsl:template>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.