p2p.wrox.com Forums

p2p.wrox.com Forums (http://p2p.wrox.com/index.php)
-   XSLT (http://p2p.wrox.com/forumdisplay.php?f=86)
-   -   How to sort a XML file itself (http://p2p.wrox.com/showthread.php?t=82243)

inieto January 14th, 2011 11:39 AM

How to sort a XML file itself
 
Hi folks,

I have a close project where we don't have the source code but a back office where we can perform some sort of operations. All these operations can be exported as an XML file. The problem is that the export method follows a hierarchy but not an order. Therefore we want to sort it in order to be able to do diffs and that way share our work.

I've taken an example from http://bytes.com/topic/net/answers/8...y-printed-diff and with some help from Martin, I've got to this XSL.

Code:

<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:strip-space elements="*"/>
 <xsl:output indent="yes"/>

 <xsl:template match="@* | text() | comment() | processing-instruction()">
  <xsl:copy/>
 </xsl:template>


 <xsl:template match="*[*]">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates select="*">
      <xsl:sort select="local-name()" data-type="text"/>
      <xsl:sort select="@id" data-type="text"/>
      <xsl:sort select="@name" data-type="text"/>
    </xsl:apply-templates>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="*[not(*)]">

  <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

I'll paste on the bottom some sample input, but first I'll describe what is missing:

There's a tag called "pagelet-component" which has a collection of slots and inside a tag name slot which has to be ordered by it's attribute tag definition-name.
There's another tag called "pagelet-pagelet-entry-pont-assignment" which has pagelet(s) and pagelet-entry-point(s) tabs which have to be ordered by it's attribute id.
I've tried adding some new sort criterias, but it didn't work
Code:

<xsl:sort select="pagelet-component/slots/slot/definition-name" data-type="text"/>
<xsl:sort select="pagelet-pagelet-entry-point-assignment/pagelet/@id" data-type="text"/>
<xsl:sort select="pagelet-pagelet-entry-point-assignment/pagelet-entry-point/@id" data-type="text"/>

Well, and below is the sample input data:
Code:

<?xml version="1.0" encoding="UTF-8"?>
<input
xmlns="http://www.x.com/xml/ns/xXx/6.5/bc_pmc/impex"
xmlns:dt="http://www.x.com/xml/ns/xXx/6.5/core/impex-dt"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.x.com/xml/ns/xXx/6.5/bc_pmc/impex bc_pmc.xsd">
<pagelet-entry-point id="systempage.productComparision.pagelet2-systempage.productComparision">
<definition-name>systempage.productComparision.pagelet2-systempage.productComparision</definition-name>
<page>true</page>
<sorting>false</sorting>
<display-name xml:lang="en-US">Product Comparision</display-name>
<custom-attributes>
</custom-attributes>
</pagelet-entry-point>
<pagelet-pagelet-entry-point-assignment>
<pagelet-entry-point id="systempage.productComparision.pagelet2-systempage.productComparision2" domain="domain"/>
<pagelet id="pg_20100829_210958" domain="domain"/>
<position>2</position>
<valid-from>08/29/10 09:09:00 pm</valid-from>
<online>true</online>
</pagelet-pagelet-entry-point-assignment>
<pagelet-entry-point id="systempage.productComparision.pagelet2-systempage.productComparision">
<definition-name>systempage.productComparision.pagelet2-systempage.productComparision</definition-name>
<page>true</page>
<sorting>false</sorting>
<display-name xml:lang="en-US">Product Comparision</display-name>
<custom-attributes>
</custom-attributes>
</pagelet-entry-point>
<pagelet-pagelet-entry-point-assignment>
<pagelet-entry-point id="systempage.productComparision.pagelet2-systempage.productComparision" domain="domain"/>
<pagelet id="pg_20100829_210957" domain="domain"/>
<position>1</position>
<valid-from>08/29/10 09:09:00 pm</valid-from>
<online>true</online>
</pagelet-pagelet-entry-point-assignment>
<pagelet-page id="pg_20100829_210957">
<definition-name>pagevariation.productComparision.pagelet2-pagevariation.productComparision</definition-name>
<display-name xml:lang="en-US">Default Product Comparision</display-name>
<description xml:lang="en-US"></description>
<valid-from>08/29/10 09:09:00 pm</valid-from>
<online>true</online>
<author business-partner-no="admin" domain="domain"/>
<configuration-parameters>
<configuration-parameter name="metaInfo">
<definition-name>pagevariation.productComparision.pagelet2-pagevariation.productComparision-metaInfo</definition-name>
</configuration-parameter>
</configuration-parameters>
<slots>
<slot>
<definition-name>slots.main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
</slots>
<custom-attributes>
</custom-attributes>
</pagelet-page>
<pagelet-slot-assignment id="tcPAqOKBrusAAAEtEwIaBHrN">
<slot definition-name="slots.main.pagelet2-slotContent" parent-pagelet-id="pg_20100829_210957" domain="domain"/>
<pagelet id="cmp_20100822_182608" domain="domain"/>
<position>3</position>
<valid-from>08/29/10 09:10:00 pm</valid-from>
<online>true</online>
</pagelet-slot-assignment>
<pagelet-component id="cmp_20100822_182608">
<definition-name>comp.footer.section.pagelet2-comp.footer.section</definition-name>
<display-name xml:lang="en-US">Footer Container</display-name>
<valid-from>08/22/10 06:26:00 pm</valid-from>
<online>true</online>
<author business-partner-no="admin" domain="domain"/>
<configuration-parameters>
<configuration-parameter name="cssClass">
<definition-name>comp.footer.section.pagelet2-comp.footer.section-cssClass</definition-name>
</configuration-parameter>
</configuration-parameters>
<slots>
<slot>
<definition-name>comp.footer.section.pagelet2-slotFooterSection</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
</slots>
<custom-attributes>
</custom-attributes>
</pagelet-component>
<pagelet-slot-assignment id="vbnAqOKB3WcAAAEt7QIaBHrN">
<slot definition-name="comp.footer.section.pagelet2-slotFooterSection" parent-pagelet-id="cmp_20100822_182608" domain="domain"/>
<pagelet id="cmp_20100812_172330" domain="domain"/>
<position>1</position>
<valid-from>08/22/10 06:26:00 pm</valid-from>
<online>true</online>
</pagelet-slot-assignment>
<pagelet-component id="cmp_20100812_172330">
<definition-name>comp.common.group.pagelet2-comp.common.group</definition-name>
<display-name xml:lang="en-US">Footer Component Group</display-name>
<valid-from>08/12/10 05:23:00 pm</valid-from>
<online>true</online>
<author business-partner-no="admin" domain="domain"/>
<configuration-parameters>
<configuration-parameter name="grid">
<definition-name>comp.common.group.pagelet2-comp.common.group-grid</definition-name>
<value name="grid">width=24;prefix=0;suffix=0;alpha=0;omega=0;push=0;pull=0</value>
</configuration-parameter>
<configuration-parameter name="customHoverClass">
<definition-name>comp.common.group.pagelet2-comp.common.group-customHoverClass</definition-name>
</configuration-parameter>
<configuration-parameter name="cssClass">
<definition-name>comp.common.group.pagelet2-comp.common.group-cssClass</definition-name>
</configuration-parameter>
<configuration-parameter name="hoverState">
<definition-name>comp.common.group.pagelet2-comp.common.group-hoverState</definition-name>
</configuration-parameter>
</configuration-parameters>
<slots>
<slot>
<definition-name>comp.common.group.pagelet2-slotContentGroup</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
</slots>
<custom-attributes>
</custom-attributes>
</pagelet-component>
<pagelet-slot-assignment id="aUXAqOKBvwMAAAEtuQMaBHrN">
<slot definition-name="comp.common.group.pagelet2-slotContentGroup" parent-pagelet-id="cmp_20100812_172330" domain="domain"/>
<pagelet id="cmp_20101119_122618" domain="domain"/>
<position>5</position>
<valid-from>11/19/10 12:26:00 pm</valid-from>
<online>true</online>
</pagelet-slot-assignment>
<pagelet-component id="cmp_20101119_122618">
<definition-name>comp.navigation.linkCollection.pagelet2-comp.navigation.linkCollection</definition-name>
<display-name xml:lang="en-US">Social Media Links</display-name>
<description xml:lang="en-US"></description>
<valid-from>11/19/10 12:26:00 pm</valid-from>
<online>true</online>
<author business-partner-no="admin" domain="domain"/>
<configuration-parameters>
<configuration-parameter name="cssClass">
<definition-name>comp.navigation.linkCollection.pagelet2-comp.navigation.linkCollection-cssClass</definition-name>
<value name="cssClass">ws-social-media-links</value>
</configuration-parameter>
<configuration-parameter name="cssId">
<definition-name>comp.navigation.linkCollection.pagelet2-comp.navigation.linkCollection-cssId</definition-name>
</configuration-parameter>
</configuration-parameters>
<slots>
<slot>
<definition-name>comp.navigation.linkCollection.pagelet2-slotLinkCollection</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
</slots>
<custom-attributes>
</custom-attributes>
</pagelet-component>
<pagelet-slot-assignment id="ydTAqOKBAf0AAAEtkwQaBHrN">
<slot definition-name="comp.navigation.linkCollection.pagelet2-slotLinkCollection" parent-pagelet-id="cmp_20101119_122618" domain="domain"/>
<pagelet id="cmp_20101119_122646" domain="domain"/>
<position>1</position>
<valid-from>11/19/10 12:26:00 pm</valid-from>
<online>true</online>
</pagelet-slot-assignment>
<pagelet-component id="cmp_20101119_122646">
<definition-name>comp.navigation.simpleLink.pagelet2-comp.navigation.simpleLink</definition-name>
<display-name xml:lang="en-US">Facebook Link</display-name>
<description xml:lang="en-US"></description>
<valid-from>11/19/10 12:26:00 pm</valid-from>
<online>true</online>
<author business-partner-no="admin" domain="domain"/>
<configuration-parameters>
<configuration-parameter name="title">
<definition-name>comp.navigation.simpleLink.pagelet2-comp.navigation.simpleLink-title</definition-name>
<value name="title" xml:lang="en-US">Facebook</value>
</configuration-parameter>
<configuration-parameter name="link">
<definition-name>comp.navigation.simpleLink.pagelet2-comp.navigation.simpleLink-link</definition-name>
<value name="link">http://www.facebook.com</value>
</configuration-parameter>
<configuration-parameter name="cssClass">
<definition-name>comp.navigation.simpleLink.pagelet2-comp.navigation.simpleLink-cssClass</definition-name>
<value name="cssClass" xml:lang="en-US">ws-facebook</value>
</configuration-parameter>
<configuration-parameter name="displayname">
<definition-name>comp.navigation.simpleLink.pagelet2-comp.navigation.simpleLink-displayname</definition-name>
<value name="displayname" xml:lang="en-US">Facebook</value>
</configuration-parameter>
</configuration-parameters>
<custom-attributes>
</custom-attributes>
</pagelet-component>
<pagelet-slot-assignment id="jL_AqOKB4f4AAAEtOQYaBHrN">
<slot definition-name="comp.navigation.linkCollection.pagelet2-slotLinkCollection" parent-pagelet-id="cmp_20101119_122618" domain="domain"/>
<pagelet id="cmp_20101119_123015" domain="domain"/>
<position>3</position>
<valid-from>11/19/10 12:30:00 pm</valid-from>
<online>true</online>
</pagelet-slot-assignment>
</input>

Any help is appreciated :)
Ignacio

Martin Honnen January 14th, 2011 12:33 PM

Let's try to identify sub problems and solve them. You say you need special treatment for the "slot" elements inside the "slots" elements of "pagelet-component" and want to sort the "slot" elements according to the "definition-name". That could be achieved with
Code:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:impex="http://www.x.com/xml/ns/xXx/6.5/bc_pmc/impex"
  version="1.0">
 
  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>
 
  <xsl:template match="@* | text() | comment() | processing-instruction()">
    <xsl:copy/>
  </xsl:template>
 
  <xsl:template match="*[*]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="*">
        <xsl:sort select="local-name()" data-type="text"/>
        <xsl:sort select="@id" data-type="text"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
 
  <xsl:template match="*[not(*)]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
 
  <xsl:template match="impex:pagelet-component/impex:slots" priority="5">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="impex:slot">
        <xsl:sort select="impex:definition-name"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template> 

</xsl:stylesheet>

Does that do what you want for those "slot" elements?

acctoujours January 17th, 2011 11:02 AM

Hi Martin,
I have tested your latest solution and i have found errors related with namespace.
If I run the XSL transformation quitting namespace from input XML and XSL, all functionality works perfect but using namespace, as you recommended for an accurate usage, the tranformation doesn't sort slot tags inside each slots.

I think the problem occurs because @* does not use a namespace, so I change to @impex:* and it keeps slot tags unsorted.

Thanks for your help!,
Juan V.

Martin Honnen January 18th, 2011 07:43 AM

Juan, if you post a minimal but complete enough XML input document that you want to sort, the result you want to achieve and the result you get with my stylesheet (or the stylesheet you have used if you make changes) then we can look into what is wrong. @* selects any attribute node, whether it is in a namespace or not does not matter. And the code I posted does not sort based on any attribute values anyway so I don't think the treatment of attribute needs to be changed.

acctoujours January 18th, 2011 09:31 AM

Okk, my input.xml and stylesheet are:

input.xml
Code:

<?xml version="1.0" encoding="UTF-8"?>
<enfinity
xmlns="http://www.intershop.com/xml/ns/enfinity/6.5/bc_pmc/impex"
xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.intershop.com/xml/ns/enfinity/6.5/bc_pmc/impex bc_pmc.xsd">
<pagelet-page id="pg_20100829_210957">
<definition-name>pagevariation.productComparision.pagelet2-pagevariation.productComparision</definition-name>
<display-name xml:lang="en-US">Default Product Comparision</display-name>
<description xml:lang="en-US"></description>
<valid-from>08/29/10 09:09:00 pm</valid-from>
<online>true</online>
<author business-partner-no="admin" domain="LeviStrauss"/>
<configuration-parameters>
<configuration-parameter name="metaInfo">
<definition-name>pagevariation.productComparision.pagelet2-pagevariation.productComparision-metaInfo</definition-name>
</configuration-parameter>
</configuration-parameters>
<slots>
<slot>
<definition-name>slots.main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
<slot>
<definition-name>aslots.main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
</slots>
<custom-attributes>
</custom-attributes>
</pagelet-page>
<pagelet-page id="pg_20100811_162140">
<definition-name>pagevariation.homepage.pagelet2-pagevariation.homepage</definition-name>
<display-name xml:lang="en-US">Default Homepage</display-name>
<valid-from>08/11/10 04:21:00 pm</valid-from>
<online>true</online>
<author business-partner-no="admin" domain="LeviStrauss"/>
<configuration-parameters>
<configuration-parameter name="metaInfo">
<definition-name>pagevariation.homepage.pagelet2-pagevariation.homepage-metaInfo</definition-name>
</configuration-parameter>
</configuration-parameters>
<slots>
<slot>
<definition-name>slots.main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
<slot>
<definition-name>main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
</slots>
<custom-attributes>
</custom-attributes>
</pagelet-page>
</enfinity>

xsl
Code:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:impex="http://www.x.com/xml/ns/xXx/6.5/bc_pmc/impex"
  version="1.0">
 
  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>
 
  <xsl:template match="@* | text() | comment() | processing-instruction()">
    <xsl:copy/>
  </xsl:template>
 
  <xsl:template match="*[*]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="*">
        <xsl:sort select="local-name()" data-type="text"/>
        <xsl:sort select="@id" data-type="text"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
 
  <xsl:template match="*[not(*)]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
 
  <xsl:template match="impex:pagelet-page/impex:slots" priority="5">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="impex:slot">
        <xsl:sort select="impex:definition-name"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template> 

</xsl:stylesheet>

The result is a sorted XML file, but slot tags are not sorted by its definition-name inside each slots tag.

I need the following result:
Code:

<?xml version="1.0" encoding="UTF-16"?>
<enfinity xsi:schemaLocation="http://www.intershop.com/xml/ns/enfinity/6.5/bc_pmc/impex bc_pmc.xsd" xmlns="http://www.intershop.com/xml/ns/enfinity/6.5/bc_pmc/impex" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<pagelet-page id="pg_20100811_162140">
<author business-partner-no="admin" domain="LeviStrauss">
</author>
<configuration-parameters>
<configuration-parameter name="metaInfo">
<definition-name>pagevariation.homepage.pagelet2-pagevariation.homepage-metaInfo</definition-name>
</configuration-parameter>
</configuration-parameters>
<custom-attributes>
</custom-attributes>
<definition-name>pagevariation.homepage.pagelet2-pagevariation.homepage</definition-name>
<display-name xml:lang="en-US">Default Homepage</display-name>
<online>true</online>
<slots>
<slot>
<definition-name>main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
<slot>
<definition-name>slots.main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
</slots>
<valid-from>08/11/10 04:21:00 pm</valid-from>
</pagelet-page>
<pagelet-page id="pg_20100829_210957">
<author business-partner-no="admin" domain="LeviStrauss">
</author>
<configuration-parameters>
<configuration-parameter name="metaInfo">
<definition-name>pagevariation.productComparision.pagelet2-pagevariation.productComparision-metaInfo</definition-name>
</configuration-parameter>
</configuration-parameters>
<custom-attributes>
</custom-attributes>
<definition-name>pagevariation.productComparision.pagelet2-pagevariation.productComparision</definition-name>
<description xml:lang="en-US">
</description>
<display-name xml:lang="en-US">Default Product Comparision</display-name>
<online>true</online>
<slots>
<slot>
<definition-name>aslots.main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
<slot>
<definition-name>slots.main.pagelet2-slotContent</definition-name>
<optional>false</optional>
<sorting>false</sorting>
</slot>
</slots>
<valid-from>08/29/10 09:09:00 pm</valid-from>
</pagelet-page>
</enfinity>

Thanks!!,
Juan V.

samjudson January 18th, 2011 09:46 AM

The "impex" namespace declaration in your stylesheet does not match the namespace of your main input XML, so the "impex:slots" template is never matching.

Input XML:

xmlns="http://www.intershop.com/xml/ns/enfinity/6.5/bc_pmc/impex"

XSLT:

xmlns:impex="http://www.x.com/xml/ns/xXx/6.5/bc_pmc/impex"

Fixing this should solve your problem I think.

acctoujours January 18th, 2011 10:17 AM

Thank you!, it works perfect.
I believed that namespaces in XSL transformation were declared only to create contexts, so I didn't think about validations over namespace-uris [:p]

Juan V.

inieto February 2nd, 2011 02:51 PM

Sort by a composite key
 
Hi guys, it's me again [:)]

Thanks for your great help!

Now I'm really going to test your great knowledge on XSLT

I have this kind of tag construction:
Code:

<pagelet-slot-assignment id="PonAqOKB2ecAAAEtjkAaBHrO">
    <online>true</online>
    <pagelet id="cmp_20100822_182608" domain="LeviStrauss-Dockers"></pagelet>
    <position>3</position>
    <slot definition-name="slots.main.pagelet2-slotContent" parent-pagelet-id="pg_20100826_194641" domain="LeviStrauss-Dockers"></slot>
    <valid-from>08/26/10 07:46:00 pm</valid-from>
  </pagelet-slot-assignment>

Note that the id="PonAqOKB2ecAAAEtjkAaBHrO" is auto generated
Therefore I need to sort by the combination of attributes pagelet@id and slot@parent-pagelet-id:
pagelet-slot-assignment/pagelet/@id (the "id" attribute of the pagelet tab of the pagelet-slot-assignment tab), and
pagelet-slot-assignment/slot/@parent-pagelet-id

The key is a composite of both attributes, avoiding the upper autogenerated id (pagelet-slot-assignment id="PonAqOKB2ecAAAEtjkAaBHrO")

Is it possible to sort it that way?

Many thanks!

mhkay February 2nd, 2011 05:03 PM

Sorry, it doesn't sound difficult from an XSLT perspective, once you've explained the requirement. But I can't work out from that description what on earth it is that you want to do.

There's an awful lot of history in this thread - I hope you're not expecting me to read and understand it.


All times are GMT -4. The time now is 06:43 AM.

Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.