【问题标题】:Convert one xml file to another xml file using xsl transformation使用 xsl 转换将一个 xml 文件转换为另一个 xml 文件
【发布时间】:2012-07-04 00:21:40
【问题描述】:

这与 XSL 转换有关。 输入.xml

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/x/transform.xsl"?>
<!-- input file root node-->
<message>           
    <header>
     <!--Many descendents will be there -->
    </header>
    <body>
     <!-- some other several elements will be there-->
      <TaskList>
        <TaskItem>
          <DataPoint>
            <Name>software.prog_name</Name>
            <Target>JAVA</Target>
          </DataPoint>
          <DataPoint>
            <Name>software.prog_rev</Name>
            <Target>1</Target>
          </DataPoint>
          <DataPoint>
            <Name>software.sw_product_id</Name>
            <Target>1000</Target>
          </DataPoint>
          <DataPoint>
            <Name>software.limits_file_name</Name>
            <Target>limits.txt</Target>
          </DataPoint>
          <DataPoint>
            <Name>software.limits_file_rev</Name>
            <Target>2</Target>
          </DataPoint>
          <DataPoint>
            <Name>hw_exp.class</Name>
            <Target>Car</Target>    
          </DataPoint>
          <DataPoint>
            <Name>hw_exp.type</Name>
            <Target>B</Target>
          </DataPoint>
          <DataPoint>
            <Name>hw_exp.rev</Name>
            <Target>32</Target>
          </DataPoint>
          <DataPoint>
            <Name>prompt_id</Name>
            <Target>100</Target>
          </DataPoint>
        </TaskItem>
        <AutomationParam>
          <Profile>Profile 1</Profile>
          <SubGroup>1</SubGroup>
          <Name>software.prog_name</Name>
          <Value>JAVA</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>1</SubGroup>
         <Name>software.sw_product_id</Name>
         <Value>1000</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>2</SubGroup>
         <Name>hw_exp.class</Name>
         <Value>Animal</Value>  
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>2</SubGroup>
         <Name>hw_exp.type</Name>
         <Value>B</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>3</SubGroup>
         <Name>hw_exp.class</Name>
         <Value>Flight</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>3</SubGroup>
         <Name>hw_exp.type</Name>
         <Value>E</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>3</SubGroup>
         <Name>hw_exp.rev</Name>
         <Value>1</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 2</Profile>
         <SubGroup>1</SubGroup>
         <Name>software.sw_product_id</Name>
         <Value>1000</Value>
       </AutomationParam>    
     </TaskList>
   </body>
 </message>

在 input.xml 上应用 XSL 转换后,生成的文件为 output.xml output.xml(应该是这样的)

<?xml version="1.0" encoding="utf-8"?>
<!-- output file root node-->
<text>    
  <header>
    <!--All descendents will/should be copied as it is-->
  </header>
  <body>
    <sub_body>
     <!-- All such several elements from input.xml will/should be there-->
     <test_profile>
       <software>
         <prog_name>JAVA</prog_name>
         <prog_rev>1</prog_rev>
         <sw_product_id>1000</sw_product_id>
         <limits_file_name>limits.txt</limits_file_name>
         <limits_file_rev>2</limits_file_rev>
       </software>
       <hw_exp>
         <class>Car</class>
         <type>B</type>
         <rev>32</rev>
       </hw_exp>
       <prompt_id>100</prompt_id>
     </test_profile>
     <test_profile>
       <software>
         <prog_name>JAVA</prog_name>
         <sw_product_id>1000</sw_product_id>
       </software>
       <hw_exp>
         <class>Animal</class>
         <type>B</type>
       </hw_exp>
       <hw_exp>
         <class>Flight</class>
         <type>E</type>
         <rev>1</rev>
       </hw_exp>
     </test_profile>
     <test_profile>
       <software>
         <sw_product_id>1000</sw_product_id>
       </software>
     </test_profile>
   </sub_body>
 </body>

请有人帮助我实现这一目标,那将是一个很大的帮助。我需要 XSL 1.0(但不是 2.x +)代码。

映射规则: a) output.xml 中的一个 记录应该映射到 input.xml 中的整个 TaskList.TaskItem b) 您在 output.xml 中看到额外的两个 元素 [records],因为您在 input.xml 中看到 元素的值为 Profile 1 和 Profile 2 [这意味着所有与 Profile 1 相关的东西都应该放在一个不同的 中,而所有与 Profile 2 相关的东西都应该放在另一个不同的 中。 c)

