Oleg
Oleg

Reputation: 69

Getting rid of excessive elements while copying data from xml using xslt

I am trying to parse file manager.xml to get a proper structure of data I need. Example of manager.xml:

<?xml version="1.0" encoding="koi8-r"?>
<manager>
        <priv id="pr.screen.access" caption="c.screen.access">
                <priv id="pr.screen.category.documents" caption="c.main.documents">
                        <priv id="pr.screen.category.documents.rcn" caption="c.main.documents.rcn">
                                <priv id="pr.screen.category.documents.rcn.create" caption="c.main.documents.rcn.create"/>
                        </priv>
                </priv>
        </priv>
        <priv id="pr.screen.category.archives" caption="c.main.archives"/>
        <priv id="pr.screen.category.documents.rcn.create_as" caption="c.main.documents.rcn.create_as" parent="pr.screen.access"/>
        <priv id="pr.screen.category.transport_management.documents" caption="c.main.transport_management.documents"/>
        <caption id="c.screen.access">
                <loctext lang="ru" long="access"/>
        </caption>
        <caption id="c.main.documents">
                <loctext lang="ru" long="documents"/>
        </caption>
        <caption id="c.main.documents.rcn">
                <loctext lang="ru" long="rcn"/>
        </caption>
        <caption id="c.main.documents.rcn.create">
                <loctext lang="ru" long="rcn_create"/>
        </caption>
        <caption id="c.main.archives">
                <loctext lang="ru" long="archives"/>
        </caption>
        <caption id="c.main.documents.rcn.create_as">
                <loctext lang="ru" long="rcn_create-as"/>
        </caption>
        <caption id="c.main.transport_management.documents">
                <loctext lang="ru" long="transport_documents"/>
        </caption>
</manager>

Basically I need to copy all "priv" elements with all nested elements and also find "priv" elements with "parent" attribute and put it into respective "priv" element with "id" attribute equal to "parent".

Besides that I also need to add "caption_ru" attribute for every "priv" element with the value fetched from attribute "long" of "loctext" element which is inside "caption" element where "id" attribute is equal to "caption" attribute of "priv". This part is working, but is there any chance that it's better to be solved by using xsl:key function?

I have next xslt, which is working almost as intended, but I am stuck with extra "priv" elements which I get after tranformation and I can't find any way to get rid of them: xsl:

<?xml version="1.0" encoding="koi8-r"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes" encoding="koi8-r" version="1.0"/>
        <xsl:strip-space elements="*"/>

        <xsl:template match="@* | node()">
                <xsl:copy>
                        <xsl:attribute name='caption_ru'>
                                <xsl:value-of select="//manager/caption[@id=current()/@caption]/loctext[@lang='ru']/@long"/>
                        </xsl:attribute>
                        <xsl:apply-templates select="@* | priv[not(@parent)]"/>
                        <xsl:call-template name="nested_priv"/>
                        <!--xsl:copy>
                                <xsl:apply-templates select="//manager/priv[@parent=current()/@id]"/>
                        </xsl:copy-->

                </xsl:copy>
        </xsl:template>

        <xsl:template name="nested_priv">
                <xsl:copy>
                        <!--xsl:attribute name='caption_ru'>
                                <xsl:value-of select="//manager/caption[@id=current()/@caption]/loctext[@lang='ru']/@long"/>
                        </xsl:attribute-->
                                <xsl:apply-templates select="//manager/priv[@parent=current()/@id]"/>
                </xsl:copy>
        </xsl:template>

</xsl:stylesheet>

This is what I get after transformation:

<?xml version="1.0" encoding="koi8-r"?>
<manager caption_ru="">
  <priv caption_ru="access" id="pr.screen.access" caption="c.screen.access">
    <priv caption_ru="documents" id="pr.screen.category.documents" caption="c.main.documents">
      <priv caption_ru="rcn" id="pr.screen.category.documents.rcn" caption="c.main.documents.rcn">
        <priv caption_ru="rcn_create" id="pr.screen.category.documents.rcn.create" caption="c.main.documents.rcn.create">
          <priv/>
        </priv>
        <priv/>
      </priv>
      <priv/>
    </priv>
    <priv>
      <priv caption_ru="rcn_create-as" id="pr.screen.category.documents.rcn.create_as" caption="c.main.documents.rcn.create_as" parent="pr.screen.access">
        <priv/>
      </priv>
    </priv>
  </priv>
  <priv caption_ru="archives" id="pr.screen.category.archives" caption="c.main.archives">
    <priv/>
  </priv>
  <priv caption_ru="transport_documents" id="pr.screen.category.transport_management.documents" caption="c.main.transport_management.documents">
    <priv/>
  </priv>
  <manager/>
</manager>

Upvotes: 1

Views: 147

Answers (2)

Oleg
Oleg

Reputation: 69

Resolved with xsl listed above which is based on the answer of user3016153 whom I am very thankful. I am not sure should I accept his answer or not, but I did since it was very helpful.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" version="1.0" encoding="koi8-r" indent="yes"/>

<xsl:key name="caption" match="caption" use="@id" />
<xsl:key name="child_priv" match="priv" use="@parent"/>

<xsl:template match="/manager">
        <xsl:copy>
            <xsl:apply-templates select="priv[not(@parent)]"/>
        </xsl:copy>
</xsl:template>

<xsl:template match="priv">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:attribute name="caption_ru">
            <xsl:value-of select="key('caption', @caption)/loctext[@lang='ru']/@long" />
        </xsl:attribute>
        <xsl:apply-templates select="priv"/>
        <xsl:apply-templates select="key('child_priv',current()/@id)"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="@*">
    <xsl:copy/>
</xsl:template>

</xsl:stylesheet>

Upvotes: 0

michael.hor257k
michael.hor257k

Reputation: 117100

How about this way?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" version="1.0" encoding="koi8-r" indent="yes"/>

<xsl:key name="caption" match="caption" use="@id" />

<xsl:template match="/manager">
<xsl:copy>
    <xsl:apply-templates select="priv"/>
</xsl:copy>
</xsl:template>

<xsl:template match="priv">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:attribute name="caption_ru">
            <xsl:value-of select="key('caption', @caption)/loctext/@long" />
        </xsl:attribute>
        <xsl:apply-templates select="priv"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="@*">
    <xsl:copy/>
</xsl:template>

</xsl:stylesheet>

Upvotes: 0

Related Questions