XSLT& XPath非常复杂的数据转换

时间:2013-04-11 15:12:44

标签: xml xslt serialization xpath

我正在研究以各种XML格式提供数据的东西,虽然我可以弄清楚如何解析它的大部分内容,但我对XSLT和XPath知之甚少知道从哪里开始汇总这个多重转换的类型,其中一些数据显然只是查找,一些数据重复,元素必须重命名,一些数据在属性中,一些在值中,模板可能必须按特定顺序处理或用变量调用。我不认为这里有这种类型的例子,如果我们能得到一个,它可能会为人们解决很多问题。

目标是从几个来源获取输入,这些来源以不同的形式提供类似的数据,将它们转换为通用的XML表单,并且只写入一(1)个程序处理路径,而不是我们现在拥有的四(4)个保持。此外,翻译应该很容易反序列化。

无论如何,这是一个INPUT文件的公平示例:

<?xml version="1.0" encoding="utf-8"?>
<PackageName TransmissionID="0792d49a-c09b-4094-9f4e-2357a042865c">
  <Version>1.0</Version>
  <DateReported>04/12/2010</DateReported>
  <TimeReported>10:16:46.9385105</TimeReported>
  <!-- Status=Disposition -->
  <ReportPackage Status="Disposition1">
    <Addresses>
      <Address>
        <!-- PersonAddress -->
        <Name>Stephen Stipulate</Name>
        <Address>1200 Any Street</Address>
        <City>Some City</City>
        <State>XX</State>
        <Zip>12345</Zip>
        <Phone>800-555-1212</Phone>
      </Address>
    </Addresses>
    <Parts packageID="APackageId">
      <packageClientAccount>00000000</packageClientAccount>
      <DiscardedIdentifier id="NothingOfInterest">
        <AssemblyId>
          <IdValue>0547224801-0908</IdValue>
        </AssemblyId>
        <!-- Status -->
        <AssemblyStatus>
          <Status>OutOfStock</Status>
          <DateReOrderReceived>2009-09-24T06:09:00</DateReOrderReceived>
        </AssemblyStatus>
        <PartVendor>
          <!-- VendorAddress -->
          <VendorName>Roger Refactor</VendorName>
          <VendorAddress>
            <IdValue name="Address">100 An Avenue Suite 13</IdValue>
            <IdValue name="City">A Different City</IdValue>
            <IdValue name="State">YY</IdValue>
            <IdValue name="Zip">54321</IdValue>
            <IdValue name="Phone">866-555-1212</IdValue>
          </VendorAddress>
        </PartVendor>
        <PartsMainSegment>
          <AdditionalSegment>
            <PartSpecs>
              <Spec>
                <PartId>123456</PartId>
                <Name>Widget1</Name>
                <ThresholdLevel>000500</ThresholdLevel>
              </Spec>
              <Spec>
                <PartId>234567</PartId>
                <Name>Widget2</Name>
                <ThresholdLevel>000200</ThresholdLevel>
              </Spec>
            </PartSpecs>
          </AdditionalSegment>
        </PartsMainSegment>
        <AdditionallPartsSegment>
          <Spec>
            <PartId>123456</PartId>
            <PartType>ABC</PartType>
          </Spec>
          <Spec>
            <PartId>234567</PartId>
            <PartType>CBA</PartType>
          </Spec>
        </AdditionallPartsSegment>
        <AdditionalItems type="RawData" qualifier="mode" vendor="rogerRefactor">
          <Text>AModeValue</Text>
        </AdditionalItems>
        <AdditionalItems type="RawData" qualifier="indicator" vendor="rogerRefactor">
          <Text>AnIndicator</Text>
        </AdditionalItems>
      </DiscardedIdentifier>
    </Parts>
  </ReportPackage>
</PackageName>

所需的OUTPUT文件:

<?xml version="1.0" encoding="utf-8"?>
<Package>
  <TransmissionID>0792d49a-c09b-4094-9f4e-2357a042865c</TransmissionID>
  <PackageType>PackageName</PackageType>
  <Version>1.0</Version>
  <DateReported>1/03/2011</DateReported>
  <TimeReported>16:25:35.1293170</TimeReported>
  <Disposition>Disposition1</Disposition>>
  <packageID>APackageId</packageID>
  <packageClientAccount>00000000</packageClientAccount>
  <Addresses>
    <PersonAddress>
      <Name>Stephen Stipulate</Name>
      <Address>1200 Any Street</Address>
      <City>Some City</City>
      <State>XX</State>
      <Zip>12345</Zip>
      <Phone>800-555-1212</Phone>
    </PersonAddress>
    <VendorAddress>
      <Name>Roger Refactor</Name>
      <Address>100 An Avenue Suite 13</Address>
      <City>A Different City</City>
      <State>YY</State>
      <Zip>54321</Zip>
      <Phone>866-555-1212</Phone>
    </VendorAddress>
  </Addresses>
  <Parts>
    <AssemblyId id="0547224801-0908">
      <Status>OutOfStock</Status>
      <DateReOrderReceived>2009-09-24T06:09:00</DateReOrderReceived>
      <Part>
        <PartId>123456</PartId>
        <PartName>Widget1</PartName>
        <Level>000500</Level>
        <PartType>ABC</PartType>
      </Part>
      <Part>
        <PartId>234567</PartId>
        <PartNameName>Widget2</PartNameName>
        <Level>000200</Level>
        <PartType>CBA</PartType>
      </Part>
    </AssemblyId>
  </Parts>
  <AdditionalData>
    <Vendor>TheVendor</Vendor>
    <Mode>AModeValue</Mode>
    <Indicator>AnIndicator</Indicator>
  </AdditionalData>
