【问题标题】:How to convert flat xml data to hierarchical data xml如何将平面 xml 数据转换为分层数据 xml
【发布时间】:2014-08-26 06:55:46
【问题描述】:

我必须将平面 xml 转换为分层 xml。 我不知道这个任务。 下面是转换的输入。

输入:-

<body>
    <p class="title">Article Title</p>
    <p class="Authors">abc, pqr and xyz</p>
    <p class="intro">here is introdution text......</p>        
    <p class="head1">1: Heading level 1</p>
    <p>some text here</p>
    <p>some text here</p>
    <p class="head2">1.1: Heading  level 2</p>
    <p>some text here</p>
    <p>some text here</p>        
    <p class="head3">1.1.1: Heading  level 3</p>
    <p>some text here</p>
    <p>some text here</p>        
    <p class="head1">2: Heading level 1</p>
    <p class="head2">2.1: Heading  level 2</p>
    <p>some text here</p>
    <p>some text here</p>        
    <p class="head3">2.1.1: Heading  level 3</p>
    <p>some text here</p>
    <p>some text here</p>        
    <p class="head3">2.1.2: Heading  level 3</p>
    <p>some text here</p>
    <p>some text here</p>        
</body>

我想把它转换成下面给定的xml。

输出:-

<article>
    <title>Article Title</title>
    <Authors>abc, pqr and xyz</Authors>
    <introduction>here is introdution text......</introduction>
    <body>
        <sec level="1">
            <title>1: Heading level 1</title>
            <p>some text here</p>
            <p>some text here</p>
            <sec level="2">
                <title>1.1: Heading  level 2</title>
                <p>some text here</p>
                <p>some text here</p>
                <sec level="3">
                    <title>1.1.1: Heading  level 3</title>
                    <p>some text here</p>
                    <p>some text here</p>                    
                </sec>
            </sec>
        </sec>
        <sec level="1">
            <title>2: Heading level 1</title>
            <sec level="2">                
                <title>2.1: Heading  level 2</title>
                <p>some text here</p>
                <p>some text here</p>
                <sec level="3">
                    <title>2.1.1: Heading  level 3</title>
                    <p>some text here</p>
                    <p>some text here</p>                        
                </sec>
                <sec level="3">
                    <title>2.1.2: Heading  level 3</title>
                    <p>some text here</p>
                    <p>some text here</p>                        
                </sec>
            </sec>                
        </sec>
    </body>
</article>

我不知道使用 xslt 转换它。

我低于输出:-

   <article>
  <p class="title">Article Title</p>
  <p class="Authors">abc, pqr and xyz</p>
  <p class="intro">here is introdution text......</p>
  <body>
     <p class="head1">1: Heading level 1</p>
     <p>some text here</p>
     <p>some text here</p>
     <p class="head2">1.1: Heading level 2</p>
     <p>some text here</p>
     <p>some text here</p>
     <p class="head3">1.1.1: Heading level 3</p>
     <p>some text here</p>
     <p>some text here</p>
     <p class="head1">2: Heading level 1</p>
     <p class="head2">2.1: Heading level 2</p>
     <p>some text here</p>
     <p>some text here</p>
     <p class="head3">2.1.1: Heading level 3</p>
     <p>some text here</p>
     <p>some text here</p>
     <p class="head3">2.1.2: Heading level 3</p>
     <p>some text here</p>
     <p>some text here</p>
  </body>
  </article>

我的代码是:-

      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
     <xsl:output method="xml" indent="yes"/>
     <xsl:strip-space elements="*"/>

     <xsl:template match="/">
        <xsl:apply-templates/>
     </xsl:template>

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

     <xsl:template match="head"/>
     <xsl:template match="body">
        <xsl:element name="article">
           <xsl:apply-templates select="p[@class='title']|p[@class='Authors']|p[@class='intro']"/>
           <xsl:element name="body">
              <xsl:apply-templates select="p[preceding-sibling::p[@class='intro']]"/>
           </xsl:element>
        </xsl:element>
     </xsl:template>
  </xsl:stylesheet>

