【问题标题】:XSLT: Copy a group of nodes with incrementing valuesXSLT:复制一组具有递增值的节点
【发布时间】:2020-01-25 03:46:59
【问题描述】:

我有一个如下所示的 XML:

<request>
    <MaterialOrderItems>
        <Item>
            <LineId>1</LineId>
            <ParentLineId>1</ParentLineId>
        </Item>
        <Item>
            <LineId>2</LineId>
            <ParentLineId>1</ParentLineId>
        </Item>
        <Item>
            <LineId>3</LineId>
            <ParentLineId>1</ParentLineId>
        </Item>
    </MaterialOrderItems>
</request>

我想获取此 XML,并将此项目组 (Item[1,2,3]) 复制为多个副本。例如,如果我想要 2 个副本,我的最终 xml 将如下所示:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<request>
    <MaterialOrderItems>
    <Item>
      <LineId>1</LineId>
      <ParentLineId>1</ParentLineId>
    </Item>
    <Item>
      <LineId>2</LineId>
      <ParentLineId>1</ParentLineId>
    </Item>
    <Item>
      <LineId>3</LineId>
      <ParentLineId>1</ParentLineId>
    </Item>
    <Item>
      <LineId>4</LineId>
      <ParentLineId>4</ParentLineId>
    </Item>
    <Item>
      <LineId>5</LineId>
      <ParentLineId>4</ParentLineId>
    </Item>
    <Item>
      <LineId>6</LineId>
      <ParentLineId>4</ParentLineId>
    </Item>
    </MaterialOrderItems>
</request>

我想出了这个 xslt 来做到这一点:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns="http://www.w3.org/1999/xhtml" version="1.0">
    <xsl:output encoding="UTF-8" indent="yes" method="xml" standalone="no" 
         omit-xml-declaration="no"/>

<xsl:param name="nmaterials" select="2" />

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


<xsl:template match="//MaterialOrderItems" name="order">
    <xsl:param name="material_number" select="1" />

    <xsl:copy>
          <Item>
            <LineId><xsl:value-of select="((($material_number - 1) * 3) + 1)"/></LineId>
            <ParentLineId><xsl:value-of select="((($material_number - 1) * 3) + 1)"/></ParentLineId>
          </Item>
          <Item>
            <LineId><xsl:value-of select="((($material_number - 1) * 3) + 2)"/></LineId>
            <ParentLineId><xsl:value-of select="((($material_number - 1) * 3) + 1)"/></ParentLineId>
          </Item>
          <Item>
            <LineId><xsl:value-of select="((($material_number - 1) * 3) + 3)"/></LineId>
            <ParentLineId><xsl:value-of select="((($material_number - 1) * 3) + 1)"/></ParentLineId>
          </Item>
    </xsl:copy>

    <xsl:if test="$material_number &lt; $nmaterials">
        <xsl:apply-templates select=".">
            <xsl:with-param name="material_number" select="$material_number + 1" />
        </xsl:apply-templates>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

我得到了这个输出:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<request>
  <MaterialOrderItems>
    <Item>
      <LineId>1</LineId>
      <ParentLineId>1</ParentLineId>
    </Item>
    <Item>
      <LineId>2</LineId>
      <ParentLineId>1</ParentLineId>
    </Item>
    <Item>
      <LineId>3</LineId>
      <ParentLineId>1</ParentLineId>
    </Item>
  </MaterialOrderItems>
  <MaterialOrderItems>
    <Item>
      <LineId>4</LineId>
      <ParentLineId>4</ParentLineId>
    </Item>
    <Item>
      <LineId>5</LineId>
      <ParentLineId>4</ParentLineId>
    </Item>
    <Item>
      <LineId>6</LineId>
      <ParentLineId>4</ParentLineId>
    </Item>
  </MaterialOrderItems>
</request>

我有两个问题:

  1. 如何去掉重复的 MaterialOrderItems 节点?我只想要一次包含所有项目。
  2. 如何以更好的方式处理原始 xml?目前,我正在对我的 XSL 模板中的原始 xml 进行硬编码。应该有更好的方法来做到这一点。

请帮忙。

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    试试下面的代码

    https://xsltfiddle.liberty-development.net/3NSTbeS查看转换

        <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
        <xsl:output indent="yes"/>
    
        <xsl:template match="node() | @*">
            <xsl:copy>
                <xsl:apply-templates select="node() | @*"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:param name="nmaterials" select="2"/>
    
        <xsl:template match="MaterialOrderItems">
            <xsl:param name="material_number" select="1"/>
            <xsl:variable name="countitem" select="count(Item)"/>
            <xsl:copy>
                <xsl:copy-of select="*"/>
                <xsl:if test="$material_number != $nmaterials">
                    <xsl:call-template name="Copy">
                        <xsl:with-param name="data" select="."/>
                        <xsl:with-param name="material_number" select="$material_number + 1"/>
                        <xsl:with-param name="countitem" select="$countitem"/>
                    </xsl:call-template>
                </xsl:if>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template name="Copy">
            <xsl:param name="data"/>
            <xsl:param name="material_number"/>
            <xsl:param name="countitem"/>
            <xsl:for-each select="$data/Item">
                <xsl:variable name="position" select="position()"/>
                <xsl:apply-templates select=".">
                    <xsl:with-param name="pos" select="$position"/>
                    <xsl:with-param name="material_number" select="$material_number"/>
                    <xsl:with-param name="countitem" select="$countitem"/>
                </xsl:apply-templates>
            </xsl:for-each>
            <xsl:if test="$material_number != $nmaterials">
                <xsl:call-template name="Copy">
                    <xsl:with-param name="data" select="$data"/>
                    <xsl:with-param name="material_number" select="$material_number + 1"/>
                    <xsl:with-param name="countitem" select="$countitem"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:template>
    
        <xsl:template match="Item">
            <xsl:param name="pos"/>
            <xsl:param name="material_number"/>
            <xsl:param name="countitem"/>
            <xsl:copy>
                <LineId>
                    <xsl:value-of select="((($material_number - 1) * $countitem) + $pos)"/>
                </LineId>
                <ParentLineId>
                    <xsl:value-of select="((($material_number - 1) * $countitem) + 1)"/>
                </ParentLineId>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 谢谢。看起来不错,我会检查它并在几个小时内返回。
    猜你喜欢
    • 2018-12-30
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 2023-03-16
    • 2017-09-10
    相关资源
    最近更新 更多