【问题标题】:replacing xml values and attributes with json file in php用php中的json文件替换xml值和属性
【发布时间】:2018-12-11 04:32:05
【问题描述】:

我正在尝试更改 xml 文件。示例文件如下所示

<?xml version="1.0" encoding="UTF-8" ?>
<country>
<display>
    <identification>
        <country>nl</country>
        <identifier>ABC01</identifier>
    </identification>
</display>
<region>
    <publicationTime>2018-04-18T09:45:00Z</publicationTime>
    <publicationCreator>
        <identifier>ABC01</identifier>
    </publicationCreator>
    <tableLoc id="ABC01_SITE_TABLE" version="14"/>
    <measurements>
        <siteLoc id="ABC01_ABC01" version="7"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC02" version="7"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC03" version="7"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC04" version="7"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC17" version="7"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC19" version="9"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC18" version="9"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC15" version="7"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC09" version="7"/>
    </measurements>
    <measurements>
        <siteLoc id="ABC01_ABC011" version="7"/>
    </measurements>
</region>
</country>

首先我需要更改 2 个标识符的标签值

<identifier>ABC01</identifier>

<identifier>NLNDW</identifier>

成功了。然后我不得不改变

的属性
<tableLoc id="ABC01_SITE_TABLE" version="14"/>

<tableLoc id="NDW_01_MT" version="14"/>

最后我需要用 json 文件中的相应 id 覆盖所有 siteloc 属性版本:

{
"ABC01": {
    "ABC01_ABC01": 9,
    "ABC01_ABC02": 7,
    "ABC01_ABC03": 4,
    "ABC01_ABC04": 1,
    "ABC01_ABC05": 2,
    "ABC01_ABC06": 16,
    "ABC01_ABC07": 3,
    "ABC01_ABC08": 8,
    "ABC01_ABC09": 7,
    "ABC01_ABC10": 6,
    "ABC01_ABC11": 4,
    "ABC01_ABC12": 3,
    "ABC01_ABC13": 2,
    "ABC01_ABC14": 2,
    "ABC01_ABC15": 2,
    "ABC01_ABC16": 3,
    "ABC01_ABC17": 5,
    "ABC01_ABC18": 5,
    "ABC01_ABC19": 2,
    "ABC01_ABC20": 3,
    "ABC01_ABC21": 5,
    "ABC01_ABC22": 39,
    "ABC01_ABC23": 23,
    "ABC01_ABC24": 13,
    "ABC01_ABC25": 1,
    "ABC01_ABC26": 1,
    "ABC01_ABC27": 3
},
"ABC02": {
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 2,
    "ABC02_ABC02": 3,
    "ABC02_ABC02": 2
},
"VWY09": {
    "VWY09_VWY10": 1,
    "VWY09_VWY11": 1,
    "VWY09_VWY12": 1,
    "VWY09_VWY13": 1,
    "VWY09_VWY14": 1,
    "VWY09_VWY15": 1,
    "VWY09_VWY16": 1,
    "VWY09_VWY17": 1,
    "VWY09_VWY18": 1,
    "VWY09_VWY19": 1
},
"GAD02": {
    "GAD02_XRZ01": 2,
    "GAD02_XRZ02": 2,
    "GAD02_XRZ03": 2,
    "GAD02_XRZ04": 2,
    "GAD02_XRZ05": 2,
    "GAD02_XRZ06": 2,
    "GAD02_XRZ07": 2,
    "GAD02_XRZ08": 2
}
}

例如

<measurements>
    <siteLoc id="ABC01_ABC03" version="7"/>
</measurements>

需要成为:

<measurements>
    <siteLoc id="ABC01_ABC03" version="4"/>
</measurements>

到目前为止我的代码:

$identification = new DomDocument;
$identification2 = new DomDocument;
$identification3 = new DomDocument;
$identification_node = $identification ->createElement('identification');
$identification_node2 = $identification2  ->createElement('publicationCreator');
$identification_node3 = $identification3 ->createElement('tableLoc');