【问题讨论】:

  • 您认为向“不知道”如何做的人提供答案是否具有很高的教育价值?尝试解决您的问题 - 或者至少在 Google 上搜索您的问题的标题。
  • @LuvKS 请不要发表个人言论。
  • 请参阅stackoverflow.com/questions/9175991/… 了解类似问题的 XSLT 2.0 解决方案,基本上您需要使用 for-each-group select="*" group-starting-with="p[@class = concat('head', $level)]" 编写递归函数或模板。

标签: xml xslt xslt-2.0


【解决方案1】:

您可以使用以下 xslt 代码获得预期输出:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf" version="2.0">

<xsl:output indent="yes"/>

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

<xsl:function name="mf:group" as="element(section)*">
    <xsl:param name="entries" as="element(p)*"/>
    <xsl:param name="level" as="xs:integer"/>
    <xsl:for-each-group select="$entries"
        group-starting-with="p[@class = concat('head',$level)]">
        <xsl:variable name="P_ID" select="generate-id(.)"/>
        <section name="{@class}">
            <title>
                <xsl:value-of select="."/>
            </title>
            <xsl:if test="following-sibling::p[1][not(@class)]">
                <ps>
                    <xsl:apply-templates
                        select="following-sibling::p[not(@class)][generate-id(preceding-sibling::p[@class][1]) = $P_ID]"
                    />
                </ps>
            </xsl:if>

            <xsl:sequence select="mf:group(current-group() except ., ($level + 1))"/>
        </section>
    </xsl:for-each-group>
</xsl:function>

<xsl:template match="body">
    <xsl:copy>
        <xsl:sequence select="mf:group(p[contains(@class,'head')], 1)"/>
    </xsl:copy>
</xsl:template>

【讨论】:

    【解决方案2】:

    这是一个使用递归函数实现嵌套的示例,当然还有一些进一步的模板来转换各种p 元素:

    <xsl:stylesheet 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:mf="http://example.com/mf"
      exclude-result-prefixes="xs mf"
      version="2.0">
    
    <xsl:output indent="yes"/>
    
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:function name="mf:group" as="element()*">
        <xsl:param name="elements" as="element(p)*"/>
        <xsl:param name="level" as="xs:integer"/>
        <xsl:for-each-group select="$elements" group-starting-with="p[@class = concat('head', $level)]">
           <xsl:choose>
                  <xsl:when test="not(self::p[@class = concat('head', $level)])">
                    <xsl:apply-templates select="current-group()"/>
                  </xsl:when>
                  <xsl:otherwise>
                    <sec level="{$level}">
                      <xsl:apply-templates select="."/>
                      <xsl:sequence select="mf:group(current-group() except ., ($level + 1))"/>
                    </sec>
                  </xsl:otherwise>
           </xsl:choose>
        </xsl:for-each-group>
    </xsl:function>
    
    <xsl:template match="body">
      <article>
        <xsl:apply-templates select="p[@class = 'head1'][1]/preceding-sibling::*"/>
        <xsl:copy>
            <xsl:sequence select="mf:group(p[@class = 'head1'][1]/(., following-sibling::*), 1)"/>
        </xsl:copy>
      </article>
    </xsl:template>
    
    <xsl:template match="p[@class = 'title'] | p[starts-with(@class, 'head')]">
      <title>
        <xsl:apply-templates/>
      </title>
    </xsl:template>
    
    <xsl:template match="p[@class = 'intro']">
      <introduction>
        <xsl:apply-templates/>
      </introduction>
    </xsl:template>
    
    <xsl:template match="p[@class = 'Authors']">
      <Authors>
        <xsl:apply-templates/>
      </Authors>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

      【解决方案3】:

      在 XSLT 1.0 中:-

      <?xml version="1.0" encoding="UTF-8"?>
      

      <xsl:template match="/">
          <xsl:apply-templates/>
      </xsl:template>
      
      <xsl:template match="@* | node()">
          <xsl:copy copy-namespaces="no">
              <xsl:apply-templates select="@* | node()"/>
          </xsl:copy>
      </xsl:template>
      <xsl:template match="html">
          <xsl:apply-templates/>
      </xsl:template>
      
      <xsl:template match="head"/>
      
      <xsl:key name="Body" match="p[not(@class)]"
          use="generate-id((preceding-sibling::p[@class='Head1'] | preceding-sibling::p[@class='Head2']| preceding-sibling::p[@class='Head3']| preceding-sibling::p[@class='Head4']| preceding-sibling::p[@class='Head5']| preceding-sibling::p[@class='Head6'])[last()])"/>
      <xsl:key name="h2" match="p[@class='Head2']"
          use="generate-id(preceding-sibling::p[@class='Head1'][1])"/>
      <xsl:key name="h3" match="p[@class='Head3']"
          use="generate-id(preceding-sibling::p[@class='Head2'][1])"/>
      <xsl:key name="h4" match="p[@class='Head4']"
          use="generate-id(preceding-sibling::p[@class='Head3'][1])"/>
      <xsl:key name="h5" match="p[@class='Head5']"
          use="generate-id(preceding-sibling::p[@class='Head4'][1])"/>
      <xsl:key name="h6" match="p[@class='Head6']"
          use="generate-id(preceding-sibling::p[@class='Head5'][1])"/>
      
      <xsl:template match="body">
          <xsl:element name="article">
              <xsl:apply-templates
                  select="p[@class='title']|p[@class='Title']|p[@class='Authors']|p[@class='intro']"/>
              <xsl:element name="body">
                  <xsl:apply-templates select="key('Body',generate-id())" mode="Body"/>
                  <xsl:apply-templates select="descendant::p[@class='Head1']" mode="h1"/>
              </xsl:element>
          </xsl:element>
      </xsl:template>
      
      <xsl:template match="p" mode="h1">
          <sec level="1">
              <title>
                  <xsl:apply-templates/>
              </title>
              <xsl:apply-templates select="key('Body',generate-id())" mode="Body"/>
              <xsl:apply-templates select="key('h2',generate-id())" mode="h2"/>
          </sec>
      </xsl:template>
      
      <xsl:template match="p" mode="h2">
          <sec level="2">
              <title>
                  <xsl:apply-templates/>
              </title>
              <xsl:apply-templates select="key('Body',generate-id())" mode="Body"/>
              <xsl:apply-templates select="key('h3',generate-id())" mode="h3"/>
          </sec>
      </xsl:template>
      
      <xsl:template match="p" mode="h3">
          <sec level="3">
              <title>
                  <xsl:apply-templates/>
              </title>
              <xsl:apply-templates select="key('Body',generate-id())" mode="Body"/>
              <xsl:apply-templates select="key('h4',generate-id())" mode="h4"/>
          </sec>
      </xsl:template>
      
      <xsl:template match="p" mode="h4">
          <sec level="4">
              <title>
                  <xsl:apply-templates/>
              </title>
              <xsl:apply-templates select="key('Body',generate-id())" mode="Body"/>
              <xsl:apply-templates select="key('h5',generate-id())" mode="h5"/>
          </sec>
      </xsl:template>
      
      <xsl:template match="p" mode="h5">
          <sec level="5">
              <title>
                  <xsl:apply-templates/>
              </title>
              <xsl:apply-templates select="key('Body',generate-id())" mode="Body"/>
              <xsl:apply-templates select="key('h6',generate-id())" mode="h6"/>
          </sec>
      </xsl:template>
      
      <xsl:template match="p" mode="h6">
          <sec level="6">
              <title>
                  <xsl:apply-templates/>
              </title>
              <xsl:apply-templates select="key('Body',generate-id())" mode="Body"/>
          </sec>
      </xsl:template>
      
      <xsl:template match="p" mode="Body">
          <p>
              <xsl:apply-templates/>            
          </p>
      </xsl:template>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多