Topic Specialization: XSD Version

The process for creating an XSD version of the FAQ question topic type is as follows (assuming you have already created the final DTD version of the faq-question topic type):
  1. Create the directory faq-question/xsd in your working area.
  2. Copy the files concept.xsd, conceptGrp.xsd, and conceptMod.xsd from the base DITA schema set to the faq-question/xsd directory.
  3. Rename the files from "concept*" to "faq-question*," resulting in faq-question.xsd, faq-questionGrp.xsd, and faq-questionMod.xsd.
  4. Copy the catalog.xml file from the dtd directory into the xsd directory.
  5. Edit xsd/catalog.xml and change it as follows:
    1. Change ".dtd" to ".xsd"
    2. Change ".mod" to "Mod.xsd"
    3. Change ".ent" to "Grp.xsd"
    4. In the public identifiers, append the corresponding last part of the filename to the end of the URN, e.g. "urn:pubid:example.org:doctypes:dita:modules:faq-question" becomes "urn:pubid:example.org:doctypes:dita:modules:faq-questionMod.xsd"
    5. Copy all the <public> elements and change "public" to "uri" and the "publicId" attributes to "name."

      This is necessary because the Apache Xerces parser incorrectly uses public ID resolution to resolve XSD schema locations. It should use URI entries (because schema locations are URIs and not entity references, they should be resolved through URI entries in catalogs). Other systems that use the catalog will likely do the correct thing and use URI entries to resolve schema locations. So you need both forms of entry.

      If you want to cover all bases you can make yet another copy of the entries and change <public> to <system> and "publicId" to "systemId." That covers the case where a processor treats a schema location as a system ID rather than a URI. That would also be wrong but some systems may do it.

  6. Edit the faq-question/catalog.xml file, copy the <nextCatalog> element and change "dtd" to "xsd" in the new copy, resulting in this catalog file:
    <?xml version="1.0" encoding="UTF-8"?>
    <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="public">
      
      <nextCatalog catalog="dtd/catalog.xml"/>
      <nextCatalog catalog="xsd/catalog.xml"/>
      
    </catalog>
  7. Copy one of the faq-question test documents to test the XSD document type shell. Modify it as follows:
    1. Delete the DOCTYPE declaration from the top of the file.
    2. Add the following attributes to the <faq-question> element:
      <?xml version="1.0"?>          
      <faq-question 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="xsd/faq-question.xsd"
        id="question-id">
       
        ...
      
      </faq-question>
      

      Where the value of the @xsi:noNamespaceSchemaLocation reflects the appropriate relative URL to the faq-question.xsd file.

      The document should not be valid at this point because the faq-question.xsd file is just an unmodified copy of the concept XSD shell.

  8. Edit faq-question.xsd and modify it as follows:
    1. Replace the header comment with something that reflects your ownership.
    2. Remove the domain module inclusions for all but the highlight and utility domains, leaving just these declarations:
        <!--  ================ TOPIC DOMAINS INLCUSION =====================  -->
        <xs:include schemaLocation="urn:oasis:names:tc:dita:xsd:highlightDomain.xsd:1.2"/>
        <xs:include schemaLocation="urn:oasis:names:tc:dita:xsd:utilitiesDomain.xsd:1.2"/>
      
        <!--  ================ CONCEPT GROUP DEFINITION=====================  -->
      
    3. After the "CONCEPT GROUP DEFINITION" comment, add a reference to the faq-questionGrp.xsd file:
        <!--  ================ CONCEPT GROUP DEFINITION=====================  -->
        <xs:include schemaLocation="faq-questionGrp.xsd"/>
        <xs:include schemaLocation="urn:oasis:names:tc:dita:xsd:conceptGrp.xsd:1.2"/>
      
    4. From the <xs:redefine> element, delete all the groups except the groups for "ph" and "fig":
        <xs:redefine schemaLocation="urn:oasis:names:tc:dita:xsd:commonElementGrp.xsd:1.2">
      
          <xs:group name="ph">
            <xs:choice>
              <xs:group ref="ph"/>
              <xs:group ref="pr-d-ph" />
              <xs:group ref="ui-d-ph" />
              <xs:group ref="hi-d-ph" />
              <xs:group ref="sw-d-ph" />
            </xs:choice>
          </xs:group>
      
          <xs:group name="fig">
            <xs:choice>
              <xs:group ref="fig"/>
              <xs:group ref="pr-d-fig"/>
              <xs:group ref="ut-d-fig" />
            </xs:choice>
          </xs:group >
          
        </xs:redefine>
    5. From the group for "ph," delete the group references for pr-d-ph, ui-d-ph, and sw-d-ph, leaving this group definition:
          <xs:group name="ph">
            <xs:choice>
              <xs:group ref="ph"/>
              <xs:group ref="hi-d-ph" />
            </xs:choice>
          </xs:group>
      
    6. From the group for "fig" delete the group reference for pr-d-fig, leaving this group definition:
          <xs:group name="fig">
            <xs:choice>
              <xs:group ref="fig"/>
              <xs:group ref="ut-d-fig" />
            </xs:choice>
          </xs:group >
    7. After the include for the conceptMod.xsd file, add an include of the faq-questionMod.xsd file:
        <xs:include schemaLocation="urn:oasis:names:tc:dita:xsd:topicMod.xsd:1.2" />  
        <xs:include schemaLocation="urn:oasis:names:tc:dita:xsd:conceptMod.xsd:1.2" />
        <xs:include schemaLocation="faq-questionMod.xsd" />
    8. Modify the default value of the @domains attribute to reflect the domains and topic types actually used:
        <xs:attributeGroup name="domains-att">
          <xs:attribute name="domains" type="xs:string" 
            default="(topic hi-d) (topic ut-d) (topic concept faq-question)"/>
        </xs:attributeGroup>

    At this point, the test document is still not valid. When you validate it you should see messages about the schema containing two occurrences of global components (concept, conbody, etc.), since faq-questionMod.xsd is still just a copy of conceptMod.xsd.

  9. Edit faq-questionGrp.xsd and modify it as follows:
    1. Replace the header comment with one that reflects your ownership.
    2. Change "concept" to "faq-question."
    3. Change "conbody" to "faq-answer-details."
    4. Make two copies of one of the groups to create new groups for faq-short-answer and faq-question-statement
    The resulting XSD file should look like this:
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- =============================================================
         FAQ Question topic type element-type group definitions
         
         Copyright (c) 2011 Your Name Here
         ============================================================= -->
    
    <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>
      <xs:group name="faq-question">
          <xs:sequence>
             <xs:choice>
                <xs:element ref="faq-question"/>
             </xs:choice>
          </xs:sequence>
       </xs:group>
    
      <xs:group name="faq-answer-details">
          <xs:sequence>
             <xs:choice>
               <xs:element ref="faq-answer-details"/>
             </xs:choice>
          </xs:sequence>
       </xs:group>
    
      <xs:group name="faq-short-answer">
        <xs:sequence>
          <xs:choice>
            <xs:element ref="faq-short-answer"/>
          </xs:choice>
        </xs:sequence>
      </xs:group>
      
      <xs:group name="faq-question-statement">
        <xs:sequence>
          <xs:choice>
            <xs:element ref="faq-question-statement"/>
          </xs:choice>
        </xs:sequence>
      </xs:group>
      
    </xs:schema>

    Validate the test document again. This time you should get messages about being unable to resolve the references to the FAQ-specific element types referenced from the groups you just created.

  10. Edit faq-questionMod.xsd and modify it as follows:
    1. Replace the header comment with one that reflects your ownership.
    2. Modify the <xs:annotation> element to add " faq-question" to the domains value string:
         <xs:annotation>
          <xs:appinfo>
            <dita:domainsModule xmlns:dita="http://dita.oasis-open.org/architecture/2005/"
              >(topic concept faq-question)</dita:domainsModule>
          </xs:appinfo>
          <xs:documentation> 
          
          </xs:documentation>
        </xs:annotation>
    3. Make the global change "concept." to "faq-question." and "conbody." to ""faq-answer-details."" (note: the trailing "." is very important).

      This changes all the building blocks for <concept> and <conbody> to their FAQ question equivalents. The trailing "." is essential because you do not want to change "concept" or "conbody" where it occurs in @class attribute values.

    4. In the element type declaration for "concept," change name="concept" to name="faq-question".
    5. In the value of the @class attribute, append " faq-question/faq-question " to the end of the default value.
    6. Update the documentation to reflect the semantics for <faq-question>.
      The resulting declaration should look like this:
        <xs:element name="faq-question">
          <xs:annotation>
            <xs:documentation>
              The &lt;<keyword>faq-question</keyword>&gt; element is the top-level
              element for a topic that represents a single question/answer pair representing
              a single question in a set of frequently asked questions.
            </xs:documentation>
          </xs:annotation>
          <xs:complexType>
            <xs:complexContent>
              <xs:extension base="faq-question.class">
                <xs:attribute ref="class" default="- topic/topic concept/concept faq-question/faq-question "/>
              </xs:extension>
            </xs:complexContent>
          </xs:complexType>
        </xs:element>
      
    7. Modify the <xs:element> for "conbody" to reflect the <faq-answer-details>, resulting in this element declaration:
        <xs:element name="faq-answer-details">
          <xs:annotation>
            <xs:documentation>
              The &lt;<keyword>faq-answer-details</keyword>&gt; element is the main body-level
              element for an faq-question. It holds any additional details for the FAQ question.
              Note that the first paragraph of the question answer is always held in the
              <keyword>faq-short-answer</keyword> element.
            </xs:documentation>
          </xs:annotation>
          <xs:complexType>
            <xs:complexContent>
              <xs:extension base="faq-answer-details.class">
                <xs:attribute ref="class" 
                  default="- topic/body concept/conbody faq-question/faq-answer-details "/>
              </xs:extension>
            </xs:complexContent>
          </xs:complexType>
        </xs:element>
    8. Change the group "concept-info-types" to "faq-question-info-types," removing the reference to the "concept" group:
        <xs:group name="faq-question-info-types">
          <xs:choice>
            <xs:group ref="info-types" />
            <!-- Removed reference to concept topic type -->
          </xs:choice>
        </xs:group>
      
    9. Find the group "faq-question.content" (created by the global change you made earlier) and modify it to reflect the content model for <faq-question>:
         <xs:group name="faq-question.content">
           <xs:sequence>
             <xs:sequence>
                <xs:group ref="faq-question-statement"/>
                <xs:group ref="titlealts" minOccurs="0"/>
                <xs:choice minOccurs="1">
                  <xs:group ref="faq-short-answer" />
                  <!-- Removed reference to abstract -->
                </xs:choice>
                <xs:group ref="prolog" minOccurs="0"/>
                <xs:group ref="faq-answer-details" minOccurs="0"/>
                <xs:group ref="related-links" minOccurs="0"/>
                <xs:group ref="faq-question-info-types" minOccurs="0" maxOccurs="unbounded"/>
              </xs:sequence>
           </xs:sequence>
         </xs:group>
    10. Copy the <xs:element> for "faq-answer-details" and rename it "faq-question-statement. "Change "faq-answer-details" to "faq-question-statement" and change the @domains attribute value to "- topic/title concept/title faq-question/faq-question-statement ":
         <xs:element name="faq-question-statement">
           <xs:annotation>
             <xs:documentation>
               The &lt;<keyword>faq-question-statement</keyword>&gt; element holds
               the question part of the question/answer pair (it is the FAQ topic's
               title).
             </xs:documentation>
           </xs:annotation>
           <xs:complexType>
             <xs:complexContent>
               <xs:extension base="faq-question-statement.class">
                 <xs:attribute ref="class" 
                   default="- topic/title concept/title faq-question/faq-question-statement "/>
               </xs:extension>
             </xs:complexContent>
           </xs:complexType>
         </xs:element>
    11. Copy the <xs:element> for "faq-answer-details" and rename it "faq-short-answer." Change "faq-answer-details" to "faq-short-answer" and change the @domains attribute value to "- topic/shortdesc concept/shortdesc faq-question/faq-short-answer ":
         <xs:element name="faq-short-answer">
           <xs:annotation>
             <xs:documentation>
               The &lt;<keyword>faq-short-answer</keyword>&gt; element holds
               the first or only paragraph of the answer. This is the short description
               for the topic.
             </xs:documentation>
           </xs:annotation>
           <xs:complexType>
             <xs:complexContent>
               <xs:extension base="faq-short-answer.class">
                 <xs:attribute ref="class" 
                   default="- topic/shortdesc concept/shortdesc faq-question/faq-short-answer "/>
               </xs:extension>
             </xs:complexContent>
           </xs:complexType>
         </xs:element>
    12. Open the file commonElementMod.xsd from the standard DITA schema distribution and find the <xs:complexType> declaration for "title.class." Copy the complexType, title.content group, and title.attributes group and paste it into faq-questionMod.xsd.
    13. Change "title." to "faq-question-statement." in the newly-pasted components except for the reference to "title.cnt." The resulting declarations should be:
         <xs:complexType name="faq-question-statement.class" mixed="true">
           <xs:sequence>
             <xs:group ref="faq-question-statement.content"/>
           </xs:sequence>
           <xs:attributeGroup ref="faq-question-statement.attributes"/>
         </xs:complexType>
         <xs:group name="faq-question-statement.content">
           <xs:sequence>
             <xs:choice minOccurs="0" maxOccurs="unbounded">
               <xs:group ref="title.cnt" minOccurs="0"/>
             </xs:choice>
           </xs:sequence>
         </xs:group>
         <xs:attributeGroup name="faq-question-statement.attributes">
           <xs:attribute name="outputclass" type="xs:string"/>
           <xs:attribute name="base" type="xs:string"/>
           <xs:attributeGroup ref="base-attribute-extensions"/>
           <xs:attributeGroup ref="id-atts"/>
           <xs:attributeGroup ref="localization-atts"/>
           <xs:attributeGroup ref="global-atts"/>
         </xs:attributeGroup>
    14. From the commonElementMod.xsd find the <xs:complexType> declaration for "shortdesc.class." Copy the complexType, title.content group, and title.attributes group and paste it into faq-questionMod.xsd.
    15. Change shortdesc. to faq-short-answer. everywhere, resulting in this set of declarations:
         <xs:complexType name="faq-short-answer.class" mixed="true">
           <xs:sequence>
             <xs:group ref="faq-short-answer.content"/>
           </xs:sequence>
           <xs:attributeGroup ref="faq-short-answer.attributes"/>
         </xs:complexType>
         <xs:group name="faq-short-answer.content">
           <xs:sequence>
             <xs:choice minOccurs="0" maxOccurs="unbounded">
               <xs:group ref="title.cnt" minOccurs="0"/>
               <xs:group ref="draft-comment" minOccurs="0"/>
             </xs:choice>
           </xs:sequence>
         </xs:group>
         <xs:attributeGroup name="faq-short-answer.attributes">
           <xs:attribute name="outputclass" type="xs:string"/>
           <xs:attributeGroup ref="univ-atts"/>
           <xs:attributeGroup ref="global-atts"/>
         </xs:attributeGroup>
  11. Validate the test document. It should be valid.

    At this point the new topic type declarations are correct, but to make them usable you need to replace all the local URL references with the URNs defined in the entity resolution catalog.

    If you have already packaged the DTD version of the module as a Toolkit plugin, you can simply redeploy the plugin to hook in the updated catalog for the XSD components. If you haven't packaged it as a Toolkit plugin, you should do so now.

  12. Edit the test document and change the @xsi:noNamespaceSchemaLocation value to the URN you associated with the faq-question.xsd file, for example:
    <faq-question 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:pubid:example.org:doctypes:dita:faq-question.xsd"
     id="question-id">
     
     ...
    
    </faq-question>

    Validate the document. Assuming that you've deployed the new catalog correctly or otherwise hooked up the catalog into your validation system, the document should be valid.

  13. Edit faq-question.xsd and modify the references to the faq-questionGrp.xsd and faq-questionMod.xsd files to use the corresponding URNs from the entity resolution catalog:
      ...
    
      <!--  ================ CONCEPT GROUP DEFINITION=====================  -->
      <xs:include schemaLocation="urn:pubid:example.org:doctypes:dita:modules:entities:faq-questionGrp.xsd"/>
      <xs:include schemaLocation="urn:oasis:names:tc:dita:xsd:conceptGrp.xsd:1.2"/>
    
      ...
    
      <xs:include schemaLocation="urn:oasis:names:tc:dita:xsd:topicMod.xsd:1.2" />  
      <xs:include schemaLocation="urn:oasis:names:tc:dita:xsd:conceptMod.xsd:1.2" />
      <xs:include schemaLocation="urn:pubid:example.org:doctypes:dita:modules:faq-questionMod.xsd" />
    
      ...
  14. Redeploy the Toolkit plugin and validate the test document. It should be valid.