使用xslt生成多个xml文件

时间:2013-08-11 19:25:31

标签: xml xslt xml-parsing xslt-2.0

我正在尝试使用xslt生成多个xml文件。 我的* input.xm * l文件是

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"     
<soapenv:Body>
 <ns1:getDocumentByKeyResponse   soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:ns1="http://www.taleo.com/ws/integration/toolkit/2005/07">
 <Document xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">
<Attributes>
 <Attribute name="duration">0:00:00.084</Attribute>
 <Attribute name="count">7</Attribute>
<Attribute name="entity">Requisition</Attribute>
<Attribute name="mode">XML</Attribute>
<Attribute name="version">http://www.taleo.com/ws/tee800/2009/01</Attribute>
</Attributes>
<Content>
<ExportXML xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">
 <record>
<field name="ContestNumber">1300000F</field>
  <field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">1300000H</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">1300000T</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">13000018</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">000123</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">1300000R</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">13000016</field>
 <field name="ManagerRequisitionTitle">Project Manager</field>
 </record>
</ExportXML>
</Content>
</Document>
</ns1:getDocumentByKeyResponse>
</soapenv:Body>
</soapenv:Envelope>

我的xslt是sample.xslt

<xsl:stylesheet version="2.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="pDest" select="'file:///c:/temp/'"/>
<xsl:template match="*[starts-with(name(),'ExportXML')]">
<xsl:for-each select="record">
<xsl:result-document href="{$pDest}section{position()}.xml">
<JobPositionPostings>
<JobPositionPosting>
<xsl:apply-templates select="*:field[starts-with(@name,'ContestNumber')]"/>
 <JobDisplayOptions>
 <xsl:apply-templates select="*:field[starts-with(@name,'ManagerRequisitionTitle')]"/>
 </JobDisplayOptions>
</JobPositionPosting>
</JobPositionPostings>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

我没有得到正确的输出。我希望每个输入标签数据都包含在这样的单独文件中

  <?xml version="1.0" encoding="UTF-8"?>
  </JobPositionPostings>
  <JobPositionPostings>
  <JobPositionPosting>
 <contestnumber>13000016</contestnumber>
 <JobDisplayOptions>
 <managerrequisitiontitle>Project Manager</managerrequisitiontitle>
 </JobDisplayOptions>
 </JobPositionPosting>
 </JobPositionPostings>

请提前告诉我任何解决方案。谢谢。

2 个答案:

答案 0 :(得分:1)

下面有两个解决方案,但我不得不做一些假设,因为你不清楚你的要求。第一个解决方案soap.xsl使用拉式样式,其中元素在样式表中显示。第二个解决方案soap2.xsl使用推送样式,其中元素是从属性名称合成的。在涵盖这些基础知识之后,我还不知道你还想用你的样式表做些什么。

t:\ftemp>type soap.xml 
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">     
<soapenv:Body>
 <ns1:getDocumentByKeyResponse   soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:ns1="http://www.taleo.com/ws/integration/toolkit/2005/07">
 <Document xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">
<Attributes>
 <Attribute name="duration">0:00:00.084</Attribute>
 <Attribute name="count">7</Attribute>
<Attribute name="entity">Requisition</Attribute>
<Attribute name="mode">XML</Attribute>
<Attribute name="version">http://www.taleo.com/ws/tee800/2009/01</Attribute>
</Attributes>
<Content>
<ExportXML xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">
 <record>
<field name="ContestNumber">1300000F</field>
  <field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">1300000H</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">1300000T</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">13000018</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">000123</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">1300000R</field>
<field name="ManagerRequisitionTitle">Project Manager</field>
</record>
<record>
<field name="ContestNumber">13000016</field>
 <field name="ManagerRequisitionTitle">Project Manager</field>
 </record>
</ExportXML>
</Content>
</Document>
</ns1:getDocumentByKeyResponse>
</soapenv:Body>
</soapenv:Envelope>
t:\ftemp>rmdir /s /q temp 

