【问题标题】:How to transform XML input with multiple identical elements into XML output without identical elements如何将具有多个相同元素的 XML 输入转换为没有相同元素的 XML 输出
【发布时间】:2012-03-20 18:17:13
【问题描述】:

我尝试将包含多个相同元素的 xml 输入文件转换为一个新的 xml 文件,该文件将所有相同的元素合并为一个。输入文件是这样的

<?xml version="1.0"?>
<InputShipmentSchedule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<DataArea>
    <ShipmentSchedule>
        <ShipmentScheduleLine>
            <ManufacturingItem>
                <ItemID>
                    <ID>P313503</ID>
                </ItemID>
            </ManufacturingItem>                
        </ShipmentScheduleLine>
        <ShipmentScheduleLine>
            <ManufacturingItem>
                <ItemID>
                    <ID>P313503</ID>
                </ItemID>
            </ManufacturingItem>            
        </ShipmentScheduleLine>
        <ShipmentScheduleLine>
            <ManufacturingItem>
                <ItemID>
                    <ID>P313504</ID>
                </ItemID>
            </ManufacturingItem>            
        </ShipmentScheduleLine>
        <ShipmentScheduleLine>
            <ManufacturingItem>
                <ItemID>
                    <ID>P313504</ID>
                </ItemID>
            </ManufacturingItem>            
        </ShipmentScheduleLine>
    </ShipmentSchedule>
</DataArea>
</InputShipmentSchedule>

我制作了以下 xsl 转换器文件:

<?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="UTF-8" omit-xml-declaration="no" indent="yes"/>
<xsl:preserve-space elements="*"/>
<xsl:template match="InputShipmentSchedule">
    <xsl:call-template name="CreateShipmentScheduleXmlns"/>
</xsl:template>

<xsl:template name="CreateShipmentScheduleXmlns">
    <xsl:element name="Output_Data">
        <xsl:element name="ShipmentSchedule">
                <xsl:call-template name="part_detail_template">
                    <xsl:with-param name="currentPartLine" select="DataArea/ShipmentSchedule/ShipmentScheduleLine"/>
                    <xsl:with-param name="nextPartLine" select="DataArea/ShipmentSchedule/ShipmentScheduleLine/following-sibling::ShipmentScheduleLine"/>
                </xsl:call-template>                
        </xsl:element>  <!-- ShipmentSchedule tag end -->
    </xsl:element>  <!-- Output_Data tag end -->
</xsl:template> <!-- CreateShipmentScheduleXmlns template end -->

<xsl:template name="part_detail_template">
    <xsl:param name="currentPartLine"/>
    <xsl:param name="nextPartLine"/>
    <xsl:element name="Part_Detail">  <!-- Part_Detail tag start -->
        <xsl:variable name="part_no" select="$currentPartLine/ManufacturingItem/ItemID/ID"/>
        <xsl:element name="part_no">
            <xsl:attribute name="value">
                <xsl:value-of select="$part_no"/>
            </xsl:attribute>
        </xsl:element>
    </xsl:element>  <!-- Part_Detail tag end -->
    <xsl:variable name="currentItem" select="$currentPartLine/ManufacturingItem/ItemID/ID"/>
    <xsl:variable name="nextItem" select="$nextPartLine/ManufacturingItem/ItemID/ID"/>
    <xsl:choose>            
        <xsl:when test="$nextPartLine and $nextItem != $currentItem">
            <xsl:call-template name="part_detail_template">
                <xsl:with-param name="currentPartLine" select="$nextPartLine"/>
                <xsl:with-param name="nextPartLine" select="$nextPartLine/following-sibling::ShipmentScheduleLine"/>
            </xsl:call-template>
        </xsl:when>
    </xsl:choose>
</xsl:template>  <!-- part_detail_template tag end -->                                        
</xsl:stylesheet>

但输出的 xml 文件中仍然包含冗余的 P313503 如下:

<?xml version="1.0" encoding="UTF-8"?>
<Output_Data>
<ShipmentSchedule>
<Part_Detail>
<part_no value="P313503"/>
</Part_Detail>
<Part_Detail>
<part_no value="P313503"/>
</Part_Detail>
<Part_Detail>
<part_no value="P313504"/>
</Part_Detail>
</ShipmentSchedule>
</Output_Data>

我不知道为什么“part_no”元素(“P313503”)会出现两次。它应该在输出 xml 文件中包含非冗余的“part_no”元素。我在上面的 xsl 文件中做错了什么?任何意见或建议将不胜感激。 提前致谢。

【问题讨论】:

    标签: xml xslt


    【解决方案1】:
                    <xsl:with-param name="currentPartLine" 
                    select="DataArea/ShipmentSchedule/ShipmentScheduleLine"/>
                    <xsl:with-param name="nextPartLine" 
                    select="DataArea/ShipmentSchedule/ShipmentScheduleLine/
                                       following-sibling::ShipmentScheduleLine"/>
    

    这两个表达式选择相同的节点集。 DataArea/ShipmentSchedule/ShipmentScheduleLine 选择所有 ShipmentScheduleLine 元素而不仅仅是第一个,因此添加following-sibling::ShipmentScheduleLine 不会选择任何不同的节点。

    XSLT2 中的分组问题比 XSLT1 容易得多,但假设您由于某种原因被困在 1 中。谷歌搜索“muenchian grouping”,它将引导您找到此解决方案:

    <xsl:stylesheet version="1.0"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>
    
    <xsl:key name="n" match="ItemID" use="ID"/>
    
    <xsl:template match="/">
     <Output_Data>
      <ShipmentSchedule>
       <xsl:for-each select="//ManufacturingItem/ItemID[generate-id()=
                 generate-id(key('n',.))]">
        <Part_Detail>
         <part_no value="{.}"/>
        </Part_Detail>
       </xsl:for-each>
      </ShipmentSchedule>
     </Output_Data>
    </xsl:template>
    
    </xsl:stylesheet>
    

    产生:

    $ saxon man.xml man.xsl
    <?xml version="1.0" encoding="utf-8"?>
    <Output_Data>
       <ShipmentSchedule>
          <Part_Detail>
             <part_no value="P313503"/>
          </Part_Detail>
          <Part_Detail>
             <part_no value="P313504"/>
          </Part_Detail>
       </ShipmentSchedule>
    </Output_Data>
    

    【讨论】:

    • 感谢您的回答。但是如何使第一个表达式只选择第一个节点,而不是所有 ShipmentScheduleLine?我试过“DataArea/ShipmentSchedule/ShipmentScheduleLine/.”。它没有删除输出 xml 文件中多余的“part_no”元素(“P313503”)。
    • DataArea/ShipmentSchedule/ShipmentScheduleLine[1] 将选择第一个
    • 如评论中所述,添加数字谓词可能会使其工作,但重复搜索完整路径无论如何都是低效的,最好使用不同的分组习语,请参阅更新的答案
    • 太棒了!您建议的“muenchian group”可以满足我的要求。非常感谢,大卫。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 2017-07-11
    • 2011-04-17
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    相关资源
    最近更新 更多