Grouping XML by record type

Help
beppeg
2008-11-29
2013-05-30
  • beppeg
    beppeg
    2008-11-29

    Hi all,

    short preamble: I guess my problem is very easy to solve and I tried to solve it reading reference and samples but I cant find a solution!
    Well, let suppose we've the following flat file as input:

    TITLE;Book title
    AUTH;Author name
    PRICE;10$
    NOTE;note 1
    NOTE;note 2
    QUANTITY;100

    and we would get an output like

    <BOOK>
      <TITLE>Book title</TITLE>
      <AUTH>Author name</AUTH>
      <PRICE>10$</PRICE>
      <NOTE-GROUP>
         <NOTE>note 1</NOTE>
         <NOTE>note 2</NOTE>
      </NOTE-GROUP>
      <QUANTITY>100</QUANTITY>
    </BOOK>

    How can I group the NOTE records?

    Thanks.

    -- Beppe

     
    • Daniel Parker
      Daniel Parker
      2008-11-30

      When you need to group records by the values of fields, use the sx:innerGroup or sx:outerGroup elements.  You'll find examples of their use in the Examples, as well as documentation in the Element Reference.

      Here's one solution:

      <sx:resources xmlns:sx="http://www.servingxml.com/core">

        <sx:service id="book">
          <sx:serialize>
            <sx:xsltSerializer>
              <sx:outputProperty name="indent" value="yes"/>
            </sx:xsltSerializer>
            <sx:transform>
              <sx:content ref="book"/>
            </sx:transform>
          </sx:serialize>
        </sx:service>

        <sx:recordContent id="book">
          <sx:flatFileReader>
            <sx:flatFile ref="bookFlatFile"/>
          </sx:flatFileReader>
          <sx:recordMapping ref="bookToXmlMapping"/>
        </sx:recordContent>

        <sx:flatFile id="bookFlatFile">
          <sx:flatFileBody>
            <sx:flatRecordType name="book">
              <sx:fieldDelimiter value=";"/>
              <sx:delimitedField name="name"/>
              <sx:delimitedField name="value"/>
            </sx:flatRecordType>
          </sx:flatFileBody>
        </sx:flatFile>

        <sx:recordMapping id="bookToXmlMapping">
            <BOOK>
              <sx:groupChoice>
                <sx:innerGroup startTest="sx:current//name='NOTE'"
                               endTest="sx:current//name!='NOTE'">
                  <NOTE-GROUP>
                    <sx:onRecord>
                      <sx:fieldElementMap field="name" element="NOTE"/>
                    </sx:onRecord>
                  </NOTE-GROUP>
                </sx:innerGroup>
                <sx:onRecord>
                  <sx:fieldElementMap field="value" element="{name}"/>
                </sx:onRecord>
              </sx:groupChoice>
            </BOOK>
        </sx:recordMapping>
      </sx:resources>

      The sx:groupChoice element produces output for the first grouping that is in effect.  If that happens to be the 'NOTE' record, the record is written inside the NOTE-GROUP tag, otherwise the sx:onRecord element (a grouping of one) applies.

      Another way of writing the record mapping section is

        <sx:recordMapping id="bookToXmlMapping">
            <BOOK>
                <sx:innerGroup startTest="sx:current//name='NOTE'"
                               endTest="sx:current//name!='NOTE'">
                  <NOTE-GROUP>
                    <sx:onRecord>
                      <sx:fieldElementMap field="name" element="NOTE"/>
                    </sx:onRecord>
                  </NOTE-GROUP>
                </sx:innerGroup>
                <sx:onRecord test="name != 'NOTE'">
                  <sx:fieldElementMap field="value" element="{name}"/>
                </sx:onRecord>
            </BOOK>
        </sx:recordMapping>

      -- Daniel

       
    • monthy
      monthy
      2008-12-04

      Hi all,

      Just a following question from this problem. I've tried to read the sample and reference and find a solution to the same problem but I couldn't find a solution ...

      suppose i have this flat file input:

      H;H1;H2
      A;1;2;
      B;3;4;5
      B;6;7;8

      Then I want to produce this output:

      <someTitle>
            <header>
                   <header1>H1</header1>
                   <header2>H2</header2>
            </header>
            <Details>
                   <detail_A>
                          <A1>1</A1>
                          <A2>2</A2>
                   </detail_A>
                   <detail_B>
                          <B1>3</B1>
                          <B2>4</B2>
                          <B3>5</B3>
                   </detail_B>
            </Details>
            <Details>
                   <detail_A/>
                   <detail_B>
                          <B1>6</B1>
                          <B2>7</B2>
                          <B3>8</B3>
                  </detail_B>
            </Details>
      </someTitle>

      any help is greatly appreciated  :-)

      Cheers,

      Monthy

       
    • Daniel Parker
      Daniel Parker
      2008-12-06

      Monthy,

      Sorry for the delay in responding, I overlooked that there was a new question.   In the future, please introduce a new question in a separate message, it's easier for me to see, and easier for others looking for help.

      There are a number of ways of performing this mapping, see the one below, you can test it with

      servingxml -r resources.xml -i input.txt -o output.xml test

      -- Daniel

      <sx:resources xmlns:sx="http://www.servingxml.com/core">
        <sx:service id="test">
          <sx:serialize>
            <sx:transform>
              <sx:content ref="test-content"/>
            </sx:transform>
          </sx:serialize>
        </sx:service>
        <sx:recordContent id="test-content">
          <sx:flatFileReader>
            <sx:flatFile ref="test-flat-file"/>
          </sx:flatFileReader>
          <sx:recordMapping ref="flat-to-xml-mapping"/>
        </sx:recordContent>
        <sx:flatFile id="test-flat-file">
          <sx:fieldDelimiter value=";"/>
          <sx:flatFileBody>
            <sx:flatRecordTypeChoice>
              <sx:delimitedField name="record_type"/>
              <sx:when test="record_type='H'">
                <sx:flatRecordType name="header">
                  <sx:delimitedField name="record_type"/>
                  <sx:delimitedField name="header1"/>
                  <sx:delimitedField name="header2"/>
                </sx:flatRecordType>
              </sx:when>
              <sx:when test="record_type='A'">
                <sx:flatRecordType name="detail_A">
                  <sx:delimitedField name="record_type"/>
                  <sx:delimitedField name="A1"/>
                  <sx:delimitedField name="A2"/>
                </sx:flatRecordType>
              </sx:when>
              <sx:when test="record_type='B'">
                <sx:flatRecordType name="detail_B">
                  <sx:delimitedField name="record_type"/>
                  <sx:delimitedField name="B1"/>
                  <sx:delimitedField name="B2"/>
                  <sx:delimitedField name="B3"/>
                </sx:flatRecordType>
              </sx:when>
            </sx:flatRecordTypeChoice>
          </sx:flatFileBody>
        </sx:flatFile>
        <sx:recordMapping id="flat-to-xml-mapping">
          <someTitle>
            <sx:onRecord recordType="header">
              <header>
                <sx:fieldElementMap field="header1" element="header1"/>
                <sx:fieldElementMap field="header2" element="header2"/>
              </header>
            </sx:onRecord>
            <sx:innerGroup startTest="sx:current/detail_A or sx:current/detail_B"
                           endTest="not(sx:current/detail_A or sx:current/detail_B)">
              <Details>
                <sx:onRecord recordType="detail_A">
                  <detail_A>
                    <sx:fieldElementMap field="A1" element="A1"/>
                    <sx:fieldElementMap field="A2" element="A2"/>
                  </detail_A>
                </sx:onRecord>
                <sx:onRecord recordType="detail_B">
                  <detail_B>
                    <sx:fieldElementMap field="B1" element="B1"/>
                    <sx:fieldElementMap field="B2" element="B2"/>
                    <sx:fieldElementMap field="B3" element="B3"/>
                  </detail_B>
                </sx:onRecord>
              </Details>
            </sx:innerGroup>
          </someTitle>
        </sx:recordMapping>
      </sx:resources>

       
    • monthy
      monthy
      2008-12-09

      Hi daniel,

      Thanks for the reply .. :)
      That's really helpful.

      Sorry for the confusion....

      Cheers,

      Monthy