t:\ftemp>call xslt2 soap.xml soap.xsl 

t:\ftemp>type temp\section1.xml 
<JobPositionPostings>
   <JobPositionPosting>
      <contestnumber>1300000F</contestnumber>
      <JobDisplayOptions>
         <managerrequisitiontitle>Project Manager</managerrequisitiontitle>
      </JobDisplayOptions>
   </JobPositionPosting>
</JobPositionPostings>

t:\ftemp>dir temp 
 Volume in drive T is VBOX_t
 Volume Serial Number is 0E00-0001

 Directory of t:\ftemp\temp

2013-08-11  17:00               269 section1.xml
2013-08-11  17:00               269 section2.xml
2013-08-11  17:00               269 section3.xml
2013-08-11  17:00               269 section4.xml
2013-08-11  17:00               267 section5.xml
2013-08-11  17:00               269 section6.xml
2013-08-11  17:00               269 section7.xml
               7 File(s)          1,881 bytes
               0 Dir(s)   8,351,150,080 bytes free

t:\ftemp>type soap.xsl 
<xsl:stylesheet version="2.0"
  xpath-default-namespace="http://www.taleo.com/ws/integration/toolkit/2005/07"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:param name="pDest" select="'temp/'"/>

<xsl:template match="/">
  <xsl:for-each select="//record">
    <xsl:result-document href="{$pDest}section{position()}.xml">
      <JobPositionPostings>
        <JobPositionPosting>
          <contestnumber>
            <xsl:value-of select="field[@name='ContestNumber']"/>
          </contestnumber>
          <JobDisplayOptions>
            <managerrequisitiontitle>
              <xsl:value-of select="field[@name='ManagerRequisitionTitle']"/>
            </managerrequisitiontitle>
          </JobDisplayOptions>
        </JobPositionPosting>
      </JobPositionPostings>
    </xsl:result-document>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>rmdir /s /q temp 

t:\ftemp>call xslt2 soap.xml soap2.xsl 

t:\ftemp>type temp\section2.xml 
<JobPositionPostings>
   <JobPositionPosting>
      <contestnumber>1300000H</contestnumber>
      <JobDisplayOptions>
         <managerrequisitiontitle>Project Manager</managerrequisitiontitle>
      </JobDisplayOptions>
   </JobPositionPosting>
</JobPositionPostings>

t:\ftemp>dir temp 
 Volume in drive T is VBOX_t
 Volume Serial Number is 0E00-0001

 Directory of t:\ftemp\temp

2013-08-11  17:00               269 section1.xml
2013-08-11  17:00               269 section2.xml
2013-08-11  17:00               269 section3.xml
2013-08-11  17:00               269 section4.xml
2013-08-11  17:00               267 section5.xml
2013-08-11  17:00               269 section6.xml
2013-08-11  17:00               269 section7.xml
               7 File(s)          1,881 bytes
               0 Dir(s)   8,351,670,272 bytes free

t:\ftemp>type soap2.xsl 
<xsl:stylesheet version="2.0" 
  xpath-default-namespace="http://www.taleo.com/ws/integration/toolkit/2005/07"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:param name="pDest" select="'temp/'"/>

<xsl:template match="/">
  <xsl:for-each select="//record">
    <xsl:result-document href="{$pDest}section{position()}.xml">
      <JobPositionPostings>
        <JobPositionPosting>
          <xsl:apply-templates select="field[@name='ContestNumber']"/>
          <JobDisplayOptions>
            <xsl:apply-templates
                     select="field[@name='ManagerRequisitionTitle']"/>
          </JobDisplayOptions>
        </JobPositionPosting>
      </JobPositionPostings>
    </xsl:result-document>
  </xsl:for-each>
</xsl:template>

<xsl:template match="field">
  <xsl:element name="{lower-case(@name)}">
    <xsl:value-of select="."/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>rem Done! 

答案 1 :(得分:0)

你的XSLT遇到了一些问题,主要是名称空间。您从以下模板匹配开始

