【问题标题】:Spilt one node with X elements into X nodes with one of of these elements将具有 X 元素的一个节点溢出到具有这些元素之一的 X 节点中
【发布时间】:2013-02-25 16:38:36
【问题描述】:

有没有可能得到这样的转变:

源 XML:

<Item>
  <stockcode>XXX1</stockcode>
  <vehicle>Bentley</vehicle>
  <model>Continental GT (2006-)</model>
  <model>Continental Flying Spur (2006-)</model>
  <width>9</width>
  <wheel_size>20</wheel_size>  
  <offset>40</offset>
  <bolt_pattermn>5x112</bolt_pattermn>
  <brand>AEZ</brand>
  <Velg_ID>AEZ Myta</Velg_ID>
  <kit1>DK-ZJAE x1</kit1>
</Item>

目标 XML:

<Item>
  <stockcode>XXX1</stockcode>
  <vehicle>Bentley</vehicle>
  <model>Continental GT (2006-)</model>
  <width>9</width>
  <wheel_size>20</wheel_size>    
  <offset>40</offset>
  <bolt_pattermn>5x112</bolt_pattermn>
  <brand>AEZ</brand>
  <Velg_ID>AEZ Myta</Velg_ID>
  <kit1>DK-ZJAE x1</kit1>
  <qty_available>8.00000000</qty_available>
  <price>174.00</price>
  <picture>41010</picture>
  <pkpcena>195.4999</pkpcena>
</Item>
<Item>
  <stockcode>XXX1</stockcode>
  <vehicle>Bentley</vehicle>
  <model>Continental Flying Spur (2006-)</model>
</Item>

在源 XML 中有 1 个节点的 X 元素,必须将其划分为 X 节点的 1 个元素。目标 XML 可以包含源中的所有元素,也可以仅包含元素 &lt;vehicle&gt;&lt;model&gt;

如果是 - 有人可以给出提示吗? ;-)

