使用php将非标准xml wsman数据加载到对象中 [英] Loading non-standard xml wsman data into object with php

查看:54
本文介绍了使用php将非标准xml wsman数据加载到对象中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题有很多不同的回答,但没有一个是针对我的情况.

This question has been answered in many variations, but none of them refer to my situation.

我正在使用 WSMan 提取数据,然后将输出作为一种 sudo-xml 返回.我什至不会认为它是真正的"xml,因为它有很多非标准属性.问题是我需要能够将输出引用为 PHP 中的对象.所以目前我使用了很多 str_replace.这样做的问题是,如果非标准格式有偏差(在某些情况下它会返回类似这样的 <KeyID xsi:nil="true"/> 在其他情况下它可能是一些东西像这样<CMCIP xsi:nil="true"/>),很难预见我将不得不考虑的所有不同属性,并在此之前从变量中提取出来使用 simplexml_load_string 将其作为对象导入.

I'm pulling data using WSMan, which then returns the output as a kind of sudo-xml. I wouldn't even consider it "real" xml, since it has so many non-standard attributes. The problem is that I need to be able to reference the output as an object within PHP. So at the moment I'm using a lot of str_replace. The problem with this is that if the non-standard format deviates (in some cases it will return something like this <KeyID xsi:nil="true"/> in other cases it might be something like this <CMCIP xsi:nil="true"/>), it is difficult to foresee all of the different attributes I'm going to have to account for and pull out of the variable before importing it as an object using simplexml_load_string.

所以,我的问题很简单:有没有办法将非标准 XML 加载到对象中?这是 xml 数据的示例,以便您了解我们在这里处理的疯狂事件.

So, my question in all simplicity : Is there a way to load non-standard XML into an object? Here is a sample of the xml data, so that you know what madness we're dealing with here.

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsen="http://schemas.xmlsoap.org/ws/2004/09/enumeration">
  <s:Header>
    <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
    <wsa:Action>http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse</wsa:Action>
    <wsa:RelatesTo>uuid:3ae2d181-04f0-14f0-8002-89040b5d1500</wsa:RelatesTo>
    <wsa:MessageID>uuid:43a291ab-04f0-14f0-8073-b516f1d9bed4</wsa:MessageID>
  </s:Header>
  <s:Body>
    <wsen:EnumerateResponse>
      <wsen:EnumerationContext>439c90e9-04f0-14f0-8072-b516f1d9bed4</wsen:EnumerationContext>
    </wsen:EnumerateResponse>
  </s:Body>
