xml-model and xml-stylesheet

"Grosso, Paul" <pgrosso@ptc.com> writes:
> I'm not sure I appreciate all the considerations from
> reading the minutes, but if we are going to create anything
> even slightly beyond what we currently have in the document,
> I would really like it to talk about xml-stylesheet if feasible.

The xml-model and xml-stylesheet PIs only came into the conversation
near the end of the meeting. I think we've actually decided not to do
more, but rather to offer both we currently offer and *less*.

By the way, handling the xml-model and xml-stylesheet PIs is no simple
thing. Here's a pipeline that does it, to a first approximation. I'm
not finished yet.

<p:pipeline xmlns:p="http://www.w3.org/ns/xproc"
            xmlns:c="http://www.w3.org/ns/xproc-step"
            xmlns:cx="http://xmlcalabash.com/ns/extensions"
            xmlns:x="http://exproc.org/extension/steps"
            name="main" version="1.0">
  <!-- validation options -->
  <p:option name="assert-valid" select="'true'"/>
  <p:option name="schematypens"/>
  <p:option name="group"/>

  <!-- style options -->
  <p:option name="type" select="'text/xsl'"/>

  <p:pipeline type="x:pi-to-xml">
    <p:xslt>
      <p:input port="stylesheet">
        <p:inline>
          <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                          xmlns:c="http://www.w3.org/ns/xproc-step"
                          xmlns:f="http://docbook.org/xslt/ns/extension"
                          xmlns:xs="http://www.w3.org/2001/XMLSchema"
                          exclude-result-prefixes="f xs"
                          version="2.0">

            <xsl:template match="/">
              <document-pis>
                <xsl:for-each select="/processing-instruction()">
                  <xsl:element name="{node-name(.)}">
                    <xsl:call-template name="parse-pseudo-atts">
                      <xsl:with-param name="value" select="normalize-space(.)"/>
                    </xsl:call-template>
                  </xsl:element>
                </xsl:for-each>
              </document-pis>
            </xsl:template>

            <xsl:template name="parse-pseudo-atts" as="attribute()*">
              <xsl:param name="value" as="xs:string"/>

              <xsl:choose>
                <xsl:when test="$value = ''">
                  <xsl:sequence select="()"/>
                </xsl:when>
                <!-- N.B.: this matches only a small subset of legal attr names -->
                <xsl:when
                    test="matches($value, '^[A-Za-z0-9_][-A-Za-z_0-9]*=[&quot;'']')">
                  <xsl:variable name="n"
                                select="replace($value,'^(.*?)=.*','$1')"/>
                  <xsl:variable name="q"
                                select="replace($value,'^.*?=(.).*','$1')"/>

                  <xsl:variable name="vmatch"
                                select="concat('^.*?=',$q,'(.*?)',$q,'(.*)')"/>

                  <xsl:variable name="v"
                                select="replace($value,$vmatch,'$1')"/>

                  <xsl:variable name="rest"
                      select="normalize-space(replace($value, $vmatch, '$2'))"/>

                  <xsl:attribute name="{$n}" select="$v"/>

                  <xsl:call-template name="parse-pseudo-atts">
                    <xsl:with-param name="value" select="$rest"/>
                  </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                  <!-- Not a list of pseudo-attributes, bail. -->
                  <xsl:sequence select="()"/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:template>
          </xsl:stylesheet>
        </p:inline>
      </p:input>
    </p:xslt>
  </p:pipeline>

  <p:declare-step type="x:filter-sequence">
    <p:input port="source" sequence="true"/>
    <p:output port="result" sequence="true"/>
    <p:option name="select" required="true"/>
    <p:for-each>
      <p:filter>
        <p:with-option name="select" select="$select"/>
      </p:filter>
    </p:for-each>
  </p:declare-step>

  <p:declare-step type="x:validate" name="main">
    <p:input port="source" primary="true"/>
    <p:input port="schema"/>
    <p:output port="result"/>

    <p:option name="schematypens" required="true"/>
    <p:option name="assert-valid" select="'true'"/>
    <p:option name="phase" select="''"/>

    <p:choose>
      <p:when test="$schematypens = 'http://relaxng.org/ns/structure/1.0'">
        <p:validate-with-relax-ng>
          <p:input port="schema">
            <p:pipe step="main" port="schema"/>
          </p:input>
          <p:with-option name="assert-valid" select="$assert-valid"/>
        </p:validate-with-relax-ng>
      </p:when>

      <p:when test="$schematypens = 'http://www.w3.org/2001/XMLSchema'">
        <p:validate-with-xml-schema>
          <p:input port="schema">
            <p:pipe step="main" port="schema"/>
          </p:input>
          <p:with-option name="assert-valid" select="$assert-valid"/>
        </p:validate-with-xml-schema>
      </p:when>

      <p:when test="$schematypens = 'http://purl.oclc.org/dsdl/schematron'">
        <p:choose>
          <p:when test="string($phase) != ''">
            <p:validate-with-schematron>
              <p:input port="schema">
                <p:pipe step="main" port="schema"/>
              </p:input>
              <p:input port="parameters">
                <p:empty/>
              </p:input>
              <p:with-option name="assert-valid" select="$assert-valid"/>
              <p:with-option name="phase" select="$phase"/>
            </p:validate-with-schematron>
          </p:when>
          <p:otherwise>
            <p:validate-with-schematron>
              <p:input port="schema">
                <p:pipe step="main" port="schema"/>
              </p:input>
              <p:input port="parameters">
                <p:empty/>
              </p:input>
              <p:with-option name="assert-valid" select="$assert-valid"/>
            </p:validate-with-schematron>
          </p:otherwise>
        </p:choose>
      </p:when>

      <p:when test="$schematypens='http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0'">
        <!-- FIXME: use extension step -->
        <p:identity/>
      </p:when>

      <p:otherwise>
        <!-- FIXME: unrecognized type -->
        <p:identity/>
      </p:otherwise>
    </p:choose>
  </p:declare-step>

  <x:pi-to-xml name="get-pis"/>

  <p:identity>
    <p:input port="source" select="/document-pis/xml-model"/>
  </p:identity>

  <p:choose>
    <p:xpath-context>
      <p:empty/>
    </p:xpath-context>
    <p:when test="p:value-available('group')">
      <x:filter-sequence>
        <p:with-option name="select"
                       select="concat('/*[@group=&quot;',$group,'&quot;]')">
          <p:empty/>
        </p:with-option>
      </x:filter-sequence>
    </p:when>
    <p:otherwise>
      <p:identity>
        <p:input port="source" select="/*[not(@group)]"/>
      </p:identity>
    </p:otherwise>
  </p:choose>

  <p:choose>
    <p:xpath-context>
      <p:empty/>
    </p:xpath-context>
    <p:when test="p:value-available('schematypens')">
      <x:filter-sequence>
        <p:with-option name="select"
           select="concat('/*[@schematypens=&quot;',$schematypens,'&quot;]')">
          <p:empty/>
        </p:with-option>
      </x:filter-sequence>
    </p:when>
    <p:otherwise>
      <p:identity/>
    </p:otherwise>
  </p:choose>

  <p:split-sequence test="true()" initial-only="true" name="xml-model"/>

  <p:count name="xml-model-count"/>

  <p:choose>
    <p:xpath-context>
      <p:pipe step="xml-model" port="matched"/>
    </p:xpath-context>

    <p:when test="/c:result = '0'">
      <p:xpath-context>
        <p:pipe step="xml-model-count" port="result"/>
      </p:xpath-context>
      <p:identity>
        <p:input port="source">
          <p:pipe step="main" port="source"/>
        </p:input>
      </p:identity>
    </p:when>

    <p:when test="/*/@type = 'application/xml-dtd'">
      <!-- I'm not prepared to deal with an alternate DTD, -->
      <!-- but I'll do a validating parse for you... -->
      <p:load dtd-validate="true">
        <p:with-option name="href" select="base-uri(/)">
          <p:pipe step="main" port="source"/>
        </p:with-option>
      </p:load>
    </p:when>

    <p:when test="/*/@type = 'application/relax-ng-compact-syntax'">
      <!-- FIXME: -->
      <p:identity>
        <p:input port="source">
          <p:pipe step="main" port="source"/>
        </p:input>
      </p:identity>
    </p:when>

    <p:otherwise>
      <p:variable name="pistns"
                  select="/*/@schematypens">
        <p:pipe step="xml-model" port="matched"/>
      </p:variable>

      <p:load name="load-schema">
        <p:with-option name="href" select="/*/@href">
          <p:pipe step="xml-model" port="matched"/>
        </p:with-option>
      </p:load>

      <x:validate>
        <p:input port="source">
          <p:pipe step="main" port="source"/>
        </p:input>
        <p:input port="schema">
          <p:pipe step="load-schema" port="result"/>
        </p:input>
        <p:with-option name="schematypens"
                       select="if ($pistns != '') then $pistns
                               else namespace-uri(/*)">
          <p:pipe step="load-schema" port="result"/>
        </p:with-option>
      </x:validate>
    </p:otherwise>
  </p:choose>

  <p:identity name="validated"/>

  <p:identity>
    <p:input port="source" select="/document-pis/xml-stylesheet">
      <p:pipe step="get-pis" port="result"/>
    </p:input>
  </p:identity>

  <x:filter-sequence>
    <p:with-option name="select"
                   select="concat('/*[@type=&quot;',$type,'&quot;]')">
      <p:empty/>
    </p:with-option>
  </x:filter-sequence>

  <p:split-sequence test="true()" initial-only="true" name="xml-stylesheet"/>

  <p:count name="xml-stylesheet-count"/>

  <p:choose name="styled">
    <p:xpath-context>
      <p:pipe step="xml-stylesheet" port="matched"/>
    </p:xpath-context>

    <p:when test="/c:result = '0'">
      <p:xpath-context>
        <p:pipe step="xml-stylesheet-count" port="result"/>
      </p:xpath-context>
      <p:identity>
        <p:input port="source">
          <p:pipe step="validated" port="result"/>
        </p:input>
      </p:identity>
    </p:when>

    <p:otherwise>
      <p:load name="load-style">
        <p:with-option name="href" select="/*/@href">
          <p:pipe step="xml-stylesheet" port="matched"/>
        </p:with-option>
      </p:load>

      <p:xslt>
        <p:input port="source">
          <p:pipe step="validated" port="result"/>
        </p:input>
        <p:input port="stylesheet">
          <p:pipe step="load-style" port="result"/>
        </p:input>
      </p:xslt>
    </p:otherwise>
  </p:choose>

</p:pipeline>

                                        Be seeing you,
                                          norm

-- 
Norman Walsh <ndw@nwalsh.com> | Art happens--no hovel is safe from it,
http://nwalsh.com/            | no prince may depend upon it, and
                              | vastest intelligence cannot bring it
                              | about.--J. M. Whistler

Received on Friday, 9 April 2010 15:18:33 UTC