元素及其全部内容(可以是多个后代)应按原样复制。 d) 不是固定数量的元素。这些东西可以是 0 [要么没有] 到无穷大 [许多],这意味着一切都应该动态完成,而且可以有 0 到多个配置文件 [即配置文件 1、配置文件 2、配置文件 3 ......它可以是任何字符串,如jack, jill etc..,] 用于 AutomationParams

注意:认为这个 input.xml 文件是根据数据库中的记录动态填充的。

【问题讨论】:

  • 您好,如果问题不清楚,请在此处评论,我会尝试详细说明...但我特意寻找合乎逻辑的想法,因为它有点棘手..
  • 您的问题与其说是一个问题,不如说是一个“你能为我做这件事”的问题。你能告诉我们你的一些尝试吗?您是否完全不熟悉 XSLT?如果是这样,互联网上充满了很棒的教程。 W3Schools 受到了很多批评,但我仍然觉得这是最好的起点:w3schools.com/xsl。如果您有任何其他问题,请尝试并回来!
  • @SandyGifford 我尝试了所有我能做的基本事情。实际上我对 XSL 很陌生。我尝试在某种程度上进行编码。我被困在 //DataPoint.Name 的 prompt_id 值。它没有“。”在里面。所以对我来说使用模板变得有点复杂。但是,无论谁保留答案,我也在寻求解释。我知道这可以通过使用两遍变换来完成,但我没有得到任何解决方案/想法来实现这一点(但我可以说这很棘手,需要正确理解这个问题)
  • 如果你能发布你目前拥有的 XSLT 还是很好的,这样我们就可以从你所在的地方为你提供帮助。
  • 你需要解释一下变换的规则。这些不能简单地从您当前的示例文档中推断出来。例如,有 3 个输出 test_profile 节点。关于最后两个来自哪里没有明显的规则。可以有超过 3 个 test_profile 节点吗?如果有,它取决于什么?

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


【解决方案1】:

这不是一个完整的解决方案。你的问题太不清楚了,不允许这样做。此 XSLT 1.0 样式表可能会为您提供自己的解决方案提供有用的指示。

这个样式表 ...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>

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

<xsl:template match="body">
 <xsl:copy>
  <sub_body>
   <test_profile>
    <xsl:apply-templates select="TaskList/TaskItem"/>
   </test_profile>
  </sub_body>
 </xsl:copy>
</xsl:template>

<xsl:template match="TaskItem">
 <test_profile>
  <software>
   <prog_name><xsl:value-of select="DataPoint[Name='software.prog_name']/Target" /></prog_name>
    <prog_rev><xsl:value-of select="DataPoint[Name='software.prog_re']/Target"/></prog_rev>
   <sw_product_id><xsl:value-of select="DataPoint[Name='software.sw_product_id']/Target"/></sw_product_id>
   <limits_file_name><xsl:value-of select="DataPoint[Name='software.limits_file_name']/Target"/></limits_file_name>
   <limits_file_rev><xsl:value-of select="DataPoint[Name='software.limits_file_rev']/Target" /></limits_file_rev>
  </software>
  <hw_exp>
   <class><xsl:value-of select="DataPoint[Name='hw_exp.class']/Target" /></class>
   <type><xsl:value-of select="DataPoint[Name='hw_exp.type']/Target" /></type>
   <rev><xsl:value-of select="DataPoint[Name='hw_exp.rev']/Target" /></rev>
  </hw_exp>
  <prompt_id><xsl:value-of select="DataPoint[Name='prompt_id']/Target" /></prompt_id>
 </test_profile>
</xsl:template>

</xsl:stylesheet>

...当应用于您的示例输入时,将生成所需输出的第一个 test_profile 节点。您还没有解释与其他两个 test_profile 节点相关的转换规则。


更新

此样式表将使用 muenchian 分组和运行时计算的元素名称来生成额外的 test_profile 节点并按子组组织 hw_exp 节点。

这个样式表 ...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>

<xsl:key name="param-by-profile" match="AutomationParam" use="substring-after( Profile, 'Profile ')" />
<xsl:key name="subgroup" match="AutomationParam" use="SubGroup" />

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

<xsl:template match="body">
 <xsl:copy>
  <sub_body>
    <xsl:apply-templates select="TaskList/TaskItem"/>
    <xsl:for-each select="TaskList/AutomationParam[
      generate-id(.) = generate-id( key('param-by-profile', substring-after( Profile, 'Profile '))[1])
      ]">
        <xsl:sort data-type="number" select="substring-after( Profile, 'Profile ')" />
        <xsl:call-template name="profile-from-param">
          <xsl:with-param name="automations" select="key('param-by-profile',substring-after( Profile, 'Profile '))" />
        </xsl:call-template>  
    </xsl:for-each>
  </sub_body>
 </xsl:copy>
</xsl:template>

<xsl:template match="TaskItem">
 <test_profile>
  <software>
   <prog_name><xsl:value-of select="DataPoint[Name='software.prog_name']/Target" /></prog_name>    
   <prog_rev><xsl:value-of select="DataPoint[Name='software.prog_rev']/Target"/></prog_rev>
   <sw_product_id><xsl:value-of select="DataPoint[Name='software.sw_product_id']/Target"/></sw_product_id>
   <limits_file_name><xsl:value-of select="DataPoint[Name='software.limits_file_name']/Target"/></limits_file_name>
   <limits_file_rev><xsl:value-of select="DataPoint[Name='software.limits_file_rev']/Target" /></limits_file_rev>
  </software>
  <hw_exp>
   <class><xsl:value-of select="DataPoint[Name='hw_exp.class']/Target" /></class>
   <type><xsl:value-of select="DataPoint[Name='hw_exp.type']/Target" /></type>
   <rev><xsl:value-of select="DataPoint[Name='hw_exp.rev']/Target" /></rev>
  </hw_exp>
  <prompt_id><xsl:value-of select="DataPoint[Name='prompt_id']/Target" /></prompt_id>
 </test_profile>
</xsl:template>

<xsl:template name="profile-from-param">
 <xsl:param name="automations" />
 <test_profile>
  <software>
   <xsl:apply-templates select="$automations[SubGroup=1]" /> 
  </software>
  <xsl:for-each select="$automations
    [generate-id(.) = generate-id( key('subgroup', SubGroup)[1])]
    [SubGroup >= 2]
    ">
    <xsl:sort data-type="number" select="SubGroup" />
    <xsl:call-template name="hw-group">
      <xsl:with-param name="automations" select="key('subgroup', SubGroup)" />
    </xsl:call-template>  
   </xsl:for-each>    
 </test_profile>  
</xsl:template>  

<xsl:template name="hw-group">
  <xsl:param name="automations" />
  <hw_exp>
   <xsl:apply-templates select="$automations" /> 
  </hw_exp>
</xsl:template>  

<xsl:template match="AutomationParam">
 <xsl:element name="{substring-after(Name,'.')}"> 
  <xsl:value-of select="Value" />
 </xsl:element>
</xsl:template>

</xsl:stylesheet>

...当应用于提供的示例输入时,将生成此文档...

<?xml version="1.0" encoding="utf-8"?>
<message>           
 <header>
     <!--Many descendents will be there -->
 </header>
 <body>
  <sub_body>

   <test_profile>
    <software>
     <prog_name>JAVA</prog_name>
     <prog_rev>1</prog_rev>
     <sw_product_id>1000</sw_product_id>
     <limits_file_name>limits.txt</limits_file_name>
     <limits_file_rev>2</limits_file_rev>
    </software>
    <hw_exp>
     <class>Car</class>
     <type>B</type>
     <rev>32</rev>
    </hw_exp>
    <prompt_id>100</prompt_id>
   </test_profile>

   <test_profile>
    <software>
     <prog_name>JAVA</prog_name>
     <sw_product_id>1000</sw_product_id>
    </software>
    <hw_exp>
     <class>Animal</class>
     <type>B</type>
    </hw_exp>
    <hw_exp>
     <class>Flight</class>
     <type>E</type>
     <rev>1</rev></hw_exp>
    </test_profile>

    <test_profile>
     <software>
      <sw_product_id>1000</sw_product_id>
     </software>
    </test_profile>

  </sub_body>
 </body>
 </message>

【讨论】:

  • Sean,所有与 DataPoint 相关的东西都应该放在一个单独的测试配置文件中。但是 相关的东西会根据 标签进入多个测试配置文件,并且在那个单独的 中可以有多个 记录,因此所有这些与软件相关的东西都由 标签标识。
  • 如果您仍然不清楚这个问题,请随时提问。与我的 Q 相关的所有内容都可以使用 input.xml 和 output.xml 中元素中的值进行分析
  • 我想我会在短时间内从@Dimitre Novatchev 那里得到一些答案,因为我看到他回答了一些类似的问题,但我开始知道我的 Q 本身并不清楚。但现在我认为问题很清楚了。
  • 感谢肖恩的努力。你的回答给了我一个解决问题的方法,即使你的回答不完整。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-18
  • 1970-01-01
相关资源
最近更新 更多