grenade
grenade

Reputation: 32179

transform and combine multiple xml documents

I have a requirement to host a NuGet repository under Apache on Linux. The design is fairly constrained and requires that the Packages feed be stored as a static file. An example of the required output format is here: http://chocolatey.org/api/v2/Packages.

I am attempting to generate this document from the *.nuspec files found inside the *.nupkg archives like so:

#!/bin/bash

#for pkg in nxlog git.install; do
#  curl -L http://chocolatey.org/api/v2/package/$pkg -o $pkg.nupkg
#done

unzip "*.nupkg" "*.nuspec"
xsltproc transform.xsl *.nuspec > Packages
rm -f *.nuspec

So far, the incorrect transform xslt looks like this:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes" />
  <feed xml:base="http://gallery-host/api/v2/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
    <title type="text">Packages</title>
    <id>http://gallery-host/api/v2/Packages</id>
    <updated></updated>
    <link rel="self" title="Packages" href="Packages" />
    <xsl:apply-templates />
  </feed>
  <xsl:template match="metadata">
    <entry>
      <id><xsl:value-of select="id"/></id>
      <title type="text"><xsl:value-of select="title"/></title>
      <summary type="text"><xsl:value-of select="summary"/></summary>
      <updated></updated>
      <author>
        <name><xsl:value-of select="authors"/></name>
      </author>
      <link rel="edit-media" title="V2FeedPackage">
        <xsl:attribute name="href">Packages(Id='<xsl:value-of select="id"/>',Version='<xsl:value-of select="version"/>')/$value</xsl:attribute>
      </link>
      <link rel="edit" title="V2FeedPackage">
        <xsl:attribute name="href">Packages(Id='<xsl:value-of select="id"/>',Version='<xsl:value-of select="version"/>')</xsl:attribute>
      </link>
      <category term="NuGetGallery.V2FeedPackage" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
      <content type="application/zip">
        <xsl:attribute name="src">http://chocolatey.org/api/v2/package/<xsl:value-of select="id"/>/<xsl:value-of select="version"/></xsl:attribute>
      </content>
      <m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
        <d:Version><xsl:value-of select="version"/></d:Version>
        <d:Copyright><xsl:value-of select="copyright"/></d:Copyright>
        <!--
        <d:Created m:type="Edm.DateTime"></d:Created>
        <d:Dependencies></d:Dependencies>
        -->
        <d:Description><xsl:value-of select="description"/></d:Description>
        <!--
        <d:DownloadCount m:type="Edm.Int32"></d:DownloadCount>
        -->
        <d:GalleryDetailsUrl>http://gallery-host/packages/<xsl:value-of select="id"/>/<xsl:value-of select="version"/></d:GalleryDetailsUrl>
        <d:IconUrl><xsl:value-of select="iconUrl"/></d:IconUrl>
        <!--
        <d:IsLatestVersion m:type="Edm.Boolean"></d:IsLatestVersion>
        <d:IsAbsoluteLatestVersion m:type="Edm.Boolean"></d:IsAbsoluteLatestVersion>
        <d:IsPrerelease m:type="Edm.Boolean"></d:IsPrerelease>
        <d:Language m:null="true"></d:Language>
        <d:Published m:type="Edm.DateTime"></d:Published>
        -->
        <d:LicenseUrl><xsl:value-of select="licenseUrl"/></d:LicenseUrl>
        <!--
        <d:PackageHash></d:PackageHash>
        <d:PackageHashAlgorithm></d:PackageHashAlgorithm>
        <d:PackageSize m:type="Edm.Int64"></d:PackageSize>
        -->
        <d:ProjectUrl><xsl:value-of select="projectUrl"/></d:ProjectUrl>
        <!--
        <d:ProjectSourceUrl m:null="true"></d:ProjectSourceUrl>
        <d:PackageSourceUrl m:null="true"></d:PackageSourceUrl>
        <d:DocsUrl m:null="true"></d:DocsUrl>
        <d:MailingListUrl m:null="true"></d:MailingListUrl>
        <d:BugTrackerUrl m:null="true"></d:BugTrackerUrl>
        -->
        <d:ReportAbuseUrl>http://gallery-host/package/ReportAbuse/<xsl:value-of select="id"/>/<xsl:value-of select="version"/></d:ReportAbuseUrl>
        <d:ReleaseNotes><xsl:value-of select="releaseNotes"/></d:ReleaseNotes>
        <!--
        <d:PackageStatus></d:PackageStatus>
        <d:PackageSubmittedStatus m:null="true"></d:PackageSubmittedStatus>
        <d:RequireLicenseAcceptance m:type="Edm.Boolean"></d:RequireLicenseAcceptance>
        -->
        <d:Tags xml:space="preserve"><xsl:value-of select="tags"/></d:Tags>
        <d:Title><xsl:value-of select="title"/></d:Title>
        <!--
        <d:VersionDownloadCount m:type="Edm.Int32"></d:VersionDownloadCount>
        -->
      </m:properties>
    </entry>
  </xsl:template>