</Package>

我们实际上将XML报告给Web服务。注意所需的重命名,数据移动到树的不同部分,特别是必须连接的不同段,以创建没有父/子关系的部分记录列表。我没有提供任何糟糕的启动尝试,因为我不知道从哪里开始,因为我根本不明白如何对处理进行排序,我确信有人在那里(Dimitre!),而不是故意,会让我看起来像个白痴! :)

非常感谢所有帮助 - 干杯! :)

1 个答案:

答案 0 :(得分:2)

这样的东西非常简单,主要是编写单个模板并使用XPath选择器从XML树中提取信息。

目前尚不清楚某些项目是否可以多次出现 - 例如VendorAddress - 但此变换至少会根据您提供的输入创建所需的输出。

Package/AdditionalData/Vendor存在问题,因为您说您希望值为TheVendor,但此字符串不会出现在源数据中。我从PartVendor/VendorName取而代之。也没有任何内容可以将该名称与vendor="rogerRefactor"的{​​{1}}属性联系起来,但我相信您会对这些内容进行排序。

AdditionalItems

<强>输出

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/PackageName">
        <Package>
            <TransmissionID><xsl:value-of select="@TransmissionID"/></TransmissionID>
            <PackageType>PackageName</PackageType>
            <xsl:copy-of select="Version"/>
            <xsl:copy-of select="DateReported"/>
            <xsl:copy-of select="TimeReported"/>
            <Disposition><xsl:value-of select="ReportPackage/@Status"/></Disposition>
            <packageID><xsl:value-of select="ReportPackage/Parts/@packageID"/></packageID>
            <packageClientAccount><xsl:value-of select="ReportPackage/Parts/packageClientAccount"/></packageClientAccount>
            <Addresses>
                <PersonAddress>
                    <xsl:apply-templates select="ReportPackage/Addresses/Address"/>
                </PersonAddress>
                <VendorAddress>
                    <xsl:apply-templates select="ReportPackage/Parts//PartVendor"/>
                </VendorAddress>
            </Addresses>
            <xsl:apply-templates select="ReportPackage/Parts"/>
            <AdditionalData>
                <Vendor><xsl:value-of select=".//PartVendor/VendorName"/></Vendor>
                <Mode><xsl:value-of select=".//AdditionalItems[@qualifier='mode']/Text"/></Mode>
                <Indicator><xsl:value-of select=".//AdditionalItems[@qualifier='indicator']/Text"/></Indicator>
            </AdditionalData>
        </Package>
    </xsl:template>

    <xsl:template match="Parts">
        <Parts>
            <AssemblyId>
                <xsl:attribute name="id">
                    <xsl:value-of select=".//AssemblyId/IdValue"/>
                </xsl:attribute>
                <Status><xsl:value-of select=".//AssemblyStatus/Status"/></Status>
                <DateReOrderReceived><xsl:value-of select=".//AssemblyStatus/DateReOrderReceived"/></DateReOrderReceived>
                <xsl:for-each select=".//PartsMainSegment/AdditionalSegment/PartSpecs/Spec">
                    <Part>
                        <xsl:variable name="part-id" select="PartId"/>
                        <PartId><xsl:value-of select="PartId"/></PartId>
                        <PartName><xsl:value-of select="Name"/></PartName>
                        <Level><xsl:value-of select="ThresholdLevel"/></Level>
                        <PartType><xsl:value-of select="//AdditionallPartsSegment/Spec[PartId = $part-id]/PartType"/></PartType>
                    </Part>
                </xsl:for-each>
            </AssemblyId>
        </Parts>
    </xsl:template>

    <xsl:template match="Address">
        <Name><xsl:value-of select="Name"/></Name>
        <Address><xsl:value-of select="Address"/></Address>
        <City><xsl:value-of select="City"/></City>
        <State><xsl:value-of select="State"/></State>
        <Zip><xsl:value-of select="Zip"/></Zip>
        <Phone><xsl:value-of select="Phone"/></Phone>
    </xsl:template>

    <xsl:template match="PartVendor">
        <Name><xsl:value-of select="VendorName"/></Name>
        <Address><xsl:value-of select="VendorAddress/IdValue[@name='Address']"/></Address>
        <City><xsl:value-of select="VendorAddress/IdValue[@name='City']"/></City>
        <State><xsl:value-of select="VendorAddress/IdValue[@name='State']"/></State>
        <Zip><xsl:value-of select="VendorAddress/IdValue[@name='Zip']"/></Zip>
        <Phone><xsl:value-of select="VendorAddress/IdValue[@name='Phone']"/></Phone>
    </xsl:template>

</xsl:stylesheet>