【问题标题】:Split xml from nth element to xth element将 xml 从第 n 个元素拆分为第 x 个元素
【发布时间】:2013-08-19 05:07:15
【问题描述】:

下面是我的 XML 结构:

<cars>  
  <car>  
    <ford color="black" >eco sport</ford>    
    <maruti color="red" >zen</maruti>  
    <hyundai color="blue" >accent</hyundai>  
  </car>  
  <car>  
    <ford color="green" >figo</ford >    
    <maruti color="red" >swift</maruti>  
    <hyundai color="white" >santro</hyundai>  
  </car> 
  <car>  
    <ford color="red" >aaa</ford >    
    <maruti color="red" >bbb</maruti>  
    <hyundai color="red" >ccc</hyundai>  
  <car>  
  </car>
    <ford color="white" >ddd</ford >    
    <maruti color="white" >eee</maruti>  
    <hyundai color="white" >fff</hyundai>  
  </car>
</cars>

从上面的 XML 结构中,我需要在 java 中有一个解析器,它将拆分 xml 并返回一个只有 2 或 3 个元素(如来自 1-2 或 2-3 或 2-4)的 xml动态指定元素行。所以如果我在方法splitXML(2,3) 中传递参数,我返回的新xml 应该是这样的:

<cars>  
    <car>  
      <ford color="green" >figo</ford >    
      <maruti color="red" >swift</maruti>  
      <hyundai color="white" >santro</hyundai>  
    </car> 
    <car>  
      <ford color="red" >aaa</ford >    
      <maruti color="red" >bbb</maruti>  
      <hyundai color="red" >ccc</hyundai>  
    </car>  
</cars>  

有人能帮帮我吗?

【问题讨论】:

    标签: java xml xslt xml-parsing xslt-1.0


    【解决方案1】:

    在 XSLT 2.0 中,您可以使用 subsequence()。 (我知道这个问题被标记为 1.0,但也许这会对未来的访问者有所帮助。)

    XML 输入

    <cars>  
        <car>  
            <ford color="black" >eco sport</ford>    
            <maruti color="red" >zen</maruti>  
            <hyundai color="blue" >accent</hyundai>  
        </car>  
        <car>  
            <ford color="green" >figo</ford >    
            <maruti color="red" >swift</maruti>  
            <hyundai color="white" >santro</hyundai>  
        </car> 
        <car>  
            <ford color="red" >aaa</ford >    
            <maruti color="red" >bbb</maruti>  
            <hyundai color="red" >ccc</hyundai>  
        </car>  
        <car>
            <ford color="white">ddd</ford>
            <maruti color="white">eee</maruti>
            <hyundai color="white">fff</hyundai>
        </car>
    </cars>
    

    XSLT 2.0

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:param name="start" select="2"/>
        <xsl:param name="end" select="3"/>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="cars">
            <xsl:copy>
                <xsl:apply-templates select="@*|subsequence(car,$start,($end - $start)+1)"/>
            </xsl:copy>
        </xsl:template>
    
    </xsl:stylesheet>
    

    XML 输出

    <cars>
       <car>
          <ford color="green">figo</ford>
          <maruti color="red">swift</maruti>
          <hyundai color="white">santro</hyundai>
       </car>
       <car>
          <ford color="red">aaa</ford>
          <maruti color="red">bbb</maruti>
          <hyundai color="red">ccc</hyundai>
       </car>
    </cars>
    

    【讨论】:

      【解决方案2】:

      您可以使用基于Identity transform 的xslt,您可以将具有所需范围的参数传递到其中(如何完成的方式取决于您使用的xslt 处理器)。 XSLT 可能如下所示

      <?xml version="1.0" encoding="UTF-8"?>
      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
          <xsl:output method="xml" />
      
          <!-- Take a start and end position to be output as a parameters from outside-->
          <xsl:param name="startPosition"  />
          <xsl:param name="endPosition"  />
      
          <!-- Use "Identity transform" -->
          <xsl:template match="node() | @*">
              <xsl:copy>
                  <xsl:apply-templates select="node() | @*" />
              </xsl:copy>
          </xsl:template>
      
          <!-- When you are processing car element... -->
          <xsl:template match="car">
              <!-- ... take a look at its position. Copy it only if its position is in the desired range -->
              <xsl:if test="not((position() &lt; $startPosition) or (position() &gt; $endPosition))">
                  <xsl:copy>
                      <xsl:apply-templates select="node() | @*" />
                  </xsl:copy>
              </xsl:if>
          </xsl:template>
      </xsl:stylesheet>
      

      使用值 startPosition = 2 和 endPosition = 3,您将获得以下输出

      <?xml version="1.0" encoding="UTF-8"?>
      <cars>
          <car>
              <ford color="green">figo</ford>
              <maruti color="red">swift</maruti>
              <hyundai color="white">santro</hyundai>
          </car>
          <car>
              <ford color="red">aaa</ford>
              <maruti color="red">bbb</maruti>
              <hyundai color="red">ccc</hyundai>
          </car>
      </cars>
      

      这只是一个概念。实际上,您应该检查参数的一些约束,例如它们是否是数字,endPosition 是否不低于 startPosition 等。

      【讨论】:

      • 我认为您需要&lt;xsl:strip-space elements="*"/&gt;&lt;xsl:strip-space elements="cars"/&gt; 才能使position() 按预期工作,除非您使用像MSXML 这样默认去除空白的XML 解析器。
      • 我尝试了 Altova 并且成功了。但是,是的,您是对的,根据您的建议,解决方案将更加强大。
      【解决方案3】:

      您需要一个 XML 解析器。网上有很多资源。这是一篇关于阅读和操作 XML 的simple tutorial

      【讨论】:

        猜你喜欢
        • 2012-07-09
        • 1970-01-01
        • 2023-03-12
        • 2021-10-03
        • 2019-06-29
        • 2015-01-12
        • 2014-07-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多