</xsl:stylesheet>

This results in the output file containing no xml tags (the content is correctly included).

How can I correct my transform.xsl to produce a single root <feed> element, with multiple child <entry> elements (so that my output is formatted like http://chocolatey.org/api/v2/Packages)?

UPDATE

Thanks to the pointer from @Martin Honnen, and another from @Frédéric Hamidi (why is it always namespaces that kick you in the nethers, working with xml?), I got a little further with the transform:

<?xml version="1.0" ?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
  <xsl:template match="/">
    <feed>
      <xsl:for-each select="p:package/p:metadata" xmlns:p="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
        <xsl:element name="entry">
          <xsl:element name="id"><xsl:value-of select="p:id"/></xsl:element>
          <xsl:element name="title">
            <xsl:attribute name="type">text</xsl:attribute>
            <xsl:value-of select="p:title"/>
          </xsl:element>
          <xsl:element name="summary">
            <xsl:attribute name="type">text</xsl:attribute>
            <xsl:value-of select="p:summary"/></xsl:element>
          <xsl:element name="author">
            <xsl:element name="name"><xsl:value-of select="p:authors"/></xsl:element>
          </xsl:element>
          <xsl:element name="link">
            <xsl:attribute name="rel">edit-media</xsl:attribute>
            <xsl:attribute name="title">V2FeedPackage</xsl:attribute>
            <xsl:attribute name="href">Packages(Id='<xsl:value-of select="p:id"/>',Version='<xsl:value-of select="p:version"/>')/$value</xsl:attribute>
          </xsl:element>
          <xsl:element name="link">
            <xsl:attribute name="rel">edit</xsl:attribute>
            <xsl:attribute name="title">V2FeedPackage</xsl:attribute>
            <xsl:attribute name="href">Packages(Id='<xsl:value-of select="p:id"/>',Version='<xsl:value-of select="p:version"/>')</xsl:attribute>
          </xsl:element>
          <xsl:element name="category">
            <xsl:attribute name="term">NuGetGallery.V2FeedPackage</xsl:attribute>
            <xsl:attribute name="scheme">http://schemas.microsoft.com/ado/2007/08/dataservices/scheme</xsl:attribute>
          </xsl:element>
          <xsl:element name="content">
            <xsl:attribute name="type">application/zip</xsl:attribute>
            <xsl:attribute name="src">http://chocolatey.org/api/v2/package/<xsl:value-of select="p:id"/>/<xsl:value-of select="p:version"/></xsl:attribute>
          </xsl:element>
        </xsl:element>
        <m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
          <d:Version><xsl:value-of select="p:version"/></d:Version>
          <d:Copyright><xsl:value-of select="p:copyright"/></d:Copyright>
          <!--
          <d:Created m:type="Edm.DateTime"></d:Created>
          <d:Dependencies></d:Dependencies>
          -->
          <d:Description><xsl:value-of select="p:description"/></d:Description>
          <!--
          <d:DownloadCount m:type="Edm.Int32"></d:DownloadCount>
          -->
          <d:GalleryDetailsUrl>http://gallery-host/packages/<xsl:value-of select="p:id"/>/<xsl:value-of select="p:version"/></d:GalleryDetailsUrl>
          <d:IconUrl><xsl:value-of select="p:iconUrl"/></d:IconUrl>
          <!--
          <d:IsLatestVersion m:type="Edm.Boolean"></d:IsLatestVersion>
          <d:IsAbsoluteLatestVersion m:type="Edm.Boolean"></d:IsAbsoluteLatestVersion>
          <d:IsPrerelease m:type="Edm.Boolean"></d:IsPrerelease>
          <d:Language m:null="true"></d:Language>
          <d:Published m:type="Edm.DateTime"></d:Published>
          -->
          <d:LicenseUrl><xsl:value-of select="p:licenseUrl"/></d:LicenseUrl>
          <!--
          <d:PackageHash></d:PackageHash>
          <d:PackageHashAlgorithm></d:PackageHashAlgorithm>
          <d:PackageSize m:type="Edm.Int64"></d:PackageSize>
          -->
          <d:ProjectUrl><xsl:value-of select="p:projectUrl"/></d:ProjectUrl>
          <!--
          <d:ProjectSourceUrl m:null="true"></d:ProjectSourceUrl>
          <d:PackageSourceUrl m:null="true"></d:PackageSourceUrl>
          <d:DocsUrl m:null="true"></d:DocsUrl>
          <d:MailingListUrl m:null="true"></d:MailingListUrl>
          <d:BugTrackerUrl m:null="true"></d:BugTrackerUrl>
          -->
          <d:ReportAbuseUrl>http://gallery-host/package/ReportAbuse/<xsl:value-of select="p:id"/>/<xsl:value-of select="p:version"/></d:ReportAbuseUrl>
          <d:ReleaseNotes><xsl:value-of select="p:releaseNotes"/></d:ReleaseNotes>
          <!--
          <d:PackageStatus></d:PackageStatus>
          <d:PackageSubmittedStatus m:null="true"></d:PackageSubmittedStatus>
          <d:RequireLicenseAcceptance m:type="Edm.Boolean"></d:RequireLicenseAcceptance>
          -->
          <d:Tags xml:space="preserve"><xsl:value-of select="p:tags"/></d:Tags>
          <d:Title><xsl:value-of select="p:title"/></d:Title>
          <!--
          <d:VersionDownloadCount m:type="Edm.Int32"></d:VersionDownloadCount>
          -->
        </m:properties>
      </xsl:for-each>
      <xsl:for-each select="p:package/p:metadata" xmlns:p="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
        <xsl:element name="entry">
          <xsl:element name="id"><xsl:value-of select="p:id"/></xsl:element>
          <xsl:element name="title">
            <xsl:attribute name="type">text</xsl:attribute>
            <xsl:value-of select="p:title"/>
          </xsl:element>
          <xsl:element name="summary">
            <xsl:attribute name="type">text</xsl:attribute>
            <xsl:value-of select="p:summary"/></xsl:element>
          <xsl:element name="author">
            <xsl:element name="name"><xsl:value-of select="p:authors"/></xsl:element>
          </xsl:element>
          <xsl:element name="link">
            <xsl:attribute name="rel">edit-media</xsl:attribute>
            <xsl:attribute name="title">V2FeedPackage</xsl:attribute>
            <xsl:attribute name="href">Packages(Id='<xsl:value-of select="p:id"/>',Version='<xsl:value-of select="p:version"/>')/$value</xsl:attribute>
          </xsl:element>
          <xsl:element name="link">
            <xsl:attribute name="rel">edit</xsl:attribute>
            <xsl:attribute name="title">V2FeedPackage</xsl:attribute>
            <xsl:attribute name="href">Packages(Id='<xsl:value-of select="p:id"/>',Version='<xsl:value-of select="p:version"/>')</xsl:attribute>
          </xsl:element>
          <xsl:element name="category">
            <xsl:attribute name="term">NuGetGallery.V2FeedPackage</xsl:attribute>
            <xsl:attribute name="scheme">http://schemas.microsoft.com/ado/2007/08/dataservices/scheme</xsl:attribute>
          </xsl:element>
          <xsl:element name="content">
            <xsl:attribute name="type">application/zip</xsl:attribute>
            <xsl:attribute name="src">http://chocolatey.org/api/v2/package/<xsl:value-of select="p:id"/>/<xsl:value-of select="p:version"/></xsl:attribute>
          </xsl:element>
        </xsl:element>
        <m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
          <d:Version><xsl:value-of select="p:version"/></d:Version>
          <d:Copyright><xsl:value-of select="p:copyright"/></d:Copyright>
          <!--
          <d:Created m:type="Edm.DateTime"></d:Created>
          <d:Dependencies></d:Dependencies>
          -->
          <d:Description><xsl:value-of select="p:description"/></d:Description>
          <!--
          <d:DownloadCount m:type="Edm.Int32"></d:DownloadCount>
          -->
          <d:GalleryDetailsUrl>http://gallery-host/packages/<xsl:value-of select="p:id"/>/<xsl:value-of select="p:version"/></d:GalleryDetailsUrl>
          <d:IconUrl><xsl:value-of select="p:iconUrl"/></d:IconUrl>
          <!--
          <d:IsLatestVersion m:type="Edm.Boolean"></d:IsLatestVersion>
          <d:IsAbsoluteLatestVersion m:type="Edm.Boolean"></d:IsAbsoluteLatestVersion>
          <d:IsPrerelease m:type="Edm.Boolean"></d:IsPrerelease>
          <d:Language m:null="true"></d:Language>
          <d:Published m:type="Edm.DateTime"></d:Published>
          -->
          <d:LicenseUrl><xsl:value-of select="p:licenseUrl"/></d:LicenseUrl>
          <!--
          <d:PackageHash></d:PackageHash>
          <d:PackageHashAlgorithm></d:PackageHashAlgorithm>
          <d:PackageSize m:type="Edm.Int64"></d:PackageSize>
          -->
          <d:ProjectUrl><xsl:value-of select="p:projectUrl"/></d:ProjectUrl>
          <!--
          <d:ProjectSourceUrl m:null="true"></d:ProjectSourceUrl>
          <d:PackageSourceUrl m:null="true"></d:PackageSourceUrl>
          <d:DocsUrl m:null="true"></d:DocsUrl>
          <d:MailingListUrl m:null="true"></d:MailingListUrl>
          <d:BugTrackerUrl m:null="true"></d:BugTrackerUrl>
          -->
          <d:ReportAbuseUrl>http://gallery-host/package/ReportAbuse/<xsl:value-of select="p:id"/>/<xsl:value-of select="p:version"/></d:ReportAbuseUrl>
          <d:ReleaseNotes><xsl:value-of select="p:releaseNotes"/></d:ReleaseNotes>
          <!--
          <d:PackageStatus></d:PackageStatus>
          <d:PackageSubmittedStatus m:null="true"></d:PackageSubmittedStatus>
          <d:RequireLicenseAcceptance m:type="Edm.Boolean"></d:RequireLicenseAcceptance>
          -->
          <d:Tags xml:space="preserve"><xsl:value-of select="p:tags"/></d:Tags>
          <d:Title><xsl:value-of select="p:title"/></d:Title>
          <!--
          <d:VersionDownloadCount m:type="Edm.Int32"></d:VersionDownloadCount>
          -->
        </m:properties>
      </xsl:for-each>
    </feed>
  </xsl:template>
</xsl:stylesheet>

The output still contains too many feed elements, which I think is due to the way xsltproc handles wildcards/multiple input files (it's running a separate transform for each file, which is actually rather logical). If I could get rid of those, and find a nicer way of handling multiple input namespaces (rather than duplicating the transform code for each namespace), I'd be a happy bunny.

Upvotes: 0

Views: 133

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167516

I think you want to replace

  <feed xml:base="http://gallery-host/api/v2/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
    <title type="text">Packages</title>
    <id>http://gallery-host/api/v2/Packages</id>
    <updated></updated>
    <link rel="self" title="Packages" href="Packages" />
    <xsl:apply-templates />
  </feed>

with

<xsl:template match="/">
  <feed xml:base="http://gallery-host/api/v2/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
    <title type="text">Packages</title>
    <id>http://gallery-host/api/v2/Packages</id>
    <updated></updated>
    <link rel="self" title="Packages" href="Packages" />
    <xsl:apply-templates />
  </feed>
</xsl:template>

But you also need to move all the namespace declarations to the xsl:stylesheet, i.g.

<xsl:stylesheet xml:base="http://gallery-host/api/v2/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">...</xsl:stylesheet>

Upvotes: 1

Related Questions