</s:Envelope>
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsen="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:n1="http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_SystemView" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <s:Header>
    <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
    <wsa:Action>http://schemas.xmlsoap.org/ws/2004/09/enumeration/PullResponse</wsa:Action>
    <wsa:RelatesTo>uuid:3af0a1eb-04f0-14f0-8003-89040b5d1500</wsa:RelatesTo>
    <wsa:MessageID>uuid:43a41fe8-04f0-14f0-8074-b516f1d9bed4</wsa:MessageID>
  </s:Header>
  <s:Body>
    <wsen:PullResponse>
      <wsen:Items>
        <n1:DCIM_SystemView>
          <n1:AssetTag/>
          <n1:BIOSReleaseDate>11/20/2013</n1:BIOSReleaseDate>
          <n1:BIOSVersionString>2.1.3</n1:BIOSVersionString>
          <n1:BaseBoardChassisSlot>NA</n1:BaseBoardChassisSlot>
          <n1:BatteryRollupStatus>1</n1:BatteryRollupStatus>
          <n1:BladeGeometry>255</n1:BladeGeometry>
          <n1:BoardPartNumber>061P35A00</n1:BoardPartNumber>
          <n1:BoardSerialNumber>CN70163231007K</n1:BoardSerialNumber>
          <n1:CMCIP xsi:nil="true"/>
          <n1:CPLDVersion>1.0.3</n1:CPLDVersion>
          <n1:CPURollupStatus>1</n1:CPURollupStatus>
          <n1:ChassisModel/>
          <n1:ChassisName>Main System Chassis</n1:ChassisName>
          <n1:ChassisServiceTag>REMOVED</n1:ChassisServiceTag>
          <n1:ChassisSystemHeight>2</n1:ChassisSystemHeight>
          <n1:DeviceDescription>System</n1:DeviceDescription>
          <n1:ExpressServiceCode>33088672189</n1:ExpressServiceCode>
          <n1:FQDD>System.Embedded.1</n1:FQDD>
          <n1:FanRollupStatus>1</n1:FanRollupStatus>
          <n1:HostName/>
          <n1:InstanceID>System.Embedded.1</n1:InstanceID>
          <n1:LastSystemInventoryTime>20140928010936.000000+000</n1:LastSystemInventoryTime>
          <n1:LastUpdateTime>20140220171215.000000+000</n1:LastUpdateTime>
          <n1:LicensingRollupStatus>1</n1:LicensingRollupStatus>
          <n1:LifecycleControllerVersion>2.1.0</n1:LifecycleControllerVersion>
          <n1:Manufacturer>Dell Inc.</n1:Manufacturer>
          <n1:MaxCPUSockets>2</n1:MaxCPUSockets>
          <n1:MaxDIMMSlots>24</n1:MaxDIMMSlots>
          <n1:MaxPCIeSlots>6</n1:MaxPCIeSlots>
          <n1:MemoryOperationMode>OptimizerMode</n1:MemoryOperationMode>
          <n1:Model>PowerEdge R720xd</n1:Model>
          <n1:NodeID>F7852V1</n1:NodeID>
          <n1:PSRollupStatus>1</n1:PSRollupStatus>
          <n1:PlatformGUID>3156324f-c0c6-3580-3810-00374c4c4544</n1:PlatformGUID>
          <n1:PopulatedCPUSockets>2</n1:PopulatedCPUSockets>
          <n1:PopulatedDIMMSlots>8</n1:PopulatedDIMMSlots>
          <n1:PopulatedPCIeSlots>2</n1:PopulatedPCIeSlots>
          <n1:PowerCap>598</n1:PowerCap>
          <n1:PowerCapEnabledState>3</n1:PowerCapEnabledState>
          <n1:PowerState>2</n1:PowerState>
          <n1:PrimaryStatus>1</n1:PrimaryStatus>
          <n1:RollupStatus>1</n1:RollupStatus>
          <n1:ServerAllocation xsi:nil="true"/>
          <n1:ServiceTag>REMOVED</n1:ServiceTag>
          <n1:StorageRollupStatus>1</n1:StorageRollupStatus>
          <n1:SysMemErrorMethodology>6</n1:SysMemErrorMethodology>
          <n1:SysMemFailOverState>NotInUse</n1:SysMemFailOverState>
          <n1:SysMemLocation>3</n1:SysMemLocation>
          <n1:SysMemMaxCapacitySize>1572864</n1:SysMemMaxCapacitySize>
          <n1:SysMemPrimaryStatus>1</n1:SysMemPrimaryStatus>
          <n1:SysMemTotalSize>65536</n1:SysMemTotalSize>
          <n1:SystemGeneration>12G Monolithic</n1:SystemGeneration>
          <n1:SystemID>1320</n1:SystemID>
          <n1:SystemRevision>0</n1:SystemRevision>
          <n1:TempRollupStatus>1</n1:TempRollupStatus>
          <n1:UUID>4c4c4544-0037-3810-8035-c6c04f325631</n1:UUID>
          <n1:VoltRollupStatus>1</n1:VoltRollupStatus>
          <n1:smbiosGUID>44454c4c-3700-1038-8035-c6c04f325631</n1:smbiosGUID>
        </n1:DCIM_SystemView>
      </wsen:Items>
      <wsen:EndOfSequence/>
    </wsen:PullResponse>
  </s:Body>
</s:Envelope>

推荐答案

作为响应/输出返回的是多个 XML 文档的串联.在您的示例中,它们是两个.

What you get back as response/output is a concatenation of multiple XML documents. In your example those are two.

这不是有效的 XML,但也很常见.

This isn't valid XML but it's also not uncommon.

所以您需要做的就是拆分文档并选择您需要处理的文档(在您的示例中是第二个):

So all you need to do is to split the documents and pick the one you need want to deal with (in your example the second):

$split = preg_split('~\Q<?xml version="1.0" encoding="UTF-8"?>\E\R~u', $sequenced_xml, 2, PREG_SPLIT_NO_EMPTY);
$xml   = simplexml_load_string($split[1]);

由于您现在拥有感兴趣的 XML 文档,因此您可以按照许多其他答案所建议的方法解析 SOAP 响应.不再有格式错误的 XML(实际上是一系列格式正确的 XML 文档串联在一起).

As you now have the XML document your're interested in, you can do what all the many other answers suggest on how to parse the SOAP Response. There is no malformed XML (which actually was a sequence of concatenated wellformed XML documents) any longer.

剩下的就是处理命名空间.

The rest is dealing with the namespaces.

一些提示:

... 获取 SOAP 信封正文:

... to get the SOAP envelope body:

$soap = 'http://www.w3.org/2003/05/soap-envelope';
$body = $xml->children($soap)->Body;

...作为数组的所有枚举项:

... all enumerated items as array:

$wsen = 'http://schemas.xmlsoap.org/ws/2004/09/enumeration';
$xml->registerXPathNamespace('wsen', $wsen);
$items = $body->xpath('.//wsen:*/*[not(namespace-uri(.) = namespace-uri(..))]');

等等等等.

关于您在答案中给出的代码示例的注释:如果您要在任何命名空间中查找元素名称,您可以在 xpath 中使用 local-name():

a note on your own code-example you've given in your answer: if you're looking for an element name in any namespace, you can do this in xpath with local-name():

$pullitem = 'ServiceTag';
$try      = $xml->xpath(sprintf("//*[local-name(.)='%s']", $pullitem));

printf("pullitem '%s' has been foun in the following namespaces:\n", $pullitem);
foreach ($try as $element) {
    $nsURI = dom_import_simplexml($element)->namespaceURI;
    printf(" - %s\n", $nsURI);
}

