简体   繁体   中英

Transform atrribute in XML to JSON

I have a XML document and want to transform it into a JSON string:

<?xml  version="1.0" encoding="UTF-8"?>
<root name="test-root">
<id lang="en">9876</id>
<jobCode name="Teacher" xmlns:teacher="http://example.com/ns/teacher">1009</jobCode>
</root>

I use this custom config to do it:

let $config := json:config("custom")     
let $_ := map:put( $config, "whitespace", "ignore" )
let $_ := map:put( $config, "ignore-attribute-names",(xs:QName("name"),xs:QName("lang")) )
return json:transform-to-json( fn:doc("/test1.xml"),$config)

Below is the output of this script:

{
    "root": {
        "id": "9876", 
        "jobCode": "1009"
    }
}

It is not what i expected, I want to include the name attribute in element root but ignore the name attribute in element jobCode . what i expected is like below:

{
    "root": {
        "name": "test-root",
        "id": "9876", 
        "jobCode": "1009"
    }
}

How can I custom the config to get this output? Thanks!

I don't believe the option is as advanced as you are hoping.

In this case, I would use a stylesheet to pre-process my XML to massage it a bit more. Here's a working sample:

  xquery version "1.0-ml";
import module namespace json="http://marklogic.com/xdmp/json"
 at "/MarkLogic/json/json.xqy";


let $xml := <root name="test-root">
<id lang="en">9876</id>
<jobCode name="Teacher"    xmlns:teacher="http://example.com/ns/teacher">1009</jobCode>
</root>

let $template := <xsl:stylesheet version="1.0"     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@name[name(./..) = 'jobCode']" />

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

let $filtered-xml := xdmp:xslt-eval($template, $xml)

let $config := json:config("custom")     
let $_ := map:put( $config, "whitespace", "ignore" )
let $_ := map:put( $config, "ignore-attribute-names",(xs:QName("lang")) )
return json:transform-to-json( $filtered-xml,$config)

results:

{
  "root": {
    "name": "test-root",
    "id": "9876",
    "jobCode": "1009"
  }
}

And if you go this route, then you can also just match on the @lang in the template as well and remove the ignore-attribute config all-together.

In your original, both the name attributes are in the unnamed namespace. Elements, but not attributes, inherit the namespace of the current scope. by specifying to ignore all attributes QName("name") the processor is correctly omitting all "name" attributes. I understand this is not what you 'wanted' but on reflection, it should be what you 'expect' ... ie how is the code to know the difference between root/@name and jobCode/@name when both name attributes are the same QName?

David (Ennis)'s approach is (one of) the recommended approaches to this kind of problem. The json:xxx code is a convenience library that addresses common use cases reasonably well and reasonably simply, but as a compromprise doent address every use case simply, if at all.

Often a combination of pre-transformation then json:xxx calls is useful if your input is and output 'almost but not quite' ... Then sometimes a simple transformation of just the problem cases followed by the json:xxx library is a reasonable tradeoff.

In particular in ML 8.0 and above the result of json:transform-from-xml() produces a native JSON Object (not a string). Depending on your use case, this can be a significant difference -- it does not require re-parsing to turn into native JSON. On the other hand it does require serialization to turn into a string.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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