如何从XSLT中的输入XML中删除大多数命名空间(nokogiri示例)

时间:2011-03-02 19:39:55

标签: ruby xml xslt nokogiri

我有这段nokogiri代码,运行速度慢,然后我喜欢大输入。你会如何在XSLT中重做这个?还有其他想法让它运行得更快吗?

# remove namespaces (other then soapenv) from input xml, and move
# them to type attribute.
# xml is Nokogiri::XML object
def cleanup_namespaces(xml)
  protected_ns = %w( soapenv )
  xml.traverse do |el|
    next unless el.respond_to? :namespace
    if (ns=el.namespace) && 
        !protected_ns.include?(ns.prefix) then
      el['type'] = "#{ns.prefix}:#{el.name}"
      el.namespace = nil
    end
  end

  xml
end

我正在测试的样本输入是:

<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:getAccountDTOResponse xmlns:ns1="http://www.example.com/pw/services/PWServices"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

      <getAccountDTOReturn xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:ns2="urn:PWServices"
      soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
      xsi:type="ns2:Account">
        <ns1:ID soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xsi:type="xsd:long">0</ns1:ID>
        <ns1:accountNumber xsi:type="soapenc:string" />
        <ns1:accountType xsi:type="soapenc:string" />
        <ns1:clientData xsi:type="soapenc:Array" xsi:nil="true" />
        <ns1:name xsi:type="soapenc:string" />
        <ns1:parentRef xsi:type="soapenc:string" />
      </getAccountDTOReturn>
    </ns1:getAccountDTOResponse>
  </soapenv:Body>
</soapenv:Envelope>

预期的输出是:

<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <getAccountDTOResponse xmlns:ns1="http://www.example.com/pw/services/PWServices"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    type="ns1:getAccountDTOResponse">
      <getAccountDTOReturn xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:ns2="urn:PWServices"
      soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
      xsi:type="ns2:Account">
        <ID soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xsi:type="xsd:long" type="ns1:ID">0</ID>
        <accountNumber xsi:type="soapenc:string"
        type="ns1:accountNumber" />
        <accountType xsi:type="soapenc:string"
        type="ns1:accountType" />
        <clientData xsi:type="soapenc:Array" xsi:nil="true"
        type="ns1:clientData" />
        <name xsi:type="soapenc:string" type="ns1:name" />
        <parentRef xsi:type="soapenc:string"
        type="ns1:parentRef" />
      </getAccountDTOReturn>
    </getAccountDTOResponse>
  </soapenv:Body>
</soapenv:Envelope>

此输入是SOAP响应。一个切线问题是,什么是 SOAP响应中ns1类型命名空间的重点,是它 合理的把它们扔掉。我似乎不需要 在解析响应时引用它们。

1 个答案:

答案 0 :(得分:4)

这个XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@* | node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[namespace-uri() =
        'http://www.example.com/pw/services/PWServices']">
        <xsl:element name="{local-name()}">
            <xsl:attribute name="type">
                <xsl:value-of select="name()"/>
            </xsl:attribute>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

针对您的样本将产生以下结果:

<?xml version="1.0" encoding="UTF-16"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <getAccountDTOResponse type="ns1:getAccountDTOResponse" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <getAccountDTOReturn soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:Account" xmlns:ns1="http://www.example.com/pw/services/PWServices" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:PWServices">
                <ID type="ns1:ID" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:long">0</ID>
                <accountNumber type="ns1:accountNumber" xsi:type="soapenc:string"></accountNumber>
                <accountType type="ns1:accountType" xsi:type="soapenc:string"></accountType>
                <clientData type="ns1:clientData" xsi:type="soapenc:Array" xsi:nil="true"></clientData>
                <name type="ns1:name" xsi:type="soapenc:string"></name>
                <parentRef type="ns1:parentRef" xsi:type="soapenc:string"></parentRef>
            </getAccountDTOReturn>
        </getAccountDTOResponse>
    </soapenv:Body>
</soapenv:Envelope>