1
votes

Im hoping someone may be able to assist me with transforming one xml file into another xml file. Im new XSLT; so have muddle through the other question/answers to get to a point where I'm almost able to complete the transformation....just need some final assistance.

I have an XML input document :

<copy>
  <paragraph>
    <name>Letter Text 1</name>
    <lastModDate>DD:MM:YY</lastModDate>
  </paragraph>
  <paragraph>
    <name>Letter Text 2</name>
    <lastModDate>DD:MM:YY</lastModDate>
  </paragraph>
  <paragraph>
    <name>Letter Text 3</name>
    <lastModDate>DD:MM:YY</lastModDate>
  </paragraph>
</copy>

What I am trying to do, is condense the tags per paragraph tag into attributes of the paragraph element. Desired output in another xml document to be :

<Paragraph name="Letter Text 1" lastModDate="DD:MM:YY" />
<Paragraph name="Letter Text 2" lastModDate="DD:MM:YY" />
<Paragraph name="Letter Text 3" lastModDate="DD:MM:YY" />

I have my XSL File :

<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
  <Paragraph>
    <xsl:for-each select="copy/paragraph">
      <xsl:attribute name="name">
        <xsl:value-of select="name"/>
      </xsl:attribute>
      <xsl:attribute name="lastModDate">
        <xsl:value-of select="lastModDate"/>
      </xsl:attribute>
    </xsl:for-each>
  </Paragraph>
</xsl:template>

Which gives me an output of this :

<Paragraph name="Letter Text 3" lastModDate="DD:MM:YY" />

Just the last child paragraph node; I've tried moving the tag inside of the for-each tags but throws errors, relating to empty document.

Can someone assist me in recommending the final pieces to my puzzle ?

3

3 Answers

0
votes

Place the <Paragraph> tags inside the xsl:for-eachinstruction. The way you have it now, you are creating a single Paragraph element, and you keep overwriting its attributes.

--
Note that your output is not well-formed XML, because it does not have a single root element.

0
votes

This XSLT 2.0 stylesheet ...

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">

<xsl:output indent="yes" encoding="utf-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />

<xsl:template match="/">
  <xsl:apply-templates select="copy/paragraph" />
</xsl:template>

<xsl:template match="paragraph">
  <Paragraph name="{name}" lastModDate="{lastModDate}" />
</xsl:template>

</xsl:stylesheet>

... will transform your sample input document into this XDM result tree ...

<Paragraph name="Letter Text 1" lastModDate="DD:MM:YY"/>
<Paragraph name="Letter Text 2" lastModDate="DD:MM:YY"/>
<Paragraph name="Letter Text 3" lastModDate="DD:MM:YY"/>

This result tree is not a well-formed XML document. However, it will be a well-formed external general parsed entity, and possibly that may suit your purposes. If does not, and you need your output to be a proper XML document, then instead use a root element wrapper like thus ...

<xsl:output indent="yes" encoding="utf-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />

<xsl:template match="/">
  <t>
    <xsl:apply-templates select="copy/paragraph" />
  </t>
</xsl:template>

<xsl:template match="paragraph">
  <Paragraph name="{name}" lastModDate="{lastModDate}" />
</xsl:template>

</xsl:stylesheet>

... which will give you result document ...

<t>
  <Paragraph name="Letter Text 1" lastModDate="DD:MM:YY"/>
  <Paragraph name="Letter Text 2" lastModDate="DD:MM:YY"/>
  <Paragraph name="Letter Text 3" lastModDate="DD:MM:YY"/>
</t>
0
votes

This will do the job. It has the advantage, that you don't need to know the names of the attributes. Hope it helps!

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes" omit-xml-declaration="no"  method="xml" ></xsl:output>
    <xsl:template match="/">
        <xsl:apply-templates select="//*/paragraph" />
    </xsl:template>

    <xsl:template match="paragraph" xml:space="default">
        <xsl:element name="Paragraph">
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>

    <xsl:template match="paragraph/*" xml:space="default">
        <xsl:attribute name="{name(.)}"><xsl:value-of select="."/></xsl:attribute>
    </xsl:template>
</xsl:stylesheet>