<xsl:template match="*[starts-with(name(),'ExportXML')]">

这很好,但是如果你知道 ExportXML 元素属于一个命名空间(在你的情况下它就是这样),你真的只需要这样做,但是不要命名空间。理想情况下,您应该在这里使用“local-name()”,而不是“name()”,因为name()将包含任何名称空间前缀,因此在以下情况下不起作用。

<x:ExportXML xmlns:x="http://www.taleo.com/ws/integration/toolkit/2005/07">

无论如何,您的下一行XSLT

会出现问题
<xsl:for-each select="record">

当XML中的记录元素与 ExportXML 属于同一名称空间时,这正在寻找记录元素不属于任何命名空间的一部分强>(和它的所有后代一样)。你应该在这里使用类似的语法(假设你真的不提前知道命名空间)

<xsl:for-each select="*[starts-with(local-name(),'record')]">

下一个问题是您使用的代码来获取“ContestNumber”(和“ManagerRequisitionTitle”)的值:

<xsl:apply-templates select="*:field[starts-with(@name,'ContestNumber')]"/>

除了在语法上无效之外,你也有同样的问题, field 元素也在命名空间中,所以你需要这样做

<xsl:apply-templates select="*[starts-with(local-name(), 'field')][@name='ContestNumber']"/>

虽然此处可能不需要使用 xsl:apply-templates ,但 xsl:value-of 应该这样做。

试试这个XSLT

<xsl:stylesheet version="2.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="pDest" select="'file:///c:/temp/'"/>
   <xsl:template match="*[starts-with(local-name(),'ExportXML')]">
      <xsl:for-each select="*[starts-with(local-name(),'record')]">
         <xsl:result-document href="{$pDest}section{position()}.xml">
            <JobPositionPostings>
               <JobPositionPosting>
                  <xsl:value-of select="*[starts-with(local-name(), 'field')][@name='ContestNumber']"/>
                  <JobDisplayOptions>
                     <xsl:value-of select="*[starts-with(local-name(), 'field')][@name='ManagerRequisitionTitle']"/>
                  </JobDisplayOptions>
               </JobPositionPosting>
            </JobPositionPostings>
         </xsl:result-document>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="*[starts-with(local-name(), 'Attributes')]"/>
</xsl:stylesheet>

还要注意要匹配的模板,并忽略属性,否则XSLT的内置模板会匹配这些模板,并输出文本值。

当然,如果您现在确实命名空间始终是相同的,那么您可以通过声明命名空间来简化XSLT。这个XSLT也应该有效:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.taleo.com/ws/integration/toolkit/2005/07">
   <xsl:output omit-xml-declaration="yes" indent="yes"/>
   <xsl:strip-space elements="*"/>
   <xsl:param name="pDest" select="'file:///c:/temp/'"/>
   <xsl:template match="ExportXML">
      <xsl:for-each select="record">
         <xsl:result-document href="{$pDest}section{position()}.xml">
            <JobPositionPostings>
               <JobPositionPosting>
                  <xsl:value-of select="field[@name='ContestNumber']"/>
                  <JobDisplayOptions>
                     <xsl:value-of select="field[@name='ManagerRequisitionTitle']"/>
                  </JobDisplayOptions>
               </JobPositionPosting>
            </JobPositionPostings>
         </xsl:result-document>
      </xsl:for-each>
   </xsl:template>
   <xsl:template match="Attributes"/>
</xsl:stylesheet>

编辑:测试模板的一种方法是匹配是暂时将XSLT更改为不使用 xsl:result-document 。相反,将其更改为此时输出普通元素

<!-- <xsl:result-document href="{$pDest}section{position()}.xml"> -->
<file href="{$pDest}section{position()}.xml">
   <JobPositionPostings>...</JobPositionPostings>
</file>

然后,使用XSLT测试工具(例如http://xslttest.appspot.com/)并测试XML并修改XSLT,以查看是否正在创建多个文件元素。如果是这样,您应该可以改回使用 xsl:result-document