谢谢!

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    这样就可以了:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="/">
        <root>
          <xsl:apply-templates select="//model" mode="split" />
        </root>
      </xsl:template>
    
      <xsl:template match="model" mode="split">
        <xsl:apply-templates select="..">
          <xsl:with-param name="currentModel" select="." />
        </xsl:apply-templates>
      </xsl:template>
    
      <xsl:template match="Item">
        <xsl:param name="currentModel" />
    
        <xsl:copy>
          <xsl:apply-templates
             select="@* | node()[not(self::model)] | $currentModel" />
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
    

    当应用于您的示例输入时,这会产生:

    <root>
      <Item>
        <stockcode>XXX1</stockcode>
        <vehicle>Bentley</vehicle>
        <model>Continental GT (2006-)</model>
        <width>9</width>
        <wheel_size>20</wheel_size>
        <offset>40</offset>
        <bolt_pattermn>5x112</bolt_pattermn>
        <brand>AEZ</brand>
        <Velg_ID>AEZ Myta</Velg_ID>
        <kit1>DK-ZJAE x1</kit1>
      </Item>
      <Item>
        <stockcode>XXX1</stockcode>
        <vehicle>Bentley</vehicle>
        <model>Continental Flying Spur (2006-)</model>
        <width>9</width>
        <wheel_size>20</wheel_size>
        <offset>40</offset>
        <bolt_pattermn>5x112</bolt_pattermn>
        <brand>AEZ</brand>
        <Velg_ID>AEZ Myta</Velg_ID>
        <kit1>DK-ZJAE x1</kit1>
      </Item>
    </root>
    

    这是一个我缩短了上述方法的实现,其中包含 Dimitre 技术的一些指针:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="model">
        <xsl:apply-templates select=".." mode="gen">
          <xsl:with-param name="currentModel" select="." />
        </xsl:apply-templates>
      </xsl:template>
    
      <xsl:template match="@* | node()" mode="gen">
        <xsl:param name="currentModel" select="/.." />
    
        <xsl:copy>
          <xsl:apply-templates
             select="@* | node()[not(self::model)] | $currentModel" 
             mode="gen" />
        </xsl:copy>
      </xsl:template>
      <xsl:template match="text()" />
    </xsl:stylesheet>
    

    【讨论】:

    • 非常感谢!它有效......这不仅仅是“一个提示”! ;-D
    • 很高兴为您提供帮助。我刚刚做了一个小修改,使 XSLT 更简洁一些,并避免使用generate-id()。并且不要忘记将此答案标记为已接受。谢谢! :)
    • JLRishe,您的解决方案仍然只适用于“模型”......如果用户指定重复元素的名称怎么办?
    • JLRishe,此外,您需要删除以下文字:“使用 Dimitre 技术中的一些指针,但可以处理具有两个以上 &lt;model&gt;s 的 &lt;Item&gt;s 和具有多个 @987654327 的文档@:"——这会误导读者相信我的答案有所谓的缺点,而实际上并没有。
    • 我已经删除了你现在提到的文字,它不再是真的了。我不认为提问者在寻找您所指的通用程度,所以我将保留我现在的答案。
    【解决方案2】:

    我。这种转变:

    <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="text()"/>
    
     <xsl:template match="model">
      <xsl:apply-templates select=".." mode="gen">
       <xsl:with-param name="pInclude" select="."/>
      </xsl:apply-templates>
     </xsl:template>
    
     <xsl:template match="node()|@*" mode="gen">
      <xsl:param name="pInclude" select="/.."/>
          <xsl:copy>
           <xsl:apply-templates mode="gen" select=
            "node()[not(name()=name($pInclude)) or count(.|$pInclude)=1]|@*" >
            <xsl:with-param name="pInclude" select="$pInclude"/>
           </xsl:apply-templates>
          </xsl:copy>
     </xsl:template>
    </xsl:stylesheet>
    

    应用于此 XML 文档时(提供的添加了第三个model 和多个Item 元素):

    <t>
        <Item>
            <stockcode>XXX1</stockcode>
            <vehicle>Bentley</vehicle>
            <model>Continental GT (2006-)</model>
            <model>Continental Flying Spur (2006-)</model>
            <model>Galactic Flying Spur (2006-)</model>
            <width>9</width>
            <wheel_size>20</wheel_size>
            <offset>40</offset>
            <bolt_pattermn>5x112</bolt_pattermn>
            <brand>AEZ</brand>
            <Velg_ID>AEZ Myta</Velg_ID>
            <kit1>DK-ZJAE x1</kit1>
        </Item>
        <Item>
            <stockcode>XXX1</stockcode>
            <vehicle>Bentley</vehicle>
            <model>XXX Continental GT (2006-)</model>
            <model>YYY Continental Flying Spur (2006-)</model>
            <model>ZZZ Galactic Flying Spur (2006-)</model>
            <width>9</width>
            <wheel_size>20</wheel_size>
            <offset>40</offset>
            <bolt_pattermn>5x112</bolt_pattermn>
            <brand>AEZ</brand>
            <Velg_ID>AEZ Myta</Velg_ID>
            <kit1>DK-ZJAE x1</kit1>
        </Item>
    </t>
    

    产生想要的正确结果:

    <Item>
       <stockcode>XXX1</stockcode>
       <vehicle>Bentley</vehicle>
       <model>Continental GT (2006-)</model>
       <width>9</width>
       <wheel_size>20</wheel_size>
       <offset>40</offset>
       <bolt_pattermn>5x112</bolt_pattermn>
       <brand>AEZ</brand>
       <Velg_ID>AEZ Myta</Velg_ID>
       <kit1>DK-ZJAE x1</kit1>
    </Item>
    <Item>
       <stockcode>XXX1</stockcode>
       <vehicle>Bentley</vehicle>
       <model>Continental Flying Spur (2006-)</model>
       <width>9</width>
       <wheel_size>20</wheel_size>
       <offset>40</offset>
       <bolt_pattermn>5x112</bolt_pattermn>
       <brand>AEZ</brand>
       <Velg_ID>AEZ Myta</Velg_ID>
       <kit1>DK-ZJAE x1</kit1>
    </Item>
    <Item>
       <stockcode>XXX1</stockcode>
       <vehicle>Bentley</vehicle>
       <model>Galactic Flying Spur (2006-)</model>
       <width>9</width>
       <wheel_size>20</wheel_size>
       <offset>40</offset>
       <bolt_pattermn>5x112</bolt_pattermn>
       <brand>AEZ</brand>
       <Velg_ID>AEZ Myta</Velg_ID>
       <kit1>DK-ZJAE x1</kit1>
    </Item>
    <Item>
       <stockcode>XXX1</stockcode>
       <vehicle>Bentley</vehicle>
       <model>XXX Continental GT (2006-)</model>
       <width>9</width>
       <wheel_size>20</wheel_size>
       <offset>40</offset>
       <bolt_pattermn>5x112</bolt_pattermn>
       <brand>AEZ</brand>
       <Velg_ID>AEZ Myta</Velg_ID>
       <kit1>DK-ZJAE x1</kit1>
    </Item>
    <Item>
       <stockcode>XXX1</stockcode>
       <vehicle>Bentley</vehicle>
       <model>YYY Continental Flying Spur (2006-)</model>
       <width>9</width>
       <wheel_size>20</wheel_size>
       <offset>40</offset>
       <bolt_pattermn>5x112</bolt_pattermn>
       <brand>AEZ</brand>
       <Velg_ID>AEZ Myta</Velg_ID>
       <kit1>DK-ZJAE x1</kit1>
    </Item>
    <Item>
       <stockcode>XXX1</stockcode>
       <vehicle>Bentley</vehicle>
       <model>ZZZ Galactic Flying Spur (2006-)</model>
       <width>9</width>
       <wheel_size>20</wheel_size>
       <offset>40</offset>
       <bolt_pattermn>5x112</bolt_pattermn>
       <brand>AEZ</brand>
       <Velg_ID>AEZ Myta</Velg_ID>
       <kit1>DK-ZJAE x1</kit1>
    </Item>
    

    二。一个更通用且更短的转换,其中要拆分的元素名称作为(外部)参数传递

    <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:param name="pName" select="'model'"/>
    
     <xsl:template match="*">
      <xsl:apply-templates select="parent::*[$pName = name(current())]" mode="gen">
       <xsl:with-param name="pInclude" select="."/>
      </xsl:apply-templates>
      <xsl:apply-templates/>
     </xsl:template>
    
     <xsl:template match="node()|@*" mode="gen">
      <xsl:param name="pInclude" select="/.."/>
    
          <xsl:copy>
           <xsl:apply-templates mode="gen" select=
           "node()[not(name()=name($pInclude)) or count(.|$pInclude)=1]|@*" >
            <xsl:with-param name="pInclude" select="$pInclude"/>
           </xsl:apply-templates>
          </xsl:copy>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    三。此类通用问题的最通用解决方案

    看到这个答案:https://stackoverflow.com/a/8597577/36305

    【讨论】:

    • 这不是附加要求。 OP 声明:“在源 XML 中有 1 个节点的 X 元素,必须将其划分为 X 节点的 1 个元素。”除此之外,正如您前段时间告诉我的,重要的是预测 OP 可能需要什么,而不仅仅是解决简化的示例。对提问者过去问题的视图显示了类似的 XML,其中多个 &lt;model&gt;s 对应一个 &lt;Item&gt;
    • @JLRishe,是的,但问题的标题是“将 1 个节点中的 2 个元素拆分为 2 个元素和 2 个节点”......我编辑了标题,所以现在它不会误导。感谢您澄清这一点。第一个夏季约会时间节省周日早上我有点困(嗯,...中午!)但即使在这种情况下仍然可以产生明显更短和更通用的解决方案:)
    猜你喜欢
    • 1970-01-01
    • 2012-09-02
    • 2021-12-24
    • 2019-12-03
    • 1970-01-01
    • 2013-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多