这确实省去了您五个左右的单独 xpath 调用.

that does spare you your five or so individual xpath calls.

如果您最终不想关心命名空间,因为您希望它无论如何都是每个项目的那个",您可以在 DOMDocument 的帮助下,通过将每个结果提取到一个新的结果中,为每个结果创建一个 SimpleXMLElement它自己的文档:

and if you finally don't want to care about the namespace as you expect it to be "that one" of each item anyway, you can with the help of DOMDocument create a SimpleXMLElement for each result by extracting each into a new document of it's own:

/**
 * create a new SimpleXMLElement out of an existing one
 *
 * @param SimpleXMLElement $item
 *
 * @return SimpleXMLElement
 */
function simplexml_export_element(SimpleXMLElement $item) {
    $doc  = new DOMDocument();
    $node = $doc->importNode(dom_import_simplexml($item), true);
    $node = $doc->appendChild($node);
    return simplexml_load_string($doc->saveXML($doc->documentElement), get_class($item), 0, $node->namespaceURI);
}

这样的辅助例程很有用,因为它将元素自己的命名空间作为新 SimpleXMLElement 的命名空间.这允许直接访问同一命名空间中的子项.进一步使用它的代码不需要特别关心这个默认"命名空间.

Such a helper routine is helpful as it puts the element's own namespace as the namespace for the new SimpleXMLElement. This allows to directly access children in the same namespace. Code using it further on won't need to care about this "default" namespace specifically.

示例:

$split = preg_split('~\Q<?xml version="1.0" encoding="UTF-8"?>\E\R~u', $sequenced_xml, 2, PREG_SPLIT_NO_EMPTY);

$xml  = new SimpleXMLElement($split[1]);

$soap = 'http://www.w3.org/2003/05/soap-envelope';
$body = $xml->children($soap)->Body;

$wsen = 'http://schemas.xmlsoap.org/ws/2004/09/enumeration';
$xml->registerXPathNamespace('wsen', $wsen);

$enumerated = $body->xpath('.//wsen:*/*[not(namespace-uri(.) = namespace-uri(..))]');
$enumerated = array_map('simplexml_export_element', $enumerated);

foreach ($enumerated as $item) {
    echo $item->getName(), "\n";
    foreach ($item as $key => $value) {
        printf(" - %s: %s\n", $key, $value);
    }
}

输出:

DCIM_SystemView
 - AssetTag: 
 - BIOSReleaseDate: 11/20/2013
 - BIOSVersionString: 2.1.3
 - BaseBoardChassisSlot: NA
 - BatteryRollupStatus: 1
 - BladeGeometry: 255
 - BoardPartNumber: 061P35A00
 - BoardSerialNumber: CN70163231007K
 - CMCIP: 
 - CPLDVersion: 1.0.3
 - CPURollupStatus: 1
 - ChassisModel: 
 - ChassisName: Main System Chassis
 - ChassisServiceTag: REMOVED
 - ChassisSystemHeight: 2
 - DeviceDescription: System
 - ExpressServiceCode: 33088672189
 - FQDD: System.Embedded.1
 - FanRollupStatus: 1
 - HostName: 
 - InstanceID: System.Embedded.1
 - LastSystemInventoryTime: 20140928010936.000000+000
 - LastUpdateTime: 20140220171215.000000+000
 - LicensingRollupStatus: 1
 - LifecycleControllerVersion: 2.1.0
 - Manufacturer: Dell Inc.
 - MaxCPUSockets: 2
 - MaxDIMMSlots: 24
 - MaxPCIeSlots: 6
 - MemoryOperationMode: OptimizerMode
 - Model: PowerEdge R720xd
 - NodeID: F7852V1
 - PSRollupStatus: 1
 - PlatformGUID: 3156324f-c0c6-3580-3810-00374c4c4544
 - PopulatedCPUSockets: 2
 - PopulatedDIMMSlots: 8
 - PopulatedPCIeSlots: 2
 - PowerCap: 598
 - PowerCapEnabledState: 3
 - PowerState: 2
 - PrimaryStatus: 1
 - RollupStatus: 1
 - ServerAllocation: 
 - ServiceTag: REMOVED
 - StorageRollupStatus: 1
 - SysMemErrorMethodology: 6
 - SysMemFailOverState: NotInUse
 - SysMemLocation: 3
 - SysMemMaxCapacitySize: 1572864
 - SysMemPrimaryStatus: 1
 - SysMemTotalSize: 65536
 - SystemGeneration: 12G Monolithic
 - SystemID: 1320
 - SystemRevision: 0
 - TempRollupStatus: 1
 - UUID: 4c4c4544-0037-3810-8035-c6c04f325631
 - VoltRollupStatus: 1
 - smbiosGUID: 44454c4c-3700-1038-8035-c6c04f325631

希望这对您的情况仍然有帮助.

Hope this is still helpful in your case.

这篇关于使用php将非标准xml wsman数据加载到对象中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