// Add some children
$identification_node->appendChild($identification->createElement('country', 'nl'));
$identification_node->appendChild($identification->createElement('identifier', 'NLNDW'));
$identification_node2->appendChild($identification2->createElement('identifier     ', 'NLNDW'));
$newnode3 = $identification3->appendChild($identification_node3);
$newnode3->setAttribute("align", "left");

$identification->appendChild($identification_node);
$identification2->appendChild($identification_node2);

$dom = new DomDocument;
$dom->loadXML($xml);

$xpath = new DOMXpath($dom);
$xpath1 = new DOMXpath($dom);
$xpath2 = new DOMXpath($dom);


$nodelist = $xpath->query('/country/display/identification');
$nodelist1 = $xpath1->query('/country/region/publicationCreator');
$oldnode = $nodelist->item(0);
$oldnode1 = $nodelist1->item(0);

$newnode = $dom->importNode($identification->documentElement, true);
$newnode1 = $dom->importNode($identification2->documentElement, true);

$oldnode->parentNode->replaceChild($newnode, $oldnode);
$oldnode1->parentNode->replaceChild($newnode1, $oldnode1);

echo $dom->saveXML($dom);
$dom->save('result.xml');

我知道如何遍历 xml,但我不知道如何在 json 文件中找到匹配的 siteloc id 属性并用 json 中的版本覆盖 siteloc 版本属性。

我们将不胜感激

