简体   繁体   English

使用php将非标准xml wsman数据加载到对象中

[英]Loading non-standard xml wsman data into object with php

This question has been answered in many variations, but none of them refer to my situation. 这个问题在许多变化中得到了回答,但没有一个涉及我的情况。

I'm pulling data using WSMan, which then returns the output as a kind of sudo-xml. 我使用WSMan提取数据,然后将输出作为一种sudo-xml返回。 I wouldn't even consider it "real" xml, since it has so many non-standard attributes. 我甚至不认为它是“真正的”xml,因为它有很多非标准属性。 The problem is that I need to be able to reference the output as an object within PHP. 问题是我需要能够将输出作为PHP中的对象引用。 So at the moment I'm using a lot of str_replace. 所以目前我正在使用很多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. 这个问题是,如果非标准格式偏离(在某些情况下,它会返回类似这样的<KeyID xsi:nil="true"/>在其他情况下它可能是这样的<CMCIP xsi:nil="true"/> ),在使用simplexml_load_string将其作为对象导入之前,很难预见到我将要考虑的所有不同属性并将其拉出。

So, my question in all simplicity : Is there a way to load non-standard XML into an object? 所以,我的问题很简单:有没有办法将非标准XML加载到对象中? Here is a sample of the xml data, so that you know what madness we're dealing with here. 这是一个xml数据的示例,以便您知道我们在这里处理的是什么疯狂。

<?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>

What you get back as response/output is a concatenation of multiple XML documents. 您作为响应/输出返回的是多个XML文档的串联。 In your example those are two. 在你的例子中,那是两个。

This isn't valid XML but it's also not uncommon. 这不是有效的XML,但它也并不罕见。

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]);

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. 由于您现在拥有您感兴趣的XML文档,因此您可以执行许多其他答案建议如何解析SOAP响应。 There is no malformed XML (which actually was a sequence of concatenated wellformed XML documents) any longer. 不再存在格式错误的XML(实际上是一系列连接良好的XML文档)。

The rest is dealing with the namespaces. 其余的是处理命名空间。

Some pointers: 一些指示:

... to get the SOAP envelope body: ...获取SOAP信封体:

$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(..))]');

and so on and so forth. 等等等等。

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() : 关于您自己的代码的注释 - 您在答案中给出的示例:如果您在任何命名空间中查找元素名称,则可以使用local-name()在xpath中执行此操作:

$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);
}

that does spare you your five or so individual xpath calls. 这样可以省去你的五个左右的xpath调用。

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: 如果您最终不想关心命名空间,因为您希望它是每个项目的“那一个”,您可以在DOMDocument的帮助下为每个结果创建一个SimpleXMLElement,方法是将每个结果提取到一个新的文档中。拥有:

/**
 * 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);
}

Such a helper routine is helpful as it puts the element's own namespace as the namespace for the new SimpleXMLElement. 这样的辅助例程很有用,因为它将元素自己的命名空间作为新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. 进一步使用它的代码将不需要特别关注这个“默认”命名空间。

Example: 例:

$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);
    }
}

Output: 输出:

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. 希望这对你的情况仍然有用。

Thanks you @Paul Crovella for your comment, this actually got me on the right track. 谢谢@Paul Crovella的评论,这实际上让我走上正轨。 I ended up learning a lot. 我最终学到了很多东西。 In any case, the solution ended up being a combination of things. 无论如何,解决方案最终成为了事物的组合。 This post was of the most help, however : 这篇文章是最有帮助的,但是:

How do I read SOAP reply Envelope by PHP 如何通过PHP读取SOAP回复包络

For those of you curious how I got it working, I ended up writing a function that will parse this out for me. 对于那些好奇我是如何工作的人,我最终编写了一个函数来解析这个问题。 For your convinience it's located below. 为了您的方便,它位于下方。 Hopefully this helps someone else down the road who is looking for the same thing I was! 希望这有助于其他人在寻找同样的事情!

function pull_wsman_idrac($run_iDRAC_IP,$user,$pass,$namespace,$pullitem,$context="NULL"){
    //Example pull_wsman("10.10.10.10","root","calvin","DCIM_SystemView","ServiceTag")
    //Possible namespaces are listed on the DCIM profile page on Dell's website. http://en.community.dell.com/techcenter/systems-management/w/wiki/1906.dcim-library-profile
    //Namspaces used (primary) : DCIM_SystemView, DCIM_CPUView, DCIM_ControllerView, DCIM_VFlashView, DCIM_MemoryView, DCIM_PCIDeviceView, DCIM_NICView, DCIM_IDRACCARDView
    $wsman_output = shell_exec("wsman enumerate http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/root/dcim/$namespace -h $run_iDRAC_IP -V -v -c dummy.cert -P 443 -u $user -p $pass -j utf-8 -y basic");
    $wsman_output = preg_replace('/\<\?xml version="1.0" encoding="UTF-8"\?\>/', '', $wsman_output);
    $wsman_output = preg_replace('/\<\?xml version="1.0" encoding="utf-8"\?\>/', '', $wsman_output);
    $wsman_output = trim($wsman_output);
    $conv = <<<XML  
    <root> $wsman_output </root> 
    XML;
    $xml = new SimpleXMLElement($conv);
    $xml->registerXPathNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
    $xml->registerXPathNamespace("wsa", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
    $xml->registerXPathNamespace("wsen", "http://schemas.xmlsoap.org/ws/2004/09/enumeration");
    $xml->registerXPathNamespace("n1", "http://schemas.dell.com/wbem/wscim/1/cim-schema/2/$namespace");
    $xml->registerXPathNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    if($context == "NULL"){
        $try = $xml->xpath("//s:$pullitem");
        if(!empty($try)){ $cpath="s"; goto gotit;   }
        $try = $xml->xpath("//wsa:$pullitem");
        if(!empty($try)){ $cpath="wsa"; goto gotit; }
        $try = $xml->xpath("//wsen:$pullitem");
        if(!empty($try)){ $cpath="wsen"; goto gotit;    }
        $try = $xml->xpath("//n1:$pullitem");
        if(!empty($try)){ $cpath="n1"; goto gotit;  }
        $try = $xml->xpath("//xsi:$pullitem");
        if(!empty($try)){ $cpath="xsi"; goto gotit; }
        gotit:
        if(empty($cpath)){ return 0; }
            else{
                $a = array();
                $i = 0;
                foreach($try as $tried){
                    foreach($tried->xpath("//n1:*") as $trys) { 
                    $go = $trys->getName();
                    //$i++; echo "$i : " . $go . "\n";
                    $a[] = $go;
                }
            }
            $a = array_unique($a);
            return $a;      
        }
    }
    elseif($context !== "NULL"){
        $try = $xml->xpath("//$context:$pullitem");
        $a = array();
        foreach($try as $extract){
            $a[] = $extract;
        }
        if(!empty($a)){
            return $a;
        }
        else{ return 0; }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM