duanpacan9388 2016-10-20 07:13
浏览 55

条件XML重组

I'm looking for an efficient way to reorganize parts of an XML document that contain multiple children of a type such as 'SmallCat' or 'BigCat'.

Here are the rules:

  1. Everything except for Habitat nodes should be passed through; attributes and all.
  2. Habitat nodes with less than 2 instances of either BigCat or SmallCat should be passed through.

The input document looks like:

<Zoo>
  <Habitat HabitatID="habitat.cage.1">
    <Type>Cats</Type>
    <Food>Birds</Food>
    <BigCat AnimalID="Tiger.1">
      <Type>Bengal</Type>
    </BigCat>
    <SmallCat AnimalID="bobcat.1">
      <Type>Bobcat</Type>
    </SmallCat>
    <BodyTemp>endothermic</BodyTemp>
  </Habitat>
  <Habitat HabitatID="cage.2">
    <Type>Cats</Type>
    <Food>Birds</Food>
    <SmallCat AnimalID="tabycat.1">
      <Type>Tabycat</Type>
    </SmallCat>
    <BodyTemp>endothermic</BodyTemp>
  </Habitat>
  <ConsessionStand>
    <Type>PopcornStand</Type>
  </ConsessionStand>
</Zoo>

The output should look like:

<Zoo>
  <Habitat HabitatID="sub_habitat.1.habitat.cage.1">
    <Type>Cats</Type>
    <Food>Birds</Food>
    <BigCat AnimalID="Tiger.1">
      <Type>Bengal</Type>
    </BigCat>
  </Habitat>

  <Habitat HabitatID="sub_habitat.2.habitat.cage.1">
    <Type>Cats</Type>
    <Food>Birds</Food>
    <SmallCat AnimalID="bobcat.1">
      <Type>Bobcat</Type>
    </SmallCat>
  </Habitat>

  <Habitat HabitatID="habitat.cage.1">
    <BodyTemp>endothermic</BodyTemp>
    <Child>
        <HabitatID>sub_habitat.1.habitat.cage.1</HabitatID>
    </Child>
    <Child>
        <HabitatID>sub_habitat.2.habitat.cage.1</HabitatID>
    </Child>
  </Habitat>

  <Habitat HabitatID="cage.2">
    <Type>Cats</Type>
    <Food>Birds</Food>
    <SmallCat AnimalID="tabycat.1">
      <Type>Tabycat</Type>
    </SmallCat>
    <BodyTemp>endothermic</BodyTemp>
  </Habitat>
  <ConsessionStand>
    <Type>PopcornStand</Type>
  </ConsessionStand>
</Zoo>

The ideal solution will use XSLT but, any solution (bash, javascript, php, python, ruby, go, etc) that gets the job done is a worthy contender.

Here's an implementation that does ~90% of the work.

This solution does not reconstruct the first Habitat node with references to the new sub_habitat child nodes.

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

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

    <xsl:template match="Habitat[count(BigCat|SmallCat) &gt; 1]">
        <xsl:param name="i"/>
        <xsl:for-each select="BigCat|SmallCat">
          <xsl:choose>
            <xsl:when test="self::BigCat">
              <Habitat HabitatID="sub_habitat.{position()}.{../@HabitatID}">
                <xsl:copy-of select="../*[not(self::SmallCat|self::BodyTemp)]"/>
              </Habitat>
            </xsl:when>
            <xsl:when test="self::SmallCat">
              <Habitat HabitatID="sub_habitat.{position()}.{../@HabitatID}">
                <xsl:copy-of select="../*[not(self::BigCat|self::BodyTemp)]"/>
              </Habitat>
            </xsl:when>
          </xsl:choose> 
        </xsl:for-each>
    </xsl:template> 

</xsl:stylesheet>

The resulting output is seen here.

<Zoo>
  <Habitat HabitatID="sub_habitat.1.habitat.cage.1">
    <Type>Cats</Type>
    <Food>Birds</Food>
    <BigCat AnimalID="Tiger.1">
      <Type>Bengal</Type>
    </BigCat>
  </Habitat>
  <Habitat HabitatID="sub_habitat.2.habitat.cage.1">
    <Type>Cats</Type>
    <Food>Birds</Food>
    <SmallCat AnimalID="bobcat.1">
      <Type>Bobcat</Type>
    </SmallCat>
  </Habitat>
  <Habitat HabitatID="cage.2">
    <Type>Cats</Type>
    <Food>Birds</Food>
    <SmallCat AnimalID="tabycat.1">
      <Type>Tabycat</Type>
    </SmallCat>
    <BodyTemp>endothermic</BodyTemp>
  </Habitat>
  <ConsessionStand>
    <Type>PopcornStand</Type>
  </ConsessionStand>
</Zoo>
  • 写回答

2条回答 默认 最新

  • dongxiegao3071 2016-10-20 13:29
    关注

    What have you tried? Each of the rules in your prose description of the problem translates pretty directly into a template rule. For example, the rule:

    This experience contains more than 1 element (Audiovisual and Gallery), it will be reorganized as a set of 2 discrete experience children

    becomes something like

    <xsl:template match="Experience[count(Audiovisual|Gallery) gt 1]">
      <xsl:for-each select="AudioVisual|Gallery">
        <Experience ExperienceID="{../@ExperienceID}.ce.{position()}"/>
          <xsl:copy-of select="../*[not(self::AudioVisual|self::Gallery)]"/>
          <xsl:copy-of select="."/>
        </Experience>
      </xsl:for-each>
    </xsl:template> 
    

    Just go through all your rules and write a template rule for each one.

    评论

报告相同问题?

悬赏问题

  • ¥15 winform的chart曲线生成时有凸起
  • ¥15 msix packaging tool打包问题
  • ¥15 finalshell节点的搭建代码和那个端口代码教程
  • ¥15 用hfss做微带贴片阵列天线的时候分析设置有问题
  • ¥50 我撰写的python爬虫爬不了 要爬的网址有反爬机制
  • ¥15 Centos / PETSc / PETGEM
  • ¥15 centos7.9 IPv6端口telnet和端口监控问题
  • ¥120 计算机网络的新校区组网设计
  • ¥20 完全没有学习过GAN,看了CSDN的一篇文章,里面有代码但是完全不知道如何操作
  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录