【问题讨论】:

    标签: php json xml domdocument


    【解决方案1】:

    考虑XSLT,这是一种专用语言,旨在转换XML 文件,例如替换节点和属性文本。 PHP 可以使用其php-xsl 类运行 XSLT 1.0 脚本,需要在 .ini 文件中启用扩展。

    但是,首先需要将相对扁平的 JSON 转换为 PHP 可以构建的 XML,然后 XSLT 脚本将递归引用以使用 document() 函数跨文档映射所需的站点位置值。请务必将两个 XML 文件(原始源文件和 json 转换后的文件)保存在同一目录中。

    PHP (JSON 转换的 XML;仅在使用循环的地方)

    $data = json_decode($site_json, TRUE);
    
    // Create a DOM document 
    $dom = new DOMDocument('1.0', 'UTF-8');
    $dom->formatOutput = true;
    $dom->preserveWhiteSpace = false;
    
    // Create the root element of XML tree
    $root = $dom->createElement("site_locations");
    $root = $dom->appendChild($root);
    
    // Iterate json elements for child nodes
    foreach ($data as $outer) {      
        foreach ($outer as $k=>$v) {  
            $node = $dom->createElement('site');
            $root->appendChild($node);
            $node->setAttribute("id", $k);
            $node->setAttribute("version", $v);
        }
    }
    
    // Output XML content to screen
    echo $dom->saveXML();
    // <?xml version="1.0"?>
    // <site_locations>
    //   <site id="ABC01_ABC01" version="9"/>
    //   <site id="ABC01_ABC02" version="7"/>
    //   <site id="ABC01_ABC03" version="4"/>
    //   <site id="ABC01_ABC04" version="1"/>
    //   <site id="ABC01_ABC05" version="2"/>
    //   <site id="ABC01_ABC06" version="16"/>
    //   ...
    
    // Output XML content to file
    file_put_contents("SiteLocationsLookups.xml", $dom->saveXML());
    

    XSLT 脚本 (另存为.xsl 文件,特殊的.xml 文件)

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="identifier">
        <xsl:copy>NLNDW</xsl:copy>
      </xsl:template>
    
      <xsl:template match="tableLoc">
        <xsl:copy>      
          <xsl:attribute name="id">NDW_01_MT</xsl:attribute>
          <xsl:copy-of select="@version"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="siteLoc">
        <xsl:copy>
          <xsl:variable name="curr_id"><xsl:value-of select="@id"/></xsl:variable>
          <xsl:apply-templates select="@*"/>
          <xsl:attribute name="version">
             <xsl:value-of select="document('SiteLocationsLookups.xml')//site[@id=$curr_id]/@version"/>
          </xsl:attribute>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    PHP (处理最终的 XML)

    // Load XML and XSLT files
    $doc = new DOMDocument();
    $doc->load('Input.xml');
    
    $xsl = new DOMDocument;
    $xsl->load('XSLT_Script.xsl');              // REFERENCES JSON CONVERTED XML
    
    // Configure the transformer
    $proc = new XSLTProcessor;
    $proc->importStyleSheet($xsl); 
    
    // Transform XML source
    $newXml = $proc->transformToXML($doc);
    
    // Save output to file
    file_put_contents('Output.xml', $newXml);
    

    XML 输出

    <?xml version="1.0" encoding="utf-8"?>
    <country>
      <display>
        <identification>
          <country>nl</country>
          <identifier>NLNDW</identifier>
        </identification>
      </display>
      <region>
        <publicationTime>2018-04-18T09:45:00Z</publicationTime>
        <publicationCreator>
          <identifier>NLNDW</identifier>
        </publicationCreator>
        <tableLoc id="NDW_01_MT" version="14" />
        <measurements>
          <siteLoc id="ABC01_ABC01" version="9" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC02" version="7" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC03" version="4" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC04" version="1" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC17" version="5" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC19" version="2" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC18" version="5" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC15" version="2" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC09" version="7" />
        </measurements>
        <measurements>
          <siteLoc id="ABC01_ABC011" version="" />
        </measurements>
      </region>
    </country>
    

    【讨论】:

    • 您的代码运行良好,但是当我使用不同的 xml(带有命名空间)尝试它时,当我删除所有命名空间时,它似乎不起作用。我不知道当命名空间在 xml 中时可能会出现问题。谢谢你的回答
    • 当然,名称空间会影响 XML 解析和 XSLT 处理!始终,始终,始终,将它们包含在原始帖子中。但我看到你找到了一个解决方案,但是是的,这可以更新以处理命名空间。
    • 是的,吸取了教训。不过我很好奇,你能给我一个关于如何调整代码以处理命名空间的提示吗?。
    • 请使用命名空间发布您的 XML。
    • xsl:stylesheet 元素上添加命名空间定义,并根据需要在 Xpath 表达式中使用前缀。
    【解决方案2】:

    为什么要创建 4 个不同的 DOM 文档?要替换你只需要一个的数据,加载原始数据并替换它。

    $document = new DOMDocument();
    // load the original data
    $document->loadXml($xml);
    $xpath = new DOMXpath($document);
    
    // iterate any "identifier" element node
    foreach ($xpath->evaluate('//identifier') as $identifier) {
      // change its content
      $identifier->textContent = 'NLNDW';
    }
    // iterate any "id" attribute of an "tableLoc" node 
    foreach ($xpath->evaluate('//tableLoc/@id') as $tableLocId) {
      // change its value
      $tableLocId->value = 'NDW_01_MT';
    }
    
    // decode json, force arrays
    $map = json_decode($json, TRUE);
    
    // iterate any "siteLoc" element node in the document
    foreach ($xpath->evaluate('//siteLoc[@id]') as $siteLocation) {
      // read the "id"attribute
      $id = $siteLocation->getAttribute('id');
      // the json seems to be grouped by the first part
      $groupId = strstr($id, '_', TRUE);
      // check if here is a new value
      if (isset($map[$groupId][$id])) {
        // change the version attribute
        $siteLocation->setAttribute('version', $map[$groupId][$id]);
      } 
    }
    
    // output/save the modified document
    echo $document->saveXml();
    

    【讨论】:

    • 回答你的问题,因为这是我第一次接触 PHP。您的解决方案非常适合问题中提到的 xml,我在另一个带有命名空间的 xml 上尝试了它,调整了 php 脚本,令我惊讶的是它不再起作用了。我不知道为什么它不起作用。经过一番搜索,我发现我必须使用 getElementsByTagNameNS。我还没有成功转换xml thgough。
    • 在 $xpath 对象上注册一个命名空间前缀并在表达式中使用它。
    猜你喜欢
    • 1970-01-01
    • 2012-11-15
    • 2012-12-15
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    • 2019-05-01
    • 2012-08-03
    • 2020-07-20
    相关资源
